Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions packages/core/src/shared/utilities/timeoutUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,34 @@ export class Timeout {
}
}

export class Interval {
private _setCompleted: (() => void) | undefined
private _nextCompletion: Promise<void>
private ref: NodeJS.Timer | number | undefined

constructor(intervalMillis: number, onCompletion: () => Promise<void>) {
this._nextCompletion = new Promise<void>((resolve) => {
this._setCompleted = () => resolve()
})
this.ref = globals.clock.setInterval(async () => {
await onCompletion()
this._setCompleted!()
this._nextCompletion = new Promise<void>((resolve) => {
this._setCompleted = () => resolve()
})
}, intervalMillis)
}

/** Allows to wait for the next interval to finish running */
public async nextCompletion() {
await this._nextCompletion
}

public dispose() {
globals.clock.clearInterval(this.ref)
}
}

interface WaitUntilOptions {
/** Timeout in ms (default: 5000) */
readonly timeout?: number
Expand Down
54 changes: 54 additions & 0 deletions packages/core/src/test/shared/utilities/timeoutUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,29 @@ import * as FakeTimers from '@sinonjs/fake-timers'
import * as timeoutUtils from '../../../shared/utilities/timeoutUtils'
import { installFakeClock, tickPromise } from '../../../test/testUtil'
import { sleep } from '../../../shared/utilities/timeoutUtils'
import { SinonStub, SinonSandbox, createSandbox } from 'sinon'

// We export this describe() so it can be used in the web tests as well
export const timeoutUtilsDescribe = describe('timeoutUtils', async function () {
let clock: FakeTimers.InstalledClock
let sandbox: SinonSandbox

before(function () {
clock = installFakeClock()
})

beforeEach(function () {
sandbox = createSandbox()
})

after(function () {
clock.uninstall()
})

afterEach(function () {
clock.reset()
this.timer?.dispose()
sandbox.restore()
})

describe('Timeout', async function () {
Expand Down Expand Up @@ -192,6 +199,53 @@ export const timeoutUtilsDescribe = describe('timeoutUtils', async function () {
})
})

describe('Interval', async function () {
let interval: timeoutUtils.Interval
let onCompletionStub: SinonStub

beforeEach(async function () {
onCompletionStub = sandbox.stub()
interval = new timeoutUtils.Interval(1000, onCompletionStub)
})

afterEach(async function () {
interval?.dispose()
})

it('Executes the callback on an interval', async function () {
await clock.tickAsync(999)
assert.strictEqual(onCompletionStub.callCount, 0)
await clock.tickAsync(1)
assert.strictEqual(onCompletionStub.callCount, 1)

await clock.tickAsync(500)
assert.strictEqual(onCompletionStub.callCount, 1)
await clock.tickAsync(500)
assert.strictEqual(onCompletionStub.callCount, 2)

await clock.tickAsync(1000)
assert.strictEqual(onCompletionStub.callCount, 3)
})

it('allows to wait for next completion', async function () {
clock.uninstall()

let curr = 'Did Not Change'

const realInterval = new timeoutUtils.Interval(50, async () => {
await sleep(50)
curr = 'Did Change'
})

const withoutWait = curr
await realInterval.nextCompletion()
const withWait = curr

assert.strictEqual(withoutWait, 'Did Not Change')
assert.strictEqual(withWait, 'Did Change')
})
})

describe('waitUntil', async function () {
const testSettings = {
callCounter: 0,
Expand Down
Loading