Last active
September 10, 2020 16:56
-
-
Save groupsky/28446ef02590043f78a53eaea99256de to your computer and use it in GitHub Desktop.
Allow to manually trigger specific timers
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
import MockTimer from './MockTimer.js' | |
const timer1 = new MockTimer(100) | |
const timer2 = new MockTimer(200) | |
// timeout are numbers and can be compared | |
assert(timer1.timeout > 0) | |
// and computed | |
assert(timer1.timeout + 1 > timer1.timeout) | |
const calls = [] | |
setTimeout(() => calls.push('A'), timer1.timeout) | |
const timerB = setTimeout(() => calls.push('B'), timer2.timeout) | |
setTimeout(() => calls.push('C'), 100) | |
// lets wait for all timers to expire | |
await new Promise(resolve => setTimeout(resolve, 200)) | |
// only the timer that is not using the mocked number fired | |
assert(calls.join() === 'C') | |
// at any time it can be triggered | |
timer1.trigger() | |
assert(calls.join() === 'C,A') | |
// or cleared the regular way | |
clearTimeout(timerB) | |
timer2.trigger() | |
assert(calls.join() === 'C,A') |
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
import { act } from 'react-dom/test-utils' | |
class UniqueNumber extends Number {} | |
/** | |
* Mock specific timer and allow the others to passthrough normally | |
*/ | |
export default class MockTimer { | |
/** | |
* timeout value to pass to setTimeout as second parameter | |
* @type (Number) | |
*/ | |
timeout | |
pending = [] | |
constructor (timeout = 9999) { | |
timeout = new UniqueNumber(timeout) | |
// scope to the instance for faster check | |
class ClearTimeout { | |
constructor (fn) { this.fn = fn } | |
} | |
global.setTimeout = ((setTimeout) => (fn, tm) => { | |
if (tm !== this.timeout) { | |
return setTimeout(fn, this.timeout) | |
} | |
this.pending.push(fn) | |
return new ClearTimeout(fn) | |
})(global.setTimeout) | |
global.clearTimeout = (clearTimeout) => (h) => { | |
if (!(h instanceof ClearTimeout)) { | |
return clearTimeout(h) | |
} | |
const idx = this.pending.indexOf(h.fn) | |
if (idx === -1) { | |
throw new Error('multiple calls to clearTimeout with same handle') | |
} | |
this.pending.splice(idx, 1) | |
} | |
} | |
/** | |
* Trigger the last pending callback | |
* @return {Promise<void>} | |
*/ | |
async trigger () { | |
await act(async () => { | |
const fn = this.pending.pop() | |
if (fn == null) { | |
throw new Error('no pending timers') | |
} | |
fn() | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment