Skip to content

Warning: An update to Animated(View) inside a test was not wrapped in act(...). #1772

Open
@abrahamgalue

Description

@abrahamgalue

Hey guys, I'm unit testing my React Native components, and one in particular is causing a console.error with a Warning every time I run the tests. I've searched online and through the official documentation for solutions, but I haven't found one. Hopefully, you can help me here, as this is my first time using this tool, which I'm really enjoying.

The error in particular shows this log:

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

When testing, code that causes React state updates should be wrapped in 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 C:\mobile\react-native\project\node_modules\react-native\Libraries\Animated\createAnimatedComponent.js:38:59 
at TouchableOpacity (C:\mobile\react-native\project\node_modules\react-native\Libraries\Components\Touchable\TouchableOpacity.js:132:23) 
at TouchableOpacity 
at View 
at View (C:\mobile\react-native\project\node_modules\react-native\jest\mockComponent.js:33:18) 
at showNotifications (C:\mobile\react-native\project\components\ui\Notifications.jsx:11:2)

The tests file that is Notifications-test.jsx looks like this:

import {
	render,
	fireEvent,
	screen,
	waitFor
} from '@testing-library/react-native'
import Notifications from '@/components/ui/Notifications'
import { initialNotifications } from '@/lib/utils'

jest.mock('@/lib/useColorScheme', () => ({
	useColorScheme: () => ({ isDarkColorScheme: true })
}))

jest.mock('@/lib/utils', () => ({
	initialNotifications: jest.fn()
}))

const mockInitialNotifications = initialNotifications

jest.mock('@/components/ui/IconSymbol', () => ({
	IconSymbol: jest.fn(() => <></>)
}))

jest.mock('@/components/ui/Icons', () => ({
	WaterObstructionIcon: jest.fn(() => <></>),
	TemperatureSubstrateIcon: jest.fn(() => <></>)
}))

const mockHandleNotificationPress = jest.fn()
const mockHandleClearNotifications = jest.fn()

const initialNotificationsValue = [
	{
		type: 'waterObstruction',
		content: '60% de agua restante'
	},
	{
		type: 'temperatureSubstrate',
		content: '0.5% obstrucción'
	}
]

describe('<Notifications />', () => {
	beforeEach(() => {
		jest.clearAllMocks()
	})

	test('should render notification button', () => {
		mockInitialNotifications.mockReturnValue(initialNotificationsValue)

		render(
			<Notifications
				showNotifications={false}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		expect(screen.getByRole('button')).toBeOnTheScreen()
	})

	test('should show notification count badge when there are notifications', () => {
		mockInitialNotifications.mockReturnValue(initialNotificationsValue)

		render(
			<Notifications
				showNotifications={false}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		expect(
			screen.getByText(initialNotificationsValue.length.toString())
		).toBeOnTheScreen()
	})

	test('does not show notification count when there are no notifications', () => {
		mockInitialNotifications.mockReturnValue([])

		render(
			<Notifications
				showNotifications={false}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		expect(
			screen.queryByText(initialNotificationsValue.length.toString())
		).not.toBeOnTheScreen()
	})

	test.each(initialNotificationsValue)(
		'should display $count when showNotifications is true',
		({ content }) => {
			mockInitialNotifications.mockReturnValue(initialNotificationsValue)

			render(
				<Notifications
					showNotifications={true}
					handleNotificationPress={mockHandleNotificationPress}
					handleClearNotifications={mockHandleClearNotifications}
				/>
			)

			expect(screen.getByRole('text', { name: content })).toBeOnTheScreen()
		}
	)

	test('should call handleNotificationPress when button is pressed', async () => {
		mockInitialNotifications.mockReturnValue(initialNotificationsValue)

		render(
			<Notifications
				showNotifications={false}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		fireEvent.press(screen.getByRole('button'))
		await waitFor(() => {
			expect(mockHandleNotificationPress).toHaveBeenCalled()
		})
	})

	test('does not call handleNotificationPress when button is disabled', async () => {
		mockInitialNotifications.mockReturnValue([])

		render(
			<Notifications
				showNotifications={false}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		fireEvent.press(screen.getByRole('button'))
		await waitFor(() => {
			expect(mockHandleNotificationPress).not.toHaveBeenCalled()
		})
	})

	test('should render clear notifications button', () => {
		mockInitialNotifications.mockReturnValue(initialNotificationsValue)

		render(
			<Notifications
				showNotifications={true}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		const clearBtn = screen.getByText('Limpiar todo')

		expect(clearBtn).toBeOnTheScreen()
		expect(clearBtn).toHaveStyle({ color: 'white' })
		expect(clearBtn.props).toHaveProperty('className', 'font-bold')
	})

	test('should call handleClearNotifications when clear button is pressed', async () => {
		mockInitialNotifications.mockReturnValue(initialNotificationsValue)

		render(
			<Notifications
				showNotifications={true}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		const clearBtn = screen.getByText('Limpiar todo')

		expect(clearBtn).toBeOnTheScreen()
		expect(clearBtn).toHaveStyle({ color: 'white' })
		expect(clearBtn.props).toHaveProperty('className', 'font-bold')

		fireEvent.press(clearBtn)
		await waitFor(() => {
			expect(mockHandleClearNotifications).toHaveBeenCalled()
		})
	})

	test('should display "+9" when there are 10 or more notifications', () => {
		mockInitialNotifications.mockReturnValue(
			Array(10).fill({
				type: 'waterObstruction',
				content: '60% de agua restante'
			})
		)

		render(
			<Notifications
				showNotifications={false}
				handleNotificationPress={mockHandleNotificationPress}
				handleClearNotifications={mockHandleClearNotifications}
			/>
		)

		expect(screen.getByText('+9')).toBeOnTheScreen()
	})
})

It is important to clarify that all tests are passing correctly, but this warning is displayed, which I find annoying and makes me doubt if I am doing something wrong. I currently use Jest with Expo and I configured it according to its official documentation. If you need any other resources such as the Notifications component code, please let me know. I would really appreciate your help 🙌

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions