testing react-redux useSelector
Asked Answered
R

4

15

I have a react application which uses react-redux, useSelector to get data from the store. The react component has

function PersonDataView() {
  const name= useSelector(state => state.data.name)
  const dob= useSelector(state => state.data.dob)
  const dispatch = useDispatch()
  const show= () => dispatch({type: 'SHOW'})
  const remove= () => dispatch({type: 'REMOVE'})
  return (
    <div>
      <h2>Person Details</h2>
     <div>
      <button onClick={show}>Show</button>
      <span aria-label="name">{name}</span>
      <span aria-label="dob">{dob}</span>
      <button onClick={remove}>Remove</button>
     </div>
   </div>
  )
}

I am using react-testing-library to test this component. Is there any API which makes testing these components easier for us. I know two ways of testing these: 1) I can mock the store using redux-mock-store and then wrap this component under provider component. 2) mock the useSelector method in jest

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

But the problem using jest mock is in case of multiple selector, all the useSelectors will return same mocked value. Using jest way of mocking, jest.fn().mockReturnValueOnce() doesn't look correct to me.

Roughen answered 31/1, 2020 at 21:29 Comment(0)
P
21

I'd suggest different approach - extracting your selectors into separate file, as e.g. file selectors.js:

const nameSelector = state => state.data.name;
const dobSelector = state => state.data.dob;

Then in test, you could mock useSelector as below:

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

And mock selectors separately, like:

jest.mock('./selectors.js', () => ({
  nameSelector: jest.fn().mockReturnValue("myTestName"),
  dobSelector: jest.fn().mockReturnValue("myTestDob"),
}));
Pelican answered 1/4, 2020 at 15:0 Comment(0)
B
1

Try this:

jest.mock('react-router');
const useSelectorMock = useSelector as any;

describe('something', () {

test('name', () => {

// Use this for each useSelector call:
useSelectorMock.mockImplementationOnce(jest.fn(() => returnValue as yourType));
}

}
Bakke answered 17/2, 2020 at 9:27 Comment(1)
TypeError: _reactRedux.useSelector.mockImplementationOnce is not a functionSerg
B
1

Try this approach:

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

You should also add one layer here:

jest.mock('react-redux', () => {
  const store = {
    data: {
      name: { 
           ...
      },
      dob: {
           ...
      }
    }
  };
Bindweed answered 1/4, 2021 at 22:54 Comment(0)
T
0

It's not a great practice to mock Redux. You want to test the integration between Redux and React components, not the Redux implementation of selectors. If you use react-testing-library it's pretty simple to hijack the render() method and implement your store using a Redux Provider component. Here are the docs and recommended approach for setting up a Reusable Test Render function.

Here's an example test using React Testing Library + Jest:

import { renderWithProviders } from '../../test-utils' // <-- Hijacked render

it('displays data when ready', {
  renderWithProviders(<YourComponent />, { 
    initialState: {
      dataready: true // <-- Pass data for selector
    }
  })
  expect(screen.getByText('data reader')).toBeInTheDocument();
})

Thrilling answered 14/6, 2023 at 16:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.