import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest'; import { fireEvent, render, screen } from '@testing-library/svelte'; function getStoreValue(store: { subscribe: (run: (value: T) => void) => () => void }): T { let value!: T; const unsubscribe = store.subscribe((current) => { value = current; }); unsubscribe(); return value; } describe('4.1 expertMode store', () => { beforeEach(() => { vi.resetModules(); (localStorage.getItem as Mock).mockReturnValue(null); }); it('4.1.1 expertMode defaults to false when not in localStorage', async () => { const store = await import('../../src/lib/stores/expertMode'); expect(getStoreValue(store.expertMode)).toBe(false); }); it('4.1.2 expertMode reads "true" from localStorage', async () => { (localStorage.getItem as Mock).mockReturnValue('true'); const store = await import('../../src/lib/stores/expertMode'); expect(getStoreValue(store.expertMode)).toBe(true); expect(localStorage.getItem).toHaveBeenCalledWith('headroom.capacity.expertMode'); }); it('4.1.3 expertMode ignores invalid localStorage values', async () => { (localStorage.getItem as Mock).mockReturnValue('invalid'); const store = await import('../../src/lib/stores/expertMode'); expect(getStoreValue(store.expertMode)).toBe(false); }); it('4.1.4 toggleExpertMode writes to localStorage', async () => { const store = await import('../../src/lib/stores/expertMode'); store.toggleExpertMode(); expect(getStoreValue(store.expertMode)).toBe(true); expect(localStorage.setItem).toHaveBeenCalledWith('headroom.capacity.expertMode', 'true'); }); it('4.1.5 setExpertMode updates value and localStorage', async () => { const store = await import('../../src/lib/stores/expertMode'); store.setExpertMode(true); expect(getStoreValue(store.expertMode)).toBe(true); expect(localStorage.setItem).toHaveBeenCalledWith('headroom.capacity.expertMode', 'true'); store.setExpertMode(false); expect(getStoreValue(store.expertMode)).toBe(false); expect(localStorage.setItem).toHaveBeenCalledWith('headroom.capacity.expertMode', 'false'); }); }); describe('4.2 ExpertModeToggle component', () => { beforeEach(() => { vi.resetModules(); (localStorage.getItem as Mock).mockReturnValue(null); }); it.todo('4.2.1 renders with default unchecked state'); it.todo('4.2.2 toggles and updates store on click'); it.todo('4.2.3 appears right-aligned in container'); }); describe('6.1-6.2 CapacityExpertGrid component layout', () => { it.todo('6.1 renders a row per active team member'); it.todo('6.2 renders a column per day of the month'); }); describe('6.3-6.11 Token normalization', () => { it.todo('6.3 normalizes H to { rawToken: "H", numericValue: 0, valid: true }'); it.todo('6.4 normalizes O to { rawToken: "O", numericValue: 0, valid: true }'); it.todo('6.5 normalizes .5 to { rawToken: "0.5", numericValue: 0.5, valid: true }'); it.todo('6.6 normalizes 0.5 to { rawToken: "0.5", numericValue: 0.5, valid: true }'); it.todo('6.7 normalizes 1 to { rawToken: "1", numericValue: 1, valid: true }'); it.todo('6.8 normalizes 0 to { rawToken: "0", numericValue: 0, valid: true }'); it.todo('6.9 marks invalid token 2 as { rawToken: "2", numericValue: null, valid: false }'); it.todo('6.10 auto-render: 0 on weekend column becomes O'); it.todo('6.11 auto-render: 0 on holiday column becomes H'); }); describe('6.12-6.14 Grid validation and submit', () => { it.todo('6.12 invalid cell shows red border on blur'); it.todo('6.13 Submit button disabled when any invalid cell exists'); it.todo('6.14 Submit button disabled when no dirty cells exist'); }); describe('8.1-8.4 KPI bar calculations', () => { it.todo('8.1 capacity = sum of all members numeric cell values (person-days)'); it.todo('8.2 revenue = sum(member person-days × hourly_rate × 8)'); it.todo('8.3 invalid cells contribute 0 to KPI totals'); it.todo('8.4 KPI bar updates when a cell value changes'); });