Как ускорить время с помощью поддельных таймеров Sinon? (например, при переключении вкладок и возвращении позже)
На основе Синон
Как мы делаем это?
Например, когда мы переключаем вкладки, циклы requestAnimationFrame не продолжают работать. Когда мы переключимся назад, requestAnimationFrame запустится снова, но в первом кадре после переключения назад будет время, которое продвинулось вперед (перескочило) на большую величину по сравнению с обычным запуском.
Синон
Как нам пропустить (перепрыгнуть), скажем, 1 минуту, не запуская кадров, чтобы поведение было такое, как будто мы переключили вкладки и вернулись обратно?
1 ответ
Я не думаю, что Sinon Fake Timers сможет это сделать. Вот индивидуальное решение:
function customFakeTimers() {
let time = Date.now();
const OriginalDate = globalThis.Date;
const originalRAF = globalThis.requestAnimationFrame;
const originalCancelRAF = globalThis.cancelAnimationFrame;
globalThis.Date = class Date {
static now() { return time; }
// Good enough for my cases.
getUTCHours() { return 0; }
getUTCMinutes() { return 1; }
getUTCSeconds() { return 5; }
};
/** @type {Map<number, FrameRequestCallback>} */
const frameFns = new Map;
let frameId = 0;
/**
* @param deltaTime - Emulate 60fps by default (16.666ms per frame).
* Provide a custom value to make rAF skip a particular amount of time,
* for example to emulate a tab switch and returning to a tab in which
* case a lot more time than normal would pass since the last frame.
*/
async function toNextFrame(deltaTime = 16.6666) {
const currentFrames = new Set(frameFns.values());
frameFns.clear();
await new Promise((r) => setTimeout(r, 0));
time += deltaTime;
for (const fn of currentFrames) { fn(time); }
await new Promise((r) => setTimeout(r, 0));
}
/** @param {FrameRequestCallback} fn */
globalThis.requestAnimationFrame = (fn) => {
frameId++;
frameFns.set(frameId, fn);
return frameId;
};
/** @param {number} id */
globalThis.cancelAnimationFrame = (id) => frameFns.delete(id);
return {
toNextFrame,
undoCustomFakeTimers() {
globalThis.Date = OriginalDate;
globalThis.requestAnimationFrame = originalRAF;
globalThis.cancelAnimationFrame = originalCancelRAF;
},
};
}
Чтобы использовать его,
const {toNextFrame, undoCustomFakeTimers} = customFakeTimers()
// ...
await toNextFrame(5000) // jump 5 seconds, as if we switched tabs and came back 5 seconds later
// ... when done,
undoCustomFakeTimers()