javascript - 解释 "jest.advanceTimersToNextTimer "

标签 javascript jestjs mocking

我正在学习用 jest 进行测试,我想出了这个方法: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) ,您不再需要手动提供毫秒来运行已通过 setTimeout()setInterval() 排队的宏任务。正如医生所说:

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

此外,您可以为 jest.advanceTimersToNextTimer() 方法提供 steps ,以便它将运行 steps 下一个超时/间隔时间。请参阅“应按步骤通过” 测试用例。默认步骤1,请参阅here

使用jest.advanceTimersByTime()时,如果有大量宏任务通过setTimeout()setInterval()排队,如果我们想要提前所有计时器,我们必须自己计算 msToRun 毫秒。这也许是非常麻烦的。请参阅“应通过提前所有计时器”测试用例。

此外,有时您可能想在计时器执行之前检查状态。在这种情况下,您必须使用 jest.advanceTimersByTime(),请参阅此 real world example ,定时器是200毫秒,但他们在199毫秒内检查快进的状态。

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

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

jest.advanceTimersByTime()只需使用 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  stackoverflow/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的使用场景。

关于javascript - 解释 "jest.advanceTimersToNextTimer ",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71667406/

相关文章:

javascript - Canvas 清除未编程的矩形

javascript - Mongodb 与和尚 : error catching and handling if db is down

javascript - 如何让两个不相关的 React 组件一起工作?

reactjs - Jest——编写测试描述的正确方法

python - 测试 Django 国际化 - 模拟 gettext

当用户在控制台中键入 quit 时用于退出程序的 Java 编写单元测试

javascript - 错误: function is not defined when calling a function returned by another function

unit-testing - 在Jest中进行每次测试之前运行全局测试设置

javascript - aws-sdk-mock 模拟 s3.putBucketPolicy 不起作用

java - DoReturn 抛出 UnfinishedStubbingException