@@ -10,7 +10,14 @@ import { runInlineTests } from '../../test-utils'
1010// <- *
1111// <------
1212
13- const deadlockSource = `
13+ // In the deadlocking variant "c" resolves the deadlock only after "b" reported
14+ // its timeout: whether a deadlocked test is reported as timed out depends on
15+ // its own elapsed time the moment the deadlock resolves, and "b" starts its
16+ // clock a few event-loop turns after "a", so an unconditional resolve can
17+ // release "b" while it is still within its own budget. The passing variant
18+ // must not gate: nothing fails there, so the gate would never open.
19+ function deadlockSource ( gateOnTimeout : boolean ) {
20+ return `
1421import { describe, expect, test } from 'vitest'
1522import { createDefer } from '@vitest/utils/helpers'
1623
@@ -20,14 +27,18 @@ describe.concurrent('wrapper', () => {
2027 createDefer<void>(),
2128 createDefer<void>(),
2229 ]
30+ const bTimedOut = createDefer<void>()
2331
2432 test('a', async () => {
2533 expect(1).toBe(1)
2634 defers[0].resolve()
2735 await defers[2]
2836 })
2937
30- test('b', async () => {
38+ test('b', async ({ onTestFailed }) => {
39+ onTestFailed(() => {
40+ bTimedOut.resolve()
41+ })
3142 expect(1).toBe(1)
3243 await defers[0]
3344 defers[1].resolve()
@@ -37,14 +48,16 @@ describe.concurrent('wrapper', () => {
3748 test('c', async () => {
3849 expect(1).toBe(1)
3950 await defers[1]
51+ ${ gateOnTimeout ? 'await bTimedOut' : '' }
4052 defers[2].resolve()
4153 })
4254})
4355`
56+ }
4457
4558test ( 'deadlocks with insufficient maxConcurrency' , async ( ) => {
4659 const { errorTree } = await runInlineTests ( {
47- 'basic.test.ts' : deadlockSource ,
60+ 'basic.test.ts' : deadlockSource ( true ) ,
4861 } , {
4962 maxConcurrency : 2 ,
5063 testTimeout : 500 ,
@@ -74,7 +87,7 @@ test('deadlocks with insufficient maxConcurrency', async () => {
7487
7588test ( 'passes when maxConcurrency is high enough' , async ( ) => {
7689 const { stderr, errorTree } = await runInlineTests ( {
77- 'basic.test.ts' : deadlockSource ,
90+ 'basic.test.ts' : deadlockSource ( false ) ,
7891 } , {
7992 maxConcurrency : 3 ,
8093 } )
@@ -93,7 +106,8 @@ test('passes when maxConcurrency is high enough', async () => {
93106 ` )
94107} )
95108
96- const suiteDeadlockSource = `
109+ function suiteDeadlockSource ( gateOnTimeout : boolean ) {
110+ return `
97111import { describe, expect, test } from 'vitest'
98112import { createDefer } from '@vitest/utils/helpers'
99113
@@ -103,6 +117,7 @@ describe.concurrent('wrapper', () => {
103117 createDefer<void>(),
104118 createDefer<void>(),
105119 ]
120+ const bTimedOut = createDefer<void>()
106121
107122 describe('1st suite', () => {
108123 test('a', async () => {
@@ -111,7 +126,10 @@ describe.concurrent('wrapper', () => {
111126 await defers[2]
112127 })
113128
114- test('b', async () => {
129+ test('b', async ({ onTestFailed }) => {
130+ onTestFailed(() => {
131+ bTimedOut.resolve()
132+ })
115133 expect(1).toBe(1)
116134 await defers[0]
117135 defers[1].resolve()
@@ -123,15 +141,17 @@ describe.concurrent('wrapper', () => {
123141 test('c', async () => {
124142 expect(1).toBe(1)
125143 await defers[1]
144+ ${ gateOnTimeout ? 'await bTimedOut' : '' }
126145 defers[2].resolve()
127146 })
128147 })
129148})
130149`
150+ }
131151
132152test ( 'suite deadlocks with insufficient maxConcurrency' , async ( ) => {
133153 const { errorTree } = await runInlineTests ( {
134- 'basic.test.ts' : suiteDeadlockSource ,
154+ 'basic.test.ts' : suiteDeadlockSource ( true ) ,
135155 } , {
136156 maxConcurrency : 2 ,
137157 testTimeout : 500 ,
@@ -162,7 +182,7 @@ test('suite deadlocks with insufficient maxConcurrency', async () => {
162182
163183test ( 'suite passes when maxConcurrency is high enough' , async ( ) => {
164184 const { stderr, errorTree } = await runInlineTests ( {
165- 'basic.test.ts' : suiteDeadlockSource ,
185+ 'basic.test.ts' : suiteDeadlockSource ( false ) ,
166186 } , {
167187 maxConcurrency : 3 ,
168188 } )
0 commit comments