diff --git a/lib/internal/test_runner/mock/mock_timers.js b/lib/internal/test_runner/mock/mock_timers.js index a718bf34d5ba50..7e38f9f7b5113c 100644 --- a/lib/internal/test_runner/mock/mock_timers.js +++ b/lib/internal/test_runner/mock/mock_timers.js @@ -11,6 +11,8 @@ const { DateNow, FunctionPrototypeApply, FunctionPrototypeBind, + ObjectDefineProperty, + ObjectGetOwnPropertyDescriptor, Promise, SymbolAsyncIterator, SymbolDispose, @@ -239,11 +241,7 @@ class MockTimers { toFake: { __proto__: null, setTimeout: () => { - this.#realSetTimeout = globalThis.setTimeout; - this.#realClearTimeout = globalThis.clearTimeout; - this.#realTimersSetTimeout = nodeTimers.setTimeout; - this.#realTimersClearTimeout = nodeTimers.clearTimeout; - this.#realPromisifiedSetTimeout = nodeTimersPromises.setTimeout; + this.#storeOriginalSetTimeout(); globalThis.setTimeout = this.#setTimeout; globalThis.clearTimeout = this.#clearTimeout; @@ -257,11 +255,7 @@ class MockTimers { ); }, setInterval: () => { - this.#realSetInterval = globalThis.setInterval; - this.#realClearInterval = globalThis.clearInterval; - this.#realTimersSetInterval = nodeTimers.setInterval; - this.#realTimersClearInterval = nodeTimers.clearInterval; - this.#realPromisifiedSetInterval = nodeTimersPromises.setInterval; + this.#storeOriginalSetInterval(); globalThis.setInterval = this.#setInterval; globalThis.clearInterval = this.#clearInterval; @@ -275,10 +269,7 @@ class MockTimers { ); }, setImmediate: () => { - this.#realSetImmediate = globalThis.setImmediate; - this.#realClearImmediate = globalThis.clearImmediate; - this.#realTimersSetImmediate = nodeTimers.setImmediate; - this.#realTimersClearImmediate = nodeTimers.clearImmediate; + this.#storeOriginalSetImmediate(); globalThis.setImmediate = this.#setImmediate; globalThis.clearImmediate = this.#clearImmediate; @@ -295,31 +286,13 @@ class MockTimers { toReal: { __proto__: null, setTimeout: () => { - globalThis.setTimeout = this.#realSetTimeout; - globalThis.clearTimeout = this.#realClearTimeout; - - nodeTimers.setTimeout = this.#realTimersSetTimeout; - nodeTimers.clearTimeout = this.#realTimersClearTimeout; - - nodeTimersPromises.setTimeout = this.#realPromisifiedSetTimeout; + this.#restoreOriginalSetTimeout(); }, setInterval: () => { - globalThis.setInterval = this.#realSetInterval; - globalThis.clearInterval = this.#realClearInterval; - - nodeTimers.setInterval = this.#realTimersSetInterval; - nodeTimers.clearInterval = this.#realTimersClearInterval; - - nodeTimersPromises.setInterval = this.#realPromisifiedSetInterval; + this.#restoreOriginalSetInterval(); }, setImmediate: () => { - globalThis.setImmediate = this.#realSetImmediate; - globalThis.clearImmediate = this.#realClearImmediate; - - nodeTimers.setImmediate = this.#realTimersSetImmediate; - nodeTimers.clearImmediate = this.#realTimersClearImmediate; - - nodeTimersPromises.setImmediate = this.#realPromisifiedSetImmediate; + this.#restoreSetImmediate(); }, }, }; @@ -329,6 +302,159 @@ class MockTimers { this.#isEnabled = activate; } + #restoreSetImmediate() { + ObjectDefineProperty( + globalThis, + 'setImmediate', + this.#realSetImmediate, + ); + ObjectDefineProperty( + globalThis, + 'clearImmediate', + this.#realClearImmediate, + ); + ObjectDefineProperty( + nodeTimers, + 'setImmediate', + this.#realTimersSetImmediate, + ); + ObjectDefineProperty( + nodeTimers, + 'clearImmediate', + this.#realTimersClearImmediate, + ); + ObjectDefineProperty( + nodeTimersPromises, + 'setImmediate', + this.#realPromisifiedSetImmediate, + ); + } + + #restoreOriginalSetInterval() { + ObjectDefineProperty( + globalThis, + 'setInterval', + this.#realSetInterval, + ); + ObjectDefineProperty( + globalThis, + 'clearInterval', + this.#realClearInterval, + ); + ObjectDefineProperty( + nodeTimers, + 'setInterval', + this.#realTimersSetInterval, + ); + ObjectDefineProperty( + nodeTimers, + 'clearInterval', + this.#realTimersClearInterval, + ); + ObjectDefineProperty( + nodeTimersPromises, + 'setInterval', + this.#realPromisifiedSetInterval, + ); + } + + #restoreOriginalSetTimeout() { + ObjectDefineProperty( + globalThis, + 'setTimeout', + this.#realSetTimeout, + ); + ObjectDefineProperty( + globalThis, + 'clearTimeout', + this.#realClearTimeout, + ); + ObjectDefineProperty( + nodeTimers, + 'setTimeout', + this.#realSetTimeout, + ); + ObjectDefineProperty( + nodeTimers, + 'clearTimeout', + this.#realTimersClearTimeout, + ); + ObjectDefineProperty( + nodeTimersPromises, + 'setTimeout', + this.#realPromisifiedSetTimeout, + ); + } + + #storeOriginalSetImmediate() { + this.#realSetImmediate = ObjectGetOwnPropertyDescriptor( + globalThis, + 'setImmediate', + ); + this.#realClearImmediate = ObjectGetOwnPropertyDescriptor( + globalThis, + 'clearImmediate', + ); + this.#realTimersSetImmediate = ObjectGetOwnPropertyDescriptor( + nodeTimers, + 'setImmediate', + ); + this.#realTimersClearImmediate = ObjectGetOwnPropertyDescriptor( + nodeTimers, + 'clearImmediate', + ); + this.#realPromisifiedSetImmediate = ObjectGetOwnPropertyDescriptor( + nodeTimersPromises, + 'setImmediate', + ); + } + + #storeOriginalSetInterval() { + this.#realSetInterval = ObjectGetOwnPropertyDescriptor( + globalThis, + 'setInterval', + ); + this.#realClearInterval = ObjectGetOwnPropertyDescriptor( + globalThis, + 'clearInterval', + ); + this.#realTimersSetInterval = ObjectGetOwnPropertyDescriptor( + nodeTimers, + 'setInterval', + ); + this.#realTimersClearInterval = ObjectGetOwnPropertyDescriptor( + nodeTimers, + 'clearInterval', + ); + this.#realPromisifiedSetInterval = ObjectGetOwnPropertyDescriptor( + nodeTimersPromises, + 'setInterval', + ); + } + + #storeOriginalSetTimeout() { + this.#realSetTimeout = ObjectGetOwnPropertyDescriptor( + globalThis, + 'setTimeout', + ); + this.#realClearTimeout = ObjectGetOwnPropertyDescriptor( + globalThis, + 'clearTimeout', + ); + this.#realTimersSetTimeout = ObjectGetOwnPropertyDescriptor( + nodeTimers, + 'setTimeout', + ); + this.#realTimersClearTimeout = ObjectGetOwnPropertyDescriptor( + nodeTimers, + 'clearTimeout', + ); + this.#realPromisifiedSetTimeout = ObjectGetOwnPropertyDescriptor( + nodeTimersPromises, + 'setTimeout', + ); + } + tick(time = 1) { if (!this.#isEnabled) { throw new ERR_INVALID_STATE( diff --git a/test/parallel/test-runner-mock-timers.js b/test/parallel/test-runner-mock-timers.js index 7b37c6ae4b8d74..c740aa3b4958d4 100644 --- a/test/parallel/test-runner-mock-timers.js +++ b/test/parallel/test-runner-mock-timers.js @@ -47,6 +47,52 @@ describe('Mock Timers Test Suite', () => { }); }); + it('should check that propertyDescriptor gets back after reseting timers', (t) => { + const getDescriptor = (ctx, fn) => Object.getOwnPropertyDescriptor(ctx, fn); + const getCurrentTimersDescriptors = () => { + const timers = [ + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'setImmediate', + 'clearImmediate', + ]; + + const globalTimersDescriptors = timers.map((fn) => getDescriptor(global, fn)); + const nodeTimersDescriptors = timers.map((fn) => getDescriptor(nodeTimers, fn)); + const nodeTimersPromisesDescriptors = timers + .filter((fn) => !fn.includes('clear')) + .map((fn) => getDescriptor(nodeTimersPromises, fn)); + + return { + global: globalTimersDescriptors, + nodeTimers: nodeTimersDescriptors, + nodeTimersPromises: nodeTimersPromisesDescriptors, + }; + }; + const before = getCurrentTimersDescriptors(); + t.mock.timers.enable(); + const during = getCurrentTimersDescriptors(); + t.mock.timers.reset(); + const after = getCurrentTimersDescriptors(); + + assert.deepStrictEqual( + before, + after, + ); + + assert.notDeepStrictEqual( + before, + during, + ); + + assert.notDeepStrictEqual( + during, + after, + ); + }); + it('should reset all timers when calling .reset function', (t) => { t.mock.timers.enable(); const fn = t.mock.fn();