import { renderToStaticMarkup } from "react-dom/server"; import { afterEach, describe, expect, it, vi } from "vite-plus/test"; import { scrollToSettingsTarget, SettingsRow, SettingsSearchTargetProvider, SettingsUnavailableGroup, } from "./settingsLayout"; afterEach(() => { vi.unstubAllGlobals(); }); describe("unavailable settings", () => { it("groups disabled controls under one reason", () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain("Only available in the desktop app."); expect(markup).toContain("border-border/60"); expect(markup).toContain("[&_h3]:opacity-64"); }); }); describe("settings search targets", () => { it("does not persist destination styling in the rendered row", () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain('id="word-wrap" tabindex="-1"'); expect(markup).not.toContain("data-settings-search-target"); expect(markup).not.toContain("settings-search-target-pulse"); }); it("scrolls directly to a section header and restarts the destination pulse", () => { const sectionScrollIntoView = vi.fn(); const headerScrollIntoView = vi.fn(); const focus = vi.fn(); const remove = vi.fn(); const add = vi.fn(); const addEventListener = vi.fn(); const target = { tagName: "SECTION", firstElementChild: { scrollIntoView: headerScrollIntoView }, scrollIntoView: sectionScrollIntoView, focus, classList: { remove, add }, addEventListener, offsetWidth: 100, } as unknown as HTMLElement; vi.stubGlobal("document", { getElementById: vi.fn(() => target), }); vi.stubGlobal("window", { matchMedia: vi.fn(() => ({ matches: false })), }); expect(scrollToSettingsTarget("providers")).toBe(true); expect(headerScrollIntoView).toHaveBeenCalledWith({ behavior: "smooth", block: "center", }); expect(sectionScrollIntoView).not.toHaveBeenCalled(); expect(focus).toHaveBeenCalledWith({ preventScroll: true }); expect(remove).toHaveBeenCalledWith("settings-search-target-pulse"); expect(add).toHaveBeenCalledWith("settings-search-target-pulse"); expect(addEventListener).toHaveBeenCalledWith("blur", expect.any(Function), { once: true }); }); it("does not animate the destination when reduced motion is requested", () => { const scrollIntoView = vi.fn(); const focus = vi.fn(); const remove = vi.fn(); const add = vi.fn(); const target = { tagName: "DIV", firstElementChild: null, scrollIntoView, focus, classList: { remove, add }, offsetWidth: 100, } as unknown as HTMLElement; vi.stubGlobal("document", { getElementById: vi.fn(() => target), }); vi.stubGlobal("window", { matchMedia: vi.fn(() => ({ matches: true })), }); expect(scrollToSettingsTarget("word-wrap")).toBe(true); expect(scrollIntoView).toHaveBeenCalledWith({ behavior: "auto", block: "center", }); expect(focus).toHaveBeenCalledWith({ preventScroll: true }); expect(remove).toHaveBeenCalledWith("settings-search-target-pulse"); expect(add).not.toHaveBeenCalled(); }); it("leaves not-yet-mounted destinations to their mount lifecycle", () => { vi.stubGlobal("document", { getElementById: vi.fn(() => null), }); expect(scrollToSettingsTarget("archive")).toBe(false); }); });