Jacob
Jacob

Reputation: 301

What is the correct way to mock useSelector multiple times in a component?

I have a component that makes two useSelector calls upon rendering. Right now I have mocked useSelector and successfully returned 2 separate values from the 2 calls, it looks like:

const Redux = require('react-redux');
const mockSelectorSpy = jest.spyOn(Redux, 'useSelector');  
mockSelectorSpy.mockReturnValueOnce(userGuid).mockReturnValueOnce(user);

This works and I can log out the return values, however, this causes the test to break and throws the following error:

Warning: React has detected a change in the order of Hooks called by ProfileScreen. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks
    
       Previous render            Next render
       ------------------------------------------------------
    1. useState                   useContext
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
        in ProfileScreen (created by _class)
        in _class (created by _class2)
        in ThemeProvider (created by _class2)
        in _class2
        in Provider

If I only call the first selector call, the app runs but, the test fails because I need the data from the second call.

Any tips are much appreciated.

Upvotes: 1

Views: 1271

Answers (1)

Paweł Gościcki
Paweł Gościcki

Reputation: 9624

In my opinion it's best to mock specific part of the Redux store in the following way, which makes it independable on subsequent calls to useSelector (which might be caused by re-renders which happens during test run):

  import * as redux from 'react-redux'

  const user = {
    id: 1,
    name: 'User',
  }

  const state = { user }

  jest
    .spyOn(redux, 'useSelector')
    .mockImplementation((callback) => callback(state))

Upvotes: 1

Related Questions