Search code examples
reactjsjestjsreact-routerreact-router-domreact-testing-library

reactjs - Find Navlink using getByRole in unit test


In my React Testing Library unit test, I am unable to get the Navlink by role.

getByRole('link', { name: 'help' }) - This fails

The Navlink does not have text, rather it has a help icon which seems to be the problem.

The error I recieve is:

TestingLibraryElementError: Unable to find an accessible element with the role "link" and name "help"

Here are the accessible roles:

link:

Name "Home":
<a
class="active"
href="home"
name="home"
/>

Name "About":
<a
class="inactive"
href="/about"
name="about"
/>

Name "":          <--- No name for link with icon
<a
class="inactive"
href="/help"
name="help"
/>

My NavBar:

const NavBar = () => {

  return (
    <>
        <div className="navbar">
            <ul>
                <li>
                  <NavLink to="home" className={({isActive}) => (isActive ? 'active' : 'inactive')}>Home</NavLink>
                </li>
                <li>
                  <NavLink to="about" className={({isActive}) => (isActive ? 'active' : 'inactive')}>About</NavLink>
                </li>
                <li>
                    <NavLink to="help" name="help" className={({isActive}) => (isActive ? 'active' : 'inactive')}><FaQuestionCircle size='1.5rem' className="helpicon"/></NavLink>
                </li>
            </ul> 
        </div>
    </>
  );
};

export default NavBar;

The failing unit test:

describe(Navbar, () => {

    const mockedNavigation = jest.fn();
    
    it('should navigate to help page', () => {
        
        const { getByRole } = render(<Navbar />, { wrapper: Router });
        fireEvent.click(getByRole('link', { name: 'help' }));

        expect(mockedNavigation).toHaveBeenCalledWith(
            "help", 
            {
                preventScrollReset: undefined,
                relative: undefined,
                replace: false,
                state: undefined,
                unstable_viewTransition: undefined
            });
    });
});

How do I select a Navlink that does not have text, but uses an icon instead?

Maybe I can use classNames? Add an additional class as well as the active/inactive? Another method would be easier though and more readable.


Solution

  • The <NavLink/> component can't accept the name property. If you use TypeScript, you will get a TS-type error:

    Type '{ children: Element; to: string; name: string; className: ({ isActive }: NavLinkRenderProps) => "active" | "inactive"; }' is not assignable to type 'IntrinsicAttributes & NavLinkProps & RefAttributes<HTMLAnchorElement>'.
      Property 'name' does not exist on type 'IntrinsicAttributes & NavLinkProps & RefAttributes<HTMLAnchorElement>'.ts(2322)
    

    Instead, you can pass a title prop to the icon component as the accessible name of the <NavLink/>. E.g.

    import React from 'react';
    import { NavLink } from 'react-router-dom';
    import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
    import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
    
    const NavBar = () => {
      return (
        <>
          <div className="navbar">
            <ul>
              <li>
                <NavLink to="/home" className={({ isActive }) => (isActive ? 'active' : 'inactive')}>
                  Home
                </NavLink>
              </li>
              <li>
                <NavLink to="/about" className={({ isActive }) => (isActive ? 'active' : 'inactive')}>
                  About
                </NavLink>
              </li>
              <li>
                <NavLink to="/help" className={({ isActive }) => (isActive ? 'active' : 'inactive')}>
                  <FontAwesomeIcon icon={faQuestionCircle} className="helpicon" title="help" />
                </NavLink>
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default NavBar;
    

    NavBar.test.tsx:

    import React from 'react';
    import { fireEvent, render, screen } from '@testing-library/react';
    import '@testing-library/jest-dom';
    import NavBar from './NavBar';
    import { MemoryRouter } from 'react-router-dom';
    
    describe('Navbar', () => {
      it('should navigate to help page', () => {
        render(
          <MemoryRouter initialEntries={['/help']}>
            <NavBar />
          </MemoryRouter>,
        );
        const navLink = screen.getByRole('link', { name: 'help' });
        console.log('🚀 ~ it ~ navLink:', navLink);
        fireEvent.click(navLink);
        expect(navLink).toHaveClass('active');
      });
    });
    

    Test result:

     PASS  stackoverflow/77897051/NavBar.test.tsx
      Navbar
        √ should navigate to help page (109 ms)                                                                                                                                                                                                          
                                                                                                                                                                                                                                                         
    Test Suites: 1 passed, 1 total                                                                                                                                                                                                                       
    Tests:       1 passed, 1 total                                                                                                                                                                                                                       
    Snapshots:   0 total
    Time:        1.627 s
    Ran all test suites related to changed files.
    

    package version:

    "@fortawesome/fontawesome-svg-core": "^6.5.1",
    "@fortawesome/free-solid-svg-icons": "^6.5.1",
    "@fortawesome/react-fontawesome": "^0.2.0",
    "react": "^18.2.0",
    "react-router-dom": "^6.21.1",
    
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "@testing-library/jest-dom": "^6.1.4",
    "@testing-library/react": "^14.1.2",