enzyme: shallow().dive() does not work with react-redux Provider

it('should work', () => {
  const Component = () => {
    return <div>Hello World</div>;
  };
  const wrapper = shallow(
    <Provider store={mockStore()}>
      <Component />
    </Provider>
  ).dive();
  expect(wrapper).toMatchSnapshot();
});

This is just a simple example - please assume that Component needs to have access to the react-redux context so I can use useSelector() in there, so something like .find(Component).dive() won’t work

Current behavior

exports[`<UserMenu /> hopefully works 1`] = `<Component />`;

Expected behavior

exports[`<UserMenu /> hopefully works 1`] = `
<div>
  Hello World
</div>
`;

API

  • shallow

Version

library version
enzyme 3.10.0
react 16.8.6
react-dom 16.8.6
react-test-renderer -
adapter (below) 1.14.0

Adapter

  • enzyme-adapter-react-16

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 49
  • Comments: 59 (16 by maintainers)

Most upvoted comments

Any solution for this issue, out there?

+1 here, doesn’t seem to work for me either.

const component = shallow(
      <Provider store={store}>
        <Test {...props} />
      </Provider>
    )
      .find(NavItem)
      .dive();
    expect(component).toMatchSnapshot();

throws this

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

Same Problem. Found a temporary solution though

  1. While testing use the older version of the library.
  2. There will be 2 versions of react-redux in your project, second older version installed as a dev dependency.
  3. Use jest.mock to point to this file while testing.

https://stackoverflow.com/questions/59191129/enzyme-jest-react-testing-shallow-connected-component-with-react-redux-6

use mount instead of shallow

@idangozlan that’s why i suggested using the wrappingComponent option:

const wrapper = shallow(<ComponentThatNeedsContext>, {
  wrappingComponent: ContextProvider
});
wrapper.debug()

Same here. seems like enzyme and redux hooks are not getting along.

@chris-fran pass the store as prop to connect HOC.

This is very actual problem. I spent several hours to solve it and i just wrote mount() instead of shallow()

I was having issues with TypeScript and React-Redux Provider. I don’t know if this helps anyone but I was able to get a DOM snapshot via the below code.

library version
enzyme 3.11.0
react 16.12.0
react-redux 7.1.7
react-dom 16.12.0
react-test-renderer 16.9.2
enzyme-adapter-react-16 1.15.2
redux-mock-store 1.5.4
typescript 3.7.2

testUtils.ts

export const storeFactory = (initialState: any) => {
	return createStore(rootReducer, initialState);
};

test.tsx

const connectedSetup = (initialState={}) => {
    const store = storeFactory(initialState);
    const wrapper = shallow(<ConnectedSplashScreen store={store}/>).dive().dive();
	console.log(wrapper.debug({verbose:true}));
	return wrapper;
};

Though I do receive a Type error on ‘store’ on this line <ConnectedSplashScreen store={store}/>

(JSX attribute) store: Store<CombinedState<{
    clientState: ClientState;
    myForm: FormState;
    data: DataState;
}>, setVoucherUrlAction | ... 22 more ... | dataSetAction>
Type '{ store: Store<CombinedState<{ clientState: ClientState; myForm: FormState; data: DataState; }>, setVoucherUrlAction | ... 22 more ... | dataSetAction>; }' is not assignable to type 'IntrinsicAttributes & Pick<ReduxType, never>'.
  Property 'store' does not exist on type 'IntrinsicAttributes & Pick<ReduxType, never>'.ts(2322)

Indeed, I tried it myself again and even without snapshots etc, the problem is that wrappingComponent doesn’t seem to work with useContext (which react-redux uses internally)…

@joan-saum and it will still have no solution in 2119, since it’s blocked on the react team providing hooks for testing/reaching into hooks.

Closing; if wrappingComponent doesn’t work for anyone, please file a new issue.

@ljharb Still happening (Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a <Provider>).

The sample code is:

Test.js:

import React from 'react';
import { useSelector } from 'react-redux';

