从index.js导入router致Jest/RTL测试出现DOM元素错误
问题原因及解决方法
问题原因
- 只要你从
index.js导入任何变量(包括router),整个index.js的代码都会被执行,包括末尾那段ReactDOM.createRoot(...).render(...)的应用渲染逻辑。 - 测试环境(Jest/React Testing Library)运行时,测试页面里不存在
id="root"的DOM元素,document.getElementById('root')会返回null,调用createRoot(null)自然就抛出Target container is not a DOM element错误。 - 哪怕你导入后根本没用到这个变量,只要触发了
index.js的代码执行,就会触发这个错误。
解决方法
方案一:把路由配置单独抽成文件(推荐)
这是最干净的解决方案,彻底分离路由配置和应用渲染逻辑:
- 新建
src/router.js文件,把路由配置移进去:
import React from "react"; import { createBrowserRouter } from "react-router-dom"; import App from "./App"; import ErrorPage from "./components/ErrorPage/ErrorPage"; export const router = createBrowserRouter([ { path: "/", element: <App />, errorElement: <ErrorPage />, }, ]);
- 修改
src/index.js,从新文件导入router:
import React from "react"; import ReactDOM from "react-dom/client"; import { Provider } from "react-redux"; import { RouterProvider } from "react-router-dom"; import "./index.css"; import store from "./store"; import { router } from "./router"; // 从单独文件导入路由配置 const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <Provider store={store}> <RouterProvider router={router} /> </Provider> </React.StrictMode> );
- 在测试文件(
setupTests.js或App.test.js)中,从router.js导入router:
import { router } from "../router"; // 不再导入index.js,避免触发渲染逻辑
这样导入路由配置时,只会加载路由相关代码,不会执行应用渲染,测试环境就不会报错。
方案二:给index.js加环境判断
如果不想抽离文件,可以在index.js里判断当前环境,只在浏览器环境执行渲染:
修改src/index.js的末尾代码:
export const router = createBrowserRouter([ { path: "/", element: <App />, errorElement: <ErrorPage />, }, ]); // 只在浏览器环境执行渲染(测试环境中window对象不存在) if (typeof window !== 'undefined') { const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <Provider store={store}> <RouterProvider router={router} /> </Provider> </React.StrictMode> ); }
测试环境中typeof window会返回undefined,渲染代码不会执行,也就不会出现找不到DOM元素的问题。
补充:测试错误页面的正确姿势
用抽离后的路由配置,你可以直接用createMemoryRouter来模拟错误路径的场景:
test('An invalid path returns an error page', () => { import { createMemoryRouter, RouterProvider } from 'react-router-dom'; import ErrorPage from './components/ErrorPage/ErrorPage'; // 创建测试用的内存路由 const testRouter = createMemoryRouter([ { path: "/", element: <App />, errorElement: <ErrorPage />, }, ], { initialEntries: ["/invalid-path"] // 模拟访问无效路径 }); // 直接渲染RouterProvider,不需要MemoryRouter renderWithProviders(<RouterProvider router={testRouter} />, { useRouter: false }); expect(screen.getByText("Sorry, an unexpected error has occurred!")).toBeInTheDocument(); });
内容的提问来源于stack exchange,提问作者Cmastris
相关产品推荐
相关产品推荐

