如何使用react-testing-library和jest测试链接

5

尝试学习测试。使用testing-library、Jest和React-Router v6以及Typescript。我正在尝试找出如何测试链接。我已经到处寻找解决方案,但找不到一个。使用React-Router v6。代码看起来像下面这样(link仅是带有href的常规元素),只想确保用户能够到达新页面(在这种情况下是从“忘记密码”页面到登录页面)。

//omitted imports but imported all appropriate items from below

describe('ForgotPassword', () => {
  test('User can navigate to login screen', async () => {
    render(
      <MemoryRouter initialEntries={['/forgot-password' ]}>
        <ForgotPassword />
      </MemoryRouter>)

    userEvent.click(screen.getByRole('link', { name: 'Back to Login' }))

    await waitFor(() => {
      expect(screen.getByRole('heading', { name: 'Login' })).toBeInTheDocument()
    })
  })

//also tried:

describe('ForgotPassword', () => {
  test('User can navigate to login screen', async () => {
    render(
      <MemoryRouter initialEntries={['/forgot-password' ]}>
        <Routes>
            <Route path='/forgot-password' component={<ForgotPassword />} />
            <Route path='/login' component={<Login />} />
        <Routes>
      </MemoryRouter>)

    userEvent.click(screen.getByRole('link', { name: 'Back to Login' }))

    await waitFor(() => {
      expect(screen.getByRole('heading', { name: 'Login' })).toBeInTheDocument()
    })
  })

//also tried the following:

const history = createMemoryHistory({ initialEntries: ['/home'] });
    const { getByText } = render(
      <Router history={history}>
        <ButtonLogin />
      </Router>
    );

got a TS error: Property 'history' does not exist on type 'IntrinsicAttributes & RouterProps'.

//also tried using fireEvent instead of userEvent

这个回答解决了你的问题吗?如何使用Jest测试React Router - Willow
你正在尝试测试的链接是你创建的组件吗?不要测试你没有编写的第三方代码。你提到了使用 href,请在你的问题中也包含所有相关的代码。https://stackoverflow.com/help/minimal-reproducible-example - Drew Reese
2个回答

6
@exaucae的回答对于普通的Link非常完美。如果你在Link中使用reloadDocument,你的测试将会失败,并且控制台会显示一个错误信息,指出“错误:未实现导航(除哈希更改外)”。
我想在我的链接中使用reloadDocument,这样当用户导航时整个应用程序就会刷新。下面是我如何测试这些链接的方式。这不是我想要的测试方式,但它让我确信这些链接正在工作。
// NavMenu.tsx
import React from "react";
import { Link } from "react-router-dom";

export const NavMenu = () => {
    return (
        <div data-testid={"nav-menu"}>
            <Link reloadDocument to={"/some-page"}>Some Page</Link>
        </div>
    );
};


// NavMenu.test.tsx
import { NavMenu } from "./NavMenu";
import { render, screen } from "@testing-library/react";
import React from "react";
import { MemoryRouter, Route, Routes } from "react-router-dom";

describe(NavMenu.name, () => {
    test("should link", () => {
        render(
            <MemoryRouter>
                <Routes>
                    <Route path="/" element={<NavMenu/>}/>
                </Routes>
            </MemoryRouter>,
        );
        const links: HTMLAnchorElement[] = screen.getAllByRole("link");

        expect(links[0].textContent).toEqual("Some Page");
        expect(links[0].href).toContain("/some-page");
    });

我还打算在Link周围实现自己的包装器,称为RefreshingLink,它始终具有reloadDocument。这样,任何其他想将链接添加到NavMenu的开发人员都可以遵循该模式并使用RefreshingLink,而不必考虑它是否会刷新。


3

你的第二次尝试已经很接近成功了。在react-router v6.x中,你需要将component属性改为element


describe('ForgotPassword', () => {
  test('User can navigate to login screen', async () => {

    function ForgotPassword() {
      return (
        <div>
          <h1>Home</h1>
          <Link to="../login">Back to Login</Link>
        </div>
      );
    }
    render(
      <MemoryRouter initialEntries={['/forgot-password' ]}>
        <Routes>
            <Route path='/forgot-password' element={<ForgotPassword/>} />
            <Route path='/login' element={<h1>Login</h1>} />
        <Routes>
      </MemoryRouter>)

    userEvent.click(screen.getByRole('link', { name: 'Back to Login' }))

    await waitFor(() => {
      expect(screen.getByRole('heading', { name: 'Login' })).toBeInTheDocument()
    })
  })
})

注意:无论何时不确定,React-router-dom的内部测试都是获取提示的好方法。

不幸的是,这也不起作用。我收到了这个错误:“未实现:导航(除哈希更改外)”。顺便说一下,我正在导入Login组件,并使用material-ui库,如果有任何线索,请告诉我。非常感谢您的帮助! - Juan Portillo
在我的情况下,即使它在浏览器中工作,它仍然停留在同一个视图,并且导航回到主页。 - SalahAdDin
我有同样的问题。我认为这是因为测试在NodeJS中运行,而不是在浏览器中运行,而且JSDOM没有实现一些window方法。如果我想出来了,我会在这里发布... - lortimer
@JuanPortillo @SalahAdDin 我的测试不通过,因为我在点击时使用了<Link reloadDocument ...>来刷新整个页面。React Router使用该标志来决定是使用它自己的点击实现还是让点击穿过锚点标签。当它在Jest测试期间传递给锚点时,导航失败,因为测试在NodeJS环境中运行,而window.location.reload不存在。我尝试了许多方式来模拟window.location.reload但都没有成功。我将在下面发布一个答案,说明我如何测试这些链接。 - lortimer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接