2

I'm fairly new to the world of writing tests for React so forgive the possible newbie question. I've done a fair amount of research and have not found anything that covers this as yet.

I have a really simple BackButton component, all it does is render a button and have an onClick event that goes back in the history. It uses react-router v6 if that is helpful.

import * as React from 'react';
import Stack from '@mui/material/Stack';
import { ArrowCircleLeftOutlined } from '@mui/icons-material';
import { Link, useNavigate } from 'react-router-dom';

export default function BackButton() {
    const navigate = useNavigate();
    return (
        <Stack direction="row" spacing={1}>
            <Link onClick={() => navigate(-1)} aria-label="back" data-testid="backButton">
                <ArrowCircleLeftOutlined />
            </Link>
        </Stack>
    );
}

I've written a test for this using Testing Library but can't seem to figure out a way to see what the location changed to. window.location.href just returns http://localhost

import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import BackButton from './BackButton';

it('has a href that refers to the previous page', () => {
    const initialLink = "/foo";

    render(
        <MemoryRouter initialEntries={[initialLink]}>
            <BackButton />
        </MemoryRouter>
    );

    const element = screen.getByTestId('backButton');
    expect(element.getAttribute('href')).toBe(initialLink);
    fireEvent.click(element);
    // How do I test the location changed?
})
Catharsis
  • 616
  • 4
  • 20
  • Does this answer your question? [Simplest test for react-router's Link with @testing-library/react](https://stackoverflow.com/questions/61869886/simplest-test-for-react-routers-link-with-testing-library-react) – Florian Motteau Sep 26 '22 at 14:31
  • @FlorianMotteau Not quite, I tried something like this but `MemoryRouter` does not have a `history` property and using `Router` gives me an error `Uncaught [TypeError: Cannot read property 'pathname' of undefined]` – Catharsis Sep 26 '22 at 15:52
  • Why are you testing the 3rd-party code from `react-router-dom`? Why are you using `react-testing-library` if you are not unit testing the `BackButton` component? The unit test should *mock* the `useNavigate` hook with a mock `navigate` function and assert it was called with a specific argument. – Drew Reese Sep 26 '22 at 16:31
  • @DrewReese as I said still fairly new to React testing and I've not found many understandable examples out there. I'll look into how to mock `useNavigate`. If you have any good links for this I'd appreciate it. – Catharsis Sep 27 '22 at 08:02

2 Answers2

1

After being pointed in the direction of mocking useNavigate (Thanks @DrewReece) I was then able to check to see how many times and how useNavigate was called. The test I ended up with is below. I still had to use react-testing-library so I could fire the event on the screen but very open to learning if this is not the best way to do it.

import React from 'react';
import BackButton from './BackButton';
import { MemoryRouter } from 'react-router-dom';
import { render, fireEvent, screen } from '@testing-library/react';

const mockedUseNavigate = jest.fn();

jest.mock('react-router-dom', () => ({
   ...jest.requireActual('react-router-dom'),
  useNavigate: () => mockedUseNavigate,
}));

it('navigates to previous page on click', () => {
    render(<MemoryRouter><BackButton /></MemoryRouter>);

    const element = screen.getByTestId('backButton');
    fireEvent.click(element);

    expect(mockedUseNavigate).toBeCalledTimes(1);
    expect(mockedUseNavigate).toBeCalledWith(-1);
})
Catharsis
  • 616
  • 4
  • 20
  • Nope, this looks pretty good. The Jest docs are typically sufficient enough to see how to mock various functions/modules. And OFC RTL is still needed so you can interact with the component under test. – Drew Reese Sep 27 '22 at 15:34
-3

location for react-router

import { useLocation } from "react-router-dom"

const location = useLocation() console.log(location.pathname)