如何使用RTL异步测试React中的history.push路由跳转功能
问题根因
- 没有mock异步依赖
createAuthor:测试环境下没有真实的后端服务支撑这个接口调用,接口要么抛出异常要么永远处于pending状态,导致await createAuthor之后的跳转逻辑永远不会执行。 - 没有等待异步逻辑执行完成就做断言:
handleSave是异步函数,点击按钮后你没有等异步任务跑完就立刻校验跳转结果,此时跳转逻辑还没触发。另外你给history.length、history.location.pathname加await完全无效,这两个都是history对象的同步属性,不会等待异步逻辑执行。
修复方案
- 首先mock
createAuthor方法,让它返回正常resolve的Promise,模拟接口调用成功的场景 - 点击按钮时等待异步事件执行完成,或者用
waitFor包裹跳转断言,保证校验时异步逻辑已经跑完 - 移除history属性前无效的
await
以下是修改后的完整测试代码:
import React from "react"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { createMemoryHistory } from "history"; import { Router } from "react-router-dom"; import { ROUTE_AUTHOR_LIST } from "../constants"; // 导入要mock的异步方法 import { createAuthor } from "../../services/authors"; // mock整个authors服务 jest.mock("../../services/authors", () => ({ createAuthor: jest.fn().mockResolvedValue({ id: 1, name: '测试作者' }) })); describe("Save button functionality", () => { test("redirect to correct URL", async () => { const history = createMemoryHistory(); render( <Router history={history}> <AuthorCreate /> </Router> ); // 如果组件内没有对应heading可以删掉这行断言 expect( screen.getByRole("heading", { name: /create author/i }) ).toBeInTheDocument(); const saveBtn = screen.getByRole("button", { name: /save/i, type: "button", }); // userEvent.click本身支持await,等待事件触发的所有异步逻辑执行完成 await userEvent.click(saveBtn); // 用waitFor包裹断言,保证跳转完成后再校验 await waitFor(() => { expect(history.length).toBe(2); expect(history.location.pathname).toBe(ROUTE_AUTHOR_LIST); }) // 可额外加断言验证createAuthor是否被正确调用 expect(createAuthor).toHaveBeenCalledTimes(1); }); })
内容的提问来源于stack exchange,提问作者kornavol
相关产品推荐
相关产品推荐

