我已经建立了一个github项目,以了解如何更好地测试react(v 16.8.0) useEffect 挂钩。 我进行了api调用以获取 useEffect 中的数据,并将接收到的数据设置为状态组件元素。 我的组件将查询作为道具接收,如果查询道具字符串不为空,则进行api调用。我想测试使用无空查询prop进行的api调用,并且组件将其状态设置为正确。
我知道测试 useEffect 面临的问题是与 useEffect 相关的效果不会阻止浏览器更新屏幕,因此测试进入了在 useEffect 发挥作用之前结束。 我从React文档中了解到,有一个来自 act-test-utils 的API,称为 act ,该API被认为可以包装用于渲染组件并对其进行更新的代码。 即使我尝试使用它,我的代码仍然会遇到相同的问题。
这是我要测试的组件:
const DisplayData = ({ query, onQueryChange }) => {
const [data, setData] = useState({ hits: [] });
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(
`http://hn.algolia.com/api/v1/search?query=${query}`,
);
setData(result.data);
};
if (!!query) fetchData();
}, [query]);
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
};
这是我为此编写的测试:
it("should show new entries when query is set", () => {
const el = document.createElement("div");
document.body.appendChild(el);
axios.get.mockResolvedValue({ data: { hits: FAKE_HITS } });
act(() => {
render(<DisplayData query='pippo' />, el);
});
const liCounts = el.querySelectorAll("li");
expect(liCounts.length).toBe(2);
});
我不断收到警告,告诉我测试中DisplayData的更新未包含在act(...)中,并且由于 liCounts ,我的测试失败了收到的是_0_,而不是预期的 2 。
插入相同的控制台消息来调试应用程序,我相信问题在于 useEffect 是在测试执行后启动的,但是我不知道如何继续。
更新 感谢@jonrsharpe我使用React版本16.9.0-alpha.0解决了我的问题,该版本具有 act api的异步版本。
答案 0 :(得分:3)
这是单元测试解决方案:
index.tsx
:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export const DisplayData = ({ query, onQueryChange }) => {
const [data, setData] = useState<any>({ hits: [] });
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(`http://hn.algolia.com/api/v1/search?query=${query}`);
setData(result.data);
};
if (!!query) fetchData();
}, [query]);
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
};
index.spec.tsx
:
import React from 'react';
import { DisplayData } from './';
import axios from 'axios';
import renderer, { act } from 'react-test-renderer';
describe('DisplayData', () => {
it('should show new entries when query is set', async () => {
const mProps = {
query: 'pippo',
onQueryChange: jest.fn()
};
const FAKE_HITS = [{ objectID: 1, url: 'haha.com', title: 'haha' }];
const axiosGetSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce({ data: { hits: FAKE_HITS } });
let component;
await act(async () => {
component = renderer.create(<DisplayData {...mProps}></DisplayData>);
});
expect(axiosGetSpy).toBeCalledWith('http://hn.algolia.com/api/v1/search?query=pippo');
expect(component.toJSON()).toMatchSnapshot();
axiosGetSpy.mockRestore();
});
it('should not fetch data when query is empty string', async () => {
const mProps = {
query: '',
onQueryChange: jest.fn()
};
const axiosGetSpy = jest.spyOn(axios, 'get');
let component;
await act(async () => {
component = renderer.create(<DisplayData {...mProps}></DisplayData>);
});
expect(axiosGetSpy).not.toBeCalled();
expect(component.toJSON()).toMatchSnapshot();
axiosGetSpy.mockRestore();
});
});
覆盖率100%的单元测试结果:
PASS src/stackoverflow/56410688/index.spec.tsx
DisplayData
✓ should show new entries when query is set (28ms)
✓ should not fetch data when query is empty string (5ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.tsx | 100 | 100 | 100 | 100 | |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 2 passed, 2 total
Time: 3.666s
index.spec.tsx.snap
:
// Jest Snapshot v1,
exports[`DisplayData should not fetch data when query is empty string 1`] = `<ul />`;
exports[`DisplayData should show new entries when query is set 1`] = `
<ul>
<li>
<a
href="haha.com"
>
haha
</a>
</li>
</ul>
`;
依赖版本:
"jest": "^24.9.0",
"react-test-renderer": "^16.11.0",
"react": "^16.11.0",
"axios": "^0.19.0",
源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/56410688