17 timers - ranhs/soda-test GitHub Wiki
In some cases you need to test code that depends on the timing of the system. It may check the current date & time or it may schudle something to a later time. When running the tests you don't want to wait the time of the action, or you might want to check timings that are hard to produce.
To be able to manage the time in your test-code you need to define a varible of type SinonFakeTimers and put a decorator on it, named userFakeTimers the decorator have one argument that is the time (as number) you want the fake timer to have. this value will be return by Date.now(). If no argument is pass, it set the value to 0.
@useFakeTimers(1000)
clock: SinonFakeTimers
This variable may be an argument to test-step method, or a member variable in a context, or global. The effect will start for each test-step in the scope idependatly.
Use the method tick on SinonFakeTimers to advance the time by specific number of miniseconds. Note that the time will not advance by itself.
@it('Fake timers affect on Date.now() sample')
sampleTimerTest(@useFakeTiemrs(1000) clock: SinonFakeTimers): TR {
expect(Date.now()).to.equal(1000)
clock.tick(501)
expect(Date.now()).to.equal(1501)
}
If the code you are testing is using timeouts, you can use this feature to simulate it. However calling tick method by itself will not have a chance to run the timeout-callback code, even if the fake time is right. To allow this callback to be called you need yeild the test-code, this can be done by calling atick instead of tick and await on its return value
This is a simple implementation of a sleep method:
function sleep(msec: number): Promise<void> {
return new Promise<void>( (resolve) => {
setTimeout( resolve, msec )
})
}
The following code tests it, using fake-timers:
@useFakeTimers()
clock: SinonFakeTimers
@it('sleep for 500ms')
async sleep1(): PTR {
let timeoutPass = false
let method = async () => {
await sleep(500)
timeoutPass = true
}
method() // don't use await, or this will stack forever
expect(timeoutPass).to.be.false
await this.clock.atick(499)
expect(timeoutPass).to.be.false
await this.clock.atick(1)
expect(timeoutPass).to.be.true
}
The above test doesn't take much time, alough it use sleep(500), becouse it fakes the advance of the clock.
When methos is called, the calls returns immediatly, but its call is stuck in the sleep method.
Calling this.clock.atick() and awaiting on it, returns immediatly, but yeilds, so other codes may run. On the first time the timeout was not expired, because it set to 500ms and the fake timer only advanced 499ms. On the second time the fake-timer is set to 500ms, and the timeout was expired, and the code after the await sleep(500) is executing setting timeoutPass to true, so the test passes.