fix(StorageCleaner): 修复 IndexedDB 清理竞态、部分成功计数与刷新后状态同步

This commit is contained in:
2026-06-25 23:31:44 +08:00
parent ebf9f7a153
commit edd4cf266c
13 changed files with 1545 additions and 128 deletions
@@ -1,6 +1,9 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { beforeEach, describe, it, expect, vi } from 'vitest';
import { browser } from 'wxt/browser';
import Index from '../index';
import { clearStorage, getCookieSize, getCurrentTab } from '@/utils/storageCleaner';
import { toast } from 'sonner';
// Mock the chrome APIs
vi.mock('@/utils/chromeStorage', () => ({
@@ -22,10 +25,82 @@ vi.mock('@/utils/storageCleaner', () => ({
formatCleaningResult: vi.fn().mockReturnValue('Cleaned successfully'),
}));
vi.mock('sonner', () => ({
toast: {
success: vi.fn(),
warning: vi.fn(),
error: vi.fn(),
},
}));
describe('StorageCleaner 页面', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(getCurrentTab).mockResolvedValue({ id: 1, url: 'https://example.com' } as any);
vi.mocked(clearStorage).mockResolvedValue({ overallSuccess: true });
});
it('应该渲染初始化加载状态', () => {
// storageCleaner:initializing 的中文文案为「正在读取站点数据...」
render(<Index />);
expect(screen.getByText(/正在读取站点数据/)).toBeInTheDocument();
expect(screen.getByText(/正在读取数据/)).toBeInTheDocument();
});
it('读取当前标签页失败时应显示错误提示', async () => {
vi.mocked(getCurrentTab).mockRejectedValueOnce(new Error('Tabs unavailable'));
render(<Index />);
expect(await screen.findByText('读取数据失败')).toBeInTheDocument();
});
it('确认清理前如果当前标签页变为受限页面,不应执行清理', async () => {
render(<Index />);
const cleanButton = await screen.findByRole('button', { name: /立即清理/ });
fireEvent.click(cleanButton);
vi.mocked(getCurrentTab).mockResolvedValueOnce({
id: 1,
url: 'chrome://extensions',
} as any);
fireEvent.click(screen.getByRole('button', { name: /确认清理/ }));
await waitFor(() => {
expect(clearStorage).not.toHaveBeenCalled();
expect(toast.warning).toHaveBeenCalledWith('存储清理功能不支持此页面');
});
});
it('自动刷新后应等待标签页完成加载并重新读取信息后再允许再次清理', async () => {
const tabUpdatedListeners: Array<(tabId: number, changeInfo: { status?: string }) => void> = [];
(browser.tabs.onUpdated.addListener as any).mockImplementation((listener: any) => {
tabUpdatedListeners.push(listener);
});
(browser.tabs.onUpdated.removeListener as any).mockImplementation((listener: any) => {
const index = tabUpdatedListeners.indexOf(listener);
if (index >= 0) tabUpdatedListeners.splice(index, 1);
});
render(<Index />);
const cleanButton = await screen.findByRole('button', { name: /立即清理/ });
fireEvent.click(cleanButton);
fireEvent.click(screen.getByRole('button', { name: /确认清理/ }));
await waitFor(() => expect(browser.tabs.reload).toHaveBeenCalledWith(1));
const loadingButton = screen.getByRole('button', { name: /正在清理/ });
expect(loadingButton).toBeDisabled();
fireEvent.click(loadingButton);
expect(clearStorage).toHaveBeenCalledTimes(1);
const reloadListener = tabUpdatedListeners.at(-1);
expect(reloadListener).toBeDefined();
reloadListener?.(1, { status: 'complete' });
await waitFor(() => {
expect(getCookieSize).toHaveBeenCalledTimes(2);
expect(screen.getByRole('button', { name: /立即清理/ })).not.toBeDisabled();
});
});
});