-
Notifications
You must be signed in to change notification settings - Fork 30.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test_runner: add initial draft for fakeTimers
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
- Loading branch information
1 parent
b31d587
commit 568ad96
Showing
4 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
'use strict'; | ||
|
||
const { | ||
DateNow, | ||
SafeMap, | ||
Symbol, | ||
globalThis, | ||
} = primordials; | ||
|
||
class Timers { | ||
constructor() { | ||
this.timers = new SafeMap(); | ||
|
||
this.setTimeout = this.#createTimer.bind(this, false); | ||
this.clearTimeout = this.#clearTimer.bind(this); | ||
this.setInterval = this.#createTimer.bind(this, true); | ||
this.clearInterval = this.#clearTimer.bind(this); | ||
} | ||
|
||
#createTimer(isInterval, callback, delay, ...args) { | ||
const timerId = Symbol('kTimerId'); | ||
const timer = { | ||
id: timerId, | ||
callback, | ||
time: DateNow() + delay, | ||
interval: isInterval, | ||
args, | ||
}; | ||
this.timers.set(timerId, timer); | ||
return timerId; | ||
} | ||
|
||
#clearTimer(timerId) { | ||
this.timers.delete(timerId); | ||
} | ||
|
||
} | ||
|
||
let realSetTimeout; | ||
let realClearTimeout; | ||
let realSetInterval; | ||
let realClearInterval; | ||
|
||
class FakeTimers { | ||
constructor() { | ||
this.fakeTimers = {}; | ||
this.isEnabled = false; | ||
this.now = DateNow(); | ||
} | ||
|
||
tick(time = 0) { | ||
|
||
// if (!this.isEnabled) { | ||
// throw new Error('you should enable fakeTimers first by calling the .enable function'); | ||
// } | ||
|
||
this.now += time; | ||
const timers = this.fakeTimers.timers; | ||
|
||
for (const timer of timers.values()) { | ||
|
||
if (!(this.now >= timer.time)) continue; | ||
|
||
timer.callback(...timer.args); | ||
if (timer.interval) { | ||
timer.time = this.now + (timer.time - this.now) % timer.args[0]; | ||
continue; | ||
} | ||
|
||
timers.delete(timer.id); | ||
} | ||
} | ||
|
||
enable() { | ||
// if (this.isEnabled) { | ||
// throw new Error('fakeTimers is already enabled!'); | ||
// } | ||
this.now = DateNow(); | ||
this.isEnabled = true; | ||
this.fakeTimers = new Timers(); | ||
|
||
realSetTimeout = globalThis.setTimeout; | ||
realClearTimeout = globalThis.clearTimeout; | ||
realSetInterval = globalThis.setInterval; | ||
realClearInterval = globalThis.clearInterval; | ||
|
||
globalThis.setTimeout = this.fakeTimers.setTimeout; | ||
globalThis.clearTimeout = this.fakeTimers.clearTimeout; | ||
globalThis.setInterval = this.fakeTimers.setInterval; | ||
globalThis.clearInterval = this.fakeTimers.clearInterval; | ||
|
||
} | ||
|
||
reset() { | ||
this.isEnabled = false; | ||
this.fakeTimers = {}; | ||
|
||
// Restore the real timer functions | ||
globalThis.setTimeout = realSetTimeout; | ||
globalThis.clearTimeout = realClearTimeout; | ||
globalThis.setInterval = realSetInterval; | ||
globalThis.clearInterval = realClearInterval; | ||
} | ||
|
||
releaseAllTimers() { | ||
|
||
} | ||
} | ||
|
||
module.exports = { FakeTimers }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
'use strict'; | ||
const common = require('../common'); | ||
process.env.NODE_TEST_KNOWN_GLOBALS = 0; | ||
|
||
const assert = require('node:assert'); | ||
const { fakeTimers, it, mock, afterEach, describe } = require('node:test'); | ||
describe('Faketimers Test Suite', () => { | ||
|
||
describe('setTimeout Suite', () => { | ||
afterEach(() => fakeTimers.reset()); | ||
|
||
it('should advance in time and trigger timers when calling the .tick function', (t) => { | ||
fakeTimers.enable(); | ||
|
||
const fn = mock.fn(() => {}); | ||
|
||
global.setTimeout(fn, 4000); | ||
|
||
fakeTimers.tick(4000); | ||
assert.ok(fn.mock.callCount()); | ||
}); | ||
|
||
it('should advance in time and trigger timers when calling the .tick function multiple times', (t) => { | ||
fakeTimers.enable(); | ||
const fn = mock.fn(); | ||
|
||
global.setTimeout(fn, 2000); | ||
|
||
fakeTimers.tick(1000); | ||
fakeTimers.tick(1000); | ||
|
||
assert.strictEqual(fn.mock.callCount(), 1); | ||
}); | ||
|
||
it('should keep setTimeout working if fakeTimers are disabled', (t, done) => { | ||
const now = Date.now(); | ||
const timeout = 2; | ||
const expected = () => now - timeout; | ||
global.setTimeout(common.mustCall(() => { | ||
assert.strictEqual(now - timeout, expected()); | ||
done(); | ||
}), timeout); | ||
}); | ||
|
||
}); | ||
}); |