react-native-testing-library icon indicating copy to clipboard operation
react-native-testing-library copied to clipboard

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

Open abrahamgalue opened this issue 7 months ago • 2 comments

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 🙌

abrahamgalue avatar May 25 '25 19:05 abrahamgalue

@abrahamgalue yeah, I've also observed this in other context when using Animated(View). Treating it as low priority due to tests passing correctly.

mdjastrzebski avatar Jul 14 '25 13:07 mdjastrzebski

Did you try jest.useFakeTimers(); as mentioned in the Readme? That fixed it for my problem.

KiwiKilian avatar Nov 19 '25 07:11 KiwiKilian