Files
testing-tool/src/providers/__tests__/ThemeModeProvider.test.tsx
T
rsgltzyd 17a4dbd8a7 refactor: 优化 RouterProvider 组件的数据加载逻辑
- 使用批量获取方法 `getMany` 替代多个单独的 `get` 调用,简化数据加载过程。
- 更新 `loadInitialData` 函数,确保从存储中获取的默认值更为一致。
- 修改测试用例以验证批量获取的功能,确保组件在不同情况下的正确性。
2026-06-30 22:56:31 +08:00

121 lines
3.6 KiB
TypeScript

import { act, render, screen, waitFor } from '@testing-library/react';
import { browser } from 'wxt/browser';
import { ThemeModeProvider, useThemeMode } from '@/providers/ThemeModeProvider';
import { storageUtil } from '@/utils/chromeStorage';
import { THEME_MODE_SNAPSHOT_KEY, THEME_MODE_STORAGE_KEY } from '@/utils/themeSnapshot';
vi.mock('@/utils/chromeStorage', () => ({
storageUtil: {
get: vi.fn(),
set: vi.fn(() => Promise.resolve()),
},
}));
const TestComponent = () => {
const { mode, resolvedMode, setMode } = useThemeMode();
return (
<div>
<div data-testid="mode">{mode}</div>
<div data-testid="resolved-mode">{resolvedMode}</div>
<button type="button" data-testid="set-dark" onClick={() => setMode('dark')}>
Set Dark
</button>
</div>
);
};
describe('ThemeModeProvider', () => {
beforeEach(() => {
vi.clearAllMocks();
localStorage.clear();
document.documentElement.classList.remove('dark');
(storageUtil.get as ReturnType<typeof vi.fn>).mockImplementation(
(_key: string, defaultValue: unknown) => Promise.resolve(defaultValue),
);
});
it('应从 localStorage 快照初始化主题', () => {
localStorage.setItem(THEME_MODE_SNAPSHOT_KEY, JSON.stringify('dark'));
render(
<ThemeModeProvider>
<TestComponent />
</ThemeModeProvider>,
);
expect(screen.getByTestId('mode')).toHaveTextContent('dark');
expect(screen.getByTestId('resolved-mode')).toHaveTextContent('dark');
expect(document.documentElement.classList.contains('dark')).toBe(true);
expect(storageUtil.get).not.toHaveBeenCalled();
});
it('异步恢复 storage 后应写回 snapshot', async () => {
(storageUtil.get as ReturnType<typeof vi.fn>).mockResolvedValue('dark');
render(
<ThemeModeProvider>
<TestComponent />
</ThemeModeProvider>,
);
await waitFor(() => {
expect(localStorage.getItem(THEME_MODE_SNAPSHOT_KEY)).toBe(JSON.stringify('dark'));
});
});
it('用户已切换主题时不应被较慢的 storage 恢复覆盖', async () => {
let resolveStorage: (value: 'light' | 'dark' | 'system') => void;
const storagePromise = new Promise<'light' | 'dark' | 'system'>((resolve) => {
resolveStorage = resolve;
});
(storageUtil.get as ReturnType<typeof vi.fn>).mockImplementation(() => storagePromise);
render(
<ThemeModeProvider>
<TestComponent />
</ThemeModeProvider>,
);
await act(async () => {
screen.getByTestId('set-dark').click();
});
expect(screen.getByTestId('mode')).toHaveTextContent('dark');
await act(async () => {
resolveStorage!('light');
await storagePromise;
});
expect(screen.getByTestId('mode')).toHaveTextContent('dark');
});
it('storage.onChanged 同步时应更新 mode 与 snapshot', async () => {
(storageUtil.get as ReturnType<typeof vi.fn>).mockResolvedValue('system');
render(
<ThemeModeProvider>
<TestComponent />
</ThemeModeProvider>,
);
await waitFor(() => {
expect(browser.storage.onChanged.addListener).toHaveBeenCalled();
});
const storageChangeHandler = vi.mocked(browser.storage.onChanged.addListener).mock
.calls[0][0] as (changes: Record<string, { newValue?: unknown }>) => void;
await act(async () => {
storageChangeHandler({
[THEME_MODE_STORAGE_KEY]: { newValue: 'dark' },
});
});
expect(screen.getByTestId('mode')).toHaveTextContent('dark');
expect(localStorage.getItem(THEME_MODE_SNAPSHOT_KEY)).toBe(JSON.stringify('dark'));
expect(document.documentElement.classList.contains('dark')).toBe(true);
});
});