繁体   English   中英

Promise 解决后如何正确测试 setTimeout

[英]How properly test setTimeout after Promise resolve

如何正确测试此功能。

  1. 设置超时
  2. 超时后回调
  3. 和递归调用
export function initScheduler(timeout: number, callback: () => Promise<void>): void {
  setTimeout(() => {
    callback().then(() => {
      initScheduler(timeout, callback);
    });
  }, timeout);
}

我试过类似的东西

describe('initScheduler', () => {
  it('should call on schedule', () => {
    jest.useFakeTimers();

    const timeout: number = 60000;
    const callback: jest.Mock = jest.fn().mockResolvedValue(undefined);

    initScheduler(timeout, callback);

    expect(setTimeout).toHaveBeenCalledTimes(1);
    expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), timeout);
    expect(callback).not.toBeCalled();

    jest.advanceTimersByTime(timeout);

    expect(callback).toBeCalled();
    expect(setTimeout).toHaveBeenCalledTimes(2);
  });
});

但最后的期望返回 1

不要专注于对setTimeout断言。 专注于您的功能应该做什么。

describe('', () => {
  jest.useFakeTimers();
  const timeout = 300;
  const callback = jest.fn();

  beforeEach(() => {
    jest.clearAllTimers();
    callback
      .mockClear()
      .mockReturnValue(Promise.resolve()); 
  });

  it('runs callback only after delay given', () => {
    initScheduler(timeout, callback);
    jest.advanceTimersByTime(timeout - 1);
    expect(callback).not.toHaveBeenCalled();
    jest.advanceTimersByTime(2);
    expect(callback).toHaveBeenCalledTimes(1);
  });

  it('reruns scheduler if callback been resolved successfully', async () => {
    initScheduler(timeout, callback);
    expect(callback).not.toHaveBeenCalled();
    jest.advanceTimersByTime(timeout);
    await Promise.resolve();
    jest.advanceTimersByTime(timeout);
    await Promise.resolve();
    jest.advanceTimersByTime(timeout);
    await Promise.resolve();
    expect(callback).toHaveBeenCalledTimes(3);
  });

  it('stops scheduler if callback rejected', async () => {
    callback.mockReturnValue(Promise.reject());
    initScheduler(timeout, callback);
    jest.advanceTimersByTime(timeout);
    await Promise.resolve();
    jest.advanceTimersByTime(timeout);
    await Promise.resolve();
    expect(callback).toHaveBeenCalledTimes(1);
  });
});

一些细节。

  1. 我很惊讶,但是如果没有jest.clearAllTimers()it()之间的计时器不会被清除。 可能,这取决于jsdom实现或jest版本,我不知道。
  2. 没有await Promise.resolve()你的callback模拟不会运行.then部分。 实际上它可能是await <anything else> ,我只看到await Promise.resolve(); 看起来不像await 42;那样神奇await 42; . 无论如何,它的目的是刷新微任务队列,而 jest 本身并没有提供直接的 API。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM