我已经解决了这一问题几天,并相信我已经接近解决方案。我正在尝试模拟useEffect
useEffect(() => {
getAdminOrg();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const getAdminOrg = () => {
const token = localStorage.getItem("token");
const URL = `organizations/organizations/`;
let config = {
headers: { Authorization: "JWT " + token }
};
axios
.get(URL, config)
.then(response => {
setOrgTitle(response.data.name);
})
.catch(error => {
if (error.response) {
console.log(error.response);
if (error.response.status === 401) {
props.renewToken();
}
}
});
};
如果运行setOrgTitle
钩子,我将能够通过更改文本字段来检测到这一点。我正在尝试在这里进行测试:
it("mocks API call", done => {
const wrapper = mount(
<OrganizationDocs />
);
const mock = new MockAdapter(axios);
mock
.onGet(`organizations/organizations/`, {
headers: { Authorization: "JWT1111" }
})
.reply(200, response.data);
setImmediate(() => {
wrapper.update();
expect(findByTestId(wrapper, "org-docs-header").text()).toContain(
organizationsOrganizations[0].name
);
done();
});
});
运行测试时,我收到未处理的承诺拒绝警告。另外,当我尝试控制台wrapper
日志时,我可以看到API调用未使用我正在应用的测试标头,因此我可以肯定API调用未在使用我的模拟。
任何帮助将不胜感激。
答案 0 :(得分:0)
这里是仅使用jestjs
+ enzyme
+ react-dom/test-utils
的单元测试解决方案。
例如
index.ts
:
import React, { useEffect, useState } from 'react';
import axios from 'axios';
export const OrganizationDocs = (props) => {
const [orgTitle, setOrgTitle] = useState('');
useEffect(() => {
getAdminOrg();
}, []);
const getAdminOrg = () => {
const token = localStorage.getItem('token');
const URL = `organizations/organizations/`;
let config = {
headers: { Authorization: 'JWT ' + token },
};
axios
.get(URL, config)
.then((response) => {
setOrgTitle(response.data.name);
})
.catch((error) => {
if (error.response) {
console.log(error.response);
if (error.response.status === 401) {
props.renewToken();
}
}
});
};
return <div className="org-docs-header">orgTitle: {orgTitle}</div>;
};
index.spec.ts
:
import React from 'react';
import { OrganizationDocs } from '.';
import { mount } from 'enzyme';
import axios from 'axios';
import { act } from 'react-dom/test-utils';
const mLocalStorage = {
_storage: {},
getItem: jest.fn((key) => {
return mLocalStorage._storage[key];
}),
setItem: jest.fn((key, value) => {
mLocalStorage._storage[key] = value;
}),
};
Object.defineProperty(window, 'localStorage', {
value: mLocalStorage,
});
describe('MyComponent', () => {
afterEach(() => {
jest.restoreAllMocks();
jest.resetAllMocks();
});
it('mocks API call', async () => {
const token = 'JWT1111';
mLocalStorage.setItem('token', token);
const response = { data: { name: 'mocked name' } };
jest.spyOn(axios, 'get').mockResolvedValueOnce(response);
const wrapper = mount(<OrganizationDocs />);
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
expect(wrapper.find('.org-docs-header').text()).toContain('mocked name');
expect(axios.get).toBeCalledWith('organizations/organizations/', {
headers: { Authorization: 'JWT ' + token },
});
});
});
带有覆盖率报告的单元测试结果:
PASS src/stackoverflow/59379085/index.spec.tsx (9.958s)
MyComponent
✓ mocks API call (85ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 78.95 | 0 | 80 | 76.47 | |
index.tsx | 78.95 | 0 | 80 | 76.47 | 23,24,25,26 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 11.427s
源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59379085