React-hook-form: React warning in tests that a form is updated outside act despite being wrapped in act

Created on 24 Sep 2019  路  3Comments  路  Source: react-hook-form/react-hook-form

Describe the bug

React display a warning in test that updates need to be wrapped in act despite using act.

Warning: An update to Form inside a test was not wrapped in act(...).

      When testing, code that causes React state updates should be wrapped into act(...):

      act(() => {
        /* fire events that update state */
      });
      /* assert on the output */

      This ensures that you're testing the behavior the user would see in the browser. Learn more at https://fb.me/react-wrap-tests-with-act

To Reproduce
Steps to reproduce the behavior:

  1. Use the FormContext
  2. Use defaultValues
  3. Use an input with validation
  4. be in mode onBlur or onChange

Without any of these things the warning disappears

example test:

import React from 'react'
import ReactDOM from 'react-dom'
import { act } from 'react-dom/test-utils'

import useForm, { FormContext, useFormContext } from 'react-hook-form'

const Form = ({ children }) => {
  const methods = useForm({ mode: 'onBlur', defaultValues: { checkbox: true } })
  return (
    <FormContext {...methods}>
      <form onSubmit={() => {}}>{children}</form>
    </FormContext>
  )
}

const Field = () => {
  const { register } = useFormContext()
  return <input name="checkbox" ref={register({ required: true })} type="checkbox" />
}

const container = document.createElement('div')
document.body.appendChild(container)

test('hook form act', async () => {
  act(() => {
    ReactDOM.render(
      <Form>
        <Field />
      </Form>,
      container
    )
  })
})

Expected behavior
When rendering the Form component in act, React should not display a warning about using act.

Additional context
I think it's the validation that triggers an update of the context. But I have no idea why act does not work properly.

question

Most helpful comment

I'm not sure if it suits your needs, but I got success by turning the test async and making the act call async too, awaiting for it. I use it to test submits:

    test('submits', async () => {
      // ... submit mocks ...

      const app = mount(
        <MyForm onSubmit={mockSubmit}/>
      )

      const Form = app.find(MyForm)
      await act(async () => {
        await Form.simulate('submit')
      })

      // ... asserts ...
    })

All 3 comments

I'm not sure if it suits your needs, but I got success by turning the test async and making the act call async too, awaiting for it. I use it to test submits:

    test('submits', async () => {
      // ... submit mocks ...

      const app = mount(
        <MyForm onSubmit={mockSubmit}/>
      )

      const Form = app.find(MyForm)
      await act(async () => {
        await Form.simulate('submit')
      })

      // ... asserts ...
    })

hey @eugenenelou is the above answer to solve your question?

Yes thank you. I also had to update to react 16.9 for the async act.

Was this page helpful?
0 / 5 - 0 ratings