0
votes

I have a SignUp React component which uses redux form and my onSubmit basically dispatches an async action. I am trying to test my component using Enzyme and Jest by adding a spy to my dispatch and checking if dispatch is invoked on simulating a form submission. However, my test fails.

Here is my SignUp redux form component:

import React from 'react';
import {reduxForm, Field, focus} from 'redux-form';
import Input from './input';
import {required, nonEmpty, email, isTrimmed, length} from '../validators';
import {registerUser} from '../actions/users';
import {login} from '../actions/auth';
export class SignUpForm extends React.Component {
    onSubmit(values) {
        const {username, password, fname, lname} = values;
        const newUser = {
            username, 
            password, 
            user: {
               firstName: fname, 
               lastName: lname
            }
        };
        return this.props
            .dispatch(registerUser(newUser))
            .then(() => this.props.dispatch(login(username, password)));
    }

    render() {
        let errorMessage;
        if (this.props.error) {
            errorMessage = (
                <div className="message message-error">{this.props.error </div>
            );
        }

        return (
                <form className='signup-form' onSubmit={this.props.handleSubmit(values =>
                this.onSubmit(values)
            )}>

                    {errorMessage}
                    <Field
                    name="fname"
                    type="text"
                    component={Input}
                    label="First Name"
                    validate={[required, nonEmpty]}
                    />
                    <Field
                    name="lname"
                    type="text"
                    component={Input}
                    label="Last Name"
                    validate={[required, nonEmpty]}
                    />
                    <Field
                    name="username"
                    type="email"
                    component={Input}
                    label="Email"
                    validate={[required, nonEmpty, email, isTrimmed]}
                    />
                    <Field
                    name="password"
                    type="password"
                    component={Input}
                    label="Password"
                    validate={[required, nonEmpty, length({min: 10, max: 72})]}
                    />
                    <button
                    type="submit"
                    disabled={this.props.pristine || this.props.submitting}>
                    Sign Up
                    </button>
                </form>                             
        );
    }
}
export default reduxForm({
    form: 'signup',
    onSubmitFail: (errors, dispatch) => 
        dispatch(focus('signup', Object.keys(errors)[0]))
})(SignUpForm);

Here is my test:

import React from 'react';
import {shallow, mount} from 'enzyme';
import SignUpForm from './signup';
import {registerUser} from '../actions/users';
import { reducer as formReducer } from 'redux-form'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk';
import {stockReducer} from '../reducers';
describe('<SignUpForm />', () => {
    let store
    let wrapper
    let dispatch
    beforeEach(() => {
        store = createStore(combineReducers({ form: formReducer, stock: stockReducer }),applyMiddleware(thunk))
        dispatch = jest.fn()
        wrapper = mount(
            <Provider store={store}>
                <SignUpForm dispatch={dispatch}/>
            </Provider>
        );
    })

    it('should fire onSubmit callback when form is submitted', (done) => {
        const form = wrapper.find('form');
        form.find('#fname').simulate('change', {target: {value: 'fname'}});
        form.find('#lname').simulate('change', {target: {value: 'lname'}});
        form.find('#username').simulate('change', {target: {value: '[email protected]'}});
        form.find('#password').simulate('change', {target: {value: 'password1234'}});
        form.simulate('submit');
        expect(dispatch).toHaveBeenCalled();
    });
});

My test fails with the following error: expect(jest.fn()).toHaveBeenCalled() Expected mock function to have been called.

Please help me understand what is going wrong.

1
not sure how reduxForm works, but maybe you should pass dispatch from reduxForm to the actual component SignUpForm ? just an ideaJosé Quinto Zamora

1 Answers

1
votes

The problem here is that you are not awaiting anywhere in your test on the promise returned by your onSubmit function so your assert is getting executed before your promise resolves.
I will suggest you to properly refactor your code to make it "testable". You can take a look at following link on how to test async calls using jest: https://facebook.github.io/jest/docs/en/asynchronous.html
I will also suggest you to use redux-thunk which will make your life easier.