Wrapping react test with act when state change happen immediately on render

119 Views Asked by At

We have a simple iframe component that's wrapped by an "overlay" loading indicator component. We use the native onload function to clear the overlay's loading state.

export const Frame = ({ className, src }: FrameProps): JSX.Element => {
  const [status, setStatus] = useState<OverlayStatuses>('loading')

  const onLoad = useCallback(() => {
    setStatus('success')
  }, [])

  return (
    <Overlay status={status}>
      <iframe className={clsx(styles.frame, className)} onLoad={onLoad} src={src.toString()} />
    </Overlay>
  )
}

However, in our unit test (using testing-library/react in vitest) we use abount:blank for the iframe src, which I believe triggers the onload immediately, which updates state, which triggers a warning that we need to be wrapping our test in act. Except this is the original render and I don't see a way to wrap that in act or await anything.

When we use http://example.com as the URL, the issue goes away because the onload doesn't fire immediately. But using an actual internet website isn't acceptable for our automated tests.

describe('frame', () => {
  it('mounts and matches snapshot', () => {
    const { container } = render(<Frame src={new URL('about:blank')} />)

    expect(container).toBeInTheDocument()
    expect(container).toMatchSnapshot()
  })
})
stderr | app/components/frame/tests/frame.spec.tsx > frame > mounts and matches snapshot
Warning: An update to Frame 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://reactjs.org/link/wrap-tests-with-act
    at Frame (C:\...\app\components\frame\frame.tsx:13:18)
0

There are 0 best solutions below