Files
goodgo-platform/apps/web/components/providers/__tests__/theme-provider.spec.tsx
Ho Ngoc Hai 7d6fcb4d8d feat(web): design tokens, Tailwind config, base components (TEC-3057)
- Add chart palette, motion, and z-index CSS vars to globals.css
- Replace custom theme-provider with next-themes (dark default)
- Extend tailwind.config.ts with heading fonts, spacing (row-compact,
  row-roomy, sidebar), chart colors, elevation shadows, glow shadows,
  transition timing, pill border-radius, z-index scale
- Update tick-flash animations to match design token spec (480ms)
- Add prefers-reduced-motion support for all animations
- Create base design-system components:
  Surface, SurfaceElevated, Divider, DensityProvider/useDensity,
  Numeric (VND/percent/compact formatting), Signal (up/down/neutral pill)
- Add dev-only /dev/tokens showcase route (404 in production)
- Update theme-provider tests to match next-themes integration

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-21 03:19:40 +07:00

93 lines
2.2 KiB
TypeScript

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, expect, it, vi } from 'vitest';
import { ThemeProvider, useTheme } from '../theme-provider';
// Mock next-themes
const mockSetTheme = vi.fn();
let mockTheme = 'dark';
let mockResolvedTheme = 'dark';
vi.mock('next-themes', () => ({
ThemeProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
useTheme: () => ({
theme: mockTheme,
resolvedTheme: mockResolvedTheme,
setTheme: (t: string) => {
mockSetTheme(t);
mockTheme = t;
mockResolvedTheme = t;
},
}),
}));
// Test consumer component
function ThemeConsumer() {
const { theme, toggleTheme } = useTheme();
return (
<div>
<span data-testid="theme">{theme}</span>
<button onClick={toggleTheme}>Toggle</button>
</div>
);
}
describe('ThemeProvider', () => {
beforeEach(() => {
mockTheme = 'dark';
mockResolvedTheme = 'dark';
vi.clearAllMocks();
});
it('renders children', () => {
render(
<ThemeProvider>
<div>Child content</div>
</ThemeProvider>,
);
expect(screen.getByText('Child content')).toBeInTheDocument();
});
it('defaults to dark theme', () => {
render(
<ThemeProvider>
<ThemeConsumer />
</ThemeProvider>,
);
expect(screen.getByTestId('theme')).toHaveTextContent('dark');
});
it('toggles theme to light', async () => {
const user = userEvent.setup();
render(
<ThemeProvider>
<ThemeConsumer />
</ThemeProvider>,
);
await user.click(screen.getByText('Toggle'));
expect(mockSetTheme).toHaveBeenCalledWith('light');
});
it('toggles theme back to dark', async () => {
mockTheme = 'light';
mockResolvedTheme = 'light';
const user = userEvent.setup();
render(
<ThemeProvider>
<ThemeConsumer />
</ThemeProvider>,
);
await user.click(screen.getByText('Toggle'));
expect(mockSetTheme).toHaveBeenCalledWith('dark');
});
});
describe('useTheme', () => {
it('returns dark as default outside provider', () => {
render(<ThemeConsumer />);
expect(screen.getByTestId('theme')).toHaveTextContent('dark');
});
});