如何使用 jest 和 yeast 测试异步数据获取反应组件?
2020-01-03
5017
我有一个使用
useEffect
钩子进行数据提取和设置加载、成功和失败状态的反应组件。
import React, { useState, useEffect } from "react";
import { fetchData } from "./api";
function App({ id }) {
const [data, setData] = useState(null);
const [isFetching, setIsFetching] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setIsFetching(true);
fetchData(id)
.then(
response => {
setData(response.data);
setIsFetching(false);
},
err => {
setError(err);
setIsFetching(false);
}
)
.catch(err => {
setError(err);
setIsFetching(false);
});
}, [id]);
if (data) {
return <pre>{JSON.stringify(data)}</pre>;
}
if (isFetching) {
return <div>fetching...</div>;
}
if (error) {
return <pre>{JSON.stringify(error)}</pre>;
}
return <div>null</div>;
}
export default App;
我正在尝试使用 jest 和 digest 测试这个组件。
这是一个沙盒 https://codesandbox.io/s/jest-enzyme-re41k
我收到一个奇怪的错误
无法读取未定义的属性“isTTY”
有人可以帮忙修复测试吗?
1个回答
这是单元测试解决方案:
app.jsx
:
import React, { useState, useEffect } from 'react';
import { fetchData } from './api';
function App({ id }) {
const [data, setData] = useState(null);
const [isFetching, setIsFetching] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setIsFetching(true);
fetchData(id)
.then(
(response) => {
setData(response.data);
setIsFetching(false);
},
(err) => {
setError(err);
setIsFetching(false);
},
)
.catch((err) => {
setError(err);
setIsFetching(false);
});
}, [id]);
if (data) {
return <pre>{JSON.stringify(data)}</pre>;
}
if (isFetching) {
return <div>fetching...</div>;
}
if (error) {
return <pre>{JSON.stringify(error)}</pre>;
}
return <div>null</div>;
}
export default App;
api.js
:
export function fetchData() {
// real implementation
}
app.test.jsx
:
import App from './app';
import { mount } from 'enzyme';
import { fetchData } from './api';
import { act } from 'react-dom/test-utils';
jest.mock('./api.js', () => {
return {
fetchData: jest.fn(),
};
});
describe('59586141', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('should fetch data correctly', async () => {
const mResponse = { data: { id: 1 } };
const mProps = { id: 1 };
fetchData.mockResolvedValueOnce(mResponse);
const wrapper = mount(<App {...mProps}></App>);
expect(wrapper.exists).toBeTruthy();
expect(wrapper.find('div').text()).toBe('fetching...');
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('pre').text()).toBe(JSON.stringify(mResponse.data));
expect(fetchData).toBeCalledWith(1);
});
it('should handle error if fetch data failure', async () => {
const mError = new Error('some network error');
const mProps = { id: 1 };
fetchData.mockRejectedValueOnce(mError);
const wrapper = mount(<App {...mProps}></App>);
expect(wrapper.exists).toBeTruthy();
expect(wrapper.find('div').text()).toBe('fetching...');
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('pre').text()).toBe(JSON.stringify(mError));
expect(fetchData).toBeCalledWith(1);
});
});
带有覆盖率报告的单元测试结果:
PASS src/stackoverflow/59586141/api.test.jsx (9.079s)
59586141
✓ should fetch data correctly (119ms)
✓ should handle error if fetch data failure (12ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 93.1 | 100 | 80 | 91.3 | |
app.jsx | 93.1 | 100 | 80 | 91.3 | 22,23 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 10.458s
源代码: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59586141
Lin Du
2020-01-08