日期


【Dates】

模拟计时器 API 还允许对 Date 对象进行模拟。这是一个用于测试依赖时间功能或模拟内部日历函数(如 Date.now())的有用功能。

【The mock timers API also allows the mocking of the Date object. This is a useful feature for testing time-dependent functionality, or to simulate internal calendar functions such as Date.now().】

日期的实现也是 MockTimers 类的一部分。有关方法和功能的完整列表,请参阅它。

【The dates implementation is also part of the MockTimers class. Refer to it for a full list of methods and features.】

注意: 当同时模拟日期和定时器时,它们是相互依赖的。这意味着如果你同时模拟了 DatesetTimeout,时间的推进也会同时推进模拟的日期,因为它们模拟的是同一个内部时钟。

下面的示例展示了如何模拟 Date 对象并获取当前的 Date.now() 值。

【The example below show how to mock the Date object and obtain the current Date.now() value.】

import assert from 'node:assert';
import { test } from 'node:test';

test('mocks the Date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'] });
  // If not specified, the initial date will be based on 0 in the UNIX epoch
  assert.strictEqual(Date.now(), 0);

  // Advance in time will also advance the date
  context.mock.timers.tick(9999);
  assert.strictEqual(Date.now(), 9999);
});const assert = require('node:assert');
const { test } = require('node:test');

test('mocks the Date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'] });
  // If not specified, the initial date will be based on 0 in the UNIX epoch
  assert.strictEqual(Date.now(), 0);

  // Advance in time will also advance the date
  context.mock.timers.tick(9999);
  assert.strictEqual(Date.now(), 9999);
});

如果没有设置初始纪元,初始日期将基于 Unix 纪元中的 0。即 1970 年 1 月 1 日 00:00:00 UTC。你可以通过向 .enable() 方法传递 now 属性来设置初始日期。此值将用作模拟 Date 对象的初始日期。它可以是正整数,也可以是另一个 Date 对象。

【If there is no initial epoch set, the initial date will be based on 0 in the Unix epoch. This is January 1st, 1970, 00:00:00 UTC. You can set an initial date by passing a now property to the .enable() method. This value will be used as the initial date for the mocked Date object. It can either be a positive integer, or another Date object.】

import assert from 'node:assert';
import { test } from 'node:test';

test('mocks the Date object with initial time', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 300);
});const assert = require('node:assert');
const { test } = require('node:test');

test('mocks the Date object with initial time', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 300);
});

你可以使用 .setTime() 方法手动将模拟的日期移动到另一个时间。此方法只接受正整数。

【You can use the .setTime() method to manually move the mocked date to another time. This method only accepts a positive integer.】

注意: 该方法会执行从新时间开始已经过去的所有模拟计时器。

在下面的示例中,我们为模拟日期设置新时间。

【In the below example we are setting a new time for the mocked date.】

import assert from 'node:assert';
import { test } from 'node:test';

test('sets the time of a date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.setTime(1000);
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 1200);
});const assert = require('node:assert');
const { test } = require('node:test');

test('sets the time of a date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.setTime(1000);
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 1200);
});

如果你有任何设置为在过去运行的计时器,它将被执行,就好像调用了 .tick() 方法一样。如果你想测试已经发生的依赖时间的功能,这非常有用。

【If you have any timer that's set to run in the past, it will be executed as if the .tick() method has been called. This is useful if you want to test time-dependent functionality that's already in the past.】

import assert from 'node:assert';
import { test } from 'node:test';

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);

  context.mock.timers.setTime(800);
  // Timer is not executed as the time is not yet reached
  assert.strictEqual(fn.mock.callCount(), 0);
  assert.strictEqual(Date.now(), 800);

  context.mock.timers.setTime(1200);
  // Timer is executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 1);
  assert.strictEqual(Date.now(), 1200);
});const assert = require('node:assert');
const { test } = require('node:test');

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);

  context.mock.timers.setTime(800);
  // Timer is not executed as the time is not yet reached
  assert.strictEqual(fn.mock.callCount(), 0);
  assert.strictEqual(Date.now(), 800);

  context.mock.timers.setTime(1200);
  // Timer is executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 1);
  assert.strictEqual(Date.now(), 1200);
});

使用 .runAll() 将会执行当前队列中的所有定时器。这也会将模拟的日期推进到最后执行的定时器的时间,就好像时间已经过去了一样。

【Using .runAll() will execute all timers that are currently in the queue. This will also advance the mocked date to the time of the last timer that was executed as if the time has passed.】

import assert from 'node:assert';
import { test } from 'node:test';

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);
  setTimeout(fn, 2000);
  setTimeout(fn, 3000);

  context.mock.timers.runAll();
  // All timers are executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 3);
  assert.strictEqual(Date.now(), 3000);
});const assert = require('node:assert');
const { test } = require('node:test');

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);
  setTimeout(fn, 2000);
  setTimeout(fn, 3000);

  context.mock.timers.runAll();
  // All timers are executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 3);
  assert.strictEqual(Date.now(), 3000);
});