From 6dea41d2f7073f110486beb0dc7d793cdcf59160 Mon Sep 17 00:00:00 2001 From: Julian Gassner Date: Wed, 30 Oct 2024 03:10:30 +0100 Subject: [PATCH] test: split up test-runner-mock-timers test PR-URL: https://github.com/nodejs/node/pull/55506 Reviewed-By: Erick Wendel Reviewed-By: Chemi Atlow Reviewed-By: Claudio Wunder --- test/parallel/test-runner-mock-timers-date.js | 120 +++++++++ .../test-runner-mock-timers-scheduler.js | 124 +++++++++ test/parallel/test-runner-mock-timers.js | 240 +----------------- 3 files changed, 248 insertions(+), 236 deletions(-) create mode 100644 test/parallel/test-runner-mock-timers-date.js create mode 100644 test/parallel/test-runner-mock-timers-scheduler.js diff --git a/test/parallel/test-runner-mock-timers-date.js b/test/parallel/test-runner-mock-timers-date.js new file mode 100644 index 00000000000000..ebd1e430be803f --- /dev/null +++ b/test/parallel/test-runner-mock-timers-date.js @@ -0,0 +1,120 @@ +'use strict'; +process.env.NODE_TEST_KNOWN_GLOBALS = 0; +require('../common'); + +const assert = require('node:assert'); +const { it, describe } = require('node:test'); + +describe('Mock Timers Date Test Suite', () => { + it('should return the initial UNIX epoch if not specified', (t) => { + t.mock.timers.enable({ apis: ['Date'] }); + const date = new Date(); + assert.strictEqual(date.getTime(), 0); + assert.strictEqual(Date.now(), 0); + }); + + it('should throw an error if setTime is called without enabling timers', (t) => { + assert.throws( + () => { + t.mock.timers.setTime(100); + }, + { code: 'ERR_INVALID_STATE' } + ); + }); + + it('should throw an error if epoch passed to enable is not valid', (t) => { + assert.throws( + () => { + t.mock.timers.enable({ now: -1 }); + }, + { code: 'ERR_INVALID_ARG_VALUE' } + ); + + assert.throws( + () => { + t.mock.timers.enable({ now: 'string' }); + }, + { code: 'ERR_INVALID_ARG_TYPE' } + ); + + assert.throws( + () => { + t.mock.timers.enable({ now: NaN }); + }, + { code: 'ERR_INVALID_ARG_VALUE' } + ); + }); + + it('should replace the original Date with the mocked one', (t) => { + t.mock.timers.enable({ apis: ['Date'] }); + assert.ok(Date.isMock); + }); + + it('should return the ticked time when calling Date.now after tick', (t) => { + t.mock.timers.enable({ apis: ['Date'] }); + const time = 100; + t.mock.timers.tick(time); + assert.strictEqual(Date.now(), time); + }); + + it('should return the Date as string when calling it as a function', (t) => { + t.mock.timers.enable({ apis: ['Date'] }); + const returned = Date(); + // Matches the format: 'Mon Jan 01 1970 00:00:00' + // We don't care about the date, just the format + assert.ok(/\w{3}\s\w{3}\s\d{1,2}\s\d{2,4}\s\d{1,2}:\d{2}:\d{2}/.test(returned)); + }); + + it('should return the date with different argument calls', (t) => { + t.mock.timers.enable({ apis: ['Date'] }); + assert.strictEqual(new Date(0).getTime(), 0); + assert.strictEqual(new Date(100).getTime(), 100); + assert.strictEqual(new Date('1970-01-01T00:00:00.000Z').getTime(), 0); + assert.strictEqual(new Date(1970, 0).getFullYear(), 1970); + assert.strictEqual(new Date(1970, 0).getMonth(), 0); + assert.strictEqual(new Date(1970, 0, 1).getDate(), 1); + assert.strictEqual(new Date(1970, 0, 1, 11).getHours(), 11); + assert.strictEqual(new Date(1970, 0, 1, 11, 10).getMinutes(), 10); + assert.strictEqual(new Date(1970, 0, 1, 11, 10, 45).getSeconds(), 45); + assert.strictEqual(new Date(1970, 0, 1, 11, 10, 45, 898).getMilliseconds(), 898); + assert.strictEqual(new Date(1970, 0, 1, 11, 10, 45, 898).toDateString(), 'Thu Jan 01 1970'); + }); + + it('should return native code when calling Date.toString', (t) => { + t.mock.timers.enable({ apis: ['Date'] }); + assert.strictEqual(Date.toString(), 'function Date() { [native code] }'); + }); + + it('should start with a custom epoch if the second argument is specified', (t) => { + t.mock.timers.enable({ apis: ['Date'], now: 100 }); + const date1 = new Date(); + assert.strictEqual(date1.getTime(), 100); + + t.mock.timers.reset(); + t.mock.timers.enable({ apis: ['Date'], now: new Date(200) }); + const date2 = new Date(); + assert.strictEqual(date2.getTime(), 200); + }); + + it('should replace epoch if setTime is lesser than now and not tick', (t) => { + t.mock.timers.enable(); + const fn = t.mock.fn(); + const id = setTimeout(fn, 1000); + t.mock.timers.setTime(800); + assert.strictEqual(Date.now(), 800); + t.mock.timers.setTime(500); + assert.strictEqual(Date.now(), 500); + assert.strictEqual(fn.mock.callCount(), 0); + clearTimeout(id); + }); + + it('should not tick time when setTime is called', (t) => { + t.mock.timers.enable(); + const fn = t.mock.fn(); + const id = setTimeout(fn, 1000); + t.mock.timers.setTime(1200); + assert.strictEqual(Date.now(), 1200); + assert.strictEqual(fn.mock.callCount(), 0); + clearTimeout(id); + }); +}); diff --git a/test/parallel/test-runner-mock-timers-scheduler.js b/test/parallel/test-runner-mock-timers-scheduler.js new file mode 100644 index 00000000000000..6a83056e70eda2 --- /dev/null +++ b/test/parallel/test-runner-mock-timers-scheduler.js @@ -0,0 +1,124 @@ +'use strict'; +process.env.NODE_TEST_KNOWN_GLOBALS = 0; +const common = require('../common'); + +const assert = require('node:assert'); +const { it, describe } = require('node:test'); +const nodeTimersPromises = require('node:timers/promises'); + +describe('Mock Timers Scheduler Test Suite', () => { + it('should advance in time and trigger timers when calling the .tick function', (t) => { + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + + const now = Date.now(); + const durationAtMost = 100; + + const p = nodeTimersPromises.scheduler.wait(4000); + t.mock.timers.tick(4000); + + return p.then(common.mustCall((result) => { + assert.strictEqual(result, undefined); + assert.ok( + Date.now() - now < durationAtMost, + `time should be advanced less than the ${durationAtMost}ms` + ); + })); + }); + + it('should advance in time and trigger timers when calling the .tick function multiple times', async (t) => { + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + + const fn = t.mock.fn(); + + nodeTimersPromises.scheduler.wait(9999).then(fn); + + t.mock.timers.tick(8999); + assert.strictEqual(fn.mock.callCount(), 0); + t.mock.timers.tick(500); + + await nodeTimersPromises.setImmediate(); + + assert.strictEqual(fn.mock.callCount(), 0); + t.mock.timers.tick(500); + + await nodeTimersPromises.setImmediate(); + assert.strictEqual(fn.mock.callCount(), 1); + }); + + it('should work with the same params as the original timers/promises/scheduler.wait', async (t) => { + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + const controller = new AbortController(); + const p = nodeTimersPromises.scheduler.wait(2000, { + ref: true, + signal: controller.signal, + }); + + t.mock.timers.tick(1000); + t.mock.timers.tick(500); + t.mock.timers.tick(500); + t.mock.timers.tick(500); + + const result = await p; + assert.strictEqual(result, undefined); + }); + + it('should abort operation if timers/promises/scheduler.wait received an aborted signal', async (t) => { + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + const controller = new AbortController(); + const p = nodeTimersPromises.scheduler.wait(2000, { + ref: true, + signal: controller.signal, + }); + + t.mock.timers.tick(1000); + controller.abort(); + t.mock.timers.tick(500); + t.mock.timers.tick(500); + t.mock.timers.tick(500); + + await assert.rejects(() => p, { + name: 'AbortError', + }); + }); + it('should abort operation even if the .tick was not called', async (t) => { + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + const controller = new AbortController(); + const p = nodeTimersPromises.scheduler.wait(2000, { + ref: true, + signal: controller.signal, + }); + + controller.abort(); + + await assert.rejects(() => p, { + name: 'AbortError', + }); + }); + + it('should abort operation when .abort is called before calling setInterval', async (t) => { + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + const controller = new AbortController(); + controller.abort(); + const p = nodeTimersPromises.scheduler.wait(2000, { + ref: true, + signal: controller.signal, + }); + + await assert.rejects(() => p, { + name: 'AbortError', + }); + }); + + it('should reject given an an invalid signal instance', async (t) => { + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + const p = nodeTimersPromises.scheduler.wait(2000, { + ref: true, + signal: {}, + }); + + await assert.rejects(() => p, { + name: 'TypeError', + code: 'ERR_INVALID_ARG_TYPE', + }); + }); +}); diff --git a/test/parallel/test-runner-mock-timers.js b/test/parallel/test-runner-mock-timers.js index e438b2636b832a..87b8ba7e3784d2 100644 --- a/test/parallel/test-runner-mock-timers.js +++ b/test/parallel/test-runner-mock-timers.js @@ -1,3 +1,4 @@ +// Flags: --expose-internals 'use strict'; process.env.NODE_TEST_KNOWN_GLOBALS = 0; const common = require('../common'); @@ -6,6 +7,7 @@ const assert = require('node:assert'); const { it, mock, describe } = require('node:test'); const nodeTimers = require('node:timers'); const nodeTimersPromises = require('node:timers/promises'); +const { TIMEOUT_MAX } = require('internal/timers'); describe('Mock Timers Test Suite', () => { describe('MockTimers API', () => { @@ -252,10 +254,10 @@ describe('Mock Timers Test Suite', () => { }), timeout); }); - it('should change timeout to 1ms when it is >= 2 ** 31', (t) => { + it('should change timeout to 1ms when it is > TIMEOUT_MAX', (t) => { t.mock.timers.enable({ apis: ['setTimeout'] }); const fn = t.mock.fn(); - global.setTimeout(fn, 2 ** 31); + global.setTimeout(fn, TIMEOUT_MAX + 1); t.mock.timers.tick(1); assert.strictEqual(fn.mock.callCount(), 1); }); @@ -791,240 +793,6 @@ describe('Mock Timers Test Suite', () => { }); }); - describe('scheduler Suite', () => { - describe('scheduler.wait', () => { - it('should advance in time and trigger timers when calling the .tick function', (t) => { - t.mock.timers.enable({ apis: ['scheduler.wait'] }); - - const now = Date.now(); - const durationAtMost = 100; - - const p = nodeTimersPromises.scheduler.wait(4000); - t.mock.timers.tick(4000); - - return p.then(common.mustCall((result) => { - assert.strictEqual(result, undefined); - assert.ok( - Date.now() - now < durationAtMost, - `time should be advanced less than the ${durationAtMost}ms` - ); - })); - }); - - it('should advance in time and trigger timers when calling the .tick function multiple times', async (t) => { - t.mock.timers.enable({ apis: ['scheduler.wait'] }); - - const fn = t.mock.fn(); - - nodeTimersPromises.scheduler.wait(9999).then(fn); - - t.mock.timers.tick(8999); - assert.strictEqual(fn.mock.callCount(), 0); - t.mock.timers.tick(500); - - await nodeTimersPromises.setImmediate(); - - assert.strictEqual(fn.mock.callCount(), 0); - t.mock.timers.tick(500); - - await nodeTimersPromises.setImmediate(); - assert.strictEqual(fn.mock.callCount(), 1); - }); - - it('should work with the same params as the original timers/promises/scheduler.wait', async (t) => { - t.mock.timers.enable({ apis: ['scheduler.wait'] }); - const controller = new AbortController(); - const p = nodeTimersPromises.scheduler.wait(2000, { - ref: true, - signal: controller.signal, - }); - - t.mock.timers.tick(1000); - t.mock.timers.tick(500); - t.mock.timers.tick(500); - t.mock.timers.tick(500); - - const result = await p; - assert.strictEqual(result, undefined); - }); - - it('should abort operation if timers/promises/scheduler.wait received an aborted signal', async (t) => { - t.mock.timers.enable({ apis: ['scheduler.wait'] }); - const controller = new AbortController(); - const p = nodeTimersPromises.scheduler.wait(2000, { - ref: true, - signal: controller.signal, - }); - - t.mock.timers.tick(1000); - controller.abort(); - t.mock.timers.tick(500); - t.mock.timers.tick(500); - t.mock.timers.tick(500); - - await assert.rejects(() => p, { - name: 'AbortError', - }); - }); - it('should abort operation even if the .tick was not called', async (t) => { - t.mock.timers.enable({ apis: ['scheduler.wait'] }); - const controller = new AbortController(); - const p = nodeTimersPromises.scheduler.wait(2000, { - ref: true, - signal: controller.signal, - }); - - controller.abort(); - - await assert.rejects(() => p, { - name: 'AbortError', - }); - }); - - it('should abort operation when .abort is called before calling setInterval', async (t) => { - t.mock.timers.enable({ apis: ['scheduler.wait'] }); - const controller = new AbortController(); - controller.abort(); - const p = nodeTimersPromises.scheduler.wait(2000, { - ref: true, - signal: controller.signal, - }); - - await assert.rejects(() => p, { - name: 'AbortError', - }); - }); - - it('should reject given an an invalid signal instance', async (t) => { - t.mock.timers.enable({ apis: ['scheduler.wait'] }); - const p = nodeTimersPromises.scheduler.wait(2000, { - ref: true, - signal: {}, - }); - - await assert.rejects(() => p, { - name: 'TypeError', - code: 'ERR_INVALID_ARG_TYPE', - }); - }); - - }); - }); - - describe('Date Suite', () => { - it('should return the initial UNIX epoch if not specified', (t) => { - t.mock.timers.enable({ apis: ['Date'] }); - const date = new Date(); - assert.strictEqual(date.getTime(), 0); - assert.strictEqual(Date.now(), 0); - }); - - it('should throw an error if setTime is called without enabling timers', (t) => { - assert.throws( - () => { - t.mock.timers.setTime(100); - }, - { code: 'ERR_INVALID_STATE' } - ); - }); - - it('should throw an error if epoch passed to enable is not valid', (t) => { - assert.throws( - () => { - t.mock.timers.enable({ now: -1 }); - }, - { code: 'ERR_INVALID_ARG_VALUE' } - ); - - assert.throws( - () => { - t.mock.timers.enable({ now: 'string' }); - }, - { code: 'ERR_INVALID_ARG_TYPE' } - ); - - assert.throws( - () => { - t.mock.timers.enable({ now: NaN }); - }, - { code: 'ERR_INVALID_ARG_VALUE' } - ); - }); - - it('should replace the original Date with the mocked one', (t) => { - t.mock.timers.enable({ apis: ['Date'] }); - assert.ok(Date.isMock); - }); - - it('should return the ticked time when calling Date.now after tick', (t) => { - t.mock.timers.enable({ apis: ['Date'] }); - const time = 100; - t.mock.timers.tick(time); - assert.strictEqual(Date.now(), time); - }); - - it('should return the Date as string when calling it as a function', (t) => { - t.mock.timers.enable({ apis: ['Date'] }); - const returned = Date(); - // Matches the format: 'Mon Jan 01 1970 00:00:00' - // We don't care about the date, just the format - assert.ok(/\w{3}\s\w{3}\s\d{1,2}\s\d{2,4}\s\d{1,2}:\d{2}:\d{2}/.test(returned)); - }); - - it('should return the date with different argument calls', (t) => { - t.mock.timers.enable({ apis: ['Date'] }); - assert.strictEqual(new Date(0).getTime(), 0); - assert.strictEqual(new Date(100).getTime(), 100); - assert.strictEqual(new Date('1970-01-01T00:00:00.000Z').getTime(), 0); - assert.strictEqual(new Date(1970, 0).getFullYear(), 1970); - assert.strictEqual(new Date(1970, 0).getMonth(), 0); - assert.strictEqual(new Date(1970, 0, 1).getDate(), 1); - assert.strictEqual(new Date(1970, 0, 1, 11).getHours(), 11); - assert.strictEqual(new Date(1970, 0, 1, 11, 10).getMinutes(), 10); - assert.strictEqual(new Date(1970, 0, 1, 11, 10, 45).getSeconds(), 45); - assert.strictEqual(new Date(1970, 0, 1, 11, 10, 45, 898).getMilliseconds(), 898); - assert.strictEqual(new Date(1970, 0, 1, 11, 10, 45, 898).toDateString(), 'Thu Jan 01 1970'); - }); - - it('should return native code when calling Date.toString', (t) => { - t.mock.timers.enable({ apis: ['Date'] }); - assert.strictEqual(Date.toString(), 'function Date() { [native code] }'); - }); - - it('should start with a custom epoch if the second argument is specified', (t) => { - t.mock.timers.enable({ apis: ['Date'], now: 100 }); - const date1 = new Date(); - assert.strictEqual(date1.getTime(), 100); - - t.mock.timers.reset(); - t.mock.timers.enable({ apis: ['Date'], now: new Date(200) }); - const date2 = new Date(); - assert.strictEqual(date2.getTime(), 200); - }); - - it('should replace epoch if setTime is lesser than now and not tick', (t) => { - t.mock.timers.enable(); - const fn = t.mock.fn(); - const id = setTimeout(fn, 1000); - t.mock.timers.setTime(800); - assert.strictEqual(Date.now(), 800); - t.mock.timers.setTime(500); - assert.strictEqual(Date.now(), 500); - assert.strictEqual(fn.mock.callCount(), 0); - clearTimeout(id); - }); - - it('should not tick time when setTime is called', (t) => { - t.mock.timers.enable(); - const fn = t.mock.fn(); - const id = setTimeout(fn, 1000); - t.mock.timers.setTime(1200); - assert.strictEqual(Date.now(), 1200); - assert.strictEqual(fn.mock.callCount(), 0); - clearTimeout(id); - }); - }); - describe('Api should have same public properties as original', () => { it('should have hasRef', (t) => { t.mock.timers.enable();