React Router v6迁移后测试报错:RouterProvider未返回渲染内容
React Router v6 迁移后测试失败问题排查
报错信息
RouterProvider(...): Nothing was returned from render. This usually means a return statement is missing.
Or, to render nothing, return null.41 | }, 42 | ) > 43 | return render( | ^ 44 | <RouterProvider 45 | router={memRouter} 46 | fallbackElement={<p>Test DOM is loading</p>}
自定义render方法代码
type TestRenderProps = Omit<RenderOptions, 'wrapper'> & { initialState?: Partial<RootState> store?: any dispatch?: any route?: string history?: string[] } export function customRender( ui: React.ReactNode, { initialState, store = getTestStore(initialState || {}), dispatch, route = '/', history = ['/'], ...renderOptions }: TestRenderProps = {}, ) { const memRouter = createMemoryRouter( createRoutesFromElements( <Route path={route} element={ui} errorElement={<TestErrorBoundary />} />, ), { initialEntries: [...history], }, ) return render( // from react testing library <RouterProvider router={memRouter} fallbackElement={<p>Test DOM is loading</p>} />, { ...renderOptions, wrapper: props => ( <StoreProvider {...props} store={store} dispatch={dispatch} /> ), }, ) } const StoreProvider = ({ children, store, dispatch, }: { children?: React.ReactNode store: any dispatch: any }): JSX.Element => { return ( <Provider store={dispatch ? { ...store, dispatch } : store}> {children} </Provider> ) }
测试用例代码
test('test!', () => { customRender( <p>test</p>, { initialState, }, ) expect(screen.queryByText(/app.update/i)).not.toBeInTheDocument() expect(screen.queryByText(/app.close/i)).not.toBeInTheDocument() expect(screen.queryByText(/doctor.signPrescription/i)).not.toBeInTheDocument() })
问题分析与修复方案
核心问题出在createMemoryRouter的路由结构上:当你用createRoutesFromElements创建单个路由时,createMemoryRouter会自动生成一个根路由(path="/"),并把你定义的路由作为它的子路由。但这个自动生成的根路由没有指定element,所以初始进入/时,匹配到根路由却没有内容渲染,才会抛出"Nothing was returned from render"的错误。
修复方式二选一:
直接定义路由数组,跳过
createRoutesFromElements
把路由创建逻辑改成直接传入路由配置数组,让你定义的路由直接作为根路由:const memRouter = createMemoryRouter( [ { path: route, element: ui, errorElement: <TestErrorBoundary />, }, ], { initialEntries: [...history], }, )手动添加带Outlet的根路由
如果坚持用createRoutesFromElements,需要手动包裹一个根路由,并用<Outlet />渲染子路由内容:const memRouter = createMemoryRouter( createRoutesFromElements( <Route path="/" element={<Outlet />}> <Route path={route} element={ui} errorElement={<TestErrorBoundary />} /> </Route> ), { initialEntries: [...history], }, )
另外记得检查TestErrorBoundary组件是否能正常返回JSX,避免错误边界自身导致的渲染异常。
内容的提问来源于stack exchange,提问作者Gabriele Buffolino
相关产品推荐
相关产品推荐

