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

Jest测试react-router@6的Create页面:自定义render与测试失效问题

问题:Jest测试React路由页面
return (<Create/>)
失败,自定义render函数导致路由不生效

问题现象

  • 测试未生效:即使将断言改为错误值(如查找文本"2"),测试仍显示通过
  • 添加async/await后,页面渲染的是根路径"/"的首页内容,无法找到
    return (<Create/>)
    页面的元素

初始测试代码

import { render } from "../../utils/test-utils";

describe("createPage ", () => {
  it("rendering create page", () => {
    render(<Create />, { path: "/create" });
    const button = screen.findByRole("button", { name: "등록" });
    expect(screen.findByTestId("title"));
    expect(button);
  });

  it("change input text ", () => {
    render(<Create />, { path: "/create" });
    const TitleInput = screen.findByRole("textbox");

    user.type(TitleInput, "1");
    waitFor(() => {
      expect(screen.getByText("1")).toBeInTheDocument();
    });
  });
});

自定义render函数代码

function render(ui, { preloadedState = {}, path, ...renderoptions } = {}) {
  function Wrapper({ children }) {
    return (
      <Provider store={store}>
        <BrowserRouter>
          <Routes>
            <Route path="/" element={<Layout />}>
              <Route path={path} element={children} />
            </Route>
          </Routes>
        </BrowserRouter>
      </Provider>
    );
  }

  return {
    store,
    ...rtlRender(ui, { wrapper: Wrapper, ...renderoptions }),
  };
}

添加async/await后的测试代码及错误

测试代码

it("createPage title & content 값 입력", async () => {
  render(<Create />, { path: "/create" });

  const TitleInput = await screen.findByRole("textbox");

  user.type(await TitleInput, "1");
  await waitFor(() => {
    expect(screen.getByText("2")).toBeInTheDocument();
  });
});

错误信息

Unable to find role="textbox"

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="sc-beySbM fdrGAC"  <== it's my index page(path:"/")
    />
  </div>
</body>

问题原因分析

  1. 异步断言未正确处理:findByRole/findByTestId是异步查询函数,返回Promise,直接expect(Promise)永远为真,不会等待实际查询结果,导致断言无效。
  2. 路由匹配失败:测试环境使用BrowserRouter时,默认路由路径为"/",未设置目标路由/create,因此仅渲染根路径的Layout内容,嵌套的
    return (<Create/>)
    路由未激活。

解决方案

1. 修复异步断言问题

所有findBy*方法必须用await等待结果,断言要针对实际DOM元素而非Promise:

it("rendering create page", async () => {
  render(<Create />, { path: "/create" });
  const button = await screen.findByRole("button", { name: "등록" });
  const titleElement = await screen.findByTestId("title");
  expect(titleElement).toBeInTheDocument();
  expect(button).toBeInTheDocument();
});

2. 修复路由匹配问题

测试环境改用MemoryRouter替代BrowserRouter,通过initialEntries设置当前路由路径,确保路由正确匹配:

import { MemoryRouter } from 'react-router-dom'; // 导入MemoryRouter

function render(ui, { preloadedState = {}, path = "/", ...renderoptions } = {}) {
  function Wrapper({ children }) {
    return (
      <Provider store={store}>
        <MemoryRouter initialEntries={[path]}>
          <Routes>
            <Route path="/" element={<Layout />}>
              <Route path={path} element={children} />
            </Route>
          </Routes>
        </MemoryRouter>
      </Provider>
    );
  }

  return {
    store,
    ...rtlRender(ui, { wrapper: Wrapper, ...renderoptions }),
  };
}

3. 修复输入测试的异步逻辑

user.type是异步操作,需要用await等待完成,同时避免重复await已获取的元素:

it("change input text ", async () => {
  render(<Create />, { path: "/create" });
  const titleInput = await screen.findByRole("textbox");

  await user.type(titleInput, "1");
  await waitFor(() => {
    expect(screen.getByText("1")).toBeInTheDocument();
  });
});

内容的提问来源于stack exchange,提问作者dev.kip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 11:57:54