-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add automatic time advance for fake timers #10602
Comments
Potential workaround: +// Automatically advance simulated time
+setInterval(() => {
+ jest.advanceTimersByTime(20);
+}, 20);
jest.useFakeTimers('modern'); This is based on Sinon's description of the functionality:
Automatic advancement of simulated time seems like a general requirement whenever precise timeout intervals are an implementation detail. In such cases, developers won't want to hard-code progression instructions into their tests. |
I wanted to bring up two more use-cases where automatically advanced timers would be super-handy. The first use-case is for-await syntax. Imagine you need to test an async generator, e.g. /**
* Returns a promise resolving to 42 after a user-provided timeout.
*/
const timer = (duration: number) =>
new Promise((resolve) => {
setTimeout(() => resolve(42), duration);
});
/**
* Async generator that we need to test.
*/
async function* asyncIterable() {
const result = await timer(500);
yield result;
} If you write a test like for await (const value of asyncIterable()) {
// advance timers and make assertions
} this is not going to work: you need to advance timers after the promise returned by the iterator was created, but before awaiting on it, and for-await syntax doesn't let you do that. The second use-case is a library I've written that lets you create Jest snapshots of log messages. These messages include time deltas, so when you write tests you don't have to advance timers by a specific amount of time. Here's an example: import { getMessages, log } from '1log';
/**
* The function that we'll be testing, same as the one used in previous example.
*/
const timer = (duration: number) =>
new Promise((resolve) => {
setTimeout(() => resolve(42), duration);
});
test('timer', async () => {
// Wrapping an expression in `log` has no effect other than creating some log messages.
const promise = log(timer(500));
jest.runAllTimers();
await promise;
// `getMessages` retrieves log messages.
expect(getMessages()).toMatchInlineSnapshot(`
[create 1] +0ms Promise {}
[create 1] [resolve] +500ms 42
`);
}); With auto-advanced timers, the first three lines of code in the test function would become just await log(timer(500)); |
The workaround I'm currently using is enclosing async tests in import { setImmediate } from 'timers';
const autoAdvanceTimers = <Result>(
callback: () => Promise<Result>,
) => async () => {
const promise = callback();
let resolved = false;
promise.then(() => {
resolved = true;
});
while (!resolved) {
await new Promise(setImmediate);
if (jest.getTimerCount() === 0) {
break;
}
jest.advanceTimersToNextTimer();
}
return await promise;
}; |
this is causing this error for me: ReferenceError: You are trying to access a property or method of the Jest environment after it has been torn down. |
I'd like to add some way of turning |
On the surface, I sort of expected that the Any reason why it would be a bad idea to just pass-thru the config like that? (i.e. |
Nope, PR welcome! 🙂 |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
🚀 Feature Proposal
When using the fake timers, there should be an option to advance time automatically. An example of this can be seen In @sinonjs/fake-timers where you can set the system time to a particular time stamp and also have the clock advance naturally:
const clock = FakeTimers.install({ now: 1601488969000, shouldAdvanceTime: true });
Motivation
For my particular use case, I have a saved json object that was the result of running some ETL (extract, transform, load) code on a certain date. Within this json object is a field "DaysSinceCreated" that has a static value, let's say for this example 30. For my test, I want in the end to match this saved json object with the output of the ETL code. The ETL code makes use of a bottleneck library to schedule the API calls to extract the initial data, therefore relying on timers to work correctly. I want to be able to change the "current" date, as to always produce a "DaysSinceCreated" value of 30 no matter when the test is run, but also have the timers progress without having to manually trigger them.
Example
Example described above ^^
Pitch
This feature belongs in jest as it will allow users to write their tests to run on a different "current time" AND have timers progress naturally without having to directly include @sinonjs/fake-timers.
The text was updated successfully, but these errors were encountered: