Search code examples
reactjsjestjsreact-testing-libraryrecoiljs

How to mock recoil custom hook


Custom hook:

export const usersState = atom({
  key: 'usersState',
  default: [],
});

export const useUsersList = () => {
  return useRecoilValue(usersState);
};

React component:

export const UsersList = () => {
  const names = useUsersList();

  return (
    <ul>
      {names.map((name) => `<li key={name}>${name}</li>`)}
    </ul>
  );
};

Test:

jest.mock('../hooks/useUsersList');

describe('when filled', () => {
    const names = ['Moses', 'Jacob'];

    it('should render the names', () => {
      useUsersList.mockReturnValue(names);

      render(
        <RecoilRoot>
          <UsersList />
        </RecoilRoot>
      );


      const itens = screen.queryAllByRole('listitem');
      expect(itens).toHaveLength(names.length);
    });
  });

Error:

Expected length: 2
Received length: 0
Received array:  []

Even though I'm mocking the return value, when testing it always has a length of zero. Have tried a bunch of different jest mock and spyon use cases, but it always ended up in the same output.


Solution

  • Using screen.debug() I found out my component was rendering plain text instead of HTML. So I changed:

    <ul>
      {names.map((name) => `<li key={name}>${name}</li>`)}
    </ul>
    

    To this:

    <ul>
      {names.map((name, i) => <li key={i}>{name}</li>)}
    </ul>