【问题标题】:Jest test promise resolution and event loop tick开玩笑测试承诺解决和事件循环滴答声
【发布时间】:2018-08-30 12:20:32
【问题描述】:

我有一个失败的 Jest 测试用例,用于我使用 Promise 的代码。看起来,在测试完成后,promise 的解析正在发生,这意味着我无法检查我的 promise 解析代码是否已被执行。

感觉我需要让事件循环打勾,以便解决承诺并执行解决代码,但在 Jest 中没有找到任何可以做到这一点的东西。

这是一个示例案例。待测代码:

const Client = require('SomeClient');

module.exports.init = () => {
  Client.load().then(() => {
    console.log('load resolved');

    setTimeout(() => {
      console.log('load setTimeout fired, retrying init');
      module.exports.init();
    }, 1000);
  });
};

测试代码:

jest.useFakeTimers();

const mockLoad = jest.fn().mockImplementation(() => Promise.resolve());

jest.mock('SomeClient', () => {
  return {
    load: mockLoad
  };
}, { virtual: true });

const promiseTest = require('./PromiseTest');

describe('SomeClient Promise Test', () => {
  it('retries init after 10 secs', () => {
    promiseTest.init();

    expect(mockLoad).toHaveBeenCalledTimes(1);
    expect(setTimeout).toHaveBeenCalledTimes(1); // <-- FAILS - setTimeout has not been called

    jest.runAllTimers();

    expect(mockLoad).toHaveBeenCalledTimes(2);
  });
});

expect(setTimeout).toHaveBeenCalledTimes(1); 断言失败(setTimeout 根本没有被调用),我认为是因为 promise 尚未解决。

我在这里做错了吗?我可以让事件循环在测试中打勾吗?

【问题讨论】:

    标签: javascript node.js promise jestjs


    【解决方案1】:

    要勾选测试中的事件循环,您应该使其异步。 在GitHub 上提出了一个很好的解决方法。

    按照那里的建议拥有flushPromises

    function flushPromises() {
      return new Promise(resolve => setImmediate(resolve));
    }
    

    你的测试看起来像

    describe('SomeClient Promise Test', () => {
      it('retries init after 10 secs', () => {
        promiseTest.init();
        expect(mockLoad).toHaveBeenCalledTimes(1);
        
        // notice return so jest knows that the test is asynchronous
        return flushPromises()
          .then(() => {
            expect(setTimeout).toHaveBeenCalledTimes(1);
    
            jest.runAllTimers();
    
            expect(mockLoad).toHaveBeenCalledTimes(2);
          });
       });
    });
    

    或者同样使用async/await:

    describe('SomeClient Promise Test', () => {
      it('retries init after 10 secs', async () => {
        promiseTest.init();
        expect(mockLoad).toHaveBeenCalledTimes(1);
    
        await flushPromises();
        expect(setTimeout).toHaveBeenCalledTimes(1);
    
        jest.runAllTimers();
    
        expect(mockLoad).toHaveBeenCalledTimes(2);
      });
    });
    

    【讨论】:

    • 太棒了!在我的 React + Mobx 设置中也能很好地工作。
    猜你喜欢
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    • 1970-01-01
    • 2021-01-10
    • 2019-05-07
    • 2019-09-15
    • 1970-01-01
    相关资源
    最近更新 更多