@@ -23,6 +23,7 @@ const {
2323 validateAbortSignal,
2424 validateNumber,
2525 validateStringArray,
26+ validateUint32,
2627} = require ( 'internal/validators' ) ;
2728
2829const {
@@ -34,6 +35,7 @@ const {
3435} = require ( 'internal/errors' ) ;
3536
3637const { addAbortListener } = require ( 'internal/events/abort_listener' ) ;
38+ const { AbortController, AbortSignal } = require ( 'internal/abort_controller' ) ;
3739
3840const { 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+ ] ;
6676const 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 (
0 commit comments