fix(RouterProvider): 修复初始加载状态逻辑,确保在加载前不覆盖 chrome.storage
- 将 isLoaded 的初始状态设置为 false,避免在加载初始数据前错误地覆盖存储。 - 新增测试用例,验证在 localStorage 快照过期时,loadInitialData 完成前不应覆盖 chrome.storage 的行为。
This commit is contained in:
@@ -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) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user