React Testing Library+AWS Amplify测试路由回退跳转异常问题
问题根因
该问题由三处测试逻辑错误共同导致,和Cognito Mock本身无关:
- 测试组件树和生产环境不一致:你直接单独渲染
<AddTimeSeriesFiles />单组件,没有挂载<Switch>路由匹配规则、UserContext.Provider等上层依赖,PrivateRoute路由守卫读不到合法认证状态,自动触发重定向逻辑把路径打到/根路由。同时因为Page A组件被直接挂在Router下,不受Switch的路由匹配规则约束,所以DOM会一直显示Page A内容,才会出现路径和渲染内容不匹配的异常。 - 路由历史栈初始化错误:你调用
history.push('', {})时直接把初始路径设为根路径/,也没有提前在历史栈中存入Page B的访问记录。页面返回按钮本质是调用history.goBack(),历史栈里没有Page B的条目,自然无法跳回目标地址。 - 异步逻辑未等待:Mock的
Auth.currentAuthenticatedUser是异步返回,点击返回按钮后认证校验、路由跳转的逻辑还没执行完成就同步做断言,拿不到最终的路由状态。
修复方案
按以下顺序调整测试代码即可:
- 修正Memory History初始化逻辑,模拟真实的用户访问历史栈,初始路径直接指向Page A,栈底保留Page B的访问记录:
// 历史栈顺序和真实流程一致:先访问Page B,再跳转到Page A const history = createMemoryHistory({ initialEntries: ['/add-station-options', '/add-time-series-files'], initialIndex: 1 // 默认停在Page A }); - 补全测试环境的组件树,和App.tsx里的生产结构保持一致,不要单独渲染单个页面组件,同时Mock UserContext的传值,保证路由守卫能读到已认证状态:
// 提前Mock UserContext需要的值,isLoadingUser必须设为false const mockUserCtx = { user: { attributes: {} }, isLoadingUser: false, handleSignIn: jest.fn(), handleSignOut: jest.fn(), handleUpdateAttributes: jest.fn(), handleConfirmEmailChange: jest.fn(), handleChangePassword: jest.fn(), }; render( <MockTheme> <Router history={history}> <UserContext.Provider value={mockUserCtx}> <ErrorProvider> <SuccessProvider> <AddStationProvider> <Switch> <PrivateRoute exact path={urls.addTimeSeriesFiles}> <AddTimeSeriesFiles /> </PrivateRoute> <PrivateRoute exact path={urls.addStationOptions}> <AddStationOptions /> </PrivateRoute> <PrivateRoute exact path={urls.addStationInfo}> <AddStationInfoPage /> </PrivateRoute> <Route exact path="/"> <div>Root Page</div> </Route> </Switch> </AddStationProvider> </SuccessProvider> </ErrorProvider> </UserContext.Provider> </Router> </MockTheme> ); - 点击返回按钮后,等待异步路由跳转完成再做断言,优先通过DOM元素判断页面是否跳转,再校验路径值,避免异步时序问题导致假失败:
fireEvent.click(screen.getByRole('button', { name: /Back/ })); // 等待Page B的标志性元素渲染完成,证明跳转成功 await waitFor(() => { expect(screen.getByText(/Add Station Options页面的固定文本/)).toBeInTheDocument(); }); expect(history.location.pathname).toBe('/add-station-options');
优化建议
- 涉及路由跳转的测试不要单独渲染单个页面组件,一定要渲染完整的路由配置和上层依赖Provider,否则路由守卫、路由匹配逻辑都不会按预期工作。
- 路由跳转是异步行为,所有点击后的断言都要放在
waitFor里等待状态更新完成,不要同步执行断言。 - 如果
PrivateRoute是直接调用Auth.currentAuthenticatedUser做校验而非读取UserContext,需要在渲染组件后先等待认证校验完成,再操作页面元素。
内容的提问来源于stack exchange,提问作者Karim Tamer
相关产品推荐
相关产品推荐

