解释 "jest.advanceTimersToNextTimer "

Explain "jest.advanceTimersToNextTimer "

我正在开玩笑地学习测试,我想出了这个方法:jest.advanceTimersToNextTimer。 Jest 的手册说:

Advances all timers by the needed milliseconds so that only the next timeouts/intervals will run. Optionally, you can provide steps, so it will run steps amount of next timeouts/intervals.

但我不清楚它是如何工作的。有人可以解释一下它的作用,并举例说明它的用法吗?谢谢。

使用 jest.advanceTimersToNextTimer(steps) 时,您无需再手动向 运行 提供毫秒数 macro-tasks 已通过 setTimeout() 或 [=13= 排队].就像医生说的:

Advances all timers by the needed milliseconds so that only the next timeouts/intervals will run.

此外,您可以提供一个stepsjest.advanceTimersToNextTimer()的方法,这样它将运行 steps下一个timeouts/intervals的数量。请参阅 "should pass with steps" 测试用例。默认的steps1,见here

当使用jest.advanceTimersByTime()时,如果有很多macro-tasks通过setTimeout()setInterval()排队,如果我们要提前所有计时器,我们必须计算msToRun 毫秒。这可能非常麻烦。请参阅 "should pass advance all timers" 测试用例。

此外,有时您可能希望在计时器执行前检查状态。在这种情况下,你必须使用jest.advanceTimersByTime(),看到这个real world example,定时器是200毫秒,但是他们在199毫秒检查快进状态。

jest.advanceTimersToNextTimer() 使用底层 @sinonjs/faker-timers 包的 click.next() 方法。

Advances the clock to the the moment of the first scheduled timer, firing it.

jest.advanceTimersByTime() just use clock.tick(time)在下。

看下面的例子,三个测试用例以不同的方式做同样的事情。

describe('71667406', () => {
  beforeAll(() => {
    jest.useFakeTimers();
  });
  afterAll(() => {
    jest.useRealTimers();
  });
  describe('advanceTimersToNextTimer', () => {
    test('should pass', () => {
      const runOrder: Array<string> = [];
      const mock1 = jest.fn(() => runOrder.push('mock1'));
      const mock2 = jest.fn(() => runOrder.push('mock2'));
      const mock3 = jest.fn(() => runOrder.push('mock3'));
      const mock4 = jest.fn(() => runOrder.push('mock4'));

      setTimeout(mock1, 100);
      setTimeout(mock2, 0);
      setTimeout(mock3, 0);
      setInterval(() => {
        mock4();
      }, 200);

      jest.advanceTimersToNextTimer();
      // Move forward to t=0
      expect(runOrder).toEqual(['mock2', 'mock3']);

      jest.advanceTimersToNextTimer();
      // Move forward to t=100
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1']);

      jest.advanceTimersToNextTimer();
      // Move forward to t=200
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1', 'mock4']);

      jest.advanceTimersToNextTimer();
      // Move forward to t=400
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1', 'mock4', 'mock4']);
    });

    test('should pass with steps', () => {
      const runOrder: Array<string> = [];
      const mock1 = jest.fn(() => runOrder.push('mock1'));
      const mock2 = jest.fn(() => runOrder.push('mock2'));
      const mock3 = jest.fn(() => runOrder.push('mock3'));
      const mock4 = jest.fn(() => runOrder.push('mock4'));

      setTimeout(mock1, 100);
      setTimeout(mock2, 0);
      setTimeout(mock3, 0);
      setInterval(() => {
        mock4();
      }, 200);

      jest.advanceTimersToNextTimer(4);
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1', 'mock4', 'mock4']);
    });
  });

  describe('advanceTimersByTime', () => {
    test('should pass', () => {
      const runOrder: Array<string> = [];
      const mock1 = jest.fn(() => runOrder.push('mock1'));
      const mock2 = jest.fn(() => runOrder.push('mock2'));
      const mock3 = jest.fn(() => runOrder.push('mock3'));
      const mock4 = jest.fn(() => runOrder.push('mock4'));

      setTimeout(mock1, 100);
      setTimeout(mock2, 0);
      setTimeout(mock3, 0);
      setInterval(() => {
        mock4();
      }, 200);

      jest.advanceTimersByTime(0);
      // Move forward to t=0
      expect(runOrder).toEqual(['mock2', 'mock3']);

      jest.advanceTimersByTime(100);
      // Move forward to t=100
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1']);

      jest.advanceTimersByTime(200);
      // Move forward to t=200
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1', 'mock4']);

      jest.advanceTimersByTime(200);
      // Move forward to t=400
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1', 'mock4', 'mock4']);
    });

    test('should pass advance all timers', () => {
      const runOrder: Array<string> = [];
      const mock1 = jest.fn(() => runOrder.push('mock1'));
      const mock2 = jest.fn(() => runOrder.push('mock2'));
      const mock3 = jest.fn(() => runOrder.push('mock3'));
      const mock4 = jest.fn(() => runOrder.push('mock4'));

      setTimeout(mock1, 100);
      setTimeout(mock2, 0);
      setTimeout(mock3, 0);
      setInterval(() => {
        mock4();
      }, 200);

      // We need to calculate it, this is very cumbersome
      jest.advanceTimersByTime(0 + 100 + 200 + 200);
      expect(runOrder).toEqual(['mock2', 'mock3', 'mock1', 'mock4', 'mock4']);
    });
  });
});

测试结果:

 PASS  Whosebug/71667406/index.test.ts
  71667406
    advanceTimersToNextTimer
      ✓ should pass (4 ms)
      ✓ should pass with steps
    advanceTimersByTime
      ✓ should pass (1 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        1.242 s

也希望Jest官方能多举例说明API.

的使用场景