When testing, code that causes React state updates should be wrapped into act(...) - with simple react-native nested screen/components with jest axios

2.1k views Asked by At

I am new to unit testing/jest, but I know some about react native. I want to write a test for my HomeScreen, which contains a component that makes a simple request. The code runs without any issue but fails when I run it with Jest.

HomeScreen.js

import { View } from 'react-native'
import APIExample from '@components/Examples/APIExample'
const HomeScreen = () => {
    return (<View> <APIExample /> </View>)
}
export default HomeScreen

HomeScreen.test.js

import { render } from '@testing-library/react-native'
import HomeScreen from '@screens/HomeScreen'

it('should run', async () => {
    const { getByText } = await render(<HomeScreen />)
})

APIExample.js

import { useState, useEffect } from 'react'
import { Text, View } from 'react-native'
import API from '../../API'

const APIExample = () => {
    const [apiResponse, setApiResponse] = useState(null)

    const Submit = async () => {
        const response = await API.Test()
        setApiResponse(response)
    }
    useEffect(() => {
        Submit()
    }, [])
    return (
        <View>
            <Text>
                {JSON.stringify(apiResponse)}
            </Text>
        </View>
    )
}
export default APIExample

I try to figure out why does it keep saying that I should wrap it in act and what exactly do I need to wrap? I already tried to wrap the render whole line but had no success.

The API.Test is a simple axios.get

The error I've kept getting is:

Warning: An update to APIExample 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
3

There are 3 answers

1
Alexander Vidaurre Arroyo On

It happened to me with fireEvent a couple of days ago. Try this:

await waitFor(()=> render(<HomeScreen />))
2
Sam On

The reason you're facing the issue is because of state change that's happening. While on first render the apiResponse data is set as null. And later with the api response the apiResponse has a value so there is re-render that has occured, so jest complains about it.

To resolve you could use await waitFor(() => expect(api).toHaveBeenCalledTimes(1)). This will wait for a specific period of time.

Suggestion: Mock your api's in tests, instead of hitting it directly.

1
Sid On

I needed to make the callback in the waitFor function async, fixed my issue:

await waitFor(**async** () => render(<App />))