Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b883a5e

Browse filesBrowse files
DeveloperVirajaduh95
authored andcommitted
test_runner: add mock-timers support for AbortSignal.timeout
PR-URL: #60751 Fixes: #60509 Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Stefan Stojanovic <stefan.stojanovic@janeasystems.com> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk> Reviewed-By: Jacob Smith <jacob@frende.me>
1 parent 88fe50a commit b883a5e
Copy full SHA for b883a5e

2 files changed

+70-5Lines changed: 70 additions & 5 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎lib/internal/test_runner/mock/mock_timers.js‎

Copy file name to clipboardExpand all lines: lib/internal/test_runner/mock/mock_timers.js
+49-5Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const {
2323
validateAbortSignal,
2424
validateNumber,
2525
validateStringArray,
26+
validateUint32,
2627
} = require('internal/validators');
2728

2829
const {
@@ -34,6 +35,7 @@ const {
3435
} = require('internal/errors');
3536

3637
const { addAbortListener } = require('internal/events/abort_listener');
38+
const { AbortController, AbortSignal } = require('internal/abort_controller');
3739

3840
const { TIMEOUT_MAX } = require('internal/timers');
3941

@@ -60,9 +62,17 @@ function abortIt(signal) {
6062
}
6163

6264
/**
63-
* @enum {('setTimeout'|'setInterval'|'setImmediate'|'Date'|'scheduler.wait')[]} Supported timers
65+
* @typedef {('setTimeout'|'setInterval'|'setImmediate'|'Date'|'scheduler.wait'|'AbortSignal.timeout')[]} SupportedApis
66+
* Supported timers that can be enabled via MockTimers.enable({ apis: [...] })
6467
*/
65-
const SUPPORTED_APIS = ['setTimeout', 'setInterval', 'setImmediate', 'Date', 'scheduler.wait'];
68+
const SUPPORTED_APIS = [
69+
'setTimeout',
70+
'setInterval',
71+
'setImmediate',
72+
'Date',
73+
'scheduler.wait',
74+
'AbortSignal.timeout',
75+
];
6676
const TIMERS_DEFAULT_INTERVAL = {
6777
__proto__: null,
6878
setImmediate: -1,
@@ -115,6 +125,7 @@ class MockTimers {
115125
#realPromisifiedSetImmediate;
116126

117127
#nativeDateDescriptor;
128+
#realAbortSignalTimeout;
118129

119130
#timersInContext = [];
120131
#isEnabled = false;
@@ -297,6 +308,14 @@ class MockTimers {
297308
);
298309
}
299310

311+
#storeOriginalAbortSignalTimeout() {
312+
this.#realAbortSignalTimeout = ObjectGetOwnPropertyDescriptor(AbortSignal, 'timeout');
313+
}
314+
315+
#restoreOriginalAbortSignalTimeout() {
316+
ObjectDefineProperty(AbortSignal, 'timeout', this.#realAbortSignalTimeout);
317+
}
318+
300319
#createTimer(isInterval, callback, delay, ...args) {
301320
if (delay > TIMEOUT_MAX) {
302321
delay = 1;
@@ -604,6 +623,27 @@ class MockTimers {
604623
this.#nativeDateDescriptor = ObjectGetOwnPropertyDescriptor(globalThis, 'Date');
605624
globalThis.Date = this.#createDate();
606625
},
626+
'AbortSignal.timeout': () => {
627+
this.#storeOriginalAbortSignalTimeout();
628+
const mock = this;
629+
ObjectDefineProperty(AbortSignal, 'timeout', {
630+
__proto__: null,
631+
configurable: true,
632+
writable: true,
633+
value: function value(delay) {
634+
validateUint32(delay, 'delay', false);
635+
const controller = new AbortController();
636+
// Don't keep an unused binding to the timer; mock tick controls it
637+
mock.#setTimeout(
638+
() => {
639+
controller.abort();
640+
},
641+
delay,
642+
);
643+
return controller.signal;
644+
},
645+
});
646+
},
607647
},
608648
toReal: {
609649
'__proto__': null,
@@ -622,6 +662,9 @@ class MockTimers {
622662
'Date': () => {
623663
ObjectDefineProperty(globalThis, 'Date', this.#nativeDateDescriptor);
624664
},
665+
'AbortSignal.timeout': () => {
666+
this.#restoreOriginalAbortSignalTimeout();
667+
},
625668
},
626669
};
627670

@@ -664,10 +707,11 @@ class MockTimers {
664707
}
665708

666709
/**
667-
* @typedef {{apis: SUPPORTED_APIS;now: number | Date;}} EnableOptions Options to enable the timers
668-
* @property {SUPPORTED_APIS} apis List of timers to enable, defaults to all
710+
* @typedef {{apis: SupportedApis;now: number | Date;}} EnableOptions Options to enable the timers
711+
* @property {SupportedApis} apis List of timers to enable, defaults to all
669712
* @property {number | Date} now The epoch to which the timers should be set to, defaults to 0
670713
*/
714+
671715
/**
672716
* Enables the MockTimers replacing the native timers with the fake ones.
673717
* @param {EnableOptions} [options]
@@ -686,8 +730,8 @@ class MockTimers {
686730

687731
internalOptions.apis ||= SUPPORTED_APIS;
688732

689-
validateStringArray(internalOptions.apis, 'options.apis');
690733
// Check that the timers passed are supported
734+
validateStringArray(internalOptions.apis, 'options.apis');
691735
ArrayPrototypeForEach(internalOptions.apis, (timer) => {
692736
if (!ArrayPrototypeIncludes(SUPPORTED_APIS, timer)) {
693737
throw new ERR_INVALID_ARG_VALUE(
Collapse file
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
const { mock } = require('node:test');
6+
7+
const originalAbortSignalTimeout = AbortSignal.timeout;
8+
9+
mock.timers.enable({ apis: ['AbortSignal.timeout'] });
10+
11+
const signal = AbortSignal.timeout(50);
12+
assert.strictEqual(signal.aborted, false);
13+
14+
mock.timers.tick(49);
15+
assert.strictEqual(signal.aborted, false);
16+
17+
mock.timers.tick(1);
18+
assert.strictEqual(signal.aborted, true);
19+
20+
mock.timers.reset();
21+
assert.strictEqual(AbortSignal.timeout, originalAbortSignalTimeout);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.