Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add runAllTimersAsync from sinonjs #2209

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 65 additions & 0 deletions docs/api/index.md
Expand Up @@ -2553,6 +2553,19 @@ Vitest provides utility functions to help you out through it's **vi** helper. Yo
vi.advanceTimersByTime(150)
```

### vi.advanceTimersByTimeAsync

- **Type:** `(ms: number) => Promise<Vitest>`

Works just like `runAllTimersAsync`, but will end after passed milliseconds. This will include asynchronously set timers. For example this will log `1, 2, 3` and will not throw:

```ts
let i = 0
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50)

await vi.advanceTimersByTimeAsync(150)
```

### vi.advanceTimersToNextTimer

- **Type:** `() => Vitest`
Expand All @@ -2568,6 +2581,21 @@ Vitest provides utility functions to help you out through it's **vi** helper. Yo
.advanceTimersToNextTimer() // log 3
```

### vi.advanceTimersToNextTimerAsync

- **Type:** `() => Promise<Vitest>`

Will call next available timer even if it was set asynchronously. Useful to make assertions between each timer call. You can chain call it to manage timers by yourself.

```ts
let i = 0
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50)

vi.advanceTimersToNextTimerAsync() // log 1
.advanceTimersToNextTimerAsync() // log 2
.advanceTimersToNextTimerAsync() // log 3
```

### vi.getTimerCount

- **Type:** `() => number`
Expand Down Expand Up @@ -2984,6 +3012,21 @@ IntersectionObserver === undefined
vi.runAllTimers()
```

### vi.runAllTimersAsync

- **Type:** `() => Promise<Vitest>`

This method will asynchronously invoke every initiated timer until the timers queue is empty. It means that every timer called during `runAllTimersAsync` will be fired even asynchronous timers. If you have an infinite interval,
it will throw after 10 000 tries. For example this will log `result`:

```ts
setTimeout(async () => {
console.log(await Promise.resolve('result'))
}, 100)

await vi.runAllTimersAsync()
```

### vi.runOnlyPendingTimers

- **Type:** `() => Vitest`
Expand All @@ -2997,6 +3040,28 @@ IntersectionObserver === undefined
vi.runOnlyPendingTimers()
```

### vi.runOnlyPendingTimersAsync

- **Type:** `() => Promise<Vitest>`

This method will asynchronously call every timer that was initiated after `vi.useFakeTimers()` call, even asynchronous ones. It will not fire any timer that was initiated during its call. For example this will log `2, 3, 3, 1`:

```ts
setTimeout(() => {
console.log(1)
}, 100)
setTimeout(() => {
Promise.resolve().then(() => {
console.log(2)
setInterval(() => {
console.log(3)
}, 40)
})
}, 10)

await vi.runOnlyPendingTimersAsync()
```

### vi.setSystemTime

- **Type**: `(date: string | number | Date) => void`
Expand Down
28 changes: 28 additions & 0 deletions packages/vitest/src/integrations/mock/timers.ts
Expand Up @@ -52,11 +52,21 @@ export class FakeTimers {
this._clock.runAll()
}

async runAllTimersAsync(): Promise<void> {
if (this._checkFakeTimers())
await this._clock.runAllAsync()
}

runOnlyPendingTimers(): void {
if (this._checkFakeTimers())
this._clock.runToLast()
}

async runOnlyPendingTimersAsync(): Promise<void> {
if (this._checkFakeTimers())
await this._clock.runToLastAsync()
}

advanceTimersToNextTimer(steps = 1): void {
if (this._checkFakeTimers()) {
for (let i = steps; i > 0; i--) {
Expand All @@ -70,11 +80,29 @@ export class FakeTimers {
}
}

async advanceTimersToNextTimerAsync(steps = 1): Promise<void> {
if (this._checkFakeTimers()) {
for (let i = steps; i > 0; i--) {
await this._clock.nextAsync()
// Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250
this._clock.tick(0)

if (this._clock.countTimers() === 0)
break
}
}
}

advanceTimersByTime(msToRun: number): void {
if (this._checkFakeTimers())
this._clock.tick(msToRun)
}

async advanceTimersByTimeAsync(msToRun: number): Promise<void> {
if (this._checkFakeTimers())
await this._clock.tickAsync(msToRun)
}

runAllTicks(): void {
if (this._checkFakeTimers()) {
// @ts-expect-error method not exposed
Expand Down
20 changes: 20 additions & 0 deletions packages/vitest/src/integrations/vi.ts
Expand Up @@ -61,11 +61,21 @@ class VitestUtils {
return this
}

public async runOnlyPendingTimersAsync() {
await this._timers.runOnlyPendingTimersAsync()
return this
}

public runAllTimers() {
this._timers.runAllTimers()
return this
}

public async runAllTimersAsync() {
await this._timers.runAllTimersAsync()
return this
}

public runAllTicks() {
this._timers.runAllTicks()
return this
Expand All @@ -76,11 +86,21 @@ class VitestUtils {
return this
}

public async advanceTimersByTimeAsync(ms: number) {
await this._timers.advanceTimersByTimeAsync(ms)
return this
}

public advanceTimersToNextTimer() {
this._timers.advanceTimersToNextTimer()
return this
}

public async advanceTimersToNextTimerAsync() {
await this._timers.advanceTimersToNextTimerAsync()
return this
}

public getTimerCount() {
return this._timers.getTimerCount()
}
Expand Down