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

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"的错误。

修复方式二选一:

  1. 直接定义路由数组,跳过createRoutesFromElements
    把路由创建逻辑改成直接传入路由配置数组,让你定义的路由直接作为根路由:

    const memRouter = createMemoryRouter(
      [
        {
          path: route,
          element: ui,
          errorElement: <TestErrorBoundary />,
        },
      ],
      {
        initialEntries: [...history],
      },
    )
    
  2. 手动添加带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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 17:25:29