如何通过Jest正确使用Promises和Timer

我同时搜索了SO和Google,发现了很多类似的问题和答案,但是似乎没有一个问题可以帮助我解决问题。

我正在尝试编写一些需要模拟异步轮询功能的测试用例。但是无论我做什么我都会得到:

在jest.setTimeout.Timeout

指定的5000ms超时内未调用异步回调

我设置了一些最小的测试案例来重现问题:

jest.useFakeTimers();

describe('timers test',() => {
  it('plain timer works as expected',() => {
    const mock = jest.fn();
    setTimeout(mock,5000);

    jest.runAllTimers();
    expect(mock).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolution results in a jest timeout error',async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve) => setTimeout(resolve,500));
    });

    const handler = jest.fn();

    await mock().then(handler);

    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise rejection results in a jest timeout error',async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve,reject) => setTimeout(reject,500));
    });

    const handler = jest.fn();

    await mock().catch(handler);

    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });
});

有人可以解释我在做什么错以及为什么吗?

xgxiong119 回答:如何通过Jest正确使用Promises和Timer

因此,在@Bergi的后续评论中,我认为done也不是必需的。我只需要重新订购一些东西。然后,当测试承诺链进一步突显了这一点时,我遇到了一个类似的问题,因此我为此添加了一些案例。

jest.useFakeTimers();

describe('timers test',() => {
  it('Using a plain timer works as expected',() => {
    const mock = jest.fn();
    setTimeout(mock,5000);

    jest.runAllTimers();
    expect(mock).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolution',async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve) => setTimeout(resolve,500));
    });

    const handler = jest.fn();

    const actual = mock().then(handler);
    jest.runAllTimers();
    await actual;

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise rejection',async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve,reject) => setTimeout(reject,500));
    });

    const handler = jest.fn();

    const actual = mock().catch(handler);
    jest.runAllTimers();
    await actual;

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolve -> delay -> resolve chain',async () => {
    const mockA = jest.fn(() => {
      return Promise.resolve();
    });

    const mockB = jest.fn(() => {
      return new Promise((resolve,reject) => {
        setTimeout(resolve,500);
      });
    });

    const handler = jest.fn();

    const actual = mockA()
      .then(() => {
        const mockProm = mockB();
        jest.runAllTimers();
        return mockProm;
      })
      .then(handler);

    jest.runAllTimers();
    await actual;

    expect(mockA).toHaveBeenCalled();
    expect(mockB).toHaveBeenCalled();
    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolve -> delay -> reject chain',reject) => {
        setTimeout(reject,500);
      });
    });

    const handler = jest.fn();

    const actual = mockA()
      .then(() => {
        const mockProm = mockB();
        jest.runAllTimers();
        return mockProm;
      })
      .catch(handler);


    await actual;

    expect(mockA).toHaveBeenCalled();
    expect(mockB).toHaveBeenCalled();
    expect(handler).toHaveBeenCalled();
  });
});

@Bergi的评论使我找到了解决方案。我最终使用了done函数,并删除了await。这似乎至少在此最小测试用例中有效。

jest.useFakeTimers();

describe('timers test',() => {
  it('plain timer works as expected',5000);

    jest.runAllTimers();
    expect(mock).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolution results in a jest timeout error',async (done) => {
    const mock = jest.fn().mockImplementation(() => {
      return new Promise((resolve) => setTimeout(resolve,500));
    });

    // make the handler invoke done to replace the await    
    const handler = jest.fn(done);

    mock().then(handler);
    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise rejection results in a jest timeout error',async (done) => {
    const mock = jest.fn().mockImplementation(() => {
      return new Promise((resolve,500));
    });

    // make the handler invoke done to replace the await
    const handler = jest.fn(done);

    mock().catch(handler);
    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });
});
本文链接:https://www.f2er.com/2654591.html

大家都在问