Skip to content

Commit

Permalink
test_runner: add support for setImmediate
Browse files Browse the repository at this point in the history
PR-URL: #49397
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
  • Loading branch information
ErickWendel authored and UlisesGascon committed Sep 10, 2023
1 parent 23216f1 commit 40e9fcd
Show file tree
Hide file tree
Showing 3 changed files with 312 additions and 10 deletions.
7 changes: 4 additions & 3 deletions doc/api/test.md
Expand Up @@ -1594,9 +1594,10 @@ added:
Enables timer mocking for the specified timers.

* `timers` {Array} An optional array containing the timers to mock.
The currently supported timer values are `'setInterval'` and `'setTimeout'`.
If no array is provided, all timers (`'setInterval'`, `'clearInterval'`, `'setTimeout'`,
and `'clearTimeout'`) will be mocked by default.
The currently supported timer values are `'setInterval'`, `'setTimeout'`,
and `'setImmediate'`. If no value is provided, all timers (`'setInterval'`,
`'clearInterval'`, `'setTimeout'`, `'clearTimeout'`, `'setImmediate'`,
and `'clearImmediate'`) will be mocked by default.

**Note:** When you enable mocking for a specific timer, its associated
clear function will also be implicitly mocked.
Expand Down
77 changes: 72 additions & 5 deletions lib/internal/test_runner/mock/mock_timers.js
Expand Up @@ -48,13 +48,19 @@ function abortIt(signal) {
return new AbortError(undefined, { __proto__: null, cause: signal.reason });
}

const SUPPORTED_TIMERS = ['setTimeout', 'setInterval'];
const SUPPORTED_TIMERS = ['setTimeout', 'setInterval', 'setImmediate'];
const TIMERS_DEFAULT_INTERVAL = {
__proto__: null,
setImmediate: -1,
};

class MockTimers {
#realSetTimeout;
#realClearTimeout;
#realSetInterval;
#realClearInterval;
#realSetImmediate;
#realClearImmediate;

#realPromisifiedSetTimeout;
#realPromisifiedSetInterval;
Expand All @@ -63,6 +69,9 @@ class MockTimers {
#realTimersClearTimeout;
#realTimersSetInterval;
#realTimersClearInterval;
#realTimersSetImmediate;
#realTimersClearImmediate;
#realPromisifiedSetImmediate;

#timersInContext = [];
#isEnabled = false;
Expand All @@ -76,6 +85,16 @@ class MockTimers {
#setInterval = FunctionPrototypeBind(this.#createTimer, this, true);
#clearInterval = FunctionPrototypeBind(this.#clearTimer, this);

#setImmediate = (callback, ...args) => {
return this.#createTimer(
false,
callback,
TIMERS_DEFAULT_INTERVAL.setImmediate,
...args,
);
};

#clearImmediate = FunctionPrototypeBind(this.#clearTimer, this);
constructor() {
emitExperimentalWarning('The MockTimers API');
}
Expand Down Expand Up @@ -158,7 +177,7 @@ class MockTimers {
yield* iterator;
}

#setTimeoutPromisified(ms, result, options) {
#promisifyTimer({ timerFn, clearFn, ms, result, options }) {
return new Promise((resolve, reject) => {
if (options?.signal) {
try {
Expand All @@ -173,12 +192,12 @@ class MockTimers {
}

const onabort = () => {
this.#clearTimeout(id);
clearFn(id);
return reject(abortIt(options.signal));
};

const id = this.#setTimeout(() => {
return resolve(result || id);
const id = timerFn(() => {
return resolve(result);
}, ms);

if (options?.signal) {
Expand All @@ -192,6 +211,28 @@ class MockTimers {
});
}

#setImmediatePromisified(result, options) {
return this.#promisifyTimer({
__proto__: null,
timerFn: FunctionPrototypeBind(this.#setImmediate, this),
clearFn: FunctionPrototypeBind(this.#clearImmediate, this),
ms: TIMERS_DEFAULT_INTERVAL.setImmediate,
result,
options,
});
}

#setTimeoutPromisified(ms, result, options) {
return this.#promisifyTimer({
__proto__: null,
timerFn: FunctionPrototypeBind(this.#setTimeout, this),
clearFn: FunctionPrototypeBind(this.#clearTimeout, this),
ms,
result,
options,
});
}

#toggleEnableTimers(activate) {
const options = {
__proto__: null,
Expand Down Expand Up @@ -233,6 +274,23 @@ class MockTimers {
this,
);
},
setImmediate: () => {
this.#realSetImmediate = globalThis.setImmediate;
this.#realClearImmediate = globalThis.clearImmediate;
this.#realTimersSetImmediate = nodeTimers.setImmediate;
this.#realTimersClearImmediate = nodeTimers.clearImmediate;

globalThis.setImmediate = this.#setImmediate;
globalThis.clearImmediate = this.#clearImmediate;

nodeTimers.setImmediate = this.#setImmediate;
nodeTimers.clearImmediate = this.#clearImmediate;

nodeTimersPromises.setImmediate = FunctionPrototypeBind(
this.#setImmediatePromisified,
this,
);
},
},
toReal: {
__proto__: null,
Expand All @@ -254,6 +312,15 @@ class MockTimers {

nodeTimersPromises.setInterval = this.#realPromisifiedSetInterval;
},
setImmediate: () => {
globalThis.setImmediate = this.#realSetImmediate;
globalThis.clearImmediate = this.#realClearImmediate;

nodeTimers.setImmediate = this.#realTimersSetImmediate;
nodeTimers.clearImmediate = this.#realTimersClearImmediate;

nodeTimersPromises.setImmediate = this.#realPromisifiedSetImmediate;
},
},
};

Expand Down

0 comments on commit 40e9fcd

Please sign in to comment.