简体   繁体   中英

WaitForNextUpdate of renderHook of react-testing-library timeout

I'm Simone and I want to start this thread giving thanks to this community for the totally useful help you give to developers (in my case). I found all the answer to my questions here, but now i would need to ask something explicitely.

I'm testing a custom hook with react-testing-library . What you need to know about the hook is that is a simple hook that basically do this:

function useHook() {
  const [state, setState] = useState();
  
  const fetch = async () => {
    const response = await httpCall();
    if (instanceof response !== Error) {
      setState("GOOD")
    } else {
      setState("BAD")
    }
  }
  
  return { state, fetch }
}

and my test file is something like this:

it("test", async () => {
  const { result, waitForNextUpdate } = renderHooks(() => useHook())

  await result.current.fetch();
  expect(result.current.state).toBe(undefined)

  await waitForNextUpdate();
  expect(result.current.state).toBe("GOOD") //or at least "BAD"
})

I wrote this because I called the async function fetch() that should trigger the setState, I assert that no rerender has been occurred yet, and then I waitForNextUpdate() in order to wait this rerender and I assert that the state returned by the hooks has now a value "GOOD" or "BAD" .

My problem is that my test gives me an error: Timeout - Async callback was not invoked within the 5000 ms... , and this error occurred when the test waits for the waitForNextUpdate() .

I don't know what's wrong with my test. I'm sure (because i tested it) that the hook is working properly, the http call has been made. I know that checking values inside the test but also because the hook is working properly inside the application. I don't understand why it seems that the update of the state never occurres.

I'm the first one of my team who is testing with this tool so i'm quite lost. If you can help me i will be very grateful.

Thank you!

First of all you have small mistake in if statment of the hook, so let's correct that and also add import of httpCall function for example sake

import { useState } from 'react'
import { httpCall } from './httpCall'

export function useHook() {
  const [state, setState] = useState<string>()

  const fetch = async () => {
    const response = await httpCall()
    if (response instanceof Error) {
      setState('GOOD')
    } else {
      setState('BAD')
    }
  }

  return { state, fetch }
}

now we can have two test cases, based on mocking httpCall results. Note that rerender is used instead of waitForNextUpdate

import { waitFor } from '@testing-library/react'
import { renderHook } from '@testing-library/react-hooks'
import { httpCall } from './httpCall'
import { useHook } from './useHook'

jest.mock('./httpCall', () => ({
  httpCall: jest.fn()
}))

describe('useHook', () => {
  it('should return error', async () => {
    // httpCall was mocked above, so we can replace it's implementation
    httpCall.mockImplementation(() => new Error('error'))
    const { result, rerender } = renderHook(() => useHook())

    await result.current.fetch()
    rerender()

    await waitFor(() => {
      expect(result.current.state).toBe('BAD')
    })
  })

  it('should return response', async () => {
    httpCall.mockImplementation(() => ({
      ok: true
    }))

    const { result, rerender } = renderHook(() => useHook())

    await result.current.fetch()
    rerender()

    await waitFor(() => {
      expect(result.current.state).toBe('GOOD')
    })
  })
})

You should not use await when calling the function under test of your hook.

It should instead be wrapped in act() , though as specified in the documentation about async testing it can be omitted when await waitForNextUpdate() is called.

The test passes with this change:

it('test', async () => {
  const { result, waitForNextUpdate } = renderHook(() => useHook());

  act(() => {
    result.current.fetch();
  });
  expect(result.current.state).toBe(undefined);

  await waitForNextUpdate();
  expect(result.current.state).toBe('GOOD'); //or at least "BAD"
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM