6

I'm trying something like this:

const useSelector = jest.fn();
jest.mock('react-redux', () => ({
  useSelector,
}));

Then trying to do something like this:

useSelector.mockReturnValueOnce({});
shallow(
  <ComponentUsingUseSelector />
);

That will give me an error:

The module factory of jest.mock() is not allowed to reference any out-of-scope variables.

So if I can't use an out of scope variable for a mock then how would I return a different value for every test?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
HMR
  • 37,593
  • 24
  • 91
  • 160

3 Answers3

6

Simplified version, which also works:

import * as redux from 'react-redux'

jest
  .spyOn(redux, 'useSelector')
  .mockReturnValueOnce('first call')

Also, instead of relying on multiple calls to mockReturnValueOnce it's better to just stub the necessary part of the store:

const locale = 'en'

const state = {
  application: { locale },
}

jest
  .spyOn(redux, 'useSelector')
  .mockImplementation((callback) => callback(state))
Paweł Gościcki
  • 9,066
  • 5
  • 70
  • 81
5

The following seems to work, after reading tons of articles and documentation that does not do what I (think) need to do; finally found one that does.

import { useSelector } from 'react-redux';

jest.mock('react-redux', () => ({
  useSelector: jest.fn(),
}));


describe('some test', () => {
  it('do something', () => {
    useSelector.mockImplementation(() => ('hello world'));
    shallow(
      <ComponentUsingUseSelector />
    );

If it's called multiple times I can do:

describe('some test', () => {
  it('do something', () => {
    useSelector.
      .mockReturnValueOnce('first call')
      .mockReturnValueOnce('second call')
    shallow(
      <ComponentUsingUseSelector />
    );
HMR
  • 37,593
  • 24
  • 91
  • 160
  • I think it could be useful to be clear about one thing: It doesn't work if we try to implement values at the beggining, I mean, is a mandatory to init the mock with: jest.mock('react-redux', () => ({ useSelector: jest.fn(), })); – Gerson Montenegro Dec 09 '20 at 04:06
0

Update answer to versions react-redux v8

Cannot redefine property: useSelector issue

If you're getting the following error:

  TypeError: Cannot redefine property: useSelector
        at Function.defineProperty (<anonymous>)

Apply this before tests:

import * as Redux from 'react-redux';

jest.mock('react-redux', () => ({
    ...jest.requireActual('react-redux'),
    useSelector: jest.fn()
}));

Example:

import * as Redux from 'react-redux';

// This will enable to mock readonly
jest.mock('react-redux', () => ({
    ...jest.requireActual('react-redux'),
    useSelector: jest.fn()
}));

describe('Component Tests', () => {
    beforeEach(() => {
        jest.spyOn(Redux, 'useSelector').mockReturnValue({
            users: [] // your mock here
        });
       // or
       // (useSelector as jest.Mock).mockImplementation(() => ({
       //      useSelector:[] your mock
       // }));
    });
    test('should render component', () => {
        render(<MyComponent />);
    });
});