如何使用react-testing-library测试锚点的href属性

134

我正在尝试测试我的锚标签。一旦我点击它,我想看看window.location.href是否符合我的期望。

我已经尝试渲染该锚标签、单击它,然后测试window.location.href

test('should navigate to ... when link is clicked', () => {
  const { getByText } = render(<a href="https://test.com">Click Me</a>);

  const link = getByText('Click Me');

  fireEvent.click(link);

  expect(window.location.href).toBe("https://www.test.com/");
});

我希望测试能够通过,但实际上,window.location.href 只是 "http://localhost/",这意味着无论什么原因它都没有被更新。我甚至尝试用 await wait 包装我的期望,但也没有起作用。我找不到关于使用 react-testing-library 测试锚点的信息。也许有比我现在做的更好的方法来测试锚点。‍♂️

10个回答

219

2
我收到了 TypeError: getByText(...).closest is not a function 的错误信息,有什么想法吗? - S..
2
我猜 getByText 在你的情况下没有找到任何内容。 - Gio Polvara
3
我曾经遇到过同样的问题,将 import "@testing-library/jest-dom/extend-expect"; 添加到文件顶部解决了这个问题。 - Pedro Silva
5
由于使用closest('a')进行搜索,它与 react-testing-library 的精神相比略逊一筹("测试越像软件的使用方式,您就越能获得信心")。在我看来,getByRole('link')更符合库的精神,因为不需要进行这样的搜索。即使这个库本身的精神值得商榷。请注意,我没有打负面评分 - 只是说一下... - quickshiftin
这对我没有用,我有这个DOM:<a href="some-url">下一步</a>,我尝试了 expect(screen.getByText('下一步').closest('a')).toHaveAttribute('href', "some-url")。但是出现了这个错误: 期望该元素具有属性: href="some-url" 收到的是: null - Rahul Sagore
显示剩余2条评论

93

我找到了一个可能对其他人有帮助的解决方案。在React测试库中,<a> 元素被视为 link 角色。这应该可以解决问题:

expect(screen.getByRole('link')).toHaveAttribute('href', 'https://www.test.com');

5
这可能是最好的答案,因为在 RTL 文档中指出,按角色查询在查询方面具有最高的优先级。关于查询 - Corey Gumbs
这仅在页面上只有1个链接时有效。 - Constantin
@Constantin 如果页面上有更多的链接,您需要使用 getAllByRole() 并定位到您想要的特定链接。 - Dominic Dabrowiecki
你还可以使用.getByRole('link', { name: 'text of link' }) - undefined

36

如果您正在使用screen,这应该是RTL作者首选的方式:

const linkEl = screen.getByRole('link', { name: 'Click Me' });

expect(linkEl).toHaveAttribute('href', '...')

类似的,没有屏幕(名称可以是字符串或正则表达式):

const linkEl = getByRole('link', { name: /click me/i }); 

23
你可以直接使用这个代替:
expect(getByText("Click Me").href).toBe("https://www.test.com/")

1
这并不能防止开发中出现错误,例如存在prop href但没有<a />。考虑动态组件,例如将按钮呈现为链接。当然,这没有意义,但为了在测试中强制失败,您需要验证属性href是否在链接元素中使用。 - carlosnufe
1
你需要引用屏幕,但即使这样做,你仍会收到类型错误,因为: TS2339:在类型“HTMLElement”上不存在属性“href”。 - Boogie
1
在React中,/link被转换为http://localhost/link,导致测试失败。使用toHaveAttribute可以正确地工作。 - James Gentes

7

简单易懂。

试试这个

  it('should be a link that have href value to "/login"', () => {
    render(<SigningInLink />);
    const link = screen.getByRole('link', { name: /log in/i });
    expect(link.getAttribute('href')).toBe('/login');
  });

6

您可能需要在页面上检查多个链接。我发现以下建议非常有用。为了适应在同一页上检查5个链接,我进行了以下调整:

  1. 使用screen()方法查询页面上的链接 - 这是最佳实践,更加可靠。
  2. 断言链接是否存在于页面中。
  3. 将链接赋值给一个变量。
  4. 对链接调用事件。
  5. 确保使用toHaveAttribute方法来验证url,而不是使用window对象进行导航。在React中使用虚拟DOM时,如果尝试导航到另一页,则链接将指向http://localhost/link, 而不是测试重定向。
test('should navigate to url1 when link is clicked', () => {

const componentName = render(<Component/>)

const url1 = getByText("https://www.test.com/")
expect(ur1).toBeInTheDocument()
screen.userEvent.click(url1);
expect(url1).toHaveAttribute('href', 'https://www.test.com/')

});

6
也许在这种情况下,它过于工程化了。但是您也可以使用data-testid属性。这可以保证您获得a标签。我认为对于更复杂的组件,这样做有好处。
test('should navigate to ... when link is clicked', () => {
  const { getByTestId } = render(<a data-testid='link' href="https://test.com">Click Me</a>);

  expect(getByTestId('link')).toHaveAttribute('href', 'https://test.com');
   
});

6

这是我使用的:

const linkToTest = screen.getByRole("link", { name: /link to test/i })
// I used regex here as a value of name property which ignores casing

expect(linkToTest.getAttribute("href")).toMatchInlineSnapshot();

然后运行测试,toMatchInlineSnapshot 的括号将用代码中的值填充。

这样做的好处是不需要硬编码,维护会更容易。

例如:它将被填充为:

expect(linkToTest.getAttribute("href")).toMatchInlineSnapshot(`"link/to/somewhere"`);

下一次,假设您在代码库中更改此链接为其他内容,运行程序将询问您是否要更新,按u键即可完成更新(请注意,您需要检查此更新是否正确)。

了解有关内联快照的更多信息,请参阅Jest文档


3

这是对我有效的方法:


expect(screen.getByText('Click Me').closest('a')?.href).toEqual('https://test.com');


0

这是我所做的,使用testing-library/react对我有效

import { render, screen } from '@testing-library/react';
import {HomeFeature} from '../Components/HomeFeature.tsx';

let imp_content = [
    {
        title: "Next.js",
        link: "https://nextjs.org/",
    },
    {
        title: "React",
        link: "https://reactjs.org/",
    },
    {
        title: "Firebase",
        link: "https://firebase.google.com/",
    },
    {
        title: "Tailwind",
        link: "https://tailwindcss.com/",
    },
    {
        title: "TypeScript",
        link: "https://www.typescriptlang.org/",
    },
    {
        title: "Jest.js",
        link: "https://jestjs.io/",
    },
    {
        title: "testing-library/react",
        link: "https://testing-library.com/",
    }
];

imp_content.map((content) => {
    test(`${content.title} contains ${content.link}`, () => {
        render(<HomeFeature />);
        expect(screen.getByText(content.title).closest('a')).toHaveAttribute('href', content.link);
    })
})

你好,我想指出你的回答违反了 eslint-plugin-testing-library/no-node-access 规则,因为在库已经提供了查询 DOM 元素的方法时,使用 .closest 访问节点。 - George S

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