Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing a formik component with jest/enzyme

I've put together a pretty basic contact form that works just fine. However I now need to start writing my unit tests and I've run into a load of problems (like I literally have only managed to get a snapshot test to pass so far).

So to start with I'm trying to test that the form should render my validation messages when you click the submit button if you have not filled out all the required sections.

I thought I could achieve this by calling the handleSubmit() function e.g: componentRender.find('Formik').instance().props.handleSubmit(badFormValues, { resetForm });

However when I run componentRender.debug() , my validation messages aren't being rendered. It's like the validationSchema function isn't being called?

Is there something special that needs to be done? I feel like the mapPropsToValues() function is working, from looking at the state object it's being populated with the values I'm passing the form. I just can't see why validation is seemingly being skipped?

I've been at this for 2 days now and can't find any good examples through google (probably my fault) so any help would be massively appreciated.

For reference here is the test file so far:

import React from 'react';
import { shallow, mount } from 'enzyme';
import { BrowserRouter as Router } from 'react-router-dom';
import PartnerRegistrationForm from 'Components/partner-registration-form/PartnerRegistrationForm';

describe('PartnerRegistrationForm component', () => {
    const formValues = {
        companyName: 'some company',
        countryCode: 'GB +44',
        telNumber: 12345678,
        selectCountry: 'United Kingdom',
        postcode: 'ABC1 234',
        addressSelect: '123 street',
        siteName: 'blah',
        siteURL: 'https://www.blah.com',
        contactName: 'Me',
        email: '[email protected]',
    };

    const componentShallow = shallow(<PartnerRegistrationForm {...formValues} />);

    describe('Component Snapshot', () => {
        it('should match stored snapshot', () => {
            expect(componentShallow).toMatchSnapshot();
        });
    });

    describe('Component functionality', () => {
        it('should not submit if required fields are empty', () => {
            const badFormValues = {
                companyName: 'some company',
                countryCode: 'GB +44',
                telNumber: 12345678,
            };
            const resetForm = jest.fn();
            const componentRender = mount(
                <Router>
                    <PartnerRegistrationForm {...badFormValues} />
                </Router>,
            );
            componentRender.find('Formik').instance().props.handleSubmit(badFormValues, { resetForm });
            // console.log(componentRender.update().find('.validation-error'));
            // console.log(componentRender.find('Formik').instance());
            // expect(componentRender.find('.validation-error').text()).toEqual('Company Name is required');
        });
    });
});

And here is my withFormik() function:

const WrappedFormWithFormik = withFormik({
    mapPropsToValues({
        companyName,
        countryCode,
        telNumber,
        selectCountry,
        postcode,
        addressSelect,
        siteName,
        siteURL,
        contactName,
        email,
    }) {
        return {
            companyName: companyName || '',
            countryCode: countryCode || '',
            telNumber: telNumber || '',
            selectCountry: selectCountry || '',
            postcode: postcode || '',
            addressSelect: addressSelect || '',
            siteName: siteName || '',
            siteURL: siteURL || '',
            contactName: contactName || '',
            email: email || '',
        };
    },
    validationSchema, // This is a standard Yup.object(), just importing it from a separate file
    handleSubmit: (values, { resetForm }) => {
        console.log('submitting');
        const {
            companyName,
            countryCode,
            telNumber,
            selectCountry,
            postcode,
            addressSelect,
            siteName,
            siteURL,
            contactName,
            email,
        } = values;

        const emailBody = `Name: ${contactName},`
        + `Email: ${email},`
        + `Company Name: ${companyName},`
        + `Country Code: ${countryCode},`
        + `Telephone Number: ${telNumber},`
        + `Country: ${selectCountry},`
        + `Postcode: ${postcode},`
        + `Address: ${addressSelect},`
        + `Website Name: ${siteName},`
        + `Website URL: ${siteURL}`;

        // TODO set up actual contact submit logic
        window.location.href = `mailto:[email protected]?subject=New partner request&body=${emailBody}`;
        resetForm();
    },
})(PartnerRegistrationForm);
like image 607
Fabio Felizzi Avatar asked Sep 27 '18 08:09

Fabio Felizzi


1 Answers

It might not work if you are trying to submit the form by clicking on a button with type="submit"

I've found the only way to get it to submit (and thus run validations) was by simulating it directly:

const form = wrapper.find('form');
form.simulate('submit', { preventDefault: () => {} });

...and additionally you might need to use something like the following to update the wrapper after formik's async validation and state changes:

setTimeout(() => {
  wrapper.update();
}, 0);

Don't forget to use done() or async await so the test doesn't terminate early.

like image 116
spencer.sm Avatar answered Oct 16 '22 12:10

spencer.sm