How to use react testing library to type text into formik when value is controlled?

Viewed 1149

I'm currently having problems writing tests for formik fields that use value. I've managed to get my tests to work if instead of value I use defaultValue but I need to use value. I have tried to console.log in the onChange and know that text is flowing through it but I don't understand why it isn't setting. What do I need to change so that it works?

Example of code I'm trying to test

    <TextField
       id="name"
       label="Profile Name"
       onChange={formik.handleChange}
       value={formik.values.name}
       required
   </TextField>

Example of code that the test works on

    <TextField
       id="name"
       label="Profile Name"
       onChange={formik.handleChange}
       defaultValue={formik.values.name}
       required
   </TextField>

The currently failing test

    test("fills out profile name", () => {
            const field = screen.getByLabelText("Profile Name");
            userEvent.type(field, "profile name");
            expect(field).toHaveValue("profile name");
          });

The screen.debug that is telling me the text isn't being set.

     <input
            aria-invalid="false"
            aria-labelledby="TextFieldLabel24"
            class="ms-TextField-field field-80"
            id="name"
            required=""
            type="text"
            value=""
          />
3 Answers

Have you ever tried asynchronous? If the field has got the correct value, asynchronous can be the problem.

 test("fills out profile name", async () => {
     const field = screen.getByLabelText("Profile Name");
     await userEvent.type(field, "profile name");
     expect(field).toHaveValue("profile name");
 });

Try adding a delay to your call to userEvent.type(). For example:

await userEvent.type(field, "profile name", { delay: 1 })

I was facing the same issue and I am able to resolve it by just removing the value attribute from the input box. Not sure why it cause an issue when we provide it but below is the code.

Working

it('Test input field with different values', async () => {
    render(<input placeholder="test_placeholder" />)

    const input = screen.getByPlaceholderText('test_placeholder');

    userEvent.clear(input);
    userEvent.type(input, 'Test');
    
    await waitFor(() => { expect(input.value).toEqual('Test') });

    userEvent.clear(input);
    userEvent.type(input, '@#$%');
    
    await waitFor(() => { expect(input.value).toEqual('@#$%') });
})

Even if I do render with blank value then the same code is not working. Some how userEvent.type does not have any effect when value attribute is present.

Not Working

render(<input placeholder="test_placeholder"  value=""/>)

It keeps value as empty string (or whatever we gave during render) through out the test.

Failed Test Case

Notes :-

1] I have used Formik only in my actual application and the behavior is same for it as well. To short down the code I have just rendered raw input here.

2]. Below are the version of my testing library

enter image description here

3]. I have used userEvent.clear here, otherwise values are getting appended and the 2nd test would become .toEqual('Test@#$%')

4]. Add onChange={()=>{}} with input to avoid warnings.

Related