From db797a8ac0c96e4c971cc4faca214a5f241e0153 Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Tue, 17 Dec 2024 18:30:56 +0100 Subject: [PATCH 1/8] test: Add unit tests for EditThemeSetting component --- .../EditThemeSetting.test.tsx | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx diff --git a/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx b/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx new file mode 100644 index 0000000..fe11b7e --- /dev/null +++ b/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx @@ -0,0 +1,74 @@ +import { useTheme } from "@/utils/useTheme"; +import { THEMES } from "@convex/constants"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { EditThemeSetting } from "./EditThemeSetting"; + +describe("EditThemeSetting", () => { + // Mock the useTheme hook + vi.mock("@/utils/useTheme", () => ({ + useTheme: vi.fn(), + })); + + const mockUpdateTheme = vi.fn(); + const mockSetNextTheme = vi.fn(); + const mockThemeSelection = new Set(["light"]); + + beforeEach(() => { + vi.clearAllMocks(); + (useTheme as unknown as ReturnType).mockReturnValue({ + theme: "light", + themeSelection: mockThemeSelection, + setTheme: vi.fn((theme) => { + const selectedTheme = [...theme][0]; + mockUpdateTheme({ theme: selectedTheme }); + mockSetNextTheme(selectedTheme); + }), + }); + }); + + it("renders component correctly", () => { + render(); + expect(screen.getByText("Theme")).toBeInTheDocument(); + expect(screen.getByText("Adjust your display.")).toBeInTheDocument(); + for (const theme of Object.values(THEMES)) { + expect(screen.getByText(theme.label)).toBeInTheDocument(); + } + }); + + it("renders the correct initial theme", () => { + render(); + const lightThemeButton = screen.getByRole("radio", { + name: THEMES.light.label, + }); + expect(lightThemeButton).toHaveAttribute("aria-checked", "true"); + }); + + it("calls setTheme when a theme is selected", async () => { + const user = userEvent.setup(); + render(); + const darkThemeButton = screen.getByRole("radio", { + name: THEMES.dark.label, + }); + await user.click(darkThemeButton); + expect(mockUpdateTheme).toHaveBeenCalledWith({ theme: "dark" }); + expect(mockSetNextTheme).toHaveBeenCalledWith("dark"); + }); + + it("displays the correct selected theme", () => { + render(); + const lightThemeButton = screen.getByRole("radio", { + name: THEMES.light.label, + }); + expect(lightThemeButton).toHaveAttribute("aria-checked", "true"); + const darkThemeButton = screen.getByRole("radio", { + name: THEMES.dark.label, + }); + expect(darkThemeButton).not.toHaveAttribute("aria-checked", "true"); + const systemThemeButton = screen.getByRole("radio", { + name: THEMES.system.label, + }); + expect(systemThemeButton).not.toHaveAttribute("aria-checked", "true"); + }); +}); From 3a951196c30eaf2db56d0717e61145c0c7892599 Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Tue, 17 Dec 2024 18:36:28 +0100 Subject: [PATCH 2/8] test: Add unit tests for EditMinorSetting component --- .../EditMinorSetting.test.tsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/components/settings/EditMinorSetting/EditMinorSetting.test.tsx diff --git a/src/components/settings/EditMinorSetting/EditMinorSetting.test.tsx b/src/components/settings/EditMinorSetting/EditMinorSetting.test.tsx new file mode 100644 index 0000000..bd53705 --- /dev/null +++ b/src/components/settings/EditMinorSetting/EditMinorSetting.test.tsx @@ -0,0 +1,46 @@ +import type { Doc, Id } from "@convex/_generated/dataModel"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { useMutation } from "convex/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { EditMinorSetting } from "./EditMinorSetting"; + +describe("EditMinorSetting", () => { + const mockUser: Doc<"users"> = { + _id: "user123" as Id<"users">, + isMinor: false, + _creationTime: 123, + role: "user", + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders correctly with initial state", () => { + render(); + + expect(screen.getByText("Under 18")).toBeInTheDocument(); + expect( + screen.getByText( + "Are you under 18 years old or applying on behalf of someone who is?", + ), + ).toBeInTheDocument(); + expect(screen.getByRole("switch", { name: "Is minor" })).not.toBeChecked(); + }); + + it("toggles the switch and calls updateIsMinor mutation", async () => { + const user = userEvent.setup(); + const updateIsMinorMock = vi.fn(); + (useMutation as ReturnType).mockReturnValue( + updateIsMinorMock, + ); + + render(); + + const freeSwitch = screen.getByRole("switch", { name: "Is minor" }); + await user.click(freeSwitch); + + expect(updateIsMinorMock).toHaveBeenCalledWith({ isMinor: true }); + }); +}); From b3333e7ca1193b6cb1601c19aa14e962cd875876 Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Tue, 17 Dec 2024 18:38:35 +0100 Subject: [PATCH 3/8] test: Add unit tests for EditNameSetting component --- .../EditNameSetting/EditNameSetting.test.tsx | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/components/settings/EditNameSetting/EditNameSetting.test.tsx diff --git a/src/components/settings/EditNameSetting/EditNameSetting.test.tsx b/src/components/settings/EditNameSetting/EditNameSetting.test.tsx new file mode 100644 index 0000000..d637a16 --- /dev/null +++ b/src/components/settings/EditNameSetting/EditNameSetting.test.tsx @@ -0,0 +1,102 @@ +import type { Doc, Id } from "@convex/_generated/dataModel"; +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { useMutation } from "convex/react"; +import { toast } from "sonner"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { EditNameSetting } from "./EditNameSetting"; + +describe("EditNameSetting", () => { + const mockUser: Doc<"users"> = { + _id: "123" as Id<"users">, + name: "John Doe", + role: "user", + _creationTime: 123, + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders the EditNameSetting component", () => { + render(); + expect(screen.getByText("Name")).toBeInTheDocument(); + expect( + screen.getByText("How should Namesake refer to you?"), + ).toBeInTheDocument(); + expect(screen.getByText("John Doe")).toBeInTheDocument(); + }); + + it("opens the modal when the button is clicked", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: "John Doe" })); + expect(screen.getByText("Edit name")).toBeInTheDocument(); + }); + + it("displays an error when the name is too long", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: "John Doe" })); + const input = screen.getByLabelText("Name"); + + await user.type(input, "a".repeat(101)); + await user.click(screen.getByRole("button", { name: "Save" })); + + expect( + await screen.findByText("Name must be less than 100 characters"), + ).toBeInTheDocument(); + }); + + it("submits the form successfully", async () => { + const user = userEvent.setup(); + + const updateName = vi.fn(); + (useMutation as ReturnType).mockReturnValue(updateName); + render(); + await user.click(screen.getByRole("button", { name: "John Doe" })); + + const input = screen.getByLabelText("Name"); + await user.clear(input); + await user.type(input, "Jane Doe"); + await user.click(screen.getByRole("button", { name: "Save" })); + + await waitFor(() => + expect(updateName).toHaveBeenCalledWith({ name: "Jane Doe" }), + ); + expect(toast.success).toHaveBeenCalledWith("Name updated."); + }); + + it("displays an error when the form submission fails", async () => { + const user = userEvent.setup(); + + const updateName = vi + .fn() + .mockRejectedValue(new Error("Failed to update name")); + (useMutation as ReturnType).mockReturnValue(updateName); + render(); + await user.click(screen.getByRole("button", { name: "John Doe" })); + + const input = screen.getByLabelText("Name"); + await user.clear(input); + await user.type(input, "Jane Doe"); + await user.click(screen.getByRole("button", { name: "Save" })); + expect( + await screen.findByText("Failed to update name. Please try again."), + ).toBeInTheDocument(); + }); + + it("closes the modal without saving when the cancel button is clicked", async () => { + const user = userEvent.setup(); + + render(); + await user.click(screen.getByRole("button", { name: "John Doe" })); + const input = screen.getByLabelText("Name"); + await user.clear(input); + await user.type(input, "Jane Doe"); + await user.click(screen.getByRole("button", { name: "Cancel" })); + + expect(screen.queryByText("Edit name")).not.toBeInTheDocument(); + expect(screen.getByText("John Doe")).toBeInTheDocument(); + }); +}); From dc41a55968f02b3c39bf62e3d251c7f7a67b1313 Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Tue, 17 Dec 2024 18:39:25 +0100 Subject: [PATCH 4/8] test: Add unit tests for DeleteAccountSetting component --- .../DeleteAccountSetting.test.tsx | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx diff --git a/src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx b/src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx new file mode 100644 index 0000000..67dc4fb --- /dev/null +++ b/src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx @@ -0,0 +1,107 @@ +import { useAuthActions } from "@convex-dev/auth/react"; +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { useMutation } from "convex/react"; +import { toast } from "sonner"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { DeleteAccountSetting } from "./DeleteAccountSetting"; + +describe("DeleteAccountSetting", () => { + vi.mock("convex/react"); + vi.mock("@convex-dev/auth/react"); + + const mockSignOut = vi.fn(); + const mockDeleteAccount = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + (useMutation as unknown as ReturnType).mockReturnValue( + mockDeleteAccount, + ); + (useAuthActions as unknown as ReturnType).mockReturnValue({ + signOut: mockSignOut, + }); + }); + + it("renders the DeleteAccountSetting component", () => { + render(); + expect( + screen.getByRole("button", { name: "Delete account" }), + ).toBeInTheDocument(); + expect( + screen.getByText("Permanently delete your Namesake account and data."), + ).toBeInTheDocument(); + }); + + it("opens the delete account modal when the button is clicked", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: "Delete account" })); + expect(screen.getByText("Delete account?")).toBeInTheDocument(); + expect( + screen.getByText( + "This will permanently erase your account and all data.", + ), + ).toBeInTheDocument(); + }); + + it("shows an error if the confirmation text is incorrect", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: "Delete account" })); + + const input = screen.getByLabelText("Type DELETE to confirm"); + await user.type(input, "WRONG_TEXT"); + + await user.click(screen.getByRole("button", { name: "Delete account" })); + + expect( + await screen.findByText("Please type DELETE to confirm."), + ).toBeInTheDocument(); + expect(mockDeleteAccount).not.toHaveBeenCalled(); + }); + + it("submits the form successfully", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: "Delete account" })); + + const input = screen.getByLabelText("Type DELETE to confirm"); + await user.type(input, "DELETE"); + await user.click(screen.getByRole("button", { name: "Delete account" })); + + await waitFor(() => { + expect(mockDeleteAccount).toHaveBeenCalled(); + expect(mockSignOut).toHaveBeenCalled(); + expect(toast.success).toHaveBeenCalledWith("Account deleted."); + }); + }); + + it("displays an error if account deletion fails", async () => { + const user = userEvent.setup(); + mockDeleteAccount.mockRejectedValue(new Error("Deletion failed")); + + render(); + await user.click(screen.getByRole("button", { name: "Delete account" })); + + const input = screen.getByLabelText("Type DELETE to confirm"); + await user.type(input, "DELETE"); + await user.click(screen.getByRole("button", { name: "Delete account" })); + + expect( + await screen.findByText("Failed to delete account. Please try again."), + ).toBeInTheDocument(); + expect(toast.success).not.toHaveBeenCalled(); + }); + + it("closes the modal when 'Cancel' is clicked", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: "Delete account" })); + + await user.click(screen.getByRole("button", { name: "Cancel" })); + await waitFor(() => { + expect(screen.queryByText("Delete account?")).not.toBeInTheDocument(); + }); + }); +}); From f32723f5c9e6cdd020f0f8da1a2cf6e56dd477bb Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Tue, 17 Dec 2024 20:16:20 +0100 Subject: [PATCH 5/8] test: Add unit tests for EditResidenceSetting component --- .../EditResidenceSetting.test.tsx | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx diff --git a/src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx b/src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx new file mode 100644 index 0000000..07f5e45 --- /dev/null +++ b/src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx @@ -0,0 +1,84 @@ +import type { Doc, Id } from "@convex/_generated/dataModel"; +import { JURISDICTIONS } from "@convex/constants"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { useMutation } from "convex/react"; +import { toast } from "sonner"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { EditResidenceSetting } from "./EditResidenceSetting"; + +describe("EditResidenceSetting", () => { + const mockUser: Doc<"users"> = { + _id: "user123" as Id<"users">, + _creationTime: 123, + role: "user", + residence: "CA", + }; + + const mockSetResidence = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + (useMutation as unknown as ReturnType).mockReturnValue( + mockSetResidence, + ); + }); + + it("renders the EditResidenceSetting component", () => { + render(); + expect(screen.getByText("Residence")).toBeInTheDocument(); + expect( + screen.getByText( + "Where do you live? This location is used to select the forms for your court order and state ID.", + ), + ).toBeInTheDocument(); + expect(screen.getByText(JURISDICTIONS.CA)).toBeInTheDocument(); + }); + + it("opens the modal when the button is clicked", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); + expect(screen.getByText("Edit residence")).toBeInTheDocument(); + }); + + it("updates residence and submits the form", async () => { + const user = userEvent.setup(); + mockSetResidence.mockResolvedValueOnce(undefined); + + render(); + await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); + const stateSelect = screen.getByLabelText("State"); + + await user.click(stateSelect); + + await user.click(screen.getByRole("option", { name: JURISDICTIONS.NY })); + + await user.click(screen.getByRole("button", { name: "Save" })); + + expect(mockSetResidence).toHaveBeenCalledWith({ + residence: "NY", + }); + + expect(toast.success).toHaveBeenCalledWith("Residence updated."); + }); + + it("displays an error message if the update fails", async () => { + const user = userEvent.setup(); + mockSetResidence.mockRejectedValueOnce(new Error("Update failed")); + + render(); + + await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); + const stateSelect = screen.getByLabelText("State"); + await user.click(stateSelect); + + await user.click(screen.getByRole("option", { name: JURISDICTIONS.NY })); + + await user.click(screen.getByRole("button", { name: "Save" })); + + expect( + screen.getByText("Failed to update residence. Please try again."), + ).toBeInTheDocument(); + }); +}); From 64dd9dd0749cabb93aeb855444ed628e20a0d629 Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Tue, 17 Dec 2024 20:16:42 +0100 Subject: [PATCH 6/8] test: Add unit tests for EditBirthplaceSetting component --- .../EditBirthplaceSetting.test.tsx | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx diff --git a/src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx b/src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx new file mode 100644 index 0000000..ebb5708 --- /dev/null +++ b/src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx @@ -0,0 +1,83 @@ +import type { Doc, Id } from "@convex/_generated/dataModel"; +import { JURISDICTIONS } from "@convex/constants"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { useMutation } from "convex/react"; +import { toast } from "sonner"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { EditBirthplaceSetting } from "./EditBirthplaceSetting"; + +describe("EditBirthplaceSetting", () => { + const mockUser: Doc<"users"> = { + _id: "user123" as Id<"users">, + _creationTime: 123, + role: "user", + birthplace: "CA", + }; + const mockSetBirthplace = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + (useMutation as unknown as ReturnType).mockReturnValue( + mockSetBirthplace, + ); + }); + + it("renders the EditBirthplaceSetting component", () => { + render(); + expect(screen.getByText("Birthplace")).toBeInTheDocument(); + expect( + screen.getByText( + "Where were you born? This location is used to select the forms for your birth certificate.", + ), + ).toBeInTheDocument(); + expect(screen.getByText(JURISDICTIONS.CA)).toBeInTheDocument(); + }); + + it("opens the modal when the button is clicked", async () => { + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); + expect(screen.getByText("Edit birthplace")).toBeInTheDocument(); + }); + + it("updates birthplace and submits the form", async () => { + const user = userEvent.setup(); + mockSetBirthplace.mockResolvedValueOnce(undefined); + + render(); + await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); + const stateSelect = screen.getByLabelText("State"); + + await user.click(stateSelect); + + await user.click(screen.getByRole("option", { name: JURISDICTIONS.NY })); + + await user.click(screen.getByRole("button", { name: "Save" })); + + expect(mockSetBirthplace).toHaveBeenCalledWith({ + birthplace: "NY", + }); + + expect(toast.success).toHaveBeenCalledWith("Birthplace updated."); + }); + + it("displays an error message if the update fails", async () => { + const user = userEvent.setup(); + mockSetBirthplace.mockRejectedValueOnce(new Error("Update failed")); + + render(); + + await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); + const stateSelect = screen.getByLabelText("State"); + await user.click(stateSelect); + + await user.click(screen.getByRole("option", { name: JURISDICTIONS.NY })); + + await user.click(screen.getByRole("button", { name: "Save" })); + + expect( + screen.getByText("Failed to update birthplace. Please try again."), + ).toBeInTheDocument(); + }); +}); From 7bd1329c842b324e4388394c19796aa21a3538e4 Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Wed, 18 Dec 2024 21:32:21 +0100 Subject: [PATCH 7/8] test: Update unit tests for settings components to improve assertions --- src/components/common/Banner/Banner.tsx | 2 +- .../DeleteAccountSetting.test.tsx | 9 +++---- .../EditBirthplaceSetting.test.tsx | 27 +++++++++++-------- .../EditNameSetting/EditNameSetting.test.tsx | 17 +++++++----- .../EditNameSetting/EditNameSetting.tsx | 2 +- .../EditResidenceSetting.test.tsx | 21 +++++++++------ .../EditThemeSetting.test.tsx | 11 +------- tests/vitest.setup.ts | 10 +++++++ 8 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/components/common/Banner/Banner.tsx b/src/components/common/Banner/Banner.tsx index 89fc623..ecb16f5 100644 --- a/src/components/common/Banner/Banner.tsx +++ b/src/components/common/Banner/Banner.tsx @@ -63,7 +63,7 @@ export function Banner({ children, icon: Icon, variant }: BannerProps) { Icon = Icon ?? DefaultIcon(); return ( -
+
{children}
diff --git a/src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx b/src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx index 67dc4fb..fecd4d1 100644 --- a/src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx +++ b/src/components/settings/DeleteAccountSetting/DeleteAccountSetting.test.tsx @@ -7,9 +7,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { DeleteAccountSetting } from "./DeleteAccountSetting"; describe("DeleteAccountSetting", () => { - vi.mock("convex/react"); - vi.mock("@convex-dev/auth/react"); - const mockSignOut = vi.fn(); const mockDeleteAccount = vi.fn(); @@ -54,10 +51,10 @@ describe("DeleteAccountSetting", () => { await user.type(input, "WRONG_TEXT"); await user.click(screen.getByRole("button", { name: "Delete account" })); + expect(screen.getByRole("alert")).toHaveTextContent( + "Please type DELETE to confirm.", + ); - expect( - await screen.findByText("Please type DELETE to confirm."), - ).toBeInTheDocument(); expect(mockDeleteAccount).not.toHaveBeenCalled(); }); diff --git a/src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx b/src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx index ebb5708..ddac8d3 100644 --- a/src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx +++ b/src/components/settings/EditBirthplaceSetting/EditBirthplaceSetting.test.tsx @@ -23,22 +23,27 @@ describe("EditBirthplaceSetting", () => { ); }); - it("renders the EditBirthplaceSetting component", () => { + it("renders correct jurisdiction if it exists", () => { render(); - expect(screen.getByText("Birthplace")).toBeInTheDocument(); + expect(screen.getByText(JURISDICTIONS.CA)).toBeInTheDocument(); + }); + + it("renders 'Set birthplace' if birthplace is not set", () => { + render( + , + ); expect( - screen.getByText( - "Where were you born? This location is used to select the forms for your birth certificate.", - ), + screen.getByRole("button", { name: "Set birthplace" }), ).toBeInTheDocument(); - expect(screen.getByText(JURISDICTIONS.CA)).toBeInTheDocument(); }); - it("opens the modal when the button is clicked", async () => { + it("populates correct jurisdiction when modal is opened", async () => { const user = userEvent.setup(); render(); await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); - expect(screen.getByText("Edit birthplace")).toBeInTheDocument(); + expect( + screen.getByRole("button", { name: `${JURISDICTIONS.CA} State` }), + ).toBeInTheDocument(); }); it("updates birthplace and submits the form", async () => { @@ -76,8 +81,8 @@ describe("EditBirthplaceSetting", () => { await user.click(screen.getByRole("button", { name: "Save" })); - expect( - screen.getByText("Failed to update birthplace. Please try again."), - ).toBeInTheDocument(); + expect(screen.getByRole("alert")).toHaveTextContent( + "Failed to update birthplace. Please try again.", + ); }); }); diff --git a/src/components/settings/EditNameSetting/EditNameSetting.test.tsx b/src/components/settings/EditNameSetting/EditNameSetting.test.tsx index d637a16..6be7cce 100644 --- a/src/components/settings/EditNameSetting/EditNameSetting.test.tsx +++ b/src/components/settings/EditNameSetting/EditNameSetting.test.tsx @@ -18,20 +18,23 @@ describe("EditNameSetting", () => { vi.clearAllMocks(); }); - it("renders the EditNameSetting component", () => { + it("renders correct username if exists", () => { render(); - expect(screen.getByText("Name")).toBeInTheDocument(); + expect(screen.getByText("John Doe")).toBeInTheDocument(); + }); + + it("renders 'Set name' if name is not set", () => { + render(); expect( - screen.getByText("How should Namesake refer to you?"), + screen.getByRole("button", { name: "Set name" }), ).toBeInTheDocument(); - expect(screen.getByText("John Doe")).toBeInTheDocument(); }); - it("opens the modal when the button is clicked", async () => { + it("populates correct username when modal is opened", async () => { const user = userEvent.setup(); render(); await user.click(screen.getByRole("button", { name: "John Doe" })); - expect(screen.getByText("Edit name")).toBeInTheDocument(); + expect(screen.getByRole("textbox")).toHaveValue("John Doe"); }); it("displays an error when the name is too long", async () => { @@ -44,7 +47,7 @@ describe("EditNameSetting", () => { await user.click(screen.getByRole("button", { name: "Save" })); expect( - await screen.findByText("Name must be less than 100 characters"), + await screen.findByText("Name must be less than 100 characters."), ).toBeInTheDocument(); }); diff --git a/src/components/settings/EditNameSetting/EditNameSetting.tsx b/src/components/settings/EditNameSetting/EditNameSetting.tsx index 8b1df2d..38a3ce4 100644 --- a/src/components/settings/EditNameSetting/EditNameSetting.tsx +++ b/src/components/settings/EditNameSetting/EditNameSetting.tsx @@ -38,7 +38,7 @@ const EditNameModal = ({ setError(undefined); if (name.length > 100) { - setError("Name must be less than 100 characters"); + setError("Name must be less than 100 characters."); return; } diff --git a/src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx b/src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx index 07f5e45..70931b1 100644 --- a/src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx +++ b/src/components/settings/EditResidenceSetting/EditResidenceSetting.test.tsx @@ -24,22 +24,27 @@ describe("EditResidenceSetting", () => { ); }); - it("renders the EditResidenceSetting component", () => { + it("renders correct jurisdiction if it exists", () => { render(); - expect(screen.getByText("Residence")).toBeInTheDocument(); + expect(screen.getByText(JURISDICTIONS.CA)).toBeInTheDocument(); + }); + + it("renders 'Set residence' if residence is not set", () => { + render( + , + ); expect( - screen.getByText( - "Where do you live? This location is used to select the forms for your court order and state ID.", - ), + screen.getByRole("button", { name: "Set residence" }), ).toBeInTheDocument(); - expect(screen.getByText(JURISDICTIONS.CA)).toBeInTheDocument(); }); - it("opens the modal when the button is clicked", async () => { + it("populates correct jurisdiction when modal is opened", async () => { const user = userEvent.setup(); render(); await user.click(screen.getByRole("button", { name: JURISDICTIONS.CA })); - expect(screen.getByText("Edit residence")).toBeInTheDocument(); + expect( + screen.getByRole("button", { name: `${JURISDICTIONS.CA} State` }), + ).toBeInTheDocument(); }); it("updates residence and submits the form", async () => { diff --git a/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx b/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx index fe11b7e..ea33e84 100644 --- a/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx +++ b/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx @@ -6,11 +6,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { EditThemeSetting } from "./EditThemeSetting"; describe("EditThemeSetting", () => { - // Mock the useTheme hook - vi.mock("@/utils/useTheme", () => ({ - useTheme: vi.fn(), - })); - const mockUpdateTheme = vi.fn(); const mockSetNextTheme = vi.fn(); const mockThemeSelection = new Set(["light"]); @@ -28,17 +23,13 @@ describe("EditThemeSetting", () => { }); }); - it("renders component correctly", () => { + it("renders component correctly with correct initial theme", () => { render(); expect(screen.getByText("Theme")).toBeInTheDocument(); expect(screen.getByText("Adjust your display.")).toBeInTheDocument(); for (const theme of Object.values(THEMES)) { expect(screen.getByText(theme.label)).toBeInTheDocument(); } - }); - - it("renders the correct initial theme", () => { - render(); const lightThemeButton = screen.getByRole("radio", { name: THEMES.light.label, }); diff --git a/tests/vitest.setup.ts b/tests/vitest.setup.ts index 2bd3841..6681f6f 100644 --- a/tests/vitest.setup.ts +++ b/tests/vitest.setup.ts @@ -13,3 +13,13 @@ vi.mock("sonner", () => ({ error: vi.fn(), }, })); + +// Mock the auth hook +vi.mock("@convex-dev/auth/react", () => ({ + useAuthActions: vi.fn(), +})); + +// Mock the useTheme hook +vi.mock("@/utils/useTheme", () => ({ + useTheme: vi.fn(), +})); From 7a2bb002612d8680c3222de895b6e8ca6d25848f Mon Sep 17 00:00:00 2001 From: Manel BELHADJ Date: Thu, 19 Dec 2024 21:11:51 +0100 Subject: [PATCH 8/8] test: Remove redundant theme display test --- .../EditThemeSetting/EditThemeSetting.test.tsx | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx b/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx index ea33e84..8853a03 100644 --- a/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx +++ b/src/components/settings/EditThemeSetting/EditThemeSetting.test.tsx @@ -46,20 +46,4 @@ describe("EditThemeSetting", () => { expect(mockUpdateTheme).toHaveBeenCalledWith({ theme: "dark" }); expect(mockSetNextTheme).toHaveBeenCalledWith("dark"); }); - - it("displays the correct selected theme", () => { - render(); - const lightThemeButton = screen.getByRole("radio", { - name: THEMES.light.label, - }); - expect(lightThemeButton).toHaveAttribute("aria-checked", "true"); - const darkThemeButton = screen.getByRole("radio", { - name: THEMES.dark.label, - }); - expect(darkThemeButton).not.toHaveAttribute("aria-checked", "true"); - const systemThemeButton = screen.getByRole("radio", { - name: THEMES.system.label, - }); - expect(systemThemeButton).not.toHaveAttribute("aria-checked", "true"); - }); });