From 51ccc8a4d6ea5aa7a82c44aa898cbb44046db3cf Mon Sep 17 00:00:00 2001 From: Eva Decker Date: Thu, 28 Nov 2024 00:25:31 -0500 Subject: [PATCH] Test coverage --- .../EditQuestCostsModal.test.tsx | 13 -- .../EditQuestTimeRequiredModal.test.tsx | 131 ++++++++++++++++-- .../quests/QuestCosts/QuestCosts.test.tsx | 20 ++- .../QuestTimeRequired.test.tsx | 93 +++++++++++++ vitest.setup.ts | 14 ++ 5 files changed, 239 insertions(+), 32 deletions(-) create mode 100644 src/components/quests/QuestTimeRequired/QuestTimeRequired.test.tsx diff --git a/src/components/quests/EditQuestCostsModal/EditQuestCostsModal.test.tsx b/src/components/quests/EditQuestCostsModal/EditQuestCostsModal.test.tsx index 85d5012..f5b35a8 100644 --- a/src/components/quests/EditQuestCostsModal/EditQuestCostsModal.test.tsx +++ b/src/components/quests/EditQuestCostsModal/EditQuestCostsModal.test.tsx @@ -6,19 +6,6 @@ import { toast } from "sonner"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { EditQuestCostsModal } from "./EditQuestCostsModal"; -// Mock the convex mutation hook -vi.mock("convex/react", () => ({ - useMutation: vi.fn(), -})); - -// Mock toast notifications -vi.mock("sonner", () => ({ - toast: { - success: vi.fn(), - error: vi.fn(), - }, -})); - describe("EditQuestCostsModal", () => { const mockQuest = { _id: "quest123" as Id<"quests">, diff --git a/src/components/quests/EditQuestTimeRequiredModal/EditQuestTimeRequiredModal.test.tsx b/src/components/quests/EditQuestTimeRequiredModal/EditQuestTimeRequiredModal.test.tsx index c164ded..af3808f 100644 --- a/src/components/quests/EditQuestTimeRequiredModal/EditQuestTimeRequiredModal.test.tsx +++ b/src/components/quests/EditQuestTimeRequiredModal/EditQuestTimeRequiredModal.test.tsx @@ -6,19 +6,6 @@ import { toast } from "sonner"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { EditQuestTimeRequiredModal } from "./EditQuestTimeRequiredModal"; -// Mock the convex mutation hook -vi.mock("convex/react", () => ({ - useMutation: vi.fn(), -})); - -// Mock toast notifications -vi.mock("sonner", () => ({ - toast: { - success: vi.fn(), - error: vi.fn(), - }, -})); - describe("EditQuestTimeRequiredModal", () => { const mockQuest = { _id: "quest123" as Id<"quests">, @@ -72,6 +59,124 @@ describe("EditQuestTimeRequiredModal", () => { expect(descriptionInput.value).toBe("Depends on court processing time"); }); + it("updates max time value", async () => { + const user = userEvent.setup(); + mockUpdateTimeRequired.mockResolvedValueOnce(undefined); + + render( + , + ); + + const maxInput = screen + .getAllByLabelText("Est. max time")[0] + .closest("input") as HTMLInputElement; + + await user.clear(maxInput); + await user.type(maxInput, "6"); + + await user.click(screen.getByText("Save")); + + expect(mockUpdateTimeRequired).toHaveBeenCalledWith({ + timeRequired: { + min: 2, + max: 6, + unit: "weeks", + description: "Depends on court processing time", + }, + questId: "quest123", + }); + }); + + it("updates time unit", async () => { + const user = userEvent.setup(); + mockUpdateTimeRequired.mockResolvedValueOnce(undefined); + + render( + , + ); + + const unitSelect = screen.getByLabelText("Unit"); + await user.click(unitSelect); + await user.click(screen.getByRole("option", { name: "Days" })); + + await user.click(screen.getByText("Save")); + + expect(mockUpdateTimeRequired).toHaveBeenCalledWith({ + timeRequired: { + min: 2, + max: 4, + unit: "days", + description: "Depends on court processing time", + }, + questId: "quest123", + }); + }); + + it("updates description", async () => { + const user = userEvent.setup(); + mockUpdateTimeRequired.mockResolvedValueOnce(undefined); + + render( + , + ); + + const descriptionInput = screen.getByLabelText("Description"); + await user.clear(descriptionInput); + await user.type(descriptionInput, "New description"); + + await user.click(screen.getByText("Save")); + + expect(mockUpdateTimeRequired).toHaveBeenCalledWith({ + timeRequired: { + min: 2, + max: 4, + unit: "weeks", + description: "New description", + }, + questId: "quest123", + }); + }); + + it("sets description to undefined when empty", async () => { + const user = userEvent.setup(); + mockUpdateTimeRequired.mockResolvedValueOnce(undefined); + + render( + , + ); + + const descriptionInput = screen.getByLabelText("Description"); + await user.clear(descriptionInput); + + await user.click(screen.getByText("Save")); + + expect(mockUpdateTimeRequired).toHaveBeenCalledWith({ + timeRequired: { + min: 2, + max: 4, + unit: "weeks", + description: undefined, + }, + questId: "quest123", + }); + }); + it("handles successful save", async () => { const user = userEvent.setup(); mockUpdateTimeRequired.mockResolvedValueOnce(undefined); diff --git a/src/components/quests/QuestCosts/QuestCosts.test.tsx b/src/components/quests/QuestCosts/QuestCosts.test.tsx index 1c9945e..9d98f8d 100644 --- a/src/components/quests/QuestCosts/QuestCosts.test.tsx +++ b/src/components/quests/QuestCosts/QuestCosts.test.tsx @@ -1,14 +1,9 @@ import type { Doc, Id } from "@convex/_generated/dataModel"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; import { QuestCosts } from "./QuestCosts"; -// Mock the convex mutation hook -vi.mock("convex/react", () => ({ - useMutation: vi.fn(), -})); - describe("QuestCosts", () => { const mockQuest = { _id: "quest123" as Id<"quests">, @@ -23,6 +18,14 @@ describe("QuestCosts", () => { costs: [], } as Partial>; + const mockQuestZeroCost = { + _id: "quest789" as Id<"quests">, + costs: [ + { cost: 0, description: "Free application" }, + { cost: 0, description: "No filing fee" }, + ], + } as Doc<"quests">; + it("displays costs in a description list with total", async () => { render(); @@ -60,6 +63,11 @@ describe("QuestCosts", () => { expect(screen.getByText("Free")).toBeInTheDocument(); }); + it("displays 'Free' when total cost is 0 but costs array is not empty", () => { + render(); + expect(screen.getByText("Free")).toBeInTheDocument(); + }); + it("shows edit button when editable prop is true", async () => { const user = userEvent.setup(); render(); diff --git a/src/components/quests/QuestTimeRequired/QuestTimeRequired.test.tsx b/src/components/quests/QuestTimeRequired/QuestTimeRequired.test.tsx new file mode 100644 index 0000000..e731730 --- /dev/null +++ b/src/components/quests/QuestTimeRequired/QuestTimeRequired.test.tsx @@ -0,0 +1,93 @@ +import type { Doc, Id } from "@convex/_generated/dataModel"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it } from "vitest"; +import { QuestTimeRequired } from "./QuestTimeRequired"; + +describe("QuestTimeRequired", () => { + const mockQuest = { + _id: "quest123" as Id<"quests">, + timeRequired: { + min: 2, + max: 4, + unit: "weeks", + description: "Processing time varies by court", + }, + } as Doc<"quests">; + + const mockQuestNoDescription = { + _id: "quest456" as Id<"quests">, + timeRequired: { + min: 1, + max: 3, + unit: "months", + }, + } as Doc<"quests">; + + const mockQuestNoTimeRequired = { + _id: "quest789" as Id<"quests">, + } as Doc<"quests">; + + it("returns null when quest is undefined", () => { + const { container } = render( + } />, + ); + expect(container.firstChild).toBeNull(); + }); + + it("formats and displays time required correctly", () => { + render(); + expect(screen.getByText("2–4 weeks")).toBeInTheDocument(); + }); + + it("displays 'Unknown' when timeRequired is not set", () => { + render(); + expect(screen.getByText("Unknown")).toBeInTheDocument(); + }); + + it("shows description in popover when available", async () => { + const user = userEvent.setup(); + render(); + + // Find and click the popover trigger + const popoverTrigger = screen.getByRole("button", { + name: "See details", + }); + await user.click(popoverTrigger); + + // Check if description is shown + expect( + screen.getByText("Processing time varies by court"), + ).toBeInTheDocument(); + }); + + it("does not show description popover when description is not available", () => { + render(); + expect( + screen.queryByRole("button", { name: "See details" }), + ).not.toBeInTheDocument(); + }); + + it("shows edit button when editable prop is true", async () => { + const user = userEvent.setup(); + render(); + + // Check if edit button is present + const editButton = screen.getByRole("button", { + name: "Edit time required", + }); + expect(editButton).toBeInTheDocument(); + + // Click edit button and check if modal opens + await user.click(editButton); + const modal = await screen.findByRole("dialog"); + expect(modal).toBeInTheDocument(); + }); + + it("hides edit button when editable prop is false", () => { + render(); + expect( + screen.queryByRole("button", { name: "Edit time required" }), + ).not.toBeInTheDocument(); + }); +}); diff --git a/vitest.setup.ts b/vitest.setup.ts index f149f27..2bd3841 100644 --- a/vitest.setup.ts +++ b/vitest.setup.ts @@ -1 +1,15 @@ import "@testing-library/jest-dom/vitest"; +import { vi } from "vitest"; + +// Mock the convex mutation hook +vi.mock("convex/react", () => ({ + useMutation: vi.fn(), +})); + +// Mock toast notifications +vi.mock("sonner", () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +}));