简体   繁体   中英

How to test componentWillMount inside a connected React-Redux component?

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:

  • In order in invoke componentWillMount in enzyme, you need to use mount , not shallow
  • That answer assumes that 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM