Files
gongxue-base/apps/admin/src/components/RouteKeeper.integration.test.tsx

97 lines
2.9 KiB
TypeScript

import { act } from 'react';
import { createRoot } from 'react-dom/client';
import { MemoryRouter, Route, Routes, useNavigate } from 'react-router-dom';
import { afterEach, describe, expect, it } from 'vitest';
import { RouteKeeper } from './RouteKeeper';
let container: HTMLDivElement | null = null;
let root: ReturnType<typeof createRoot> | null = null;
afterEach(async () => {
if (root) await act(async () => root?.unmount());
container?.remove();
root = null;
container = null;
});
function PageA() {
const navigate = useNavigate();
return (
<div>
<input data-testid="input-a" aria-label="A 输入" />
<button data-testid="go-b" onClick={() => navigate('/b')}>
B
</button>
</div>
);
}
function PageB() {
const navigate = useNavigate();
return (
<div>
<input data-testid="input-b" aria-label="B 输入" />
<button data-testid="go-a" onClick={() => navigate('/')}>
A
</button>
</div>
);
}
function Harness() {
return (
<MemoryRouter initialEntries={['/']}>
<Routes>
<Route path="/" element={<RouteKeeper />}>
<Route index element={<PageA />} />
<Route path="b" element={<PageB />} />
</Route>
</Routes>
</MemoryRouter>
);
}
function type(target: HTMLInputElement, value: string) {
const setter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
'value',
)?.set;
setter?.call(target, value);
target.dispatchEvent(new Event('input', { bubbles: true }));
}
describe('RouteKeeper', () => {
it('keeps page instances and input values alive across navigation', async () => {
container = document.createElement('div');
document.body.appendChild(container);
root = createRoot(container);
await act(async () => root?.render(<Harness />));
const inputA = document.querySelector('[data-testid="input-a"]') as HTMLInputElement;
expect(inputA).not.toBeNull();
await act(async () => type(inputA, '待保存的学生姓名'));
await act(async () => {
(document.querySelector('[data-testid="go-b"]') as HTMLButtonElement).click();
});
const inputB = document.querySelector('[data-testid="input-b"]') as HTMLInputElement;
expect(inputB).not.toBeNull();
await act(async () => type(inputB, '待保存的宿舍号'));
await act(async () => {
(document.querySelector('[data-testid="go-a"]') as HTMLButtonElement).click();
});
const keptA = document.querySelector('[data-testid="input-a"]') as HTMLInputElement;
expect(keptA).not.toBeNull();
expect(keptA.value).toBe('待保存的学生姓名');
const keptB = document.querySelector('[data-testid="input-b"]') as HTMLInputElement;
expect(keptB.value).toBe('待保存的宿舍号');
const pages = document.querySelectorAll('.route-keeper-page');
expect(pages.length).toBe(2);
const hidden = pages[1] as HTMLElement;
expect(hidden.style.display).toBe('none');
});
});