import { createPinia, setActivePinia } from "pinia"; import { afterEach, describe, expect, it, vi } from "vitest"; import { useLayoutStore } from "./layout"; describe("layout store", () => { afterEach(() => { vi.unstubAllGlobals(); }); it.each([ [767, "mobile"], [768, "desktop"], [769, "desktop"], ] as const)("uses the strict mobile breakpoint at %spx", (width, expectedDevice) => { setActivePinia(createPinia()); const store = useLayoutStore(); store.syncViewport(width); expect(store.device).toBe(expectedDevice); expect(store.sidebarOpened).toBe(expectedDevice === "desktop"); }); it("is safe to use without window", () => { setActivePinia(createPinia()); const store = useLayoutStore(); expect(() => store.syncViewport()).not.toThrow(); expect(() => store.startViewportWatcher()).not.toThrow(); expect(store.device).toBe("desktop"); }); it("registers one resize watcher, updates on resize, and unsubscribes idempotently", () => { const addEventListener = vi.fn(); const removeEventListener = vi.fn(); const browserWindow = { innerWidth: 993, addEventListener, removeEventListener }; vi.stubGlobal("window", browserWindow); setActivePinia(createPinia()); const store = useLayoutStore(); const stop = store.startViewportWatcher(); const sameStop = store.startViewportWatcher(); const resizeHandler = addEventListener.mock.calls[0][1] as () => void; expect(sameStop).toBe(stop); expect(addEventListener).toHaveBeenCalledTimes(1); expect(store.device).toBe("desktop"); browserWindow.innerWidth = 767; resizeHandler(); expect(store.device).toBe("mobile"); expect(store.sidebarOpened).toBe(false); stop(); stop(); expect(removeEventListener).toHaveBeenCalledTimes(1); browserWindow.innerWidth = 993; resizeHandler(); expect(store.device).toBe("mobile"); }); it("controls the sidebar and animation flag independently", () => { setActivePinia(createPinia()); const store = useLayoutStore(); store.toggleSidebar({ withoutAnimation: true }); expect(store.sidebarOpened).toBe(false); expect(store.withoutAnimation).toBe(true); store.openSidebar({ withoutAnimation: false }); expect(store.sidebarOpened).toBe(true); expect(store.withoutAnimation).toBe(false); store.closeSidebar(); expect(store.sidebarOpened).toBe(false); expect(store.withoutAnimation).toBe(false); }); });