我在 React Router v6 中使用一个组件来管理私有路由,它对身份验证令牌进行一些检查,并且将渲染
Outlet
组件或重定向到登录页面。
我有-
import { Outlet } from 'react-router-dom';
export const CheckAuth = (props) => {
const valid = ...;
if (!valid) {
window.location.replace(loginUrl);
return null;
}
return <Outlet />;
};
并像-
一样使用它<Route element={<CheckAuth token={authToken} />}>
// ... private routes ...
</Route>
我可以用 Jest 来模拟
window.location.replace
delete window.location;
window.location = { replace: jest.fn() };
...
render(<CheckAuth token={token} />)
expect(window.location.replace).toHaveBeenCalledWith(loginUrl);
但是如何使用测试库测试
Outlet
组件?
如果它对任何人有帮助,我最终只是用反应路由器组件包装测试中的组件,并将一个虚拟组件作为子组件传递给 Route 并断言该组件中的一些虚假文本已渲染或未渲染
测试块外 -
const FakeComponent = () => <div>fake text</div>;
对于 failure 场景,插座不应呈现 -
render(
<MemoryRouter initialEntries={['/']}>
<Routes>
<Route element={<CheckAuth />}>
<Route path="/" element={<FakeComponent />} />
</Route>
</Routes>
</MemoryRouter>
);
expect(screen.queryByText('fake text')).not.toBeInTheDocument();
对于“成功”场景,断言文本存在 -
render(
<MemoryRouter initialEntries={['/']}>
<Routes>
<Route element={<CheckAuth token={correctToken}/>}>
<Route path="/" element={<FakeComponent />} />
</Route>
</Routes>
</MemoryRouter>
);
expect(screen.queryByText('fake text')).toBeInTheDocument();
App.jsx
或
App.tsx
中的路由逻辑(这是事实)。因此,您实际上应该这样做:
- 您需要等待组件实际渲染,然后再检查它是否渲染例如,如果您有
/home
的私有路由,它可以通过身份验证令牌检查并呈现以下组件:
const HomePage = () => {
//...some logic
return <div>Home page</div>
}
你的
App.jsx
看起来像这样:
import { Outlet } from 'react-router-dom';
// other imports
export const App = (props) => {
//... app logic
return (
<Routes>
<Route path='/' element={<Outlet />}>
<Route element={<CheckAuth token={authToken} />}>
// ... all private routes including '/home' ...
</Route>
</Route>
</Routes>
)
}
index.js
:
import App from 'App'
const root = createRoot(document.getElementById('root'))
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
)
然后,您的测试应该如下所示:
describe("App page", async () => {
...
delete window.location;
window.location = { replace: jest.fn() };
...
test('should test for private route with invalid authToken', () => {
// example private route with no valid auth: '/not-valid'
render(
<MemoryRouter initialEntries={['/not-valid']}>
<App />
</MemoryRouter>
)
expect(window.location.replace).toHaveBeenCalledWith(loginUrl)
})
test('should test for private route with valid authToken', () => {
render(
<MemoryRouter initialEntries={['/home']}>
<App />
</MemoryRouter>
)
expect(await screen.findByText('Home page')).toBeInTheDocument()
})
})
这里的关键点是确保等待渲染发生,然后再检查组件是否已成功渲染
/home
您可以通过等待检查来完成此操作,即expect(await screen.findBy.......
。