Testing custom hook: Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
Asked Answered
D

5

32

I got a custom hook which I want to test. It receives a redux store dispatch function and returns a function. In order to get the result I'm trying to do:

const { result } = renderHook(() => { useSaveAuthenticationDataToStorages(useDispatch())});

However, I get an error:

Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a

It happens because of the useDispatch and that there is no store connected. However, I don't have any component here to wrap with a provider.. I just need to test the hook which is simply saving data to a store.

How can I fix it?

Dionedionis answered 25/12, 2019 at 9:21 Comment(0)
B
34

The react hooks testing library docs go more into depth on this. However, what we essentially are missing is the provider which we can obtain by creating a wrapper. First we declare a component which will be our provider:

import { Provider } from 'react-redux'

const ReduxProvider = ({ children, reduxStore }) => (
  <Provider store={reduxStore}>{children}</Provider>
)

then in our test we call

test("...", () => {
  const store = configureStore();
  const wrapper = ({ children }) => (
    <ReduxProvider reduxStore={store}>{children}</ReduxProvider>
  );
  const { result } = renderHook(() => {
    useSaveAuthenticationDataToStorages(useDispatch());
  }, { wrapper });
  // ... Rest of the logic
});
Bebop answered 25/12, 2019 at 9:38 Comment(4)
Note that if you put this ReduxProvider in it's own file (as I did), you need to import react for it to work import React from 'react';Choler
what is configureStore() ?Destruction
configureStore() is a helper from redux-toolkit that that adds good defaults to the store setup for a better development experience. import { configureStore } from "@reduxjs/toolkit"; It's not necessary to use configureStore to test custom hooks, though.Slaver
PS an empty store didn't work for me based on my custom hook. I had to initialize my store like so to get my test to work const store = configureStore( reducer: <my reducers here>});Slaver
P
17

This is probably a late answer but you can also use this in your test

jest.mock('react-redux', () => {
    const ActualReactRedux = jest.requireActual('react-redux');
    return {
        ...ActualReactRedux,
        useSelector: jest.fn().mockImplementation(() => {
            return mockState;
        }),
    };
});
Peg answered 11/3, 2020 at 15:18 Comment(6)
I'm not sure I understand this. I added this to a test, but I still see the error about missing a <Provider>. Could you expand this answer?Meter
Consider provide the full answer.Carleton
I get an error TypeError: require.requireActual is not a function, do you have any idea why?Ultramontane
@Ultramontane you need jest.requireActual not require.requireActualRapacious
Seems it works but you won't be able to update the mockState in test cases?Sprain
Docs say you should recreate the store for each test, not mock it. Prob not correct answer.Dapple
M
11

This issues is related your test file. You have to declarer provider and store in your test file.

Update or replace your app.test.tsx by below code

NB: Don't forget to install redux-mock-store if you don't have already.

import React from 'react';
import { render } from '@testing-library/react';

import App from './App';

import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';

describe('With React Testing Library', () => {
    const initialState = { output: 10 };
    const mockStore = configureStore();
    let store;

    it('Shows "Hello world!"', () => {
        store = mockStore(initialState);
        const { getByText } = render(
            <Provider store={store}>
                <App />
            </Provider>
        );

        expect(getByText('Hello World!')).not.toBeNull();
    });
});

I got this solution after searching 1 hours. Thanks a lot to OSTE

Original Solution: Github issues/8145 and solution link


With this solution if you get error like TypeError: window.matchMedia is not a function then solve by this way. add those line to your setupTests.ts file. Original solution link https://mcmap.net/q/129172/-cannot-read-property-39-addlistener-39-of-undefined-react-testing-library

global.matchMedia = global.matchMedia || function () {
  return {
    addListener: jest.fn(),
    removeListener: jest.fn(),
  };
};
Mucoviscidosis answered 29/11, 2021 at 1:51 Comment(0)
K
5

I think you can create test-utils.[j|t]s(?x), or whatever you set the name of the file to, like this:

https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart/blob/main/__tests__/test-utils.tsx

//root(or wherever your the file)/test-utils.tsx

import React from 'react';
import { render, RenderOptions } from '@testing-library/react';
import { Provider } from 'react-redux';

// Import your store
import { store } from '@/store';

const Wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;

const customRender = (ui: React.ReactElement, options?: Omit<RenderOptions, 'wrapper'>) => render(ui, { wrapper: Wrapper, ...options });

// re-export everything
export * from '@testing-library/react';
// override render method
export { customRender as render };


Use it like this: https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart/blob/main/__tests__/pages/index.test.tsx

//__tests__/pages/index.test.tsx


import React from 'react';
import { render, screen } from '../test-utils';
import Home from '@/pages/index';

describe('Home Pages', () => {
  test('Should be render', () => {
    render(<Home />);
    const getAText = screen.getByTestId('welcome');
    expect(getAText).toBeInTheDocument();
  });
});


Works for me.

screenshot work

BTW, if you place the test-utils.[j|t]s(?x) or whatever you set the name file place on the directory __test__, don't forget to ignore it on jest.config.js.

//jest.config.js

testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/', '<rootDir>/__tests__/test-utils.tsx'],

repo: https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart

Konstantine answered 14/12, 2021 at 17:28 Comment(1)
works for me. tks.Look
H
2

When we run test cases in jest, it assumes to have a store and provider in the jest test file where you are getting this issue. Below is the code that works for me.

import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import YourComponent from './YourComponent'; 
import store from './YourStorePath';

test('renders YourComponent', () => {
  render(
  <MemoryRouter>
     <Provider store={store}>
        <YourComponent />
     </Provider>
  </MemoryRouter>
  );
});
Homunculus answered 28/6 at 15:27 Comment(1)
This actually worked for me.Farleigh

© 2022 - 2024 — McMap. All rights reserved.