11import type { Awaitable } from '@vitest/utils'
2+ import type { ContextTestEnvironment } from '../types/worker'
23import type { Vitest } from './core'
34import type { PoolTask } from './pools/types'
45import type { TestProject } from './project'
@@ -87,7 +88,7 @@ export function createPool(ctx: Vitest): ProcessPool {
8788
8889 const sorted = await sequencer . sort ( specs )
8990 const environments = await getSpecificationsEnvironments ( specs )
90- const groups = groupSpecs ( sorted )
91+ const groups = groupSpecs ( sorted , environments )
9192
9293 const projectEnvs = new WeakMap < TestProject , Partial < NodeJS . ProcessEnv > > ( )
9394 const projectExecArgvs = new WeakMap < TestProject , string [ ] > ( )
@@ -330,9 +331,8 @@ function getMemoryLimit(config: ResolvedConfig, pool: string) {
330331 return null
331332}
332333
333- function groupSpecs ( specs : TestSpecification [ ] ) {
334- // Test files are passed to test runner one at a time, except Typechecker.
335- // TODO: Should non-isolated test files be passed to test runner all at once?
334+ function groupSpecs ( specs : TestSpecification [ ] , environments : Awaited < ReturnType < typeof getSpecificationsEnvironments > > ) {
335+ // Test files are passed to test runner one at a time, except for Typechecker or when "--maxWorker=1 --no-isolate"
336336 type SpecsForRunner = TestSpecification [ ]
337337
338338 // Tests in a single group are executed with `maxWorkers` parallelism.
@@ -346,6 +346,43 @@ function groupSpecs(specs: TestSpecification[]) {
346346 // Type tests are run in a single group, per project
347347 const typechecks : Record < string , TestSpecification [ ] > = { }
348348
349+ const serializedEnvironmentOptions = new Map < ContextTestEnvironment , string > ( )
350+
351+ function getSerializedOptions ( env : ContextTestEnvironment ) {
352+ const options = serializedEnvironmentOptions . get ( env )
353+
354+ if ( options ) {
355+ return options
356+ }
357+
358+ const serialized = JSON . stringify ( env . options )
359+ serializedEnvironmentOptions . set ( env , serialized )
360+ return serialized
361+ }
362+
363+ function isEqualEnvironments ( a : TestSpecification , b : TestSpecification ) {
364+ const aEnv = environments . get ( a )
365+ const bEnv = environments . get ( b )
366+
367+ if ( ! aEnv && ! bEnv ) {
368+ return true
369+ }
370+
371+ if ( ! aEnv || ! bEnv || aEnv . name !== bEnv . name ) {
372+ return false
373+ }
374+
375+ if ( ! aEnv . options && ! bEnv . options ) {
376+ return true
377+ }
378+
379+ if ( ! aEnv . options || ! bEnv . options ) {
380+ return false
381+ }
382+
383+ return getSerializedOptions ( aEnv ) === getSerializedOptions ( bEnv )
384+ }
385+
349386 specs . forEach ( ( spec ) => {
350387 if ( spec . pool === 'typescript' ) {
351388 typechecks [ spec . project . name ] ||= [ ]
@@ -361,6 +398,7 @@ function groupSpecs(specs: TestSpecification[]) {
361398 }
362399
363400 const maxWorkers = resolveMaxWorkers ( spec . project )
401+ const isolate = spec . project . config . isolate
364402 groups [ order ] ||= { specs : [ ] , maxWorkers }
365403
366404 // Multiple projects with different maxWorkers but same groupId
@@ -370,6 +408,15 @@ function groupSpecs(specs: TestSpecification[]) {
370408 throw new Error ( `Projects "${ last } " and "${ spec . project . name } " have different 'maxWorkers' but same 'sequence.groupId'.\nProvide unique 'sequence.groupId' for them.` )
371409 }
372410
411+ // Non-isolated single worker can receive all files at once
412+ if ( isolate === false && maxWorkers === 1 ) {
413+ const previous = groups [ order ] . specs [ 0 ] ?. [ 0 ]
414+
415+ if ( previous && previous . project . name === spec . project . name && isEqualEnvironments ( spec , previous ) ) {
416+ return groups [ order ] . specs [ 0 ] . push ( spec )
417+ }
418+ }
419+
373420 groups [ order ] . specs . push ( [ spec ] )
374421 } )
375422
0 commit comments