You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法测试使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 16:58:41