@@ -34,6 +34,7 @@ const {
3434} = require ( 'internal/errors' ) ;
3535
3636const { addAbortListener } = require ( 'internal/events/abort_listener' ) ;
37+ const { AbortController, AbortSignal } = require ( 'internal/abort_controller' ) ;
3738
3839const { TIMEOUT_MAX } = require ( 'internal/timers' ) ;
3940
@@ -59,10 +60,14 @@ function abortIt(signal) {
5960 return new AbortError ( undefined , { __proto__ : null , cause : signal . reason } ) ;
6061}
6162
62- /**
63- * @enum {('setTimeout'|'setInterval'|'setImmediate'|'Date'|'scheduler.wait')[]} Supported timers
64- */
65- const SUPPORTED_APIS = [ 'setTimeout' , 'setInterval' , 'setImmediate' , 'Date' , 'scheduler.wait' ] ;
63+ const SUPPORTED_APIS = [
64+ 'setTimeout' ,
65+ 'setInterval' ,
66+ 'setImmediate' ,
67+ 'Date' ,
68+ 'scheduler.wait' ,
69+ 'AbortSignal.timeout' ,
70+ ] ;
6671const TIMERS_DEFAULT_INTERVAL = {
6772 __proto__ : null ,
6873 setImmediate : - 1 ,
@@ -115,6 +120,7 @@ class MockTimers {
115120 #realPromisifiedSetImmediate;
116121
117122 #nativeDateDescriptor;
123+ #realAbortSignalTimeout;
118124
119125 #timersInContext = [ ] ;
120126 #isEnabled = false ;
@@ -297,6 +303,18 @@ class MockTimers {
297303 ) ;
298304 }
299305
306+ #storeOriginalAbortSignalTimeout( ) {
307+ this . #realAbortSignalTimeout = ObjectGetOwnPropertyDescriptor ( AbortSignal , 'timeout' ) ;
308+ }
309+
310+ #restoreOriginalAbortSignalTimeout( ) {
311+ if ( this . #realAbortSignalTimeout) {
312+ ObjectDefineProperty ( AbortSignal , 'timeout' , this . #realAbortSignalTimeout) ;
313+ } else {
314+ delete AbortSignal . timeout ;
315+ }
316+ }
317+
300318 #createTimer( isInterval , callback , delay , ...args ) {
301319 if ( delay > TIMEOUT_MAX ) {
302320 delay = 1 ;
@@ -604,6 +622,29 @@ class MockTimers {
604622 this . #nativeDateDescriptor = ObjectGetOwnPropertyDescriptor ( globalThis , 'Date' ) ;
605623 globalThis . Date = this . #createDate( ) ;
606624 } ,
625+ 'AbortSignal.timeout' : ( ) => {
626+ this . #storeOriginalAbortSignalTimeout( ) ;
627+ const mock = this ;
628+ ObjectDefineProperty ( AbortSignal , 'timeout' , {
629+ __proto__ : null ,
630+ configurable : true ,
631+ writable : true ,
632+ value : function value ( delay ) {
633+ if ( NumberIsNaN ( delay ) ) {
634+ throw new ERR_INVALID_ARG_VALUE ( 'delay' , delay , 'delay must be a number' ) ;
635+ }
636+ const controller = new AbortController ( ) ;
637+ // don't keep an unused binding to the timer; mock tick controls it
638+ mock . #setTimeout(
639+ ( ) => {
640+ controller . abort ( ) ;
641+ } ,
642+ delay ,
643+ ) ;
644+ return controller . signal ;
645+ } ,
646+ } ) ;
647+ } ,
607648 } ,
608649 toReal : {
609650 '__proto__' : null ,
@@ -622,6 +663,9 @@ class MockTimers {
622663 'Date' : ( ) => {
623664 ObjectDefineProperty ( globalThis , 'Date' , this . #nativeDateDescriptor) ;
624665 } ,
666+ 'AbortSignal.timeout' : ( ) => {
667+ this . #restoreOriginalAbortSignalTimeout( ) ;
668+ } ,
625669 } ,
626670 } ;
627671
@@ -664,10 +708,13 @@ class MockTimers {
664708 }
665709
666710 /**
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
669- * @property {number | Date } now The epoch to which the timers should be set to, defaults to 0
711+ * EnableOptions type:
712+ *
713+ * @typedef {object } EnableOptions
714+ * @property {Array<string> } apis List of timers to enable, defaults to all
715+ * @property {number|Date } now The epoch to which the timers should be set, defaults to 0
670716 */
717+
671718 /**
672719 * Enables the MockTimers replacing the native timers with the fake ones.
673720 * @param {EnableOptions } [options]
@@ -686,8 +733,8 @@ class MockTimers {
686733
687734 internalOptions . apis ||= SUPPORTED_APIS ;
688735
689- validateStringArray ( internalOptions . apis , 'options.apis' ) ;
690736 // Check that the timers passed are supported
737+ validateStringArray ( internalOptions . apis , 'options.apis' ) ;
691738 ArrayPrototypeForEach ( internalOptions . apis , ( timer ) => {
692739 if ( ! ArrayPrototypeIncludes ( SUPPORTED_APIS , timer ) ) {
693740 throw new ERR_INVALID_ARG_VALUE (
0 commit comments