When trying to test NavigationContainer, I get a console.error log:
console.error
Warning: An update to ForwardRef(NavigationContainer) 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://fb.me/react-wrap-tests-with-act
in ForwardRef(NavigationContainer)
No console.error log.
import React from 'react';
import { NavigationContainer } from "@react-navigation/native";
import { render, fireEvent } from 'react-native-testing-library';
// Silence the warning https://github.com/facebook/react-native/issues/11094#issuecomment-263240420
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
describe('<NavigationContainer />', () => {
it('should match snapshot', () => {
const result = render(<NavigationContainer>
</NavigationContainer>);
expect(result).toMatchSnapshot();
})
})
npmPackages:
react: ~16.9.0 => 16.9.0
react-native: ~0.61.5 => 0.61.5
react-native-testing-library: ^2.0.1 => 2.0.1
react-test-renderer: ^16.13.1 => 16.13.1
It's because your component wrapped in navigation perform some state updates that you don't await for. Instead of snapshotting the whole screen, it would be better to find certain elements in it and assert if they rendered or not. Using findBy queries the library would automatically wait for the elements to appear.
If you don't care about further updates to this component, you can call unmount on it straight away after the assertion.
Anyway it's not a bug in the library. Learn about the act warning for your tests safety.
I utilized async, await, and act to make it work without any warnings or errors.
import React from 'react';
import { NavigationContainer } from "@react-navigation/native";
import { act } from 'react-test-renderer';
import { render, fireEvent } from 'react-native-testing-library';
// Silence the warning https://github.com/facebook/react-native/issues/11094#issuecomment-263240420
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
describe('<NavigationContainer />', () => {
it('should match snapshot', async () => {
const result = render(<NavigationContainer>
</NavigationContainer>);
await act(async () => { expect(result).toMatchSnapshot(); })
});
});
Perhaps this will help someone...
I'm getting this error just running render on the NavigationContainer (and it also repros if I put anything inside):
test("Renders nav container", () => {
const rr = render(<NavigationContainer></NavigationContainer>);
});
This error can be fixed by wrapping the expect statement in act like below
await act(async () => {
expect(true).toBeTruthy()
})
It does seem like an await is key. We were able to fix it by adding this call after the render, which is similar to what's done to get an Apollo Client query to fire::
await wait();
// Wait a tick so the query runs
// https://www.apollographql.com/docs/react/development-testing/testing/#testing-final-state
export async function wait(ms = 0) {
return await act(async () => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
});
}
Even with the above two workarounds, I still get an error that I did not await even though I am.
console.error
Warning: You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);
at warningWithoutStack (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:131:32)
at node_modules/react-test-renderer/cjs/react-test-renderer.development.js:17265:13
at tryCallOne (node_modules/promise/lib/core.js:37:12)
at node_modules/promise/lib/core.js:123:15
at flush (node_modules/asap/raw.js:50:29)
Does this also mean that you add this to every test using the NavigationContainer?
Edit: I am using @testing-library/react-native and not react-native-testing-library, as the latter package has been deprecated in favour of @testing-library.
Weirdly, using cleanup solves the problem for me without having to add any async logic. The solution provided by @jonmchan also works and feels less like a hack, but just in case none of the above works for people you can try:
afterEach(cleanup)
findBy just times out and doesn't return anything.
It seems passing an async callback means there is a "signal" sent back to react-testing library when everything is rendered. My guess is the library does its (conceptual) act checks _after_ everything is rendered, and thus does not complain.
await act(async () => undefined)
I utilized async, await, and act to make it work without any warnings or errors.
import React from 'react'; import { NavigationContainer } from "@react-navigation/native"; import { act } from 'react-test-renderer'; import { render, fireEvent } from 'react-native-testing-library'; // Silence the warning https://github.com/facebook/react-native/issues/11094#issuecomment-263240420 jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper'); describe('<NavigationContainer />', () => { it('should match snapshot', async () => { const result = render(<NavigationContainer> </NavigationContainer>); await act(async () => { expect(result).toMatchSnapshot(); }) }); });Perhaps this will help someone...
Man, this works great for my case, thanks a bunch!
I have a similar issue,
I utilized async, await, and act to make it work without any warnings or errors.
import React from 'react'; import { NavigationContainer } from "@react-navigation/native"; import { act } from 'react-test-renderer'; import { render, fireEvent } from 'react-native-testing-library'; // Silence the warning https://github.com/facebook/react-native/issues/11094#issuecomment-263240420 jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper'); describe('<NavigationContainer />', () => { it('should match snapshot', async () => { const result = render(<NavigationContainer> </NavigationContainer>); await act(async () => { expect(result).toMatchSnapshot(); }) }); });Perhaps this will help someone...
This works great but fail when putting some Navigator inside NavigationContainer
describe('<NavigationContainer />', () => {
it('should match snapshot', async () => {
const result = render(<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={SomeComponent} />
</Stack.Navigator>
</NavigationContainer>);
await act(async () => { expect(result).toMatchSnapshot(); })
});
});
Why is this closed? Still having the issue as @xD3CODER have suggested.
Most helpful comment
I utilized async, await, and act to make it work without any warnings or errors.
Perhaps this will help someone...