【问题标题】:Jest manual mocking works only for the first function callJest 手动模拟仅适用于第一个函数调用
【发布时间】:2017-07-03 13:18:36
【问题描述】:

我已经使用 Jest 手动模拟功能模拟了我编写的自定义 XHR 包装器 (utils/xhr.js),我遇到的问题是 只有跟踪第一个 XHR 调用

utils/xhr.js

let xhr = {
    get: function(params) { /* XHR get implementation */ }
    post: function(params) { /* XHR post implementation */ }
};

export default xhr;

utils/__mocks__/xhr.js - 模拟实现

let xhr = jest.genMockFromModule('./../xhr');

module.exports = xhr;

Dashboard.api.js - 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);
        });
}

// ...

TrendingEntitiesPod.jsx - 使用 Dashboard.api.js 的 React 组件

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() { // ... }

}

StartPage.TrendingEntitiesPod.spec.js - 测试文件

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??
    });

});

【问题讨论】:

    标签: javascript reactjs mocking jestjs


    【解决方案1】:

    似乎在组件的第一个生命周期阶段,使用 Enzyme 安装执行多个 AJAX 调用和多个状态更改的组件,使单元测试首先运行,然后反映状态更改。

    这是由于 AJAX 和 setState() 调用的异步特性造成的。

    我找到的解决方法是在 beforeAll 块中添加一个 done 回调,该回调在 setTimeout(done, 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);
    });
    

    【讨论】:

      【解决方案2】:

      处理这个问题的另一种方法是,在所有初始请求都完成后,不测试组件的状态,因为 Jest 似乎在执行 setTimeout() 时表现不佳。您可以测试执行 XHR 请求(以及数据解析逻辑/组件状态更改)的各个方法。例如:

      AirlineCompanies.jsx

      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});
              });
          }
      
          // ...
      
      }
      

      AirlineCompanies.spec.js

      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();
          });
      
      });
      

      【讨论】:

        猜你喜欢
        • 2018-09-16
        • 1970-01-01
        • 1970-01-01
        • 2020-12-31
        • 2019-06-09
        • 2020-02-26
        • 2015-04-22
        • 1970-01-01
        相关资源
        最近更新 更多