feat: 实现多主题系统,支持6套主题切换和设置页面
重构 ThemeContext 为多主题模型(themeId + followSystem + systemIsDark), 新增设置页面(主题下拉栏 + 跟随系统开关),移除旧 ThemeToggle 按钮, 引入 antd-style 和 clsx 依赖支持 MUI/shadcn/Bootstrap/玻璃主题。
This commit is contained in:
@@ -3,11 +3,8 @@ import { describe, it, expect, vi } from 'vitest';
|
||||
import { BrowserRouter } from 'react-router';
|
||||
import { AppLayout } from '@/components/AppLayout';
|
||||
|
||||
const mockToggleTheme = vi.fn();
|
||||
const mockSetTheme = vi.fn();
|
||||
|
||||
vi.mock('@/contexts/ThemeContext', () => ({
|
||||
useTheme: vi.fn(() => ({ mode: 'light', toggleTheme: mockToggleTheme, setTheme: mockSetTheme })),
|
||||
useTheme: vi.fn(() => ({ effectiveThemeId: 'default', themeId: 'default', followSystem: false, systemIsDark: false, setThemeId: vi.fn(), setFollowSystem: vi.fn() })),
|
||||
}));
|
||||
|
||||
const renderWithRouter = (component: React.ReactNode) => {
|
||||
@@ -29,27 +26,17 @@ describe('AppLayout', () => {
|
||||
expect(screen.getByText('用量统计')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders theme toggle button with visible color in sidebar', () => {
|
||||
it('renders settings menu item', () => {
|
||||
renderWithRouter(<AppLayout />);
|
||||
|
||||
const themeButton = screen.getByRole('button', { name: 'moon' });
|
||||
expect(themeButton).toBeInTheDocument();
|
||||
expect(themeButton.style.color).toBe('rgba(255, 255, 255, 0.85)');
|
||||
expect(screen.getByText('设置')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders theme toggle button visible in dark mode', async () => {
|
||||
const { useTheme } = await import('@/contexts/ThemeContext');
|
||||
vi.mocked(useTheme).mockReturnValue({
|
||||
mode: 'dark',
|
||||
toggleTheme: mockToggleTheme,
|
||||
setTheme: mockSetTheme,
|
||||
});
|
||||
|
||||
it('does not render theme toggle button', () => {
|
||||
renderWithRouter(<AppLayout />);
|
||||
|
||||
const themeButton = screen.getByRole('button', { name: 'sun' });
|
||||
expect(themeButton).toBeInTheDocument();
|
||||
expect(themeButton.style.color).toBe('rgba(255, 255, 255, 0.85)');
|
||||
expect(screen.queryByRole('button', { name: 'moon' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: 'sun' })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders content outlet', () => {
|
||||
@@ -69,4 +56,20 @@ describe('AppLayout', () => {
|
||||
|
||||
expect(container.querySelector('.ant-layout-header')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('uses effectiveThemeId for header background in dark mode', async () => {
|
||||
const { useTheme } = await import('@/contexts/ThemeContext');
|
||||
vi.mocked(useTheme).mockReturnValue({
|
||||
effectiveThemeId: 'dark',
|
||||
themeId: 'dark',
|
||||
followSystem: false,
|
||||
systemIsDark: false,
|
||||
setThemeId: vi.fn(),
|
||||
setFollowSystem: vi.fn(),
|
||||
});
|
||||
|
||||
const { container } = renderWithRouter(<AppLayout />);
|
||||
const header = container.querySelector('.ant-layout-header') as HTMLElement;
|
||||
expect(header.style.background).toBe('#141414');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user