I am using React v18.2.0 and React Testing Library v5.17.0.
How should I unit test the NavLinks in my navigation bar?
I think this test should work, but I am getting the error:
Expected: "about"
Received: "about", {"preventScrollReset": undefined, "relative": undefined, "replace": false, "state": undefined, "unstable_viewTransition": undefined}
Looks like an object is being passed as well as the route and it is causing the test to fail?
My NavBar:
const NavBar = () => {
return (
<>
<div className="navbar">
<ul>
<li>
<NavLink to="home" className="navlink">Home</NavLink>
</li>
<li>
<NavLink to="about" className="navlink">About</NavLink>
</li>
</ul>
</div>
</>
);
};
export default Navbar;
My unit test:
import { render, fireEvent } from "@testing-library/react";
import NavBar from './NavBar';
import * as router from 'react-router';
import { BrowserRouter as Router } from 'react-router-dom';
describe(NavBar, () => {
const mockedNavigation = jest.fn();
const MockedNav = () => {
return(
<Router>
<Navbar />
</Router>
)
}
beforeEach(() => {
jest.spyOn(router, 'useNavigate').mockImplementation(() => mockedNavigation)
})
it('should navigate to the about page', () => {
const { getByText } = render(<MockedNav />);
fireEvent.click(getByText(/About/i));
expect(mockedNavigation).toHaveBeenCalledWith("about");
});
})
The function you are mocking is passed these other arguments.
You can simply add the additional arg to the test:
describe(NavBar, () => {
const mockedNavigation = jest.fn();
beforeEach(() => {
jest.spyOn(router, 'useNavigate').mockImplementation(() => mockedNavigation
}
it('should navigate to the about page', () => {
const { getByText } = render(<Navbar />, { wrapper: Router });
fireEvent.click(getByText(/About/i));
expect(mockedNavigation).toHaveBeenCalledWith(
"about",
{
preventScrollReset: undefined,
relative: undefined,
replace: false,
state: undefined,
unstable_viewTransition: undefined
}
);
});
})
You can assert the mock was called and that the first argument is what you expect:
describe(NavBar, () => {
const mockedNavigation = jest.fn();
beforeEach(() => {
jest.spyOn(router, 'useNavigate').mockImplementation(() => mockedNavigation
});
it('should navigate to the about page', () => {
const { getByText } = render(<Navbar />, { wrapper: Router });
fireEvent.click(getByText(/About/i));
expect(mockedNavigation).toHaveBeenCalled();
expect(mockedNavigation.mock.calls[0][0]).toEqual("about");
});
});
Or you can use an asymmetric matcher to assert anything passed in the second arg (since it appears you don't care what that specific value is):
describe(NavBar, () => {
const mockedNavigation = jest.fn();
beforeEach(() => {
jest.spyOn(router, 'useNavigate').mockImplementation(() => mockedNavigation
}
it('should navigate to the about page', () => {
const { getByText } = render(<Navbar />, { wrapper: Router });
fireEvent.click(getByText(/About/i));
expect(mockedNavigation).toHaveBeenCalledWith(
"about",
expect.anything(),
);
});
})