import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { NARROW_QUERY, SIDEBAR_KEY, setCollapsed, sidebarCollapsed, useSidebar, watchViewport } from '../../src/state/useSidebar' import { fakeMedia, resetState } from '../helpers' let stop: (() => void) | null = null beforeEach(() => { resetState() stop = null }) afterEach(() => { stop?.() setCollapsed(false) window.localStorage.clear() }) describe('useSidebar (D-06, T-10-22)', () => { it('uses the documented storage key and breakpoint', () => { expect(SIDEBAR_KEY).toBe('summer-admin.sidebar') expect(NARROW_QUERY).toBe('(max-width: 1099px)') }) it('restores the persisted manual choice on a wide viewport', () => { fakeMedia({ [NARROW_QUERY]: false }) window.localStorage.setItem(SIDEBAR_KEY, 'true') stop = watchViewport() expect(sidebarCollapsed.value).toBe(true) expect(useSidebar().manual.value).toBe(true) expect(useSidebar().narrow.value).toBe(false) window.localStorage.setItem(SIDEBAR_KEY, 'yes') stop() stop = watchViewport() expect(sidebarCollapsed.value).toBe(false) }) it('collapses below the breakpoint without writing the stored choice', () => { const media = fakeMedia({ [NARROW_QUERY]: true }) stop = watchViewport() expect(sidebarCollapsed.value).toBe(true) expect(useSidebar().narrow.value).toBe(true) expect(window.localStorage.getItem(SIDEBAR_KEY)).toBeNull() media.change(NARROW_QUERY, false) expect(sidebarCollapsed.value).toBe(false) expect(window.localStorage.getItem(SIDEBAR_KEY)).toBeNull() stop() stop = null expect(media.listeners(NARROW_QUERY)).toBe(0) media.change(NARROW_QUERY, true) expect(useSidebar().narrow.value).toBe(false) }) it("stores only 'true' or 'false' and nothing else", () => { fakeMedia({}) stop = watchViewport() setCollapsed(true) expect(window.localStorage.getItem(SIDEBAR_KEY)).toBe('true') expect(sidebarCollapsed.value).toBe(true) setCollapsed(false) expect(window.localStorage.getItem(SIDEBAR_KEY)).toBe('false') expect(sidebarCollapsed.value).toBe(false) expect(Object.keys(window.localStorage)).toEqual([SIDEBAR_KEY]) }) it('keeps the choice for the session when storage is unavailable', () => { fakeMedia({}) vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { throw new DOMException('full', 'QuotaExceededError') }) vi.spyOn(Storage.prototype, 'getItem').mockImplementation(() => { throw new DOMException('denied', 'SecurityError') }) stop = watchViewport() expect(sidebarCollapsed.value).toBe(false) setCollapsed(true) expect(sidebarCollapsed.value).toBe(true) }) it('never collapses by viewport when matchMedia is missing', () => { const original = window.matchMedia // @ts-expect-error simulating a browser without matchMedia window.matchMedia = undefined try { stop = watchViewport() expect(useSidebar().narrow.value).toBe(false) expect(stop()).toBeUndefined() stop = null } finally { window.matchMedia = original } }) })