Warning: An update to Example inside a test was not wrapped in act(...). #25
Description
react-native
orexpo
: react-nativenative-testing-library
version: 3.1.1jest-preset
: native-testing-libraryreact-native
version: 0.59.2node
version: 10.13.0
Relevant code or config:
import * as React from "react";
import { Button, Text, TextInput, View } from "react-native";
import { fireEvent, render, wait } from "native-testing-library";
function Example() {
const [name, setUser] = React.useState("");
const [show, setShow] = React.useState(false);
return (
<View>
<TextInput value={name} onChangeText={setUser} testID="input" />
<Button
title="Print Username"
onPress={() => {
// let"s pretend this is making a server request, so it"s async
// (you"d want to mock this imaginary request in your unit tests)...
setTimeout(() => {
setShow(!show);
}, Math.floor(Math.random() * 200));
}}
/>
{show && <Text testID="printed-username">{name}</Text>}
</View>
);
}
test("examples of some things", async () => {
const { getByTestId, getByText, queryByTestId } = render(<Example />);
const famousWomanInHistory = "Ada Lovelace";
const input = getByTestId("input");
fireEvent.changeText(input, famousWomanInHistory);
const button = getByText("Print Username");
fireEvent.press(button);
await wait(() => expect(queryByTestId("printed-username")).toBeTruthy());
expect(getByTestId("printed-username").props.children).toBe(famousWomanInHistory);
expect(baseElement).toMatchSnapshot();
});
What you did:
Ran the example found within the documentation that demonstrates an async state update: https://www.native-testing-library.com/docs/example.
What happened:
I get a console.error message suggesting there is a problem with the tests:
console.error node_modules/react-native/Libraries/YellowBox/YellowBox.js:132
Warning: An update to Example 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 Example
in View (created by View)
in View (at AppContainer.js:98)
in View (created by View)
in View (at AppContainer.js:115)
in AppContainer (at src/index.js:24)
Reproduction:
See code snippet above.
Problem description:
Whenever I run the tests, I'm flooded with these console.error
messages whenever I test components that make state changes after async logic such as network requests.
Suggested solution:
I feel this is a known issue, but I've not yet seen a ticket open for it on this project. I figured it would be helpful for others to reference and track the progress.
I've attempted to Google around to see if I can find a solution, but appears to be something fundamentally wrong with the underlying library that the *-testing-library
family uses, react-test-renderer
. This was highlighted in a react-testing-library issue and appears to have a fix on the way in React 16.9 once at least this umbrella issue is closed.
Below is my current workaround:
In my Jest config file, I have a reference to a custom setup script:
module.exports = {
// ...
preset: 'native-testing-library',
setupFiles: [
...jestPreset.setupFiles,
"<rootDir>/setupJest.js"
],
// ...
};
In the custom setup script (setupJest.js), I have the following:
// Auto-mock YellowBox component.
jest.mock("YellowBox");
const mockConsoleMethod = (realConsoleMethod) => {
const ignoredMessages = [
"test was not wrapped in act(...)"
];
return (message, ...args) => {
const containsIgnoredMessage = ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage));
if (!containsIgnoredMessage) {
realConsoleMethod(message, ...args);
}
};
};
// Suppress console errors and warnings to avoid polluting output in tests.
console.warn = jest.fn(mockConsoleMethod(console.warn));
console.error = jest.fn(mockConsoleMethod(console.error));
Note: mockConsoleMethod
is used to only suppress logs that contain "test was not wrapped in act(...)"
.