Skip to content

Commit eb98dd8

Browse files
authored
fix(core): prevent starting new run when cancelling (#8991)
1 parent f509d2a commit eb98dd8

File tree

4 files changed

+56
-1
lines changed

4 files changed

+56
-1
lines changed

packages/vitest/src/node/core.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export class Vitest {
9999
/** @internal */ filenamePattern?: string[]
100100
/** @internal */ runningPromise?: Promise<TestRunResult>
101101
/** @internal */ closingPromise?: Promise<void>
102+
/** @internal */ cancelPromise?: Promise<void | void[]>
102103
/** @internal */ isCancelling = false
103104
/** @internal */ coreWorkspaceProject: TestProject | undefined
104105
/** @internal */ _browserSessions = new BrowserSessions()
@@ -705,6 +706,7 @@ export class Vitest {
705706
await this._testRun.start(specs)
706707

707708
// previous run
709+
await this.cancelPromise
708710
await this.runningPromise
709711
this._onCancelListeners.clear()
710712
this.isCancelling = false
@@ -806,6 +808,7 @@ export class Vitest {
806808
this.state.collectPaths(filepaths)
807809

808810
// previous run
811+
await this.cancelPromise
809812
await this.runningPromise
810813
this._onCancelListeners.clear()
811814
this.isCancelling = false
@@ -859,7 +862,9 @@ export class Vitest {
859862
*/
860863
async cancelCurrentRun(reason: CancelReason): Promise<void> {
861864
this.isCancelling = true
862-
await Promise.all([...this._onCancelListeners].map(listener => listener(reason)))
865+
this.cancelPromise = Promise.all([...this._onCancelListeners].map(listener => listener(reason)))
866+
867+
await this.cancelPromise.finally(() => (this.cancelPromise = undefined))
863868
await this.runningPromise
864869
}
865870

@@ -1045,6 +1050,7 @@ export class Vitest {
10451050
private async scheduleRerun(triggerId: string): Promise<void> {
10461051
const currentCount = this.restartsCount
10471052
clearTimeout(this._rerunTimer)
1053+
await this.cancelPromise
10481054
await this.runningPromise
10491055
clearTimeout(this._rerunTimer)
10501056

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { setTimeout } from 'node:timers/promises'
2+
import {afterAll, expect, test } from 'vitest'
3+
4+
5+
test('adds two numbers', () => {
6+
expect(2 + 3).toBe(5)
7+
})
8+
9+
test('fails adding two numbers', () => {
10+
expect(2 + 3).toBe(6)
11+
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('does not run', () => {
4+
throw new Error("Should never run")
5+
})
6+
7+

test/cli/test/bail-race.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { resolve } from 'pathe'
2+
import { expect, test } from 'vitest'
3+
import { createVitest } from 'vitest/node'
4+
import { StableTestFileOrderSorter } from '../../test-utils'
5+
6+
test('cancels previous run before starting new one', async () => {
7+
const errors: unknown[] = []
8+
9+
const vitest = await createVitest('test', {
10+
maxWorkers: 1,
11+
maxConcurrency: 1,
12+
watch: false,
13+
bail: 1,
14+
root: resolve(import.meta.dirname, '../fixtures/bail-race'),
15+
sequence: { sequencer: StableTestFileOrderSorter },
16+
reporters: [{
17+
onTestRunEnd(_, unhandledErrors) {
18+
if (unhandledErrors.length) {
19+
errors.push(...unhandledErrors)
20+
}
21+
},
22+
}],
23+
})
24+
25+
for (let i = 0; i <= 10; i++) {
26+
await vitest.start()
27+
}
28+
29+
// No "Error: [vitest-pool]: Cannot run tasks while pool is cancelling" errors should show up
30+
expect(errors).toHaveLength(0)
31+
})

0 commit comments

Comments
 (0)