Pab*_*rde 37 unit-testing reactjs jestjs react-testing-library testing-library
我正在使用一个有副作用的简单组件。我的测试通过了,但我收到警告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>
)
}
Run Code Online (Sandbox Code Playgroud)
我的组件测试
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();
});
Run Code Online (Sandbox Code Playgroud)
sli*_*wp2 32
更新的答案:
请参阅下面的@mikaelrs 评论。
不需要waitFor 或waitForElement。你可以只使用 findBy* 选择器,它返回一个可以等待的承诺。例如 await findByTestId('list');
弃用的答案:
使用waitForElement是正确的方法,来自文档:
等到
get模拟的请求承诺解决并且组件调用 setState 并重新渲染。waitForElement等到回调不抛出错误
这是您案例的工作示例:
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>
);
}
Run Code Online (Sandbox Code Playgroud)
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();
});
Run Code Online (Sandbox Code Playgroud)
100% 覆盖率的单元测试结果:
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
Run Code Online (Sandbox Code Playgroud)
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>
`;
Run Code Online (Sandbox Code Playgroud)
源代码:https : //github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60115885
小智 21
我有一个错误:
console.error
Warning: A suspended resource finished loading inside a test, but the event was not wrapped in act(...).
When testing, code that resolves suspended data should be wrapped into act(...):
act(() => {
/* finish loading suspended data */
});
/* 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
Run Code Online (Sandbox Code Playgroud)
代码:
test('check login link', async () => {
renderRouter({ initialRoute: [home.path] });
const loginLink = screen.getByTestId(dataTestIds.loginLink);
expect(loginLink).toBeInTheDocument();
userEvent.click(loginLink);
const emailInput = screen.getByTestId(dataTestIds.emailInput);
expect(emailInput).toBeInTheDocument();
}
Run Code Online (Sandbox Code Playgroud)
我已经解决了:
test('check login link', async () => {
renderRouter({ initialRoute: [home.path] });
const loginLink = screen.getByTestId(dataTestIds.loginLink);
expect(loginLink).toBeInTheDocument();
userEvent.click(loginLink);
await waitFor(() => {
const emailInput = screen.getByTestId(dataTestIds.emailInput);
expect(emailInput).toBeInTheDocument();
});
}
Run Code Online (Sandbox Code Playgroud)
我刚刚包裹在回调 fn - waitFor() 中
也许对某人有用
Kar*_*umi 14
WaitFor为我工作,我尝试使用findByTestId此处提到的方法,但我仍然遇到相同的操作错误。
我的解决方案:
\nit('Should show an error message when pressing \xe2\x80\x9cNext\xe2\x80\x9d with no email', async () => {\nconst { getByTestId, getByText } = render(\n <Layout buttonText={'Common:Actions.Next'} onValidation={() => validationMock}\n />\n);\n\nconst validationMock: ValidationResults = {\n email: {\n state: ValidationState.ERROR,\n message: 'Email field cannot be empty'\n }\n};\n\nawait waitFor(() => {\n const nextButton = getByTestId('btn-next');\n fireEvent.press(nextButton);\n});\n\nexpect(getByText('Email field cannot be empty')).toBeDefined();\nRun Code Online (Sandbox Code Playgroud)\n