I have the following smart component which uses componentWillMount lifecycle method to make an async call to fetch data. I am writing tests for it but I am unable to test if the function gets called and if it does it is called before the component gets mounted. They are important cases to cover.
The code for the smart component is as follows:
const mapStateToProps = (state) => { const context = state.context; return {
isError: context.error, }; };
const options = { componentWillMount: (props) => {
const { dispatch } = props;
dispatch(fetchContextUser()); }, };
export function App(props) { return (
<div className="app">
{ props.isError ? (<ContextError />) : (<Main />) }
{ props.children }
</div> ); }
App.propTypes = { children: PropTypes.object, // eslint-disable-line react/forbid-prop-types isError: PropTypes.bool.isRequired, // eslint-disable-line react/forbid-prop-types };
export default connect(mapStateToProps, null)(functional(App, options));
I am using Enzyme, Chai and other mock adapters for testing this component. The test block is follows :
describe.only('Render Connected Component', () => { let store; beforeEach(() => {
store = mockStore({
context: {
error: false,
},
}); }); it('Should render connected components', () => {
const connectedWrapper = mount(
<Provider store={store}>
<ConnectedApp />
</Provider>
);
expect(connectedWrapper).to.be.present(); }); });
I just want to test two things :
1.) fetchContextUser is called 2.) fetchContextUser is called before the component gets mounted
I think that you just have to test that the componentWillMount
method calls the fetchContextUser
action, because you must to trust that ReactJS will call the componentWillMount
method before it gets mounted, so, that premise test your second case. So, to test the first case I think you can do something like this:
import sinon from 'sinon';
...
it('It calls fetchContextUser when calls componentWillMount', () => {
const fetchContextUserSpy = sinon.spy();
const wrapper = shallow(<App fetchContextUser={fetchContextUserSpy} />);
fetchContextUserSpy.reset(); //reset the spy to avoid unwanted calls
wrapper.instance().componentWillMount(); // Call componentWillMount directly
expect(fetchContextUserSpy.calledOnce).to.be.true; // Expect that after call componentWillMount() the fetchContextUserSpy was called once
In this test you just call directly the componentWillMount() function and expects that the fetchContextUserSpy is called, so that test your case 1 . I'm using sinon.js to test when a function is called.
Again your case 2 not needs to be tested because ReactJS guarantees that the componentWillMount method is called before the component is mounted.
=========================================================================
Try this with functional component
it('It calls fetchContextUser when mounted', () => {
const fetchContextUserSpy = sinon.spy();
const wrapper = shallow(<App fetchContextUser={fetchContextUserSpy} />);
expect(fetchContextUserSpy.calledOnce).to.be.true; // Expect that the component calls the fetchContextUserSpy
});
I think @pedro-jiminez is close, but missing two elements here:
componentWillMount
in enzyme, you need to use mount
, not shallow
fetchContextUser
is a prop, and can be replaced with a spy. In this case, you probably want to stub store.dispatch
in your test and assert that it was called with fetchContextUser
, assuming that's just a pure function. So the test would look like:
describe.only('Render Connected Component', () => {
let store;
beforeEach(() => {
store = mockStore({
context: {
error: false,
},
});
// stub dispatch
sinon.stub(store.dispatch);
});
it('Should render connected components', () => {
const connectedWrapper = mount(
<Provider store={store}>
<ConnectedApp />
</Provider>
);
expect(connectedWrapper).to.be.present();
// Now test dispatch called
expect(store.dispatch.calledOnce).to.be.true;
expect(store.dispatch.args[0][0]).to.deepEqual(fetchContextUser());
});
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.