我如何用玩笑测试承诺延迟?

Aja*_*esh 2 javascript ecmascript-6 es6-promise jestjs babel-jest

这是我用来延迟进程的代码(用于退避)

export function promiseDelay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
Run Code Online (Sandbox Code Playgroud)

我想测试它,但我不能。我尝试使用 fakeTimers 但我的测试从未结束。

test('promiseDelay delays for 1s', async (done) => {
    jest.useFakeTimers();
    Promise.resolve().then(() => jest.advanceTimersByTime(100));
    await promiseDelay(100);
  });
Run Code Online (Sandbox Code Playgroud)

Bri*_*ams 13

promiseDelay返回Promise解析后,ms所以叫spythen和测试,看是否spy已经被不同的时间间隔之后调用:

describe('promiseDelay', () => {

  beforeEach(() => { jest.useFakeTimers(); });
  afterEach(() => { jest.useRealTimers(); });

  test('should not resolve until timeout has elapsed', async () => {
    const spy = jest.fn();
    promiseDelay(100).then(spy);  // <= resolve after 100ms

    jest.advanceTimersByTime(20);  // <= advance less than 100ms
    await Promise.resolve();  // let any pending callbacks in PromiseJobs run
    expect(spy).not.toHaveBeenCalled();  // SUCCESS

    jest.advanceTimersByTime(80);  // <= advance the rest of the time
    await Promise.resolve();  // let any pending callbacks in PromiseJobs run
    expect(spy).toHaveBeenCalled();  // SUCCESS
  });

});
Run Code Online (Sandbox Code Playgroud)

请注意,测试代码是同步的,并且Timer Mocks使setTimeout同步但then 将回调PromiseJobs排队因此如果spy已调用,则需要允许任何排队的回调在测试之前运行。

这可以通过使用async测试函数并调用await已解决的方法来完成,该函数在测试继续之前允许任何挂起的回调运行Promise结束时有效地将测试的其余部分排队PromiseJobs

此处的回答中提供了有关 promise 和假计时器如何交互的其他信息。