How to test anchor's href with react-testing-library

ReactjsJestjsAnchorHrefReact Testing-Library

Reactjs Problem Overview


I am trying to test my anchor tag. Once I click it, I want to see if the window.location.href is what I expect.

I've tried to render the anchor, click it, and then test 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/");
});

I am expecting the test to pass, but instead the window.location.href is just "http://localhost/" meaning it is not getting updated for whatever reason. I even tried wrapping my expect with await wait, but that didn't work either. I can't find much information about testing anchors with react-testing-library. Maybe there is even a better way to test them than what I am doing. 路‍♂️

Reactjs Solutions


Solution 1 - Reactjs

Jest uses jsdom to run its test. jsdom is simulating a browser but it has some limitations. One of these limitations is the fact that you can't change the location. If you want to test that your link works I suggest to check the href attribute of your <a>:

expect(screen.getByText('Click Me').closest('a')).toHaveAttribute('href', 'https://www.test.com/')

Solution 2 - Reactjs

I found a solution that may help others. The <a> element is considered a link role by React Testing Library. This should work:

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

Solution 3 - Reactjs

You can simply use this instead:

expect(getByText("Click Me").href).toBe("https://www.test.com/")

Solution 4 - Reactjs

If you are using screen which should be the preferred way, by RTL authors:

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

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

Similar, without screen (name can be string or RegExp):

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

Solution 5 - Reactjs

Maybe its overtly engineered in this case. But you can also use data-testid attribute. This guarantees that you are getting the a tag. I think there are benefit to this for more complex components.

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');
   
});

Solution 6 - Reactjs

simple and easy.

try this

  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');
  });

Solution 7 - Reactjs

This is what I use:

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();

and then run the test, brackets of toMatchInlineSnapshot will be filled with the value that's there in your code.

This has the advantage of not hard coding it, and maintaining this will be easier.

For eg: it will be filled like this:

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

and next time, suppose you change this link to something else in your codebase, the runner will ask you if you want to update, press u and it will be updated. (Note, that you need to check that this update is correct).

Know more about inline snapshots on Jest Docs

Solution 8 - Reactjs

You may have several links to check on a page. I found these suggestions very useful. What I did to adapt it to checking 5 links on the same page -

  1. query the link on the page with the screen() method best practice - it is more reliable
  2. assert the link is on the page
  3. assign the link to a variable
  4. call event on the link
  5. ensure the url toHaveAttribute method rather than navigating with the window object - In react with the virtual DOM, if you try and navigate to another page the link directs to http://localhost/link rather than testing the redirect
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/')

});

Solution 9 - Reactjs

This is what worked for me:


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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjaypeeView Question on Stackoverflow
Solution 1 - ReactjsGiorgio Polvara - GpxView Answer on Stackoverflow
Solution 2 - ReactjsDominic DabrowieckiView Answer on Stackoverflow
Solution 3 - ReactjsJohnson ChinonsoView Answer on Stackoverflow
Solution 4 - ReactjsConstantinView Answer on Stackoverflow
Solution 5 - Reactjscruise_labView Answer on Stackoverflow
Solution 6 - ReactjsAndriyFMView Answer on Stackoverflow
Solution 7 - ReactjsAdnan SheikhView Answer on Stackoverflow
Solution 8 - ReactjsSumiView Answer on Stackoverflow
Solution 9 - ReactjsMelchiaView Answer on Stackoverflow