2

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
Domotor Zsolt
  • 586
  • 5
  • 10

3 Answers3

5

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

await waitFor(()=> render(<HomeScreen />))
  • Nothing changes, when I looked up everybody said similar things, but I don't have a fireEvent or any other event triggered in my test, just a simple render. – Domotor Zsolt Jan 13 '22 at 07:29
0

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.

Sam
  • 572
  • 3
  • 11
  • I didn't want to mock my requests cause I wanted to have more real tests. But I tried it anyway and it looks like it works: - Removed await before render() - added await waitFor(() => expect(axios.get).toHaveBeenCalledTimes(1)) after Used this to mock https://stackoverflow.com/a/47390898/13374682 – Domotor Zsolt Jan 13 '22 at 08:09
  • Is there a way to fix this without mocking the api? – Domotor Zsolt Jan 13 '22 at 08:11
-1

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

await waitFor(**async** () => render(<App />))
Sid
  • 846
  • 3
  • 12
  • 25
  • async won't change anything. If the return value of render is promise (and it is) then it stays a promise. If its not, than its nothing to await for. – zamuka May 02 '23 at 11:36