使用Jest和Enzyme测试AppRouter时404页面未正常渲染问题排查
解决Jest+Enzyme测试AppRouter路由匹配404页面失败问题
你的测试失败的核心原因是AppRouter组件内部已经包含了<BrowserRouter>,而测试时又用<MemoryRouter>包裹,导致路由嵌套,外部MemoryRouter的initialEntries配置被内部的Router忽略。
每个Router组件(不管是BrowserRouter还是MemoryRouter)都会创建自己独立的路由上下文和history对象。当你嵌套两个Router时,内部的<BrowserRouter>会覆盖外部<MemoryRouter>的路由上下文,所以你设置的/random路径根本没有生效,路由依然匹配到了默认的Home页面,导致测试断言失败。
解决方案1:拆分Router与路由配置(推荐)
让AppRouter只负责定义路由规则(Switch和Route),把Router的职责移到应用入口,这样测试时可以自由用MemoryRouter包裹:
修改AppRouter组件:
import React from 'react'; import { Route, Switch } from 'react-router-dom'; import Home from './Home'; import NotFoundPage from './NotFoundPage'; // 只保留路由匹配逻辑,不再包含Router const AppRouter = () => ( <div> <Switch> <Route exact path="/" component={Home} /> <Route component={NotFoundPage} /> </Switch> </div> ); export default AppRouter;
在应用入口文件(比如index.js)中添加Router:
import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter as Router } from 'react-router-dom'; import AppRouter from './components/AppRouter'; ReactDOM.render( <Router> <AppRouter /> </Router>, document.getElementById('root') );
保持测试代码不变即可:
import React from 'react'; import { mount } from 'enzyme'; import { MemoryRouter } from 'react-router'; import AppRouter from './../src/components/AppRouter'; import Home from './../src/components/Home'; import NotFoundPage from './../src/components/NotFoundPage'; describe('App Router', () => { it('should go to 404 page', () => { const wrapper = mount( <MemoryRouter initialEntries={['/random']}> <AppRouter /> </MemoryRouter> ); expect(wrapper.contains(<Home />)).toBe(false); expect(wrapper.contains(<NotFoundPage />)).toBe(true); }); });
解决方案2:让AppRouter接受自定义history
如果你不想拆分组件,可以修改AppRouter,让它支持传入自定义的history对象,这样测试时可以传入MemoryHistory:
修改AppRouter组件:
import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import Home from './Home'; import NotFoundPage from './NotFoundPage'; // 接受history属性,优先使用传入的history const AppRouter = ({ history }) => ( <Router history={history}> <div> <Switch> <Route exact path="/" component={Home} /> <Route component={NotFoundPage} /> </Switch> </div> </Router> ); export default AppRouter;
修改测试代码:
import React from 'react'; import { mount } from 'enzyme'; import { createMemoryHistory } from 'history'; import AppRouter from './../src/components/AppRouter'; import Home from './../src/components/Home'; import NotFoundPage from './../src/components/NotFoundPage'; describe('App Router', () => { it('should go to 404 page', () => { // 创建自定义MemoryHistory,指定初始路径 const history = createMemoryHistory({ initialEntries: ['/random'] }); const wrapper = mount(<AppRouter history={history} />); expect(wrapper.contains(<Home />)).toBe(false); expect(wrapper.contains(<NotFoundPage />)).toBe(true); }); });
两种方案都能解决你的问题,第一种更符合组件单一职责原则,后续扩展路由也更灵活。
内容的提问来源于stack exchange,提问作者Benoit Chassignol
相关产品推荐
相关产品推荐

