I'm working with a simple component that does a side effect. My test passes, but I'm getting the warning Warning: An update to Hello inside a test was not wrapped in act(...).
.
I'm also don't know if waitForElement
is the best way to write this test.
My component
export default function Hello() { const [posts, setPosts] = useState([]); useEffect(() => { const fetchData = async () => { const response = await axios.get('https://jsonplaceholder.typicode.com/posts'); setPosts(response.data); } fetchData(); }, []); return ( <div> <ul> { posts.map( post => <li key={post.id}>{post.title}</li> ) } </ul> </div> ) }
My component test
import React from 'react'; import {render, cleanup, act } from '@testing-library/react'; import mockAxios from 'axios'; import Hello from '.'; afterEach(cleanup); it('renders hello correctly', async () => { mockAxios.get.mockResolvedValue({ data: [ { id: 1, title: 'post one' }, { id: 2, title: 'post two' }, ], }); const { asFragment } = await waitForElement(() => render(<Hello />)); expect(asFragment()).toMatchSnapshot(); });
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.
You NEVER need to wrap userEvent or fireEvent in act. They are *already* wrapped in act. Some have noticed that they see an "act warning" go away when wrapping these in an async act. The warning would go away just as well if you added: `await act(async () => {})` on the next line.
react-dom/test-utils provides a helper called act() that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions: act(() => { // render components }); // make assertions.
cleanup Unmounts React trees that were mounted with render. Please note that this is done automatically if the testing framework you're using supports the afterEach global and it is injected to your testing environment (like mocha, Jest, and Jasmine).
Updated answer:
Please refer to @mikaelrs comment below.
No need for the waitFor or waitForElement. You can just use findBy* selectors which return a promise that can be awaited. e.g await findByTestId('list');
Deprecated answer:
Use waitForElement
is a correct way, from the docs:
Wait until the mocked
get
request promise resolves and the component calls setState and re-renders.waitForElement
waits until the callback doesn't throw an error
Here is the working example for your case:
index.jsx
:
import React, { useState, useEffect } from 'react'; import axios from 'axios'; export default function Hello() { const [posts, setPosts] = useState([]); useEffect(() => { const fetchData = async () => { const response = await axios.get('https://jsonplaceholder.typicode.com/posts'); setPosts(response.data); }; fetchData(); }, []); return ( <div> <ul data-testid="list"> {posts.map((post) => ( <li key={post.id}>{post.title}</li> ))} </ul> </div> ); }
index.test.jsx
:
import React from 'react'; import { render, cleanup, waitForElement } from '@testing-library/react'; import axios from 'axios'; import Hello from '.'; jest.mock('axios'); afterEach(cleanup); it('renders hello correctly', async () => { axios.get.mockResolvedValue({ data: [ { id: 1, title: 'post one' }, { id: 2, title: 'post two' }, ], }); const { getByTestId, asFragment } = render(<Hello />); const listNode = await waitForElement(() => getByTestId('list')); expect(listNode.children).toHaveLength(2); expect(asFragment()).toMatchSnapshot(); });
Unit test results with 100% coverage:
PASS stackoverflow/60115885/index.test.jsx ✓ renders hello correctly (49ms) -----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s -----------|---------|----------|---------|---------|------------------- All files | 100 | 100 | 100 | 100 | index.jsx | 100 | 100 | 100 | 100 | -----------|---------|----------|---------|---------|------------------- Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 1 passed, 1 total Time: 4.98s
index.test.jsx.snapshot
:
// Jest Snapshot v1 exports[`renders hello correctly 1`] = ` <DocumentFragment> <div> <ul data-testid="list" > <li> post one </li> <li> post two </li> </ul> </div> </DocumentFragment> `;
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60115885
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With