Files
headroom/frontend/tests/unit/expert-mode.test.ts
Santhosh Janardhanan 3324c4f156 feat(allocation): implement resource allocation feature
- Add AllocationController with CRUD + bulk endpoints
- Add AllocationValidationService for capacity/estimate validation
- Add AllocationMatrixService for optimized matrix queries
- Add AllocationPolicy for authorization
- Add AllocationResource for API responses
- Add frontend allocationService and matrix UI
- Add E2E tests for allocation matrix (20 tests)
- Add unit tests for validation service and policies
- Fix month format conversion (YYYY-MM to YYYY-MM-01)
2026-02-25 16:28:47 -05:00

106 lines
4.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/svelte';
function getStoreValue<T>(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');
});