Skip to content

Commit 69ee56a

Browse files
ErickWendeladuh95
authored andcommitted
test_runner: add support for scheduler.wait on mock timers
This adds support for nodetimers.promises.scheduler.wait on Mocktimers Refs: #55244 PR-URL: #55244 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
1 parent 22d7777 commit 69ee56a

File tree

2 files changed

+157
-12
lines changed

2 files changed

+157
-12
lines changed

lib/internal/test_runner/mock/mock_timers.js

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ function abortIt(signal) {
6464
}
6565

6666
/**
67-
* @enum {('setTimeout'|'setInterval'|'setImmediate'|'Date')[]} Supported timers
67+
* @enum {('setTimeout'|'setInterval'|'setImmediate'|'Date', 'scheduler.wait')[]} Supported timers
6868
*/
69-
const SUPPORTED_APIS = ['setTimeout', 'setInterval', 'setImmediate', 'Date'];
69+
const SUPPORTED_APIS = ['setTimeout', 'setInterval', 'setImmediate', 'Date', 'scheduler.wait'];
7070
const TIMERS_DEFAULT_INTERVAL = {
7171
__proto__: null,
7272
setImmediate: -1,
@@ -108,6 +108,7 @@ class MockTimers {
108108

109109
#realPromisifiedSetTimeout;
110110
#realPromisifiedSetInterval;
111+
#realTimersPromisifiedSchedulerWait;
111112

112113
#realTimersSetTimeout;
113114
#realTimersClearTimeout;
@@ -192,6 +193,13 @@ class MockTimers {
192193
);
193194
}
194195

196+
#restoreOriginalSchedulerWait() {
197+
nodeTimersPromises.scheduler.wait = FunctionPrototypeBind(
198+
this.#realTimersPromisifiedSchedulerWait,
199+
this,
200+
);
201+
}
202+
195203
#restoreOriginalSetTimeout() {
196204
ObjectDefineProperty(
197205
globalThis,
@@ -266,6 +274,14 @@ class MockTimers {
266274
);
267275
}
268276

