我使用Jest手动模拟功能嘲笑了我编写的自定义XHR包装器( utils / xhr.js ),我遇到的问题是仅跟踪第一个XHR呼叫:
let xhr = {
get: function(params) { /* XHR get implementation */ }
post: function(params) { /* XHR post implementation */ }
};
export default xhr;
let xhr = jest.genMockFromModule('./../xhr');
module.exports = xhr;
// ...
getTrendingEntities: (days, maxItems) => {
return xhr.get({url: '/api/aggregator/riskEntities/' + days + '/' + maxItems})
.then((response) => {
companyIds = parseCompanies(response.body);
return xhr.post({
url: '/api/entities/specific-companies',
data: companyIds
});
}).then((response) => {
let companies = parseCompaniesData(response.body);
return Promise.resolve(companies);
});
}
// ...
class TrendingEntitiesPod extends React.Component {
// ...
componentWillMount() {
this.loadData(this.props.days)
}
componentWillReceiveProps(nextProps) {
if (this.props.days != nextProps.days) {
this.loadData(nextProps.days);
}
}
loadData(days) {
this.setState({loading: true});
api.getTrendingEntities(days, DASHBOARD_PODS_ENTRIES_NUMBER)
.then((companies) => {
this.setState({
companies: companies,
loading: false
});
});
}
render() { // ... }
}
import React from 'react';
import { mount } from 'enzyme';
import xhr from './../../../utils/xhr';
jest.mock('./../../../utils/xhr');
import TrendingEntitiesPod from './../Dashboard/components/TrendingEntitiesPod/TrendingEntitiesPod.jsx';
describe('StartPage.TrendingEntitiesPod:', () => {
let wrapper = null;
beforeAll(() => {
xhr.get.mockReturnValueOnce(Promise.resolve({body: trendingEntities}));
xhr.post.mockReturnValueOnce(Promise.resolve({body: trendingEntitiesData}));
xhr.get.mockReturnValue(Promise.resolve({body: trendingEntityPestleData}));
wrapper = mount(<TrendingEntitiesPod days={30} />);
});
test('...stubbing works', () => {
expect(xhr.get.mock.calls.length).toBe(1);
expect(xhr.post.mock.calls.length).toBe(1); // returns false - why??
});
});
答案 0 :(得分:0)
似乎在Enzyme中安装了一个执行多个AJAX调用和多个状态更改的组件,在组件的第一个生命周期阶段,会使单元测试先运行,然后反映状态更改。
这是由于AJAX和setState()调用的异步性质。
我找到的修复是在 beforeAll 块中添加完成回调,该回调在 setTimeout(已完成,0)结束:
beforeAll((done) => {
xhr.get.mockReturnValueOnce(Promise.resolve({body: trendingEntities}));
xhr.post.mockReturnValueOnce(Promise.resolve({body: trendingEntitiesData}));
xhr.get.mockReturnValue(Promise.resolve({body: trendingEntityPestleData}));
wrapper = mount(<TrendingEntitiesPod days={30} />);
// Delay the execution of tests, at the end, after the component
// has been mounted, all XHR, setState and render calls are done.
setTimeout(done, 0);
});
答案 1 :(得分:0)
另一种处理这个问题的方法,因为似乎Jest在执行setTimeout()时不能很好地发挥作用,就是在所有初始请求完成后不测试组件的状态。您可以测试执行XHR请求的各个方法(以及数据解析逻辑/组件状态更改)。 E.g:
class AirlineCompanies extends React.Component {
// ...
loadData(numberOfCompanies) {
this.setState({loading: true});
return api.getAirlineCompanies(numberOfCompanies)
.then((companies) => {
this.setState({
companies: companies,
loading: false
});
})
.catch((error) => {
utils.logError(error, 'AirlineCompanies.loadData():');
this.setState({loading: false});
});
}
// ...
}
let component = mount(<AirlineCompanies />).instance();
let airlineCompaniesData = [ /*... mock companies data ...*/ ];
it('...should have the state changed and eight AirlineCompany components after data is loaded', (done) => {
xhr.get.mockReturnValueOnce(Promise.resolve({body: airlineCompaniesData}));
component.loadData(30).then(() => {
expect(wrapper.state('companies')).toEqual(airlineCompaniesData);
expect(wrapper.find(AirlineCompany).length).toBe(8);
done();
});
});