react-hook-form: formState.dirty not being updated after field's value changes with @testing-library/react

Describe the bug

react-hook-form does not update formState parameters when fields get updated inside testing-library tests.

To Reproduce

You can reproduce it with the following code:

// form.js
import React from 'react';

import {useState} from 'react';

import useForm from 'react-hook-form';

const Form = ({submit}) => {
  const { register, handleSubmit, formState } = useForm({mode: 'onChange'});
  
  const [val, setVal] = useState(false);

  const onSubmit = (data) => {
    setVal(true);
    // formState.dirty === false should be true
    submit(formState.dirty)
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input data-testid="myinput" name="myinput" ref={register} /> {/* register an input */}
      
      <button type="submit" data-testid="login-submit"> Login </button>

      {val && <div data-testid="my-res"> Value Set! </div>}
    </form>
  );
};

export default Form;
// form.spec.js
import React from 'react';

import { render, cleanup, fireEvent } from '@testing-library/react';

import Form from './form';

require('mutationobserver-shim');

afterEach(cleanup);

describe('form', () => {

  it('tells when submission is dirty', async () => {

    const submit = jest.fn()
    const { getByTestId, findByTestId } = render(<Form  submit={submit}/>);

    const myinput = getByTestId("myinput");

    const submitButon = await findByTestId('login-submit');

    fireEvent.change(myinput, { target: { value: 'set random input' } });

    fireEvent.click(submitButon);

    await findByTestId('my-res')

   // it's being called with false
    expect(submit).toHaveBeenCalledWith(true)
  });

});

Expected behavior When submitting, formState.dirty should be true as we’ve changed the input value.

Desktop (please complete the following information):

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 4
  • Comments: 16 (8 by maintainers)

Most upvoted comments

I think if you change fireEvent.input should work for you.

I’ve spent half of today battling with a similar issue, turns out it was painfully simple… hopefully this helps someone else!

In my case I was toggling a checkbox and then trying to check the validation state. Like so:

fireEvent.click(getByLabelText("My label"));
// attempt to test formState here

However nothing on the formState was being updated. The way my form was setup was to only validate onBlur. Additionally, validation seems to happen asynchronously, so wrapping any further expects in waitFor seemed to do the trick.

fireEvent.click(getByLabelText("My label"));
fireEvent.blur(getByLabelText("My label"));

waitFor(()=> {
    // test changes to formState here
})

@bibekg have a read this section: https://react-hook-form.com/faqs#TestingReactHookForm i think it may help on testing.

i will take a look at it again