- Create PageHeader component with title, description, and action slots - Create StatCard component with trend indicators and icons - Update dashboard with KPI cards, Quick Actions, and Allocation Preview - Polish login page with branding and centered layout - Fix auth redirect: authenticated users accessing /login go to dashboard - Fix page refresh: auth state persists, no blank page - Fix sidebar: visible after login, toggle works, state persists - Fix CSS import: add app.css to layout, fix DaisyUI import path - Fix breadcrumbs: home icon links to /dashboard - Add comprehensive E2E and unit tests Refs: openspec/changes/p03-dashboard-enhancement Closes: p03-dashboard-enhancement
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
|
|
|
|
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('layout store', () => {
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
document.documentElement.removeAttribute('data-theme');
|
|
(localStorage.getItem as Mock).mockReturnValue(null);
|
|
});
|
|
|
|
it('initializes with default values', async () => {
|
|
const store = await import('../../src/lib/stores/layout');
|
|
|
|
expect(getStoreValue(store.sidebarState)).toBe('expanded');
|
|
expect(getStoreValue(store.theme)).toBe('light');
|
|
});
|
|
|
|
it('toggleSidebar toggles expanded/collapsed and recovers from hidden', async () => {
|
|
const store = await import('../../src/lib/stores/layout');
|
|
|
|
store.setSidebarState('expanded');
|
|
store.toggleSidebar();
|
|
expect(getStoreValue(store.sidebarState)).toBe('collapsed');
|
|
expect(localStorage.setItem).toHaveBeenCalledWith('headroom_sidebar_state', 'collapsed');
|
|
|
|
store.toggleSidebar();
|
|
expect(getStoreValue(store.sidebarState)).toBe('expanded');
|
|
|
|
store.setSidebarState('hidden');
|
|
store.toggleSidebar();
|
|
expect(getStoreValue(store.sidebarState)).toBe('expanded');
|
|
});
|
|
|
|
it('theme toggle works and applies to document', async () => {
|
|
const store = await import('../../src/lib/stores/layout');
|
|
|
|
store.setTheme('light');
|
|
store.toggleTheme();
|
|
expect(getStoreValue(store.theme)).toBe('dark');
|
|
expect(document.documentElement.getAttribute('data-theme')).toBe('dark');
|
|
expect(localStorage.setItem).toHaveBeenCalledWith('headroom_theme', 'dark');
|
|
|
|
store.toggleTheme();
|
|
expect(getStoreValue(store.theme)).toBe('light');
|
|
expect(document.documentElement.getAttribute('data-theme')).toBe('light');
|
|
expect(localStorage.setItem).toHaveBeenCalledWith('headroom_theme', 'light');
|
|
});
|
|
});
|