fix(RouterProvider): 修复初始加载状态逻辑,确保在加载前不覆盖 chrome.storage

- 将 isLoaded 的初始状态设置为 false,避免在加载初始数据前错误地覆盖存储。
- 新增测试用例,验证在 localStorage 快照过期时,loadInitialData 完成前不应覆盖 chrome.storage 的行为。
This commit is contained in:
雨霖铃
2026-06-19 21:00:27 +08:00
parent 0f3060dcf3
commit bf06b61f10
2 changed files with 47 additions and 6 deletions
+1 -6
View File
@@ -104,12 +104,7 @@ export function RouterProvider({
getSyncSnapshot('app/recentlyUsedTools', [], isValidPageList), getSyncSnapshot('app/recentlyUsedTools', [], isValidPageList),
); );
const [isLoaded, setIsLoaded] = useState(() => { const [isLoaded, setIsLoaded] = useState(false);
const snapshotKey = localStorage.getItem(`snapshot/${syncKey as string}`);
const snapshotVisible = localStorage.getItem(`snapshot/${visiblePagesKey as string}`);
const snapshotOrder = localStorage.getItem(`snapshot/${pageOrderKey as string}`);
return !!(snapshotKey && snapshotVisible && snapshotOrder);
});
/** /**
* 从异步存储中安全溯源初始数据 * 从异步存储中安全溯源初始数据
@@ -277,6 +277,52 @@ describe('RouterProvider', () => {
}); });
}); });
it('localStorage 快照过期时,loadInitialData 完成前不应覆盖 chrome.storage', async () => {
const staleRoute = 'timestamp';
const correctRoute = 'jsonTools';
const defaultVisible = ['dashboard', 'timestamp', 'storageCleaner'];
const defaultOrder = ['timestamp', 'storageCleaner'];
localStorage.setItem('snapshot/app/currentRoute', JSON.stringify(staleRoute));
localStorage.setItem('snapshot/app/visiblePages', JSON.stringify(defaultVisible));
localStorage.setItem('snapshot/app/pageOrder', JSON.stringify(defaultOrder));
const storage = new Map<string, unknown>([
['app/currentRoute', correctRoute],
['app/visiblePages', defaultVisible],
['app/pageOrder', defaultOrder],
['app/recentlyUsedTools', []],
]);
let resolveGet: () => void;
const getBlocked = new Promise<void>((resolve) => {
resolveGet = resolve;
});
(storageUtil.get as any).mockImplementation(async (key: string, defaultValue: unknown) => {
await getBlocked;
return storage.get(key) ?? defaultValue;
});
(storageUtil.set as any).mockImplementation(async (key: string, value: unknown) => {
storage.set(key, value);
});
render(
<RouterProvider>
<TestComponent />
</RouterProvider>,
);
expect(screen.getByTestId('current-page')).toHaveTextContent(staleRoute);
expect(storageUtil.set).not.toHaveBeenCalledWith('app/currentRoute', staleRoute);
resolveGet!();
await waitFor(() => {
expect(screen.getByTestId('current-page')).toHaveTextContent(correctRoute);
expect(storage.get('app/currentRoute')).toBe(correctRoute);
});
});
it('组件卸载时不应设置 isLoaded 状态(竞态条件防护)', async () => { it('组件卸载时不应设置 isLoaded 状态(竞态条件防护)', async () => {
let resolveStorage: (value: unknown) => void; let resolveStorage: (value: unknown) => void;
const storagePromise = new Promise((resolve) => { const storagePromise = new Promise((resolve) => {