Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with shallow testing component handling redux hooks #2282

Open
CYB3RL1F3 opened this issue Nov 4, 2019 · 12 comments
Open

Issue with shallow testing component handling redux hooks #2282

CYB3RL1F3 opened this issue Nov 4, 2019 · 12 comments

Comments

@CYB3RL1F3
Copy link

CYB3RL1F3 commented Nov 4, 2019

Hello,

I have an issue concerning shallowing component with redux provider.

I'm using a useSelector hook from "react-redux", but this one seems not being able to reach the redux context despite this one to be mounted in the wrappingComponent option of shallow.

Here's my code:

import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import { shallow, mount } from 'enzyme';

const mockStore = configureStore([]);
store = mockStore({
   data
});

const wrapper = shallow(<Component />, {
            wrappingComponent: Provider,
            wrappingComponentProps: { store }
        })

I also tried this solution, not working either:

const wrapper = shallow(<Component />, {
            wrappingComponent: ({ children }) => (
                <Provider store={store} children={children} />
            )
        })

And I'm getting the following error:

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

I also tried to dive() the shallowed provider. Same issue.

I think the problem is in the library, cause the lone solution found (and working) is mounting... But I try to avoid mounting for performance reasons. I'm asking here because I don't know if I have to ask enzyme or react-redux but in my opinion, since it's the test issue, asking here seems being pertinent, maybe I'm wrong...

I'm using enzyme-adapter-react-16 as well.

Would you have a solution or will you publish a fix for this?

Thanks :)

@CYB3RL1F3 CYB3RL1F3 changed the title Issue with shallow testing Issue with shallow testing component handling redux hooks Nov 4, 2019
@neilbryson
Copy link

Seems related to #2202

@flavin
Copy link

flavin commented Nov 7, 2019

what I did was something like this:

const wrapper = shallow(
    <Provider store={store}>
         <Component />
     </Provider>
).dive(/* Provider */).dive(/* <Connect> */).dive(/*Consumer*/).dive(/*Component*/);

I don't like too much how verbose was but at least worked

@Mathijs003
Copy link

That's not working for me

@hb0
Copy link

hb0 commented May 6, 2020

what I did was something like this:

const wrapper = shallow(
    <Provider store={store}>
         <Component />
     </Provider>
).dive(/* Provider */).dive(/* <Connect> */).dive(/*Consumer*/).dive(/*Component*/);

I don't like too much how verbose was but at least worked

Does not seem to work, or did I get something wrong?

Screenshot from 2020-05-06 21-06-49

@JuliusKoronci
Copy link

what I did was something like this:

const wrapper = shallow(
    <Provider store={store}>
         <Component />
     </Provider>
).dive(/* Provider */).dive(/* <Connect> */).dive(/*Consumer*/).dive(/*Component*/);

I don't like too much how verbose was but at least worked

It doesnt work with the new hooks

@Mathijs003
Copy link

I think I fixed this using mount instead of shallow, and giving in a mockstore like this:

describe('NotificationsTable', () => {
  let store: any;
  const middlewares: any[] = [];
  const mockStore = configureStore(middlewares);

  beforeEach(() => {
    store = mockStore({});
  });

  it('should render correctly', () => {
    const component = mount(
      <Provider store={store}>
        <NotificationsTable />
      </Provider>
    );

    expect(component.find(NotificationsTable)).toHaveLength(1);
    expect(component.find(Table)).toHaveLength(1);
  });
});

As you can see I'm able to find things in the component without any problems

@RShergold
Copy link

Is there any roadmap for when Enzyme will support Redux useSelector?

My team work on quite a large Redux app and the lack of support in Enzyme means we can't currently use this feature. We need to decide pretty soon if we begin transitioning away from Enzyme to something like React Testing Library but obviously I'd prefer to stick to one way of doing things.

Any sense of a timeframe or even if this is simply a wontfix would be greatly appreciated.

@Lelith
Copy link

Lelith commented Jun 24, 2020

Is there an official recommendation to just use mount or is there any other update on the topic?

@adelchamas96
Copy link

there might be a solution is to mock the redux hooks. here full example

@aashayamballi
Copy link

You can mock react-redux hooks using this.

If your react project has been created using create react app then you have to create a folder named __mocks__ inside ./src directory. Now inside the __mocks__ folder create a file named react-redux.js

Inside react-redux.js we need to add the below lines

const mockDispatch = jest.fn()
const mockSelector = jest.fn()
 
const mockState = (state = {}) => {
    return mockSelector .mockImplementationOnce(callback => {
        return callback(state);
    })
}
 
module.exports = {
    ...jest.requireActual('react-redux'),
    __esModule: true,
    useSelector: mockSelector ,
    useDispatch: () => mockDispatch,
    mockDispatch,
    mockState
};

Jest docs says to keep the __mocks__ folder at the same level where node_module is located. But if your project is created using create-react-app then we need to keep it inside ./src the folder structure would like ./src/__mocks__/react-redux.js

This is actually an active issue, and here is the GitHub issue link for it node_modules Mocks are not picked up by jest with latest react-scripts

So now in test cases you just need to import mockSelector and mockDispatch as would normally import a module

for ex: import { mockSelector, mockDispatch } from "react-redux";

If your code has multiple useSelector then your test case might look like this

import { shallow} from 'enzyme';
import {mockDispatch, mockSelector} from "react-redux";

test('sample test case', () => {
        mockState({
            reducerName0: {
                someKey: [
                    {
                        ... some data
                    },
                ]
            }
        });

        mockState({
            reducerName1: {
                someKey: [
                    {
                        ... some data
                    },
                ]
            }
        });

        mockState({
            reducerName2: {
                someKey: [
                    {
                        ... some data
                    },
                ]
            }
        });

        const wrapper = shallow(<YourComponent/>);
        expect(mockDispatch).toHaveBeenCalledWith({
            type: "SOME_TYPE",
            payload: "somePaylod"
        });

    });

This is actually working for me with shallow render. Hope it will help you too.

@maxizhukov
Copy link

I have same problem:

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

  28 |
  29 |   const { t } = useTranslation();
> 30 |   const dispatch = useDispatch();

@kael-shipman
Copy link

I should say up front, I'm really fumbling around in the dark a little on this one because, while I'm a very experienced back-end Typescript engineer, I'm still somewhat fresh to the front-end.

That said, I did find a simple solution that worked for me. Essentially, you import * as reactRedux from 'react-redux', then simply replace the hook functions with your mocks:

import React from 'react';
import * as reactRedux from 'react-redux';
import { shallow } from 'enzyme';
import { MyDeepComponent } from './MyDeepComponent';
import { SomeChild } from './SomeChild';

describe("MyDeepComponent", () => {
  const originals = {};
  let selectedData;
  let dispatchedActions;

  beforeAll(() => {
    originals.useDispatch = reactRedux.useDispatch;
    originals.useSelector = reactRedux.useSelector;
    reactRedux.useDispatch = () => (action) => dispatchedActions.push(action);
    reactRedux.useSelector = (selector) => selectedData;
  });

  afterAll(() => {
    reactRedux.useDispatch = originals.useDispatch;
    reactRedux.useSelector = originals.useDispatch;
  });

  beforeEach(() => {
    selectedData = {};
    dispatchedActions = [];
  });

  test('should do thing', () => {
    selectedData = {
      thing: {
        id: 1
      }
    };

    const wrapper = shallow(<MyDeepComponent />);
    expect(wrapper.find(SomeChild)).toHaveLength(1);
    expect(dispatchedActions.find(a => a.type === 'MY_ACTION_TYPE')).not.toBeUndefined();
  });

  // ...
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests