'How to test link using react-testing-library and jest
Trying to learn testing. Using testing-library, Jest, and React-Router v6, and Typescript. I'm trying to figure out how to test a link. I've been looking all over the place for a solution and I can't find one. Using React-Router v6. Code looks like the following (link is just a regular element with an href) just want to make sure the user gets to the new page (in this case the login page from the forgot password page).
//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
Solution 1:[1]
Your second try was nearly good. You'd have to change component prop to element in react-router v6.x:
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()
})
})
})
Note: whenever in doubt, React-router-dom 's internal tests are a great way to have a hint.
Solution 2:[2]
@exaucae's answer is perfect for regular Links. If you're using reloadDocument in your Link, your test will fail, and the console will show an error that says "Error: Not implemented: navigation (except hash changes)".
I want to use reloadDocument in my links so my whole app is refreshed when the user navigates. Below is how I'm testing those links. It's not how I would prefer to test them, but it gives me confidence that the links are working.
// 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");
});
I'm also going to implement my own wrapper around Link called RefreshingLink which always has reloadDocument. That way, any other developer who wants to add a link to the NavMenu can just follow the pattern and use a RefreshingLink, and not think about whether it refreshes or not.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | exaucae |
| Solution 2 | lortimer |
