I have spent some time online searching for documents around how to do this. There seems to be a few ways. But I am not sure on which is the best way to do this.
This is what I have so far
My HOC
interface IStateProps {
errorState: IErrorState;
tList: IList;
}
interface IDispatchProps {
fetch: () => any;
}
interface IState {
isLoading: boolean;
}
interface IConnectedProps extends IStateProps, IDispatchProps {}
export class UnconnectedBrowserLoader extends React.Component<IConnectedProps, IState> {
public state = {
isLoading: true,
};
public render() {
const {errorState} = this.props;
if (errorState.error) {
return (
<div className="non-ideal">
<NonIdealState visual="error" title={"Could Not Load Tasks"}/>
</div>
);
}
if (this.state.isLoading) {
return (
<div className="non-ideal">
<NonIdealState visual={<Spinner/>}/>
</div>
);
}
return (
<div className="body">
<Container/>
</div>
);
}
public componentWillMount() {
Promise.all([
this.props.fetch(),
]).then(() => {
this.setState({isLoading: false});
});
}
}
function mapStateToProps(state: IBrowserState): IStateProps {
return {errorState: state.errorState, tList: state.taskList};
}
function mapDispatchToProps(dispatch: Dispatch<IBrowserState>): IDispatchProps {
return bindActionCreators({
fetch,
}, dispatch);
}
export const BrowserLoader = connect(
mapStateToProps, mapDispatchToProps,
)(UnconnectedBrowserLoader);
My tests now looks like this - WIP
describe("Browser tests", function() {
test("test the browser loader for error case", () => {
const mockStore = configureMockStore([thunk]);
const store = mockStore({
errorState: {
error: "internal error"
}
});
const wrapper = mount(<Provider store={store}><BrowserLoader/></Provider>);
expect(wrapper.find('.non-ideal')).toHaveLength(1); // this works
expect(wrapper.find('.body')).toHaveLength(0); // this works
});
test("test the browser loader", () => {
const mockStore = configureMockStore([thunk]);
const store = mockStore({});
const dispatch = sinon.spy();
const wrapper = shallow(
<Provider store={store}><BrowserLoader/></Provider>
);
expect(wrapper.find('Connect(UnconnectedBrowserLoader)')).toHaveLength(1); //This works
expect(wrapper.find('Connect(UnconnectedBrowserLoader)').props()).toEqual({}); // this works too
// Not sure how to pass mapStateToProps and mapDispatchToProps.
const uwrapper = shallow(<UnconnectedBrowserLoader dispatch={dispatch} store={store}/>); //This does not work it complains "Property store does not exist on IConnectedProps
// I tried this too
const uwrapper = wrapper.find('Connect(UnconnectedBrowserLoader)').shallow() // this does not work too - it gives error Could not find "store" in either the context or props of "Connect(UnconnectedBrowserLoader)".
});
});
What is it that I am doing wrong?! Can anyone point me to it?
any help would be appreciated.
SO link - http://stackoverflow.com/questions/44031658/enzyme-tests-for-higher-order-components-redux
shallow-render the wrapper, do .dive(), and then write assertions on the enzyme wrapper that provides around the inner component.
@ljharb Thanks for the reply!
Like this correct?
const wrapper = shallow(<Provider store={store}><BrowserLoader/></Provider>).dive({ context: {store: mockStore()}});
If I don't pass the store the second time it give me an error.
const wrapper = shallow(<Provider store={store}><BrowserLoader/></Provider>).dive();
Yes - although I would expect Provider to provide the context - that's filed as #664.
@ljharb Hmm. It does not provide the context for me.
I have a bigger problem actually. So I have a bunch of console statements in the render function of UnconnectedBrowserLoader but it doesn't execute any of it. Why does that happen? Am I missing something?
Hmm, the .dive() is when it should call that function.
This is the code I have. It does not look the best to me. But it works. Can you recommend a better way to do this
test("test the browser container for error case", () => {
const mockStore = configureMockStore([thunk]);
const store = mockStore({});
const wrapper = shallow(<Provider store={store}><BrowserLoader/></Provider>).dive({ context:
{
store: mockStore({
error: {
error: "internal error"
}
})
}
});
expect(wrapper.find(UnconnectedBrowserLoader).dive().find('.non-ideal')).toHaveLength(1); // this works.
});
@ljharb Please tell me a more cleaner way to do this.
I really need some help on this. Also adding cc @lelandrichardson @blainekasten
I'd define the same store for Provider and the dive call - but until #664 is resolved, that's the cleanest you can get.
@ljharb Thanks for the quick reply! I will define the same store for both.
But I have to do dive twice? If you notice above I am doing it twice. Once while creating the wrapper and the other time for the expect.
You should definitely only have to do it once per HOC - however, you have both Provider and BrowserLoader, so yes, each one needs a dive.
@ljharb How do I provide the store to the BrowserLoader without the provider?
This does not work for me.
<BrowserLoader store={store}/> --> Typescript complains in that case.
It's in context - so you'd do shallow(<BrowserLoader />, { context: { store } })
Thank you much @ljharb ! I feel better about the code now
test("test the browser container", () => {
const mockStore = configureMockStore([thunk]);
const store = mockStore(
{
error: {},
tList: [1,2,3,4]
}
);
const wrapper = shallow(<BrowserLoader />, { context: { store } });
expect(wrapper.dive().find('.non-ideal')).toHaveLength(1);
});
I have one last questions and want to know your comments around the same.
It took me a lot of time to get to this point. There are no documentation out there to test HOC.
Are you guys working on something? or is there any resources I am missing?
Also I have another question, if I want to execute setProps or setState or even spy on the child component. How does that work?
For example I want to be able to do
const spy = sinon.spy(UnconnectedBrowserLoader.prototype, 'componentWillReceiveProps');
Another example
const wrapper = shallow(<BrowserLoader />, { context: { store } }).dive();
wrapper.setState({'isLoading': false}) //Related to the example in the first block.
This does not work. How would one do this? ++ same applies to setState and setProps
If you want to spy on an instance method on a wrapped component, then your only solution is to export the inner component directly, and stub that prior to the shallow/dive combo.
@ljharb I have exported the inner component directly. And I do shallow rendering the same. But I see errors.

