I’m a newbie with testing
I’m trying to get a grip on testing React Native with Expo, Jest and React Native Testing Library
I wrote a simple screen that takes data from an API and writes the first element in the screen with a < Text >
import { StyleSheet, Text, View } from "react-native";
import React, { useEffect, useState } from "react";
import axios from "axios";
const ReadPostsFromTypicode = () => {
const [list, setList] = useState([]);
const readFromTypicode = async () => {
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
setList(response.data);
};
useEffect(() => {
readFromTypicode();
}, []);
return (
<View style={{ margin: 25 }}>
<Text>{list[0]?.title}</Text>
</View>
);
};
export default ReadPostsFromTypicode;
const styles = StyleSheet.create({});
I’m also using MSW, so the first element would be “Hello”:
import { rest } from "msw";
export const handlers = [
rest.get("https://jsonplaceholder.typicode.com/posts", (req, res, ctx) => {
return res(
ctx.json([{ userId: 1, id: 1, title: "Hello", body: "Hello World!" }])
);
}),
];
But when I run the test:
import React from "react";
import { render, screen, s } from "@testing-library/react-native";
import ReadPostsFromTypicode from "../src/screens/ReadPostsFromTypicode";
describe("ReadPostsFromTypicode", () => {
it("has 1 text", async () => {
render(<ReadPostsFromTypicode />);
expect(screen.getByText("Hello")).toBeTruthy();
});
});
I get an error in the test, saying that “Unable to find an element with text: Hello” This is the test output:
Even though I checked that the mocked server worked ok, and the state was being set right.
But I also get a strange warning:
Warning: An update to ReadPostsFromTypicode 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
at ReadPostsFromTypicode (C:\Rafael\react-tests\create-expo-app-msw\src\screens\ReadPostsFromTypicode.js:6:35)
11 | );
12 | console.log(response.data);
> 13 | setList(response.data);
| ^
14 | };
15 |
16 | useEffect(() => {
It seems that it doesn’t like the use of the state variable
I wrapped the render with act like so:
import React from "react";
import { render, screen, act } from "@testing-library/react-native";
import ReadPostsFromTypicode from "../src/screens/ReadPostsFromTypicode";
describe("ReadPostsFromTypicode", () => {
it("has 1 text", async () => {
act(() => render(<ReadPostsFromTypicode />));
expect(screen.getByText("Hello")).toBeTruthy();
});
});
I read that the render is already wrapped with Act, but I don't know what to wrap, now I get this error:
Trying to detect host component names triggered the following error:
Can't access .root on unmounted test renderer
There seems to be an issue with your configuration that prevents React Native Testing Library from working correctly.
Please check if you are using compatible versions of React Native and React Native Testing Library.
6 | describe("ReadPostsFromTypicode", () => {
7 | it("has 1 text", async () => {
> 8 | act(() => render(<ReadPostsFromTypicode />));
| ^
9 | // render(<ReadPostsFromTypicode />);
10 | expect(screen.getByText("Hello")).toBeTruthy();
11 | });
I need to know what I am doing wrong
Thanks in advance
You should be able to wrap your assertion with the waitFor method provided by React Testing Library.
describe("ReadPostsFromTypicode", () => {
it("has 1 text", async () => {
render(<ReadPostsFromTypicode />);
await waitFor(() => {
expect(screen.getByText("Hello")).toBeTruthy();
});
});
});
Here is an article on React Testing async state updates
Here are the React Testing Library docs on async testing
I am not 100% sure this is your solution as I am unable to test it myself at the moment, but let me know if you still have issues after trying it and I will try to replicate your issues. Cheers!