277+
#storeOriginalSchedulerWait() {
278+
279+
this.#realTimersPromisifiedSchedulerWait = FunctionPrototypeBind(
280+
nodeTimersPromises.scheduler.wait,
281+
this,
282+
);
283+
}
284+
269285
#storeOriginalSetTimeout() {
270286
this.#realSetTimeout = ObjectGetOwnPropertyDescriptor(
271287
globalThis,
@@ -562,8 +578,14 @@ class MockTimers {
562578
const options = {
563579
__proto__: null,
564580
toFake: {
565-
__proto__: null,
566-
setTimeout: () => {
581+
'__proto__': null,
582+
'scheduler.wait': () => {
583+
this.#storeOriginalSchedulerWait();
584+
585+
nodeTimersPromises.scheduler.wait = (delay, options) =>
586+
this.#setTimeoutPromisified(delay, undefined, options);
587+
},
588+
'setTimeout': () => {
567589
this.#storeOriginalSetTimeout();
568590

569591
globalThis.setTimeout = this.#setTimeout;
@@ -577,7 +599,7 @@ class MockTimers {
577599
this,
578600
);
579601
},
580-
setInterval: () => {
602+
'setInterval': () => {
581603
this.#storeOriginalSetInterval();
582604

583605
globalThis.setInterval = this.#setInterval;
@@ -591,7 +613,7 @@ class MockTimers {
591613
this,
592614
);
593615
},
594-
setImmediate: () => {
616+
'setImmediate': () => {
595617
this.#storeOriginalSetImmediate();
596618

597619
// setImmediate functions needs to bind MockTimers
@@ -615,23 +637,26 @@ class MockTimers {
615637
this,
616638
);
617639
},
618-
Date: () => {
640+
'Date': () => {
619641
this.#nativeDateDescriptor = ObjectGetOwnPropertyDescriptor(globalThis, 'Date');
620642
globalThis.Date = this.#createDate();
621643
},
622644
},
623645
toReal: {
624-
__proto__: null,
625-
setTimeout: () => {
646+
'__proto__': null,
647+
'scheduler.wait': () => {
648+
this.#restoreOriginalSchedulerWait();
649+
},
650+
'setTimeout': () => {
626651
this.#restoreOriginalSetTimeout();
627652
},
628-
setInterval: () => {
653+
'setInterval': () => {
629654
this.#restoreOriginalSetInterval();
630655
},
631-
setImmediate: () => {
656+
'setImmediate': () => {
632657
this.#restoreSetImmediate();
633658
},
634-
Date: () => {
659+
'Date': () => {
635660
ObjectDefineProperty(globalThis, 'Date', this.#nativeDateDescriptor);
636661
},
637662
},

test/parallel/test-runner-mock-timers.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,126 @@ describe('Mock Timers Test Suite', () => {
791791
});
792792
});
793793

794+
describe('scheduler Suite', () => {
795+
describe('scheduler.wait', () => {
796+
it('should advance in time and trigger timers when calling the .tick function', (t) => {
797+
t.mock.timers.enable({ apis: ['scheduler.wait'] });
798+
799+
const now = Date.now();
800+
const durationAtMost = 100;
801+
802+
const p = nodeTimersPromises.scheduler.wait(4000);
803+
t.mock.timers.tick(4000);
804+
805+
return p.then(common.mustCall((result) => {
806+
assert.strictEqual(result, undefined);
807+
assert.ok(
808+
Date.now() - now < durationAtMost,
809+
`time should be advanced less than the ${durationAtMost}ms`
810+
);
811+
}));
812+
});
813+
814+
it('should advance in time and trigger timers when calling the .tick function multiple times', async (t) => {
815+
t.mock.timers.enable({ apis: ['scheduler.wait'] });
816+
817+
const fn = t.mock.fn();
818+
819+
nodeTimersPromises.scheduler.wait(9999).then(fn);
820+
821+
t.mock.timers.tick(8999);
822+
assert.strictEqual(fn.mock.callCount(), 0);
823+
t.mock.timers.tick(500);
824+
825+
await nodeTimersPromises.setImmediate();
826+
827+
assert.strictEqual(fn.mock.callCount(), 0);
828+
t.mock.timers.tick(500);
829+
830+
await nodeTimersPromises.setImmediate();
831+
assert.strictEqual(fn.mock.callCount(), 1);
832+
});
833+
834+
it('should work with the same params as the original timers/promises/scheduler.wait', async (t) => {
835+
t.mock.timers.enable({ apis: ['scheduler.wait'] });
836+
const controller = new AbortController();
837+
const p = nodeTimersPromises.scheduler.wait(2000, {
838+
ref: true,
839+
signal: controller.signal,
840+
});
841+
842+
t.mock.timers.tick(1000);
843+
t.mock.timers.tick(500);
844+
t.mock.timers.tick(500);
845+
t.mock.timers.tick(500);
846+
847+
const result = await p;
848+
assert.strictEqual(result, undefined);
849+
});
850+
851+
it('should abort operation if timers/promises/scheduler.wait received an aborted signal', async (t) => {
852+
t.mock.timers.enable({ apis: ['scheduler.wait'] });
853+
const controller = new AbortController();
854+
const p = nodeTimersPromises.scheduler.wait(2000, {
855+
ref: true,
856+
signal: controller.signal,
857+
});
858+
859+
t.mock.timers.tick(1000);
860+
controller.abort();
861+
t.mock.timers.tick(500);
862+
t.mock.timers.tick(500);
863+
t.mock.timers.tick(500);
864+
865+
await assert.rejects(() => p, {
866+
name: 'AbortError',
867+
});
868+
});
869+
it('should abort operation even if the .tick was not called', async (t) => {
870+
t.mock.timers.enable({ apis: ['scheduler.wait'] });
871+
const controller = new AbortController();
872+
const p = nodeTimersPromises.scheduler.wait(2000, {
873+
ref: true,
874+
signal: controller.signal,
875+
});
876+
877+
controller.abort();
878+
879+
await assert.rejects(() => p, {
880+
name: 'AbortError',
881+
});
882+
});
883+
884+
it('should abort operation when .abort is called before calling setInterval', async (t) => {
885+
t.mock.timers.enable({ apis: ['scheduler.wait'] });
886+
const controller = new AbortController();
887+
controller.abort();
888+
const p = nodeTimersPromises.scheduler.wait(2000, {
889+
ref: true,
890+
signal: controller.signal,
891+
});
892+
893+
await assert.rejects(() => p, {
894+
name: 'AbortError',
895+
});
896+
});
897+
898+
it('should reject given an an invalid signal instance', async (t) => {
899+
t.mock.timers.enable({ apis: ['scheduler.wait'] });
900+
const p = nodeTimersPromises.scheduler.wait(2000, {
901+
ref: true,
902+
signal: {},
903+
});
904+
905+
await assert.rejects(() => p, {
906+
name: 'TypeError',
907+
code: 'ERR_INVALID_ARG_TYPE',
908+
});
909+
});
910+
911+
});
912+
});
913+
794914
describe('Date Suite', () => {
795915
it('should return the initial UNIX epoch if not specified', (t) => {
796916
t.mock.timers.enable({ apis: ['Date'] });

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy