Jest测试react-router@6的Create页面:自定义render与测试失效问题
问题:Jest测试React路由页面
失败,自定义render函数导致路由不生效return (<Create/>)
问题现象
- 测试未生效:即使将断言改为错误值(如查找文本"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>
问题原因分析
- 异步断言未正确处理:
findByRole/findByTestId是异步查询函数,返回Promise,直接expect(Promise)永远为真,不会等待实际查询结果,导致断言无效。 - 路由匹配失败:测试环境使用
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
相关产品推荐
相关产品推荐

