Repository navigation
node test mock timer promisified setTimeout & setInterval don't always return the specified value #50307
Description
Activity
For setTimeoutPromisified:
To ensure that the specified value is returned, even if it's falsy, we can modify the line to check if result is 'undefined':
return resolve(result !== undefined ? result : id);For setIntervalPromisified:
startTime += interval;
This increments the startTime by the interval, causing the value to change. To maintain the original value passed to setInterval, we can store it and return it instead of the incremented startTime.So, first we can store the original value like:
const originalValue = startTime;Then, in the callback, emit the originalValue instead of the incremented startTime:
emitter.emit('data', originalValue);For setTimeoutPromisified:
To ensure that the specified value is returned, even if it's falsy, we can modify the line to check if result is 'undefined':
return resolve(result !== undefined ? result : id);Disagree. It should always return the same value the the original
setTimeoutreturns. So forundefined, it should also returnundefined.For setIntervalPromisified:
startTime += interval;This increments the startTime by the interval, causing the value to change. To maintain the original value passed to setInterval, we can store it and return it instead of the incremented startTime.So, first we can store the original value like:
const originalValue = startTime;Then, in the callback, emit the originalValue instead of the incremented startTime:
emitter.emit('data', originalValue);That would work.
I don't know what the original intention behind returning these other values was. If they are not needed, I'd just remove them completely. If they are needed for some reason, they need to be communicated in some other way...
- addedconfirmed-bugIssues and PRs for confirmed bugs.Issues and PRs for confirmed bugs.test_runnerIssues and PRs related to the test runner subsystem.Issues and PRs related to the test runner subsystem.
on Oct 22, 2023 This seems like a pretty straightforward bug @nodejs/test_runner @ErickWendel where we should check if result is passed instead of using
||.Your report and diagnosis seems correct @mika-fischer thank you for opening a good report.
Would you be interested in opening a PR to align
setTimeoutpromisified with the non faked version?For setTimeoutPromisified:
To ensure that the specified value is returned, even if it's falsy, we can modify the line to check if result is 'undefined':
return resolve(result !== undefined ? result : id);For setIntervalPromisified:
startTime += interval;This increments the startTime by the interval, causing the value to change. To maintain the original value passed to setInterval, we can store it and return it instead of the incremented startTime.So, first we can store the original value like:
const originalValue = startTime;Then, in the callback, emit the originalValue instead of the incremented startTime:
emitter.emit('data', originalValue);Should we use
return resolve(result);and what do you think about setIntervalPromisified ? @benjamingrThat the fakes should all return the same types of results as the originals (even though I personally don't like these overloads) - the whole point of fake timers is that they match the originals.
Would you be interested in opening a PR to align
setTimeoutpromisified with the non faked version?Yes, I can do a PR tomorrow.
Reacted by Benjamin GruenbaumSee #50331
Turns out setTimeout was already fixed in main
For completeness, the setTimeout issue was already fixed here
- linked a pull request that will close this issuetest_runner: Fix mock timer promisified setInterval return value #50331
on Oct 25, 2023
Version
v20.5.1
Platform
Microsoft Windows NT 10.0.22621.0 x64
Subsystem
test
What steps will reproduce the bug?
Mocked promisified
setTimeout&setIntervaldon't return falsy values, and instead return numbers.The reason for
setTimeoutis here. It works correctly for truthy values, but returns an id for falsy values.setIntervalcompletely captures the value parameter for its own purposes so that it never resturns the value given tosetInterval(see here).fails with
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior? Why is that the expected behavior?
The mocked functions should return the value specified by the caller.
What do you see instead?
The mocked functions (sometimes) return something else.
Additional information
No response