11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci emitExperimentalWarning, 51cb0ef41Sopenharmony_ci} = require('internal/util'); 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst { 81cb0ef41Sopenharmony_ci ArrayPrototypeForEach, 91cb0ef41Sopenharmony_ci ArrayPrototypeIncludes, 101cb0ef41Sopenharmony_ci DateNow, 111cb0ef41Sopenharmony_ci FunctionPrototypeApply, 121cb0ef41Sopenharmony_ci FunctionPrototypeBind, 131cb0ef41Sopenharmony_ci ObjectDefineProperty, 141cb0ef41Sopenharmony_ci ObjectGetOwnPropertyDescriptor, 151cb0ef41Sopenharmony_ci Promise, 161cb0ef41Sopenharmony_ci SymbolAsyncIterator, 171cb0ef41Sopenharmony_ci SymbolDispose, 181cb0ef41Sopenharmony_ci globalThis, 191cb0ef41Sopenharmony_ci} = primordials; 201cb0ef41Sopenharmony_ciconst { 211cb0ef41Sopenharmony_ci validateAbortSignal, 221cb0ef41Sopenharmony_ci validateArray, 231cb0ef41Sopenharmony_ci} = require('internal/validators'); 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciconst { 261cb0ef41Sopenharmony_ci AbortError, 271cb0ef41Sopenharmony_ci codes: { 281cb0ef41Sopenharmony_ci ERR_INVALID_STATE, 291cb0ef41Sopenharmony_ci ERR_INVALID_ARG_VALUE, 301cb0ef41Sopenharmony_ci }, 311cb0ef41Sopenharmony_ci} = require('internal/errors'); 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciconst PriorityQueue = require('internal/priority_queue'); 341cb0ef41Sopenharmony_ciconst nodeTimers = require('timers'); 351cb0ef41Sopenharmony_ciconst nodeTimersPromises = require('timers/promises'); 361cb0ef41Sopenharmony_ciconst EventEmitter = require('events'); 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_cilet kResistStopPropagation; 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cifunction compareTimersLists(a, b) { 411cb0ef41Sopenharmony_ci return (a.runAt - b.runAt) || (a.id - b.id); 421cb0ef41Sopenharmony_ci} 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_cifunction setPosition(node, pos) { 451cb0ef41Sopenharmony_ci node.priorityQueuePosition = pos; 461cb0ef41Sopenharmony_ci} 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_cifunction abortIt(signal) { 491cb0ef41Sopenharmony_ci return new AbortError(undefined, { __proto__: null, cause: signal.reason }); 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ciconst SUPPORTED_TIMERS = ['setTimeout', 'setInterval', 'setImmediate']; 531cb0ef41Sopenharmony_ciconst TIMERS_DEFAULT_INTERVAL = { 541cb0ef41Sopenharmony_ci __proto__: null, 551cb0ef41Sopenharmony_ci setImmediate: -1, 561cb0ef41Sopenharmony_ci}; 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ciclass MockTimers { 591cb0ef41Sopenharmony_ci #realSetTimeout; 601cb0ef41Sopenharmony_ci #realClearTimeout; 611cb0ef41Sopenharmony_ci #realSetInterval; 621cb0ef41Sopenharmony_ci #realClearInterval; 631cb0ef41Sopenharmony_ci #realSetImmediate; 641cb0ef41Sopenharmony_ci #realClearImmediate; 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci #realPromisifiedSetTimeout; 671cb0ef41Sopenharmony_ci #realPromisifiedSetInterval; 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci #realTimersSetTimeout; 701cb0ef41Sopenharmony_ci #realTimersClearTimeout; 711cb0ef41Sopenharmony_ci #realTimersSetInterval; 721cb0ef41Sopenharmony_ci #realTimersClearInterval; 731cb0ef41Sopenharmony_ci #realTimersSetImmediate; 741cb0ef41Sopenharmony_ci #realTimersClearImmediate; 751cb0ef41Sopenharmony_ci #realPromisifiedSetImmediate; 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci #timersInContext = []; 781cb0ef41Sopenharmony_ci #isEnabled = false; 791cb0ef41Sopenharmony_ci #currentTimer = 1; 801cb0ef41Sopenharmony_ci #now = DateNow(); 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci #executionQueue = new PriorityQueue(compareTimersLists, setPosition); 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci #setTimeout = FunctionPrototypeBind(this.#createTimer, this, false); 851cb0ef41Sopenharmony_ci #clearTimeout = FunctionPrototypeBind(this.#clearTimer, this); 861cb0ef41Sopenharmony_ci #setInterval = FunctionPrototypeBind(this.#createTimer, this, true); 871cb0ef41Sopenharmony_ci #clearInterval = FunctionPrototypeBind(this.#clearTimer, this); 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci #setImmediate = (callback, ...args) => { 901cb0ef41Sopenharmony_ci return this.#createTimer( 911cb0ef41Sopenharmony_ci false, 921cb0ef41Sopenharmony_ci callback, 931cb0ef41Sopenharmony_ci TIMERS_DEFAULT_INTERVAL.setImmediate, 941cb0ef41Sopenharmony_ci ...args, 951cb0ef41Sopenharmony_ci ); 961cb0ef41Sopenharmony_ci }; 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_ci #clearImmediate = FunctionPrototypeBind(this.#clearTimer, this); 991cb0ef41Sopenharmony_ci constructor() { 1001cb0ef41Sopenharmony_ci emitExperimentalWarning('The MockTimers API'); 1011cb0ef41Sopenharmony_ci } 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci #createTimer(isInterval, callback, delay, ...args) { 1041cb0ef41Sopenharmony_ci const timerId = this.#currentTimer++; 1051cb0ef41Sopenharmony_ci this.#executionQueue.insert({ 1061cb0ef41Sopenharmony_ci __proto__: null, 1071cb0ef41Sopenharmony_ci id: timerId, 1081cb0ef41Sopenharmony_ci callback, 1091cb0ef41Sopenharmony_ci runAt: this.#now + delay, 1101cb0ef41Sopenharmony_ci interval: isInterval, 1111cb0ef41Sopenharmony_ci args, 1121cb0ef41Sopenharmony_ci }); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci return timerId; 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci #clearTimer(position) { 1181cb0ef41Sopenharmony_ci this.#executionQueue.removeAt(position); 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci async * #setIntervalPromisified(interval, startTime, options) { 1221cb0ef41Sopenharmony_ci const context = this; 1231cb0ef41Sopenharmony_ci const emitter = new EventEmitter(); 1241cb0ef41Sopenharmony_ci if (options?.signal) { 1251cb0ef41Sopenharmony_ci validateAbortSignal(options.signal, 'options.signal'); 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci if (options.signal.aborted) { 1281cb0ef41Sopenharmony_ci throw abortIt(options.signal); 1291cb0ef41Sopenharmony_ci } 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci const onAbort = (reason) => { 1321cb0ef41Sopenharmony_ci emitter.emit('data', { __proto__: null, aborted: true, reason }); 1331cb0ef41Sopenharmony_ci }; 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; 1361cb0ef41Sopenharmony_ci options.signal.addEventListener('abort', onAbort, { 1371cb0ef41Sopenharmony_ci __proto__: null, 1381cb0ef41Sopenharmony_ci once: true, 1391cb0ef41Sopenharmony_ci [kResistStopPropagation]: true, 1401cb0ef41Sopenharmony_ci }); 1411cb0ef41Sopenharmony_ci } 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci const eventIt = EventEmitter.on(emitter, 'data'); 1441cb0ef41Sopenharmony_ci const callback = () => { 1451cb0ef41Sopenharmony_ci startTime += interval; 1461cb0ef41Sopenharmony_ci emitter.emit('data', startTime); 1471cb0ef41Sopenharmony_ci }; 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci const timerId = this.#createTimer(true, callback, interval, options); 1501cb0ef41Sopenharmony_ci const clearListeners = () => { 1511cb0ef41Sopenharmony_ci emitter.removeAllListeners(); 1521cb0ef41Sopenharmony_ci context.#clearTimer(timerId); 1531cb0ef41Sopenharmony_ci }; 1541cb0ef41Sopenharmony_ci const iterator = { 1551cb0ef41Sopenharmony_ci __proto__: null, 1561cb0ef41Sopenharmony_ci [SymbolAsyncIterator]() { 1571cb0ef41Sopenharmony_ci return this; 1581cb0ef41Sopenharmony_ci }, 1591cb0ef41Sopenharmony_ci async next() { 1601cb0ef41Sopenharmony_ci const result = await eventIt.next(); 1611cb0ef41Sopenharmony_ci const value = result.value[0]; 1621cb0ef41Sopenharmony_ci if (value?.aborted) { 1631cb0ef41Sopenharmony_ci iterator.return(); 1641cb0ef41Sopenharmony_ci throw abortIt(options.signal); 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci return { 1681cb0ef41Sopenharmony_ci __proto__: null, 1691cb0ef41Sopenharmony_ci done: result.done, 1701cb0ef41Sopenharmony_ci value, 1711cb0ef41Sopenharmony_ci }; 1721cb0ef41Sopenharmony_ci }, 1731cb0ef41Sopenharmony_ci async return() { 1741cb0ef41Sopenharmony_ci clearListeners(); 1751cb0ef41Sopenharmony_ci return eventIt.return(); 1761cb0ef41Sopenharmony_ci }, 1771cb0ef41Sopenharmony_ci }; 1781cb0ef41Sopenharmony_ci yield* iterator; 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci #promisifyTimer({ timerFn, clearFn, ms, result, options }) { 1821cb0ef41Sopenharmony_ci return new Promise((resolve, reject) => { 1831cb0ef41Sopenharmony_ci if (options?.signal) { 1841cb0ef41Sopenharmony_ci try { 1851cb0ef41Sopenharmony_ci validateAbortSignal(options.signal, 'options.signal'); 1861cb0ef41Sopenharmony_ci } catch (err) { 1871cb0ef41Sopenharmony_ci return reject(err); 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci if (options.signal.aborted) { 1911cb0ef41Sopenharmony_ci return reject(abortIt(options.signal)); 1921cb0ef41Sopenharmony_ci } 1931cb0ef41Sopenharmony_ci } 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci const onabort = () => { 1961cb0ef41Sopenharmony_ci clearFn(id); 1971cb0ef41Sopenharmony_ci return reject(abortIt(options.signal)); 1981cb0ef41Sopenharmony_ci }; 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci const id = timerFn(() => { 2011cb0ef41Sopenharmony_ci return resolve(result); 2021cb0ef41Sopenharmony_ci }, ms); 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci if (options?.signal) { 2051cb0ef41Sopenharmony_ci kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; 2061cb0ef41Sopenharmony_ci options.signal.addEventListener('abort', onabort, { 2071cb0ef41Sopenharmony_ci __proto__: null, 2081cb0ef41Sopenharmony_ci once: true, 2091cb0ef41Sopenharmony_ci [kResistStopPropagation]: true, 2101cb0ef41Sopenharmony_ci }); 2111cb0ef41Sopenharmony_ci } 2121cb0ef41Sopenharmony_ci }); 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci #setImmediatePromisified(result, options) { 2161cb0ef41Sopenharmony_ci return this.#promisifyTimer({ 2171cb0ef41Sopenharmony_ci __proto__: null, 2181cb0ef41Sopenharmony_ci timerFn: FunctionPrototypeBind(this.#setImmediate, this), 2191cb0ef41Sopenharmony_ci clearFn: FunctionPrototypeBind(this.#clearImmediate, this), 2201cb0ef41Sopenharmony_ci ms: TIMERS_DEFAULT_INTERVAL.setImmediate, 2211cb0ef41Sopenharmony_ci result, 2221cb0ef41Sopenharmony_ci options, 2231cb0ef41Sopenharmony_ci }); 2241cb0ef41Sopenharmony_ci } 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci #setTimeoutPromisified(ms, result, options) { 2271cb0ef41Sopenharmony_ci return this.#promisifyTimer({ 2281cb0ef41Sopenharmony_ci __proto__: null, 2291cb0ef41Sopenharmony_ci timerFn: FunctionPrototypeBind(this.#setTimeout, this), 2301cb0ef41Sopenharmony_ci clearFn: FunctionPrototypeBind(this.#clearTimeout, this), 2311cb0ef41Sopenharmony_ci ms, 2321cb0ef41Sopenharmony_ci result, 2331cb0ef41Sopenharmony_ci options, 2341cb0ef41Sopenharmony_ci }); 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci #toggleEnableTimers(activate) { 2381cb0ef41Sopenharmony_ci const options = { 2391cb0ef41Sopenharmony_ci __proto__: null, 2401cb0ef41Sopenharmony_ci toFake: { 2411cb0ef41Sopenharmony_ci __proto__: null, 2421cb0ef41Sopenharmony_ci setTimeout: () => { 2431cb0ef41Sopenharmony_ci this.#storeOriginalSetTimeout(); 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci globalThis.setTimeout = this.#setTimeout; 2461cb0ef41Sopenharmony_ci globalThis.clearTimeout = this.#clearTimeout; 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_ci nodeTimers.setTimeout = this.#setTimeout; 2491cb0ef41Sopenharmony_ci nodeTimers.clearTimeout = this.#clearTimeout; 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci nodeTimersPromises.setTimeout = FunctionPrototypeBind( 2521cb0ef41Sopenharmony_ci this.#setTimeoutPromisified, 2531cb0ef41Sopenharmony_ci this, 2541cb0ef41Sopenharmony_ci ); 2551cb0ef41Sopenharmony_ci }, 2561cb0ef41Sopenharmony_ci setInterval: () => { 2571cb0ef41Sopenharmony_ci this.#storeOriginalSetInterval(); 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci globalThis.setInterval = this.#setInterval; 2601cb0ef41Sopenharmony_ci globalThis.clearInterval = this.#clearInterval; 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ci nodeTimers.setInterval = this.#setInterval; 2631cb0ef41Sopenharmony_ci nodeTimers.clearInterval = this.#clearInterval; 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci nodeTimersPromises.setInterval = FunctionPrototypeBind( 2661cb0ef41Sopenharmony_ci this.#setIntervalPromisified, 2671cb0ef41Sopenharmony_ci this, 2681cb0ef41Sopenharmony_ci ); 2691cb0ef41Sopenharmony_ci }, 2701cb0ef41Sopenharmony_ci setImmediate: () => { 2711cb0ef41Sopenharmony_ci this.#storeOriginalSetImmediate(); 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci globalThis.setImmediate = this.#setImmediate; 2741cb0ef41Sopenharmony_ci globalThis.clearImmediate = this.#clearImmediate; 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci nodeTimers.setImmediate = this.#setImmediate; 2771cb0ef41Sopenharmony_ci nodeTimers.clearImmediate = this.#clearImmediate; 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci nodeTimersPromises.setImmediate = FunctionPrototypeBind( 2801cb0ef41Sopenharmony_ci this.#setImmediatePromisified, 2811cb0ef41Sopenharmony_ci this, 2821cb0ef41Sopenharmony_ci ); 2831cb0ef41Sopenharmony_ci }, 2841cb0ef41Sopenharmony_ci }, 2851cb0ef41Sopenharmony_ci toReal: { 2861cb0ef41Sopenharmony_ci __proto__: null, 2871cb0ef41Sopenharmony_ci setTimeout: () => { 2881cb0ef41Sopenharmony_ci this.#restoreOriginalSetTimeout(); 2891cb0ef41Sopenharmony_ci }, 2901cb0ef41Sopenharmony_ci setInterval: () => { 2911cb0ef41Sopenharmony_ci this.#restoreOriginalSetInterval(); 2921cb0ef41Sopenharmony_ci }, 2931cb0ef41Sopenharmony_ci setImmediate: () => { 2941cb0ef41Sopenharmony_ci this.#restoreSetImmediate(); 2951cb0ef41Sopenharmony_ci }, 2961cb0ef41Sopenharmony_ci }, 2971cb0ef41Sopenharmony_ci }; 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci const target = activate ? options.toFake : options.toReal; 3001cb0ef41Sopenharmony_ci ArrayPrototypeForEach(this.#timersInContext, (timer) => target[timer]()); 3011cb0ef41Sopenharmony_ci this.#isEnabled = activate; 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci #restoreSetImmediate() { 3051cb0ef41Sopenharmony_ci ObjectDefineProperty( 3061cb0ef41Sopenharmony_ci globalThis, 3071cb0ef41Sopenharmony_ci 'setImmediate', 3081cb0ef41Sopenharmony_ci this.#realSetImmediate, 3091cb0ef41Sopenharmony_ci ); 3101cb0ef41Sopenharmony_ci ObjectDefineProperty( 3111cb0ef41Sopenharmony_ci globalThis, 3121cb0ef41Sopenharmony_ci 'clearImmediate', 3131cb0ef41Sopenharmony_ci this.#realClearImmediate, 3141cb0ef41Sopenharmony_ci ); 3151cb0ef41Sopenharmony_ci ObjectDefineProperty( 3161cb0ef41Sopenharmony_ci nodeTimers, 3171cb0ef41Sopenharmony_ci 'setImmediate', 3181cb0ef41Sopenharmony_ci this.#realTimersSetImmediate, 3191cb0ef41Sopenharmony_ci ); 3201cb0ef41Sopenharmony_ci ObjectDefineProperty( 3211cb0ef41Sopenharmony_ci nodeTimers, 3221cb0ef41Sopenharmony_ci 'clearImmediate', 3231cb0ef41Sopenharmony_ci this.#realTimersClearImmediate, 3241cb0ef41Sopenharmony_ci ); 3251cb0ef41Sopenharmony_ci ObjectDefineProperty( 3261cb0ef41Sopenharmony_ci nodeTimersPromises, 3271cb0ef41Sopenharmony_ci 'setImmediate', 3281cb0ef41Sopenharmony_ci this.#realPromisifiedSetImmediate, 3291cb0ef41Sopenharmony_ci ); 3301cb0ef41Sopenharmony_ci } 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci #restoreOriginalSetInterval() { 3331cb0ef41Sopenharmony_ci ObjectDefineProperty( 3341cb0ef41Sopenharmony_ci globalThis, 3351cb0ef41Sopenharmony_ci 'setInterval', 3361cb0ef41Sopenharmony_ci this.#realSetInterval, 3371cb0ef41Sopenharmony_ci ); 3381cb0ef41Sopenharmony_ci ObjectDefineProperty( 3391cb0ef41Sopenharmony_ci globalThis, 3401cb0ef41Sopenharmony_ci 'clearInterval', 3411cb0ef41Sopenharmony_ci this.#realClearInterval, 3421cb0ef41Sopenharmony_ci ); 3431cb0ef41Sopenharmony_ci ObjectDefineProperty( 3441cb0ef41Sopenharmony_ci nodeTimers, 3451cb0ef41Sopenharmony_ci 'setInterval', 3461cb0ef41Sopenharmony_ci this.#realTimersSetInterval, 3471cb0ef41Sopenharmony_ci ); 3481cb0ef41Sopenharmony_ci ObjectDefineProperty( 3491cb0ef41Sopenharmony_ci nodeTimers, 3501cb0ef41Sopenharmony_ci 'clearInterval', 3511cb0ef41Sopenharmony_ci this.#realTimersClearInterval, 3521cb0ef41Sopenharmony_ci ); 3531cb0ef41Sopenharmony_ci ObjectDefineProperty( 3541cb0ef41Sopenharmony_ci nodeTimersPromises, 3551cb0ef41Sopenharmony_ci 'setInterval', 3561cb0ef41Sopenharmony_ci this.#realPromisifiedSetInterval, 3571cb0ef41Sopenharmony_ci ); 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci #restoreOriginalSetTimeout() { 3611cb0ef41Sopenharmony_ci ObjectDefineProperty( 3621cb0ef41Sopenharmony_ci globalThis, 3631cb0ef41Sopenharmony_ci 'setTimeout', 3641cb0ef41Sopenharmony_ci this.#realSetTimeout, 3651cb0ef41Sopenharmony_ci ); 3661cb0ef41Sopenharmony_ci ObjectDefineProperty( 3671cb0ef41Sopenharmony_ci globalThis, 3681cb0ef41Sopenharmony_ci 'clearTimeout', 3691cb0ef41Sopenharmony_ci this.#realClearTimeout, 3701cb0ef41Sopenharmony_ci ); 3711cb0ef41Sopenharmony_ci ObjectDefineProperty( 3721cb0ef41Sopenharmony_ci nodeTimers, 3731cb0ef41Sopenharmony_ci 'setTimeout', 3741cb0ef41Sopenharmony_ci this.#realTimersSetTimeout, 3751cb0ef41Sopenharmony_ci ); 3761cb0ef41Sopenharmony_ci ObjectDefineProperty( 3771cb0ef41Sopenharmony_ci nodeTimers, 3781cb0ef41Sopenharmony_ci 'clearTimeout', 3791cb0ef41Sopenharmony_ci this.#realTimersClearTimeout, 3801cb0ef41Sopenharmony_ci ); 3811cb0ef41Sopenharmony_ci ObjectDefineProperty( 3821cb0ef41Sopenharmony_ci nodeTimersPromises, 3831cb0ef41Sopenharmony_ci 'setTimeout', 3841cb0ef41Sopenharmony_ci this.#realPromisifiedSetTimeout, 3851cb0ef41Sopenharmony_ci ); 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci #storeOriginalSetImmediate() { 3891cb0ef41Sopenharmony_ci this.#realSetImmediate = ObjectGetOwnPropertyDescriptor( 3901cb0ef41Sopenharmony_ci globalThis, 3911cb0ef41Sopenharmony_ci 'setImmediate', 3921cb0ef41Sopenharmony_ci ); 3931cb0ef41Sopenharmony_ci this.#realClearImmediate = ObjectGetOwnPropertyDescriptor( 3941cb0ef41Sopenharmony_ci globalThis, 3951cb0ef41Sopenharmony_ci 'clearImmediate', 3961cb0ef41Sopenharmony_ci ); 3971cb0ef41Sopenharmony_ci this.#realTimersSetImmediate = ObjectGetOwnPropertyDescriptor( 3981cb0ef41Sopenharmony_ci nodeTimers, 3991cb0ef41Sopenharmony_ci 'setImmediate', 4001cb0ef41Sopenharmony_ci ); 4011cb0ef41Sopenharmony_ci this.#realTimersClearImmediate = ObjectGetOwnPropertyDescriptor( 4021cb0ef41Sopenharmony_ci nodeTimers, 4031cb0ef41Sopenharmony_ci 'clearImmediate', 4041cb0ef41Sopenharmony_ci ); 4051cb0ef41Sopenharmony_ci this.#realPromisifiedSetImmediate = ObjectGetOwnPropertyDescriptor( 4061cb0ef41Sopenharmony_ci nodeTimersPromises, 4071cb0ef41Sopenharmony_ci 'setImmediate', 4081cb0ef41Sopenharmony_ci ); 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci #storeOriginalSetInterval() { 4121cb0ef41Sopenharmony_ci this.#realSetInterval = ObjectGetOwnPropertyDescriptor( 4131cb0ef41Sopenharmony_ci globalThis, 4141cb0ef41Sopenharmony_ci 'setInterval', 4151cb0ef41Sopenharmony_ci ); 4161cb0ef41Sopenharmony_ci this.#realClearInterval = ObjectGetOwnPropertyDescriptor( 4171cb0ef41Sopenharmony_ci globalThis, 4181cb0ef41Sopenharmony_ci 'clearInterval', 4191cb0ef41Sopenharmony_ci ); 4201cb0ef41Sopenharmony_ci this.#realTimersSetInterval = ObjectGetOwnPropertyDescriptor( 4211cb0ef41Sopenharmony_ci nodeTimers, 4221cb0ef41Sopenharmony_ci 'setInterval', 4231cb0ef41Sopenharmony_ci ); 4241cb0ef41Sopenharmony_ci this.#realTimersClearInterval = ObjectGetOwnPropertyDescriptor( 4251cb0ef41Sopenharmony_ci nodeTimers, 4261cb0ef41Sopenharmony_ci 'clearInterval', 4271cb0ef41Sopenharmony_ci ); 4281cb0ef41Sopenharmony_ci this.#realPromisifiedSetInterval = ObjectGetOwnPropertyDescriptor( 4291cb0ef41Sopenharmony_ci nodeTimersPromises, 4301cb0ef41Sopenharmony_ci 'setInterval', 4311cb0ef41Sopenharmony_ci ); 4321cb0ef41Sopenharmony_ci } 4331cb0ef41Sopenharmony_ci 4341cb0ef41Sopenharmony_ci #storeOriginalSetTimeout() { 4351cb0ef41Sopenharmony_ci this.#realSetTimeout = ObjectGetOwnPropertyDescriptor( 4361cb0ef41Sopenharmony_ci globalThis, 4371cb0ef41Sopenharmony_ci 'setTimeout', 4381cb0ef41Sopenharmony_ci ); 4391cb0ef41Sopenharmony_ci this.#realClearTimeout = ObjectGetOwnPropertyDescriptor( 4401cb0ef41Sopenharmony_ci globalThis, 4411cb0ef41Sopenharmony_ci 'clearTimeout', 4421cb0ef41Sopenharmony_ci ); 4431cb0ef41Sopenharmony_ci this.#realTimersSetTimeout = ObjectGetOwnPropertyDescriptor( 4441cb0ef41Sopenharmony_ci nodeTimers, 4451cb0ef41Sopenharmony_ci 'setTimeout', 4461cb0ef41Sopenharmony_ci ); 4471cb0ef41Sopenharmony_ci this.#realTimersClearTimeout = ObjectGetOwnPropertyDescriptor( 4481cb0ef41Sopenharmony_ci nodeTimers, 4491cb0ef41Sopenharmony_ci 'clearTimeout', 4501cb0ef41Sopenharmony_ci ); 4511cb0ef41Sopenharmony_ci this.#realPromisifiedSetTimeout = ObjectGetOwnPropertyDescriptor( 4521cb0ef41Sopenharmony_ci nodeTimersPromises, 4531cb0ef41Sopenharmony_ci 'setTimeout', 4541cb0ef41Sopenharmony_ci ); 4551cb0ef41Sopenharmony_ci } 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ci /** 4581cb0ef41Sopenharmony_ci * Advances the virtual time of MockTimers by the specified duration (in milliseconds). 4591cb0ef41Sopenharmony_ci * This method simulates the passage of time and triggers any scheduled timers that are due. 4601cb0ef41Sopenharmony_ci * @param {number} [time=1] - The amount of time (in milliseconds) to advance the virtual time. 4611cb0ef41Sopenharmony_ci * @throws {ERR_INVALID_STATE} If MockTimers are not enabled. 4621cb0ef41Sopenharmony_ci * @throws {ERR_INVALID_ARG_VALUE} If a negative time value is provided. 4631cb0ef41Sopenharmony_ci */ 4641cb0ef41Sopenharmony_ci tick(time = 1) { 4651cb0ef41Sopenharmony_ci if (!this.#isEnabled) { 4661cb0ef41Sopenharmony_ci throw new ERR_INVALID_STATE( 4671cb0ef41Sopenharmony_ci 'You should enable MockTimers first by calling the .enable function', 4681cb0ef41Sopenharmony_ci ); 4691cb0ef41Sopenharmony_ci } 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci if (time < 0) { 4721cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_VALUE( 4731cb0ef41Sopenharmony_ci 'time', 4741cb0ef41Sopenharmony_ci 'positive integer', 4751cb0ef41Sopenharmony_ci time, 4761cb0ef41Sopenharmony_ci ); 4771cb0ef41Sopenharmony_ci } 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci this.#now += time; 4801cb0ef41Sopenharmony_ci let timer = this.#executionQueue.peek(); 4811cb0ef41Sopenharmony_ci while (timer) { 4821cb0ef41Sopenharmony_ci if (timer.runAt > this.#now) break; 4831cb0ef41Sopenharmony_ci FunctionPrototypeApply(timer.callback, undefined, timer.args); 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci this.#executionQueue.shift(); 4861cb0ef41Sopenharmony_ci 4871cb0ef41Sopenharmony_ci if (timer.interval) { 4881cb0ef41Sopenharmony_ci timer.runAt += timer.interval; 4891cb0ef41Sopenharmony_ci this.#executionQueue.insert(timer); 4901cb0ef41Sopenharmony_ci return; 4911cb0ef41Sopenharmony_ci } 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_ci timer = this.#executionQueue.peek(); 4941cb0ef41Sopenharmony_ci } 4951cb0ef41Sopenharmony_ci } 4961cb0ef41Sopenharmony_ci 4971cb0ef41Sopenharmony_ci /** 4981cb0ef41Sopenharmony_ci * Enables MockTimers for the specified timers. 4991cb0ef41Sopenharmony_ci * @param {string[]} timers - An array of timer types to enable, e.g., ['setTimeout', 'setInterval']. 5001cb0ef41Sopenharmony_ci * @throws {ERR_INVALID_STATE} If MockTimers are already enabled. 5011cb0ef41Sopenharmony_ci * @throws {ERR_INVALID_ARG_VALUE} If an unsupported timer type is specified. 5021cb0ef41Sopenharmony_ci */ 5031cb0ef41Sopenharmony_ci enable(timers = SUPPORTED_TIMERS) { 5041cb0ef41Sopenharmony_ci if (this.#isEnabled) { 5051cb0ef41Sopenharmony_ci throw new ERR_INVALID_STATE( 5061cb0ef41Sopenharmony_ci 'MockTimers is already enabled!', 5071cb0ef41Sopenharmony_ci ); 5081cb0ef41Sopenharmony_ci } 5091cb0ef41Sopenharmony_ci 5101cb0ef41Sopenharmony_ci validateArray(timers, 'timers'); 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ci // Check that the timers passed are supported 5131cb0ef41Sopenharmony_ci ArrayPrototypeForEach(timers, (timer) => { 5141cb0ef41Sopenharmony_ci if (!ArrayPrototypeIncludes(SUPPORTED_TIMERS, timer)) { 5151cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_VALUE( 5161cb0ef41Sopenharmony_ci 'timers', 5171cb0ef41Sopenharmony_ci timer, 5181cb0ef41Sopenharmony_ci `option ${timer} is not supported`, 5191cb0ef41Sopenharmony_ci ); 5201cb0ef41Sopenharmony_ci } 5211cb0ef41Sopenharmony_ci }); 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_ci this.#timersInContext = timers; 5241cb0ef41Sopenharmony_ci this.#now = DateNow(); 5251cb0ef41Sopenharmony_ci this.#toggleEnableTimers(true); 5261cb0ef41Sopenharmony_ci } 5271cb0ef41Sopenharmony_ci 5281cb0ef41Sopenharmony_ci /** 5291cb0ef41Sopenharmony_ci * An alias for `this.reset()`, allowing the disposal of the `MockTimers` instance. 5301cb0ef41Sopenharmony_ci */ 5311cb0ef41Sopenharmony_ci [SymbolDispose]() { 5321cb0ef41Sopenharmony_ci this.reset(); 5331cb0ef41Sopenharmony_ci } 5341cb0ef41Sopenharmony_ci 5351cb0ef41Sopenharmony_ci /** 5361cb0ef41Sopenharmony_ci * Resets MockTimers, disabling any enabled timers and clearing the execution queue. 5371cb0ef41Sopenharmony_ci * Does nothing if MockTimers are not enabled. 5381cb0ef41Sopenharmony_ci */ 5391cb0ef41Sopenharmony_ci reset() { 5401cb0ef41Sopenharmony_ci // Ignore if not enabled 5411cb0ef41Sopenharmony_ci if (!this.#isEnabled) return; 5421cb0ef41Sopenharmony_ci 5431cb0ef41Sopenharmony_ci this.#toggleEnableTimers(false); 5441cb0ef41Sopenharmony_ci this.#timersInContext = []; 5451cb0ef41Sopenharmony_ci 5461cb0ef41Sopenharmony_ci let timer = this.#executionQueue.peek(); 5471cb0ef41Sopenharmony_ci while (timer) { 5481cb0ef41Sopenharmony_ci this.#executionQueue.shift(); 5491cb0ef41Sopenharmony_ci timer = this.#executionQueue.peek(); 5501cb0ef41Sopenharmony_ci } 5511cb0ef41Sopenharmony_ci } 5521cb0ef41Sopenharmony_ci 5531cb0ef41Sopenharmony_ci /** 5541cb0ef41Sopenharmony_ci * Runs all scheduled timers until there are no more pending timers. 5551cb0ef41Sopenharmony_ci * @throws {ERR_INVALID_STATE} If MockTimers are not enabled. 5561cb0ef41Sopenharmony_ci */ 5571cb0ef41Sopenharmony_ci runAll() { 5581cb0ef41Sopenharmony_ci if (!this.#isEnabled) { 5591cb0ef41Sopenharmony_ci throw new ERR_INVALID_STATE( 5601cb0ef41Sopenharmony_ci 'You should enable MockTimers first by calling the .enable function', 5611cb0ef41Sopenharmony_ci ); 5621cb0ef41Sopenharmony_ci } 5631cb0ef41Sopenharmony_ci 5641cb0ef41Sopenharmony_ci this.tick(Infinity); 5651cb0ef41Sopenharmony_ci } 5661cb0ef41Sopenharmony_ci} 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_cimodule.exports = { MockTimers }; 569