Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest + Enzyme: test Redux-form

My application has a lot of redux-form. I am using Jest and Enzyme for unit testing. However, I fail to test the redux-form. My component is a login form like:

import { login } from './actions';
export class LoginForm extends React.Component<any, any> {

  onSubmit(values) {
    this.props.login(values, this.props.redirectUrl);
  }

  render() {
    const { handleSubmit, status, invalid } = this.props;

    return (
      <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
        <TextField label="Email" name="email">
        <TextField type="password" label="Password" name="password" autoComplete/>
        <Button submit disabled={invalid} loading={status.loading}>
          OK
        </Button>
      </form>
    );
  }
}

const mapStateToProps = (state) => ({
  status: state.login.status,
});

const mapDispatchToProps = { login };

const form = reduxForm({ form: 'login' })(LoginForm);

export default connect(mapStateToProps, mapDispatchToProps)(form);

Mock the store, Import connected component

redux-form uses the store to maintain the form inputs. I then use redux-mock-store:

import ConnectedLoginForm from './LoginForm';

const configureStore = require('redux-mock-store');
const store = mockStore({});
const spy = jest.fn(); 

const wrapper = shallow(
  <Provider store={store}>
    <ConnectedLoginForm login={spy}/>
  </Provider>);

wrapper.simulate('submit');
expect(spy).toBeCalledWith();

But in this way, the submit is not simulated, my test case failed:

Expected mock function to have been called with: [] But it was not called.

Mock the store, Import React component only.

I tried to create redux form from the testing code:

import { Provider } from 'react-redux';
import ConnectedLoginForm, { LoginForm } from './LoginForm';

const props = {
  status: new Status(),
  login: spy,
};
const ConnectedForm = reduxForm({
  form: 'login',
  initialValues: {
    email: '[email protected]',
    password: '000000',
  },
})(LoginForm);

const wrapper = shallow(
  <Provider store={store}>
    <ConnectedForm {...props}/>
  </Provider>);

console.log(wrapper.html());

wrapper.simulate('submit');
expect(spy).toBeCalledWith({
  email: '[email protected]',
  password: '000000',
});

In this case, i still got error of function not called. If I add console.log(wrapper.html()), I got error:

Invariant Violation: Could not find "store" in either the context or props of "Connect(ConnectedField)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(ConnectedField)".

I cannot find documentations on official sites of redux-form or redux or jest/enzyme, or even Google.. Please help, thanks.

like image 496
Joy Avatar asked Apr 05 '18 06:04

Joy


1 Answers

I used the real store (as redux-mock-store does not support reducers) and redux-form's reducer, it worked for me. Code example:


import { createStore, Store, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { reducer as formReducer } from 'redux-form';

const rootReducer = combineReducers({
  form: formReducer,
});

let store;

describe('Redux Form', () => {

  beforeEach(() => {
    store = createStore(rootReducer);
  });

  it('should submit form with form data', () => {
    const initialValues = {...};
    const onSubmit = jest.fn();
    const wrapper = mount(
      <Provider store={store}>
        <SomeForm
          onSubmit={onSubmit}
          initialValues={initialValues}
        />
      </Provider>
    );

    const form = wrapper.find(`form`);
    form.simulate('submit');

    const expectedFormValue = {...};
    expect(onSubmit).toHaveBeenCalledTimes(1);
    expect(onSubmit.mock.calls[0][0]).toEqual(expectedFormValue);
  });

});

like image 73
Eric Xin Zhang Avatar answered Nov 15 '22 09:11

Eric Xin Zhang