React使用BrowserRouter时如何在测试中通过push url重置路由
解决方案
步骤1:重构生产代码的路由嵌套结构(不影响生产环境功能)
把原本写在App.js内的<BrowserRouter>外层标签移到项目入口index.js中,App.js仅保留路由规则、页面组件等逻辑:
// index.js 生产入口代码 import React from 'react' import ReactDOM from 'react-dom/client' import { BrowserRouter } from 'react-router-dom' import App from './App' const root = ReactDOM.createRoot(document.getElementById('root')) root.render( <BrowserRouter> <App /> </BrowserRouter> )
步骤2:自定义测试渲染函数,绑定可控的history实例
修改App.test.js,使用createMemoryHistory创建测试专用的路由实例,和测试环境的Router绑定:
import '@testing-library/jest-dom'; import {render, screen} from '@testing-library/react'; import { Router } from 'react-router-dom'; import { createMemoryHistory } from 'history'; import App from "../App"; import {clickButton, waitForPage} from "./Functions"; // 全局声明history变量,供afterEach调用 let history; // 自定义渲染方法,每次测试创建独立的路由实例 const customRender = (ui) => { history = createMemoryHistory(); return render( <Router location={history.location} navigator={history}> {ui} </Router> ) } beforeEach(() => { customRender(<App/>); }) afterEach(() => { history.push('/'); }) // 剩余测试代码保持不变即可
可选无侵入方案:mock BrowserRouter(无需修改生产代码)
如果不想调整生产代码结构,可直接在测试文件顶部添加mock逻辑,把测试环境的BrowserRouter自动替换为带可控history的Router:
jest.mock('react-router-dom', () => { const actual = jest.requireActual('react-router-dom'); const { createMemoryHistory } = require('history'); const history = createMemoryHistory(); return { ...actual, BrowserRouter: ({ children }) => ( <actual.Router location={history.location} navigator={history}> {children} </actual.Router> ), // 暴露history供测试逻辑调用 get testHistory() { return history; } }; }); // 引入后直接用mock暴露的history即可 import { testHistory } from 'react-router-dom'; afterEach(() => { testHistory.push('/'); })
注意事项
- 测试中不要直接读取
window.location.pathname校验路由,改用history.location.pathname,可规避JSDOM环境的路由限制 - 每个测试用例执行前都要重新创建history实例,避免用例之间的路由状态互相干扰
内容的提问来源于stack exchange,提问作者Andrea Mancini
相关产品推荐
相关产品推荐

