From 150e03e1fdac05f1dd878ee87329b611132171d0 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Sun, 16 Mar 2025 13:52:33 -0700 Subject: [PATCH] test(theme): add unit tests --- tests/Theme.test.svelte | 24 ---- tests/Theme/Theme.test.svelte | 23 +++ tests/Theme/Theme.test.ts | 168 ++++++++++++++++++++++ tests/Theme/ThemeSelect.test.svelte | 10 ++ tests/Theme/ThemeSelectCustom.test.svelte | 15 ++ tests/Theme/ThemeToggle.test.svelte | 10 ++ tests/Theme/ThemeToggleCustom.test.svelte | 17 +++ 7 files changed, 243 insertions(+), 24 deletions(-) delete mode 100644 tests/Theme.test.svelte create mode 100644 tests/Theme/Theme.test.svelte create mode 100644 tests/Theme/Theme.test.ts create mode 100644 tests/Theme/ThemeSelect.test.svelte create mode 100644 tests/Theme/ThemeSelectCustom.test.svelte create mode 100644 tests/Theme/ThemeToggle.test.svelte create mode 100644 tests/Theme/ThemeToggleCustom.test.svelte diff --git a/tests/Theme.test.svelte b/tests/Theme.test.svelte deleted file mode 100644 index 929e5386..00000000 --- a/tests/Theme.test.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - - console.log(e.detail.theme)} - tokens={{ "button-primary": "violet" }} - render="toggle" - toggle={{ - themes: ["g10", "g90"], - labelA: "", - labelB: "", - }} - select={{ - themes: ["g10", "g90"], - labelText: "", - }} -/> diff --git a/tests/Theme/Theme.test.svelte b/tests/Theme/Theme.test.svelte new file mode 100644 index 00000000..1fadc6b3 --- /dev/null +++ b/tests/Theme/Theme.test.svelte @@ -0,0 +1,23 @@ + + + + +
+ { + console.log("update", detail); + }} + > + + +
diff --git a/tests/Theme/Theme.test.ts b/tests/Theme/Theme.test.ts new file mode 100644 index 00000000..9758855a --- /dev/null +++ b/tests/Theme/Theme.test.ts @@ -0,0 +1,168 @@ +import { render, screen } from "@testing-library/svelte"; +import { tick } from "svelte"; +import { user } from "../setup-tests"; +import Theme from "./Theme.test.svelte"; +import ThemeSelect from "./ThemeSelect.test.svelte"; +import ThemeSelectCustom from "./ThemeSelectCustom.test.svelte"; +import ThemeToggle from "./ThemeToggle.test.svelte"; +import ThemeToggleCustom from "./ThemeToggleCustom.test.svelte"; + +describe("Theme", () => { + let documentMock: { + setAttribute: ReturnType; + style: { setProperty: ReturnType }; + }; + let consoleLog: ReturnType; + let localStorageMock: Record; + let originalLocalStorage: Storage; + + beforeEach(() => { + documentMock = { + setAttribute: vi.spyOn(document.documentElement, "setAttribute"), + style: { + setProperty: vi.spyOn(document.documentElement.style, "setProperty"), + }, + }; + consoleLog = vi.spyOn(console, "log"); + originalLocalStorage = global.localStorage; + localStorageMock = {}; + + global.localStorage = { + getItem: vi.fn((key) => localStorageMock[key] || null), + setItem: vi.fn((key, value) => { + localStorageMock[key] = value; + }), + removeItem: vi.fn((key) => { + delete localStorageMock[key]; + }), + clear: vi.fn(() => { + localStorageMock = {}; + }), + length: 0, + key: vi.fn(), + }; + }); + + afterEach(() => { + vi.restoreAllMocks(); + global.localStorage = originalLocalStorage; + localStorage.clear(); + localStorageMock = {}; + }); + + it("should set default theme to white", () => { + render(Theme); + expect(documentMock.setAttribute).toHaveBeenCalledWith("theme", "white"); + }); + + it("should update theme attribute when theme changes", async () => { + const { component } = render(Theme); + + component.$set({ theme: "g100" }); + await tick(); + + expect(documentMock.setAttribute).toHaveBeenCalledWith("theme", "g100"); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "g100" }); + }); + + it("should apply custom tokens", async () => { + const tokens = { + "interactive-01": "#ff0000", + "ui-background": "#ffffff", + }; + + render(Theme, { props: { tokens } }); + await tick(); + + expect(documentMock.style.setProperty).toHaveBeenCalledWith( + "--cds-interactive-01", + "#ff0000", + ); + expect(documentMock.style.setProperty).toHaveBeenCalledWith( + "--cds-ui-background", + "#ffffff", + ); + }); + + it("should persist theme in localStorage when persist is true", async () => { + render(Theme, { props: { persist: true } }); + await tick(); + + expect(localStorage.setItem).toHaveBeenCalledWith("theme", "white"); + }); + + it("should load persisted theme from localStorage", async () => { + localStorageMock["theme"] = "g90"; + + render(Theme, { props: { persist: true } }); + await tick(); + + expect(documentMock.setAttribute).toHaveBeenCalledWith("theme", "g90"); + }); + + it("should warn on invalid theme", async () => { + const consoleWarn = vi.spyOn(console, "warn"); + const { component } = render(Theme); + + // @ts-ignore - Testing invalid theme + component.$set({ theme: "invalid" }); + await tick(); + + expect(consoleWarn).toHaveBeenCalledWith( + expect.stringContaining('invalid theme "invalid"'), + ); + }); + + it("should render toggle when render prop is set to toggle", async () => { + render(ThemeToggle); + + const toggle = screen.getByLabelText("Dark mode"); + expect(toggle).toBeInTheDocument(); + expect(toggle).toHaveAttribute("type", "checkbox"); + + await user.click(toggle); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "g100" }); + + await user.click(toggle); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "white" }); + }); + + it("should render custom toggle when render prop is set to toggle and custom toggle options are provided", async () => { + render(ThemeToggleCustom); + + const toggle = screen.getAllByText("Enable dark mode")[0]; + expect(toggle).toBeInTheDocument(); + + await user.click(toggle); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "g80" }); + + await user.click(toggle); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "g10" }); + }); + + it("should render select when render prop is set to select", async () => { + render(ThemeSelect); + + const select = screen.getByLabelText("Themes"); + expect(select).toBeInTheDocument(); + + await user.selectOptions(select, "g100"); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "g100" }); + + await user.selectOptions(select, "white"); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "white" }); + }); + + it("should render custom select when render prop is set to select and custom select options are provided", async () => { + render(ThemeSelectCustom); + + const select = screen.getByLabelText("Select a theme"); + expect(select).toBeInTheDocument(); + + await user.selectOptions(select, "g100"); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "g100" }); + + await user.selectOptions(select, "white"); + expect(consoleLog).toHaveBeenCalledWith("update", { theme: "white" }); + }); +}); diff --git a/tests/Theme/ThemeSelect.test.svelte b/tests/Theme/ThemeSelect.test.svelte new file mode 100644 index 00000000..3648b3ef --- /dev/null +++ b/tests/Theme/ThemeSelect.test.svelte @@ -0,0 +1,10 @@ + + + { + console.log("update", detail); + }} +/> diff --git a/tests/Theme/ThemeSelectCustom.test.svelte b/tests/Theme/ThemeSelectCustom.test.svelte new file mode 100644 index 00000000..93fbfea3 --- /dev/null +++ b/tests/Theme/ThemeSelectCustom.test.svelte @@ -0,0 +1,15 @@ + + + { + console.log("update", detail); + }} +/> diff --git a/tests/Theme/ThemeToggle.test.svelte b/tests/Theme/ThemeToggle.test.svelte new file mode 100644 index 00000000..6512a23d --- /dev/null +++ b/tests/Theme/ThemeToggle.test.svelte @@ -0,0 +1,10 @@ + + + { + console.log("update", detail); + }} +/> diff --git a/tests/Theme/ThemeToggleCustom.test.svelte b/tests/Theme/ThemeToggleCustom.test.svelte new file mode 100644 index 00000000..c3f8a01e --- /dev/null +++ b/tests/Theme/ThemeToggleCustom.test.svelte @@ -0,0 +1,17 @@ + + + { + console.log("update", detail); + }} +/>