export default function Test() {
  const user = useSelector(state => state.auth.user);

  console.log(user);
  // const user = 'test user';
  // console.log(user);

  return (
    <div className="D">
      <div className="C">
        <div className="B">
          <div className="A">
My Test
            {user || ''}
          </div>
        </div>
      </div>
    </div>
  );
}

The test:

import React from 'react';
import PropTypes from 'prop-types';
import { shallow } from 'enzyme';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';

import Test from './Test';

const mockStore = configureStore([]);
const defaultStore = mockStore({
  auth: { user: 'Idan' },
});

function MyProvider(props) {
  const { children } = props;

  return (
    <Provider store={props.store}>
      {children}
    </Provider>
  );
}

MyProvider.propTypes = {
  children: PropTypes.node.isRequired,
  store: PropTypes.object,
};
MyProvider.defaultProps = {
  store: defaultStore,
};

describe('My Desc', () => {
  it('My Test', () => {
    expect.assertions(1);

    const wrapper = shallow(<Test />, {
      wrappingComponent: MyProvider,
    });
    // const provider = wrapper.getWrappingComponent();
    // provider.setProps({ store: defaultStore });

    console.log(wrapper.debug());
    expect(1).toEqual(1);
  });
});

How come this issue has still no solution? React hooks has been introduced in 2019, and it is still not possible to access the redux store with react hooks during a shallow render…

I had the same problem using dive twice solved my issues.Thats interesting.

const setup = (initialState = {}) => { const store = storeFactory(initialState); return shallow(<Input store={store} />) .dive() .dive(); };

@ajGingrich i agree; the goal is that it works with shallow. If you’re still having that trouble, it’d be great if you filed a new issue about it so we could try to work through it.

@renjithspace

yea I have tried that but no luck with wrappingComponentProps: { store } and in fact I’ve given up entirely on the wrappingComponent route, it just doesn’t work for any of my tests for different use cases period including using Router from react-router to wrap components under test. I don’t trust it…it just doesn’t work for me period in any cases I’ve tried so far.

I ended up with this working for me (had to add a childAt() oddly enough) due to how react-redux is structured these says in v7:

it('fetches featured companies', async () => {
  const companies: Array<Company> = [companyStub]
  mockGet('/api/v1/companies/featured', companies);
  const homePage = shallow(<HomePageContainer store={store} />);

  await homePage.childAt(0).props().fetchFeaturedCompanies();
  const newState = store.getState();

  expect(newState.companies.companies).to.not.exist;
  expect(newState.companies.featuredCompanies).to.exist;
});

redux v7 re-introduced the ability to pass store as a prop directly onto React components (as I like it).

@dschinkel you’d use the wrappingComponentProps option to supply props to the Provider.

@idangozlan that’s why i suggested using the wrappingComponent option:

const wrapper = shallow(<ComponentThatNeedsContext>, {
  wrappingComponent: ContextProvider
});
wrapper.debug()

Using wrappingComponent is got worked 👍

@Ba-stian don’t use mount; use the wrappingComponent option to pass Provider, and pass <ReportButton /> directly to shallow.

@vojtatranta how do inject it when the connected component is actually a child?

const wrapper = shallow(<MyComp />);

connst connected = wrapper.find('Connect(Something)');

connected.dive()                                         // doesnt work
connected.dive({ context: { store } })        // doesnt work
connected.shallow()                                   // doesnt work
connected.shallow({ context: { store } })  // doesnt work

@idangozlan, shallow() doesn’t work with React’s useContext hook. If you’re using a version of react-redux higher than 5.1.1, you’re going to have a bad time dealing with contexts. See this comment for some workarounds.

// Bare component.
const Component = () => {
  return <div>Hello World</div>;
};

// Redux connected component.
const ConnectedComponent = connect()(Component);

it('inject store work', () => {
  // Inject store directly into connected component.
  const wrapper = shallow(
    <ConnectedComponent store={mockStore()} />
  );
  expect(wrapper).toMatchSnapshot();
});