无法测试使用unstable_useBlocker的组件,求助Data Router测试方案
如何测试使用unstable_useBlocker的React Router Data Router组件
你的问题出在手动模拟内部Context时缺少了blocker机制所需的关键逻辑,React Router的Data Router内部会维护blocker的处理流程,手动套UNSAFE_*Context没法完整复现这个逻辑,所以navigator.push不会触发blocker回调。
正确的做法是直接用官方提供的createMemoryRouter和RouterProvider来搭建测试环境,这是最贴合真实场景的方式,也能保证unstable_useBlocker的逻辑正常运行。
具体实现步骤
1. 搭建测试用的Data Router
用createMemoryRouter定义包含被测组件的路由配置,它会自动处理所有内部Context和blocker相关的逻辑:
import { render, act, screen } from '@testing-library/react'; import { createMemoryRouter, RouterProvider } from 'react-router-dom'; import TestedComponent from './TestedComponent'; test('unstable_useBlocker should prevent navigation', async () => { // 定义路由:把被测组件放在根路径,另一个路径作为跳转目标 const router = createMemoryRouter([ { path: '/', element: <TestedComponent />, }, { path: '/new-path', element: <div data-testid="target-page">Target Page</div>, }, ]); // 用RouterProvider渲染,这会自动注入所有必要的Context render(<RouterProvider router={router} />);
2. 模拟跳转并验证blocker行为
用router.navigate来模拟跳转(而不是直接操作history),因为Data Router的跳转逻辑会经过blocker的拦截流程:
// 模拟跳转操作 await act(async () => { await router.navigate('/new-path'); }); // 验证blocker生效:仍停留在被测组件页面 expect(screen.getByTestId('tested-component')).toBeInTheDocument(); // 验证历史记录未新增(跳转被阻止) expect(router.state.history.length).toBe(1); });
3. 测试动态切换blocker状态的场景
如果你的组件是根据某个状态决定是否阻止跳转,可以在测试中先修改状态,再验证跳转是否允许:
test('unstable_useBlocker allows navigation when condition is met', async () => { const router = createMemoryRouter([ { path: '/', element: <TestedComponent /> }, { path: '/new-path', element: <div data-testid="target-page">Target Page</div> }, ]); render(<RouterProvider router={router} />); // 假设组件有一个按钮可以取消阻止跳转 await act(async () => { screen.getByRole('button', { name: '允许跳转' }).click(); }); // 再次模拟跳转 await act(async () => { await router.navigate('/new-path'); }); // 验证成功跳转到目标页面 expect(screen.getByTestId('target-page')).toBeInTheDocument(); });
为什么之前的方法无效?
你手动提供的UNSAFE_DataRouterContext和UNSAFE_NavigationContext缺少了blocker机制依赖的内部状态和方法,比如blockers集合、处理跳转时的拦截逻辑等。只有通过createMemoryRouter创建的完整路由实例,才能正确触发unstable_useBlocker的回调。
内容的提问来源于stack exchange,提问作者Anthony Collin-Nadeau
相关产品推荐
相关产品推荐

