【问题标题】:When I run tests on this componentDidMount in react, apparently several lines are not covered?当我在 react 中对此 componentDidMount 运行测试时,显然有几行没有被覆盖?
【发布时间】:2019-02-27 03:49:13
【问题描述】:

我正在尝试使用 jest 来测试我的 componentDidMount 方法:

componentDidMount() {
    agent.Gatherings.getAll().then((result) => {
        this.setState({ gatherings: result }) //no code coverage
    }).catch((err) => {
        this.setState({ gatherings: [] }) //no code coverage
    })
}

但我的其他测试之一工作正常:

  it('test gathering List is rendered', () => {
    wrapper.setState({ gatherings: [TestGathering] })
    expect(wrapper.find('MyList').length).toEqual(1);
  });

我希望在我的测试中涵盖每一行。如何让我的 componentDidMount() 中的行 all 被开玩笑地测试?

更新,我将一个文件直接导入到测试文件中。我要导入的文件名为 agent.js。被遗漏的函数调用的代码是:

agent.js

export const requests = {
    get: url => fetch(url).then(res => res.json()),
    post: (url, body) =>
        fetch(url, {
            method: 'POST',
            body: body,
            headers: {
                'Content-Type': 'application/json'
            }
        }).then(res => res.json()) //also this line lacks coverage
}

export const Gatherings = {
    getAll: () =>
        requests.get(API_ROOT + '/gatherings')  
}
export default {
    Gatherings
}

【问题讨论】:

    标签: reactjs unit-testing react-native jestjs


    【解决方案1】:

    问题

    必须在运行测试时运行一行代码才能包含在Jest 代码覆盖范围内。


    详情

    没有覆盖的两行是agent.Gatherings.getAll返回的Promise的回调。

    Promise 回调被添加到PromiseJobs queue 并在当前消息完成之后和下一条消息运行之前运行

    这就是为什么这些行当前不包含在代码覆盖范围内...现在它们直到同步测试完成后才会运行


    解决方案

    您只需要确保在测试运行时这两行运行


    详情

    理想的方法是await the Promise directly in your test

    在这种情况下,Promise 在测试中不容易访问,因此需要不同的方法。

    解决方法

    如果 agent.Gatherings.getAll 被模拟为立即解决或拒绝,则在组件完成渲染时,Promise 回调将在 PromiseJobs 中排队。

    要让Promise 回调运行,请使用async 测试函数并调用await Promise.resolve();,它实质上在PromiseJobs 结束时将剩余的测试排入队列,并让所有待处理的作业首先运行:

    import * as React from 'react';
    import { shallow } from 'enzyme';
    
    import { Comp } from './code';  // <= import your component here
    import * as agent from './agent';
    
    describe('Component', () => {
    
      let spy;
    
      beforeEach(() => {
        spy = jest.spyOn(agent.Gatherings, 'getAll');
      })
    
      afterEach(() => {
        spy.mockRestore();
      })
    
      it('updates when agent.Gatherings.getAll() resolves', async () => {  // use an async test function
        const response = [ 'gathering 1', 'gathering 2', 'gathering 3' ];
        spy.mockResolvedValue(response);
        const wrapper = shallow(<Comp />);  // render your component
        await Promise.resolve();  // let the callback queued in PromiseJobs run
        expect(wrapper.state()).toEqual({ gatherings: response });  // SUCCESS
      });
    
      it('handles when agent.Gatherings.getAll() rejects', async () => {  // use an async test function
        spy.mockRejectedValue(new Error());
        const wrapper = shallow(<Comp />);  // render your component
        await Promise.resolve();  // let the callback queued in PromiseJobs run
        expect(wrapper.state()).toEqual({ gatherings: [] });  // SUCCESS
      });
    });
    

    您现在应该对componentDidMount 中的Promise 回调有代码覆盖率。

    【讨论】:

    • 测试的其余部分看起来如何?嘲讽?
    • 如何模拟 agent.Gatherings.getAll ?我尝试将其设置为等于jest.fn().mockReturnValueOnce,但它不起作用
    • @user11039951 如果添加代码,显示如何将agent 导入组件模块、定义agent 的模块,以及如何在测试中导入和呈现组件我会用更详细的解决方案更新我的答案。
    • 所以资产也进入setTimeout,最后看起来像it('...', done =&gt; { expect.assertions(1); const wrapper = ...; setTimeout(() =&gt; { expect(wrapper.find('MyList')).toHaveLength(1); done();}, 0);})。对吗?
    • @brian-lives-outdoors 我的帖子已更新。请回复,谢谢!
    猜你喜欢
    • 2016-01-27
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    • 1970-01-01
    • 2021-05-02
    • 1970-01-01
    • 2014-05-31
    相关资源
    最近更新 更多