如何解决 testing-library-react 中的 "update was not wrapped in act()" 警告?
How to solve the "update was not wrapped in act()" warning in testing-library-react?
我正在使用一个有副作用的简单组件。我的测试通过了,但我收到警告 Warning: An update to Hello inside a test was not wrapped in act(...).
.
我也不知道 waitForElement
是否是编写此测试的最佳方式。
我的组件
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>
)
}
我的组件测试
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();
});
更新的答案:
请参考下方@mikaelrs 的评论。
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');
已弃用的答案:
使用 waitForElement
是正确的方法,来自文档:
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
这是您的案例的工作示例:
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();
});
100% 覆盖率的单元测试结果:
PASS Whosebug/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>
`;
源代码:https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/Whosebug/60115885
对我来说,解决方案是等待 waitForNextUpdate
it('useMyHook test', async() => {
const {
result,
waitForNextUpdate
} = renderHook(() =>
useMyHook(),
);
await waitForNextUpdate()
expect(result.current).toEqual([])
}
我正在使用一个有副作用的简单组件。我的测试通过了,但我收到警告 Warning: An update to Hello inside a test was not wrapped in act(...).
.
我也不知道 waitForElement
是否是编写此测试的最佳方式。
我的组件
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>
)
}
我的组件测试
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();
});
更新的答案:
请参考下方@mikaelrs 的评论。
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');
已弃用的答案:
使用 waitForElement
是正确的方法,来自文档:
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
这是您的案例的工作示例:
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();
});
100% 覆盖率的单元测试结果:
PASS Whosebug/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>
`;
源代码:https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/Whosebug/60115885
对我来说,解决方案是等待 waitForNextUpdate
it('useMyHook test', async() => {
const {
result,
waitForNextUpdate
} = renderHook(() =>
useMyHook(),
);
await waitForNextUpdate()
expect(result.current).toEqual([])
}