Search code examples
typescriptjestjs

Jest - passing FormEvent to function to be tested


I have the following method that I'd like to test with Jest (well, more precisely with vitest):

export const handleSave = async (
    dispatch: React.Dispatch<DeveloperAction>, 
    e: FormEvent<HTMLFormElement>, 
    handleClose: () => void, 
    setErrorMessage: (errorMessage: string) => void) => {

    e.preventDefault();

    const formData: FormData = new FormData(e.currentTarget)
    const developer: DeveloperType = toDeveloperType(formData)

    try {
        const resp: AxiosResponse = await axios({
            method: 'PUT', 
            url: `${endpointBackEnd}/developers/${formData.get('id')}`, 
            data: developer
        }); 
        dispatch({ 
            type: DEVELOPER_ACTION_TYPES.EDIT, 
            payload: resp.data 
        })       
        handleClose();
    } catch (err) {
        handleError(err, setErrorMessage)
    }
}

My question is about how to pass a FormEvent that the function can use to create a FormData which later is used to extract information from?
Should I pass a mocked FormEvent (how can I do that)? Or create an instance of FormEvent (the question is the same, how to do that please?)

Thank you for the help!


Solution

  • There are three points you need to think about for the FormEvent:

    1. e.preventDefault(); - use a jest function to mock this
    2. e.currentTarget - make sure the correct HTMLFormElement class is passed to the event
    3. formData.get('id') - build your form using .name and .value of input fields in the virtual form.

    Option 1. Use JSDom to mock out the FormData

    import { FormEvent } from 'react';
    import { JSDOM } from 'jsdom';
    
    const dom = new JSDOM('<!DOCTYPE html>'), doc = dom.window.document;
    const formElement = doc.createElement('form');
    const formField = doc.createElement('input');
    formElement.append(formField);
    
    formField.value = 'hi';
    formField.name = 'id';
    
    const form: Partial<FormEvent<HTMLFormElement>> = {
      currentTarget: formElement,
      preventDefault: () => jest.fn(),
    };
    const formData: FormData = new FormData(form.currentTarget);
    
    const e = {
      preventDefault: jest.fn(),
      currentTarget: formElement
    } as FormEvent<HTMLFormElement>;
      
    

    Option 2. Testing in isolation of the DOM

    This answer provides the method for mocking out the FormData class in jest: https://stackoverflow.com/a/59726560/4529555