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
exports[`<UserMenu /> hopefully works 1`] = `<Component />`;
exports[`<UserMenu /> hopefully works 1`] = `
<div>
Hello World
</div>
`;
| library | version
| ------------------- | -------
| enzyme | 3.10.0
| react | 16.8.6
| react-dom | 16.8.6
| react-test-renderer | -
| adapter (below) | 1.14.0
+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, are there any plans to fix this? Also, does anyone have a workaround that can be used until it is fixed?
Big corporate app - same issue. If we want to move forward and start using Redux with Hooks we need this fixed. A work around would be great. Right now we only have one component that uses .dive() heavily and if someone figures out a workaround that would be great.
Any update on how best to get around this? Or if this will be tackled?
Same here 💃
Try with the wrappingComponent option?
Same here. seems like enzyme and redux hooks are not getting along.
@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();
});
@KenLui it's still not helpful, as the component not getting rendered... it's rendering the snapshot as:
<Test store={{...}} dispatch={[Function: dispatch]} />
enzyme doesn't have snapshot support, nor recommend snapshot testing - the closest thing is .debug() (or .debug({ verbose: true })). If you're having trouble with snapshots, you'll need to file an issue on whatever is generating them.
right, but even when running .debug() it's rendering the result above, shouldn't it render the Test component with its markup?
@idangozlan with shallow, you need one .dive per HOC - so since you have connect(), you need wrapper.dive().debug() to see the contents of your inner component.
@ljharb make sense, but then @KenLui is worthless. getting Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a <Provider>. :)
Hopefully, we will have a solution to this issue soon.
@idangozlan that's why i suggested using the wrappingComponent option:
const wrapper = shallow(<ComponentThatNeedsContext>, {
wrappingComponent: ContextProvider
});
wrapper.debug()
@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);
});
});
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)...
Yes, that's very true. React hooks don't provide any hooks for testing purposes, so there's nothing for enzyme to interact with. You'd have to use the non-hook version of react-redux to be able to test it properly.
@ljharb do you expect any feature like that will be available in the future?
@idangozlan i certainly hope so - but it would require react to expose API hooks into how hooks work, and/or to implement support for such things in the shallow renderer.
Hi, @ljharb
How to invoke the .shallow() when chaining?
const wrapper = shallow(
<MockProvider>
<LottoPyoContainer {...props} />
</MockProvider>
);
console.log(
wrapper
.dive()
.find('Connect(EcommerceBarContainer)')
.shallow({ wrappingComponent: MockProvider }) // error on this line
.debug()
);
What happens here is:
The .find() gives me this:
<Connect(EcommerceBarContainer) instructionText={{...}} totalCost={1}>
<EcommerceBarLottoContent lineCountLotto={[undefined]} />
</Connect(EcommerceBarContainer)>
Now I want to render the <Connect(EcommerceBarContainer)>
But .shallow({ wrappingComponent: MockProvider }) throws an error:
Could not find "store" in the context of "Connect(EcommerceBarContainer)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(EcommerceBarContainer) in connect options.
So, my question is: how to invoke the chaining shallow() with the wrapping component, seems the top level <MockProvider> has been thrown when .dive()
Any solution for this issue, out there?
Same Problem. Found a temporary solution though
Bump on this issue - related to #2174
Currently looking like theres no way to shallow render when using the useContext hook with enzyme. Has there been any progress on this?
Hey,
just came across same issue. I concluded that for test purposes injecting store directly to the connected component is OK. The only problem is Typescript typing because types do not allow passing store directly as a prop. Otherwise, it is OK.
@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
@chris-fran pass the store as prop to connect HOC.
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)
Same issue for me, such a shame as replacing connect with the hooks removes so much boilerplate
I tried mocking out react-redux's useStore hook,
import * as reduxHooks from 'react-redux/lib/hooks/useStore';
sinon.stub(reduxHooks, 'useStore').returns(myMockedStore)
But my component under test didn't pick up the stubbed version.
Maybe using proxyquire can solve the mocking issue as described here: https://sinonjs.org/how-to/link-seams-commonjs/
But that was more work than I wanted to go to for something I assume will get fixed eventually? I will stick with mount for now.
I have the similiar issue: when I'm trying to access into connected component, then find API return 0 nodes.
If it necessary: ReportButton is functional component.
import React from 'react';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import {Provider} from 'react-redux';
import configureStore from 'redux-mock-store';
import ReportButton from './ReportButton';
configure({ adapter: new Adapter() });
const mockStore = configureStore();
const store = mockStore();
let container;
describe('Report Button', () => {
beforeEach(() => {
const mockProps = {
fullReport: false,
period_tariff_is_active: true,
dataId: '',
loading: false,
isEmpty: false,
count: 100,
filter: {},
category: [],
type: '',
};
container = shallow(<Provider store={store}><ReportButton {...mockProps}/></Provider>).dive();
});
afterEach(() => {
container = null;
});
it('should render component without crashing', () => {
expect(container).toMatchSnapshot();
});
it('should find report button', () => {
expect(container.find('.button').length).toEqual(1);
});
});
● Report Button › should find report button
expect(received).toEqual(expected) // deep equality
Expected: 1
Received: 0
36 | });
37 | it('should find report button', () => {
> 38 | expect(container.find('.button').length).toEqual(1);
| ^
39 | });
40 | });
41 |
So, the snapshot return connected component, and I simply can't get inside.
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Report Button should render component without crashing 1`] = `
<Connect(ReportButton)
category={Array []}
count={100}
dataId=""
filter={Object {}}
fullReport={false}
isEmpty={false}
loading={false}
period_tariff_is_active={true}
type=""
/>
`;
use mount instead of shallow
@Ba-stian don't use mount; use the wrappingComponent option to pass Provider, and pass <ReportButton /> directly to shallow.
@ljharb I rewrote my test like that
import React from 'react';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import ReportButton from "./ReportButton";
import {Provider} from "react-redux";
import {store} from "../../store/createdStore";
import configureStore from 'redux-mock-store';
configure({ adapter: new Adapter() });
let container;
const ShallowProvider = props => {
const {children, customStore} = props;
return (
<Provider store={customStore || store}>
{children}
</Provider>
)
};
const mockStore = configureStore();
describe('Report Button', () => {
beforeEach(() => {
const mockProps = {
fullReport: false,
period_tariff_is_active: true,
dataId: '',
loading: false,
isEmpty: false,
count: 100,
filter: {},
category: [],
type: '',
};
container = shallow(<ReportButton {...mockProps}/>, {
wrappingComponent: ShallowProvider
});
const provider = container.getWrappingComponent();
provider.setProps({ customStore: mockStore})
});
afterEach(() => {
container = null;
});
it('should render component without crashing', () => {
expect(container).toMatchSnapshot();
});
});
And now I get undefined in my snapshot((
This is very actual problem. I spent several hours to solve it and i just wrote mount() instead of shallow()
For me using mount return undefined in snapshot too
provider.setProps() won't likely work without a container.update() after it.
Separately, enzyme doesn't support or recommend using snapshot testing; the closest is .debug().
I add container.update() below provider.setProps()
and I still get undefined
TypeError: Cannot read property 'debug' of undefined
46 |
47 | it('should render component without crashing', () => {
> 48 | console.log(container.debug())
| ^
49 | });
50 | it('should find button in component', () => {
51 | expect(container.find('.button').length).toEqual(1);
in second test
it('should find button in component', () => {
expect(container.find('.button').length).toEqual(1);
})
I get this
could not find react-redux context value; please ensure the component is wrapped in a <Provider>
9 | const ReportButton = ({fullReport, dataId, count, type}) => {
10 |
> 11 | const period_tariff_is_active = useSelector(state => state.auth.user && state.auth.user.period_tariff_is_active);
| ^
12 | const lang = useSelector(state => state.auth.user && state.auth.user.lang);
13 | const filter = useSelector(state => state.selectFilter);
14 | const loading = useSelector(state => state.loading.loading);
@idangozlan that's why i suggested using the
wrappingComponentoption:const wrapper = shallow(<ComponentThatNeedsContext>, { wrappingComponent: ContextProvider }); wrapper.debug()
Using wrappingComponent is got worked 👍
@renjithspace could you please explain that code snippet. What is ContextProvider in this case?
@anosov-otg for example: An HOC of React redux provider
import { Provider } from 'react-redux'
Closing; if wrappingComponent doesn't work for anyone, please file a new issue.
wrappingComponent doesn't work for me, but these options do: https://github.com/enzymejs/enzyme/issues/1002#issuecomment-421535999
@anosov-otg the first and third are fine, I'd expect the second to work with wrappingComponent as the Provider instead.
const wrapper = shallow(<ComponentThatNeedsContext>, {
wrappingComponent: ContextProvider
});
what about provider with store..where do you put send in a store above? Unless I'm missing some context :) how is this allowing us to send in a store?
If this is not what you were thinking please elaborate:
import { Provider } from "react-redux";
const wrapper = shallow(<ComponentThatNeedsContext>, {
wrappingComponent: Provider
});
@dschinkel you'd use the wrappingComponentProps option to supply props to the Provider.
tried it, I get Cannot read property 'getState' of undefined
import { Provider } from "react-redux";
const store = createStore(rootReducer, initialState, middleware);
it('contains expected actions', () => {
const homePage = shallow(<HomePageContainer />, {
wrappingComponent: Provider,
wrappingComponentProps: store
});
expect(homePage.props().fetchFeaturedCompanies).to.exist;
expect(homePage.props().fetchCompanies).to.exist;
});
I won't derail this and can open another issue if need be.
Is this something new? I wasn't one to use Provider a lot in the past because I sent in my store via props.
wrappingComponentProps needs to be a props object. try { store }.
referring to this for further discussion 2449
@dschinkel @anosov-otg We can tackle this in different ways.
Create an HOC for your provider, here is an example with redux:
// StoreProvider.js
import { Provider } from 'react-redux'
import store from 'path/to/store'
function StoreProvider() {
return (
<Provider store={store}>
{this.props.children}
</Provider>
)
}
And use that in tests with wrappingComponent:
// ComponentThatNeedsProvider.test.js
import { shallow } from 'enzyme'
import StoreProvider from 'path/to/StoreProvider'
import ComponentThatNeedsProvider from 'path/to/ComponentThatNeedsProvider'
const wrapper = shallow(<ComponentThatNeedsProvider>, {
wrappingComponent: StoreProvider
});
You can directly pass provider props with wrappingComponentProps like below without creating an HOC for provider as @ljharb mentioned.
// ComponentThatNeedsProvider.test.js
import { shallow } from 'enzyme'
import { Provider } from 'react-redux'
import store from 'path/to/store'
import ComponentThatNeedsProvider from 'path/to/ComponentThatNeedsProvider'
const wrapper = shallow(<ComponentThatNeedsProvider>, {
wrappingComponent: Provider,
wrappingComponentProps: { store }
});
If you prefer DRY or if you have multiple providers with a bunch of props to pass, go with Solution 1 👍
@stella1013
here's an answer to that error you got about TS bitching about the store prop from tests and how to resolve it. I mention it toward the end. And this is exactly why I hate TS, it's a pain in the ass overall to have to deal with this stuff.
https://medium.com/@DaveSchinkel/setting-up-mocha-js-to-run-typescript-42f3099450eb
@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).
Most helpful comment
Any solution for this issue, out there?