Files
cypress/packages/runner/injection/timers.js
T
Chris Breiding 77b922472c fix: Improve uncaught error handling (#14826)
Co-authored-by: Chris Breiding <chrisbreiding@gmail.com>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
2021-03-01 09:23:14 -05:00

122 lines
2.7 KiB
JavaScript

export const createTimers = () => {
let paused
let flushing
let timerQueue
let canceledTimerIds
const reset = () => {
paused = false
flushing = false
timerQueue = []
canceledTimerIds = {}
}
const invoke = (fnOrCode, params = []) => {
if (typeof fnOrCode === 'function') {
return fnOrCode.apply(window, params)
}
return window.eval(fnOrCode)
}
const flushTimerQueue = () => {
flushing = true
timerQueue.forEach((timer) => {
const { timerId, type, fnOrCode, params } = timer
// if we are a setInterval and we're been canceled
// then just return. this can happen when a setInterval
// queues many callbacks, and from within that callback
// we would have canceled the original setInterval
if (type === 'setInterval' && canceledTimerIds[timerId]) {
return
}
invoke(fnOrCode, params)
})
reset()
}
const pause = (shouldPause) => {
paused = Boolean(shouldPause)
if (!paused) {
flushTimerQueue()
}
}
const wrap = () => {
const originals = {
setTimeout: window.setTimeout,
setInterval: window.setInterval,
requestAnimationFrame: window.requestAnimationFrame,
clearTimeout: window.clearTimeout,
clearInterval: window.clearInterval,
}
const callThrough = (fnName, args) => {
return originals[fnName].apply(window, args)
}
const wrapCancel = (fnName) => {
return (timerId) => {
if (flushing) {
canceledTimerIds[timerId] = true
}
return callThrough(fnName, [timerId])
}
}
const wrapTimer = (fnName) => {
return (...args) => {
let timerId
let [fnOrCode, delay, ...params] = args
const timerOverride = (...params) => {
// if we're currently paused then we need
// to enqueue this timer callback and invoke
// it immediately once we're unpaused
if (paused) {
timerQueue.push({
timerId,
fnOrCode,
params,
type: fnName,
})
return
}
// else go ahead and invoke the real function
// the same way the browser otherwise would
return invoke(fnOrCode, params)
}
timerId = callThrough(fnName, [timerOverride, delay, ...params])
return timerId
}
}
window.setTimeout = wrapTimer('setTimeout')
window.setInterval = wrapTimer('setInterval')
window.requestAnimationFrame = wrapTimer('requestAnimationFrame')
window.clearTimeout = wrapCancel('clearTimeout')
window.clearInterval = wrapCancel('clearInterval')
}
// start with initial values
reset()
return {
wrap,
reset,
pause,
}
}