97 lines
2.9 KiB
TypeScript
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');
|
|
});
|
|
});
|