Skip to content

Commit b883a5e

Browse files
DeveloperVirajaduh95
authored andcommitted
test_runner: add mock-timers support for AbortSignal.timeout
PR-URL: #60751Fixes: #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

2 files changed

Lines changed: 70 additions & 5 deletions

File tree

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

Lines 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-
constSUPPORTED_APIS=['setTimeout','setInterval','setImmediate','Date','scheduler.wait'];
68+
constSUPPORTED_APIS=[
69+
'setTimeout',
70+
'setInterval',
71+
'setImmediate',
72+
'Date',
73+
'scheduler.wait',
74+
'AbortSignal.timeout',
75+
];
6676
constTIMERS_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+
constmock=this;
629+
ObjectDefineProperty(AbortSignal,'timeout',{
630+
__proto__: null,
631+
configurable: true,
632+
writable: true,
633+
value: functionvalue(delay){
634+
validateUint32(delay,'delay',false);
635+
constcontroller=newAbortController();
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+
returncontroller.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
thrownewERR_INVALID_ARG_VALUE(
Lines 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+
constassert=require('assert');
5+
const{ mock }=require('node:test');
6+
7+
constoriginalAbortSignalTimeout=AbortSignal.timeout;
8+
9+
mock.timers.enable({apis: ['AbortSignal.timeout']});
10+
11+
constsignal=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)