The error is of type
Type `{}` is not assignable to ..
Am I missing something or doing something wrong?
That error doesn't seem to be coming from enzyme - that seems like a TypeScript issue.
@ljharb Yes I know that. It complains because typescript expects IConnectedProps and IState to be passed to it. How does one do that in Enzyme?
This is what I want to do - Export the inner component. Shallow render that and setState, setProps and also do sinon spy on the componentDidMount.
I think you'd need to file an issue on TypeScript's repo for that - anything that works in regular JS but not with TypeScript is something TypeScript needs to fix. Since we don't use TS, I don't know how we can help :-/
ok no problem! Thank you for being responsive! If I do find the answer I will update it back here.
I finally found a very good solution to get a wrapper from a decorated component. For shallowed components you can use dive() but there is no similar method for mounted components. This is the solution I did:
const wrapper = mount(shallow(<MyComponent />).get(0))
Works like a charm :)
Thanks @dabit1
Without exporting inner component, to spy on inner component method, following also works.
const shallowNode = shallow(<MyComponent />).get(0)
spy(shallowNode.type.prototype, 'componentDidMount')
const mountWrapper = mount(shallowNode)
expect(shallowNode.type.prototype.componentDidMount.calledOnce).toBe(true)
But is there any disadvantages by doing it this way?
Instead of shallow rendering, another approach is to mount and then mock the component where you want rendering to stop. Especially useful when using container components.
More details on how we implemented this:
https://medium.com/@sconnolly17/testing-graphql-container-components-with-react-apollo-and-jest-9706a00b4aeb
Not my best-engineered work, but here's how I tested a component that requires mount().
// Ugly hack - let us setProps() on the mounted component
// See https://github.com/airbnb/enzyme/issues/947
//
// The problem is: we _must_ use mount() and not shallow() because we want to
// test TableView's componentDidMount() behavior (the loading of data). And
// since one of TableView's descendents uses react-redux, we must use a
// <Provider> to make mount() succeed.
//
// We want to test setProps(), because we do things when props change. But
// mounted components' setProps() only work on the root component.
//
// So here's a root component that handles setProps() and the <Provider>, all
// in one.
function ConnectedTableView (props) {
props = { ...props } // clone
const store = props.store
delete props.store
return (
<Provider store={store}>
<TableView {...props} />
</Provider>
)
}
...
const store = mockStore({})
const wrapper = mount(<ConnectedTableView store={store} url={'http://foo.com'} />)
wrapper.setProps({ url: 'http://bar.com' })
A better approach would be composition: test the data-fetching layer separately from the rendering layer. But my current setup makes that hard, so the above workaround will suffice for now.
I don't agree that would be better; if those two layers are never used independently in production, then there's not much value in testing them independently.
This is the code I have. It does not look the best to me. But it works. Can you recommend a better way to do this
test("test the browser container for error case", () => { const mockStore = configureMockStore([thunk]); const store = mockStore({}); const wrapper = shallow(<Provider store={store}><BrowserLoader/></Provider>).dive({ context: { store: mockStore({ error: { error: "internal error" } }) } }); expect(wrapper.find(UnconnectedBrowserLoader).dive().find('.non-ideal')).toHaveLength(1); // this works. });@ljharb Please tell me a more cleaner way to do this.
I really need some help on this. Also adding cc @lelandrichardson @blainekasten
Thanks a ton ... i was stuck at this for sometime as was not passing store second time(in context) works fine now :)
Most helpful comment
shallow-render the wrapper, do
.dive(), and then write assertions on the enzyme wrapper that provides around the inner component.