Skip to content

Commit 089f935

Browse files
committed
perf: pass testfiles at once when --no-isolate --maxWorkers=1
1 parent fb95fc7 commit 089f935

File tree

7 files changed

+75
-8
lines changed

7 files changed

+75
-8
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dist
1616
.vite-node
1717
ltex*
1818
.DS_Store
19+
.zed
1920
bench/test/*/*/
2021
**/bench.json
2122
**/browser/browser.json
@@ -35,4 +36,4 @@ test/browser/html/
3536
test/core/html/
3637
.vitest-attachments
3738
explainFiles.txt
38-
.vitest-dump
39+
.vitest-dump

packages/vitest/src/node/pool.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export function createPool(ctx: Vitest): ProcessPool {
8787

8888
const sorted = await sequencer.sort(specs)
8989
const environments = await getSpecificationsEnvironments(specs)
90-
const groups = groupSpecs(sorted)
90+
const groups = groupSpecs(sorted, environments)
9191

9292
const projectEnvs = new WeakMap<TestProject, Partial<NodeJS.ProcessEnv>>()
9393
const projectExecArgvs = new WeakMap<TestProject, string[]>()
@@ -330,9 +330,8 @@ function getMemoryLimit(config: ResolvedConfig, pool: string) {
330330
return null
331331
}
332332

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?
333+
function groupSpecs(specs: TestSpecification[], environments: Awaited<ReturnType<typeof getSpecificationsEnvironments>>) {
334+
// Test files are passed to test runner one at a time, except for Typechecker or when "--maxWorker=1 --no-isolate"
336335
type SpecsForRunner = TestSpecification[]
337336

338337
// Tests in a single group are executed with `maxWorkers` parallelism.
@@ -361,6 +360,7 @@ function groupSpecs(specs: TestSpecification[]) {
361360
}
362361

363362
const maxWorkers = resolveMaxWorkers(spec.project)
363+
const isolate = spec.project.config.isolate
364364
groups[order] ||= { specs: [], maxWorkers }
365365

366366
// Multiple projects with different maxWorkers but same groupId
@@ -370,6 +370,20 @@ function groupSpecs(specs: TestSpecification[]) {
370370
throw new Error(`Projects "${last}" and "${spec.project.name}" have different 'maxWorkers' but same 'sequence.groupId'.\nProvide unique 'sequence.groupId' for them.`)
371371
}
372372

373+
// Non-isolated single worker can receive all files at once
374+
if (isolate === false && maxWorkers === 1) {
375+
groups[order].specs[0] ??= []
376+
const previous = groups[order].specs[0][0]
377+
378+
if (!previous) {
379+
return groups[order].specs[0].push(spec)
380+
}
381+
382+
if (previous.project.name === spec.project.name && environments.get(previous)?.name === environments.get(spec)?.name) {
383+
return groups[order].specs[0].push(spec)
384+
}
385+
}
386+
373387
groups[order].specs.push([spec])
374388
})
375389

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { test } from "vitest"
2+
3+
test("a", () => { })
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { test } from "vitest"
2+
3+
test("b", () => { })
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { test } from "vitest"
2+
3+
test("c", () => { })
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { test } from 'vitest'
2+
3+
test('print config', () => {
4+
// @ts-expect-error -- internal
5+
console.log(JSON.stringify(globalThis.__vitest_worker__.ctx.files.map(file => file.filepath)))
6+
})

test/config/test/pool.test.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type { SerializedConfig } from 'vitest'
22
import type { TestUserConfig } from 'vitest/node'
3+
import { normalize } from 'pathe'
34
import { assert, describe, expect, test } from 'vitest'
4-
import { runVitest } from '../../test-utils'
5+
import { runVitest, StableTestFileOrderSorter } from '../../test-utils'
56

67
describe.each(['forks', 'threads', 'vmThreads', 'vmForks'])('%s', async (pool) => {
78
test('resolves top-level pool', async () => {
@@ -51,8 +52,39 @@ test('project level pool options overwrites top-level', async () => {
5152
expect(config.fileParallelism).toBe(false)
5253
})
5354

54-
async function getConfig(options: Partial<TestUserConfig>, cliOptions: Partial<TestUserConfig> = {}) {
55-
let config: SerializedConfig | undefined
55+
test('isolated single worker pool receives single testfile at once', async () => {
56+
const files = await getConfig<string[]>({
57+
maxWorkers: 1,
58+
isolate: true,
59+
sequence: { sequencer: StableTestFileOrderSorter },
60+
}, { include: ['print-testfiles.test.ts', 'a.test.ts', 'b.test.ts', 'c.test.ts'] })
61+
62+
expect(files.map(normalizeFilename)).toMatchInlineSnapshot(`
63+
[
64+
"<process-cwd>/fixtures/pool/print-testfiles.test.ts",
65+
]
66+
`)
67+
})
68+
69+
test('non-isolated single worker pool receives all testfiles at once', async () => {
70+
const files = await getConfig<string[]>({
71+
maxWorkers: 1,
72+
isolate: false,
73+
sequence: { sequencer: StableTestFileOrderSorter },
74+
}, { include: ['print-testfiles.test.ts', 'a.test.ts', 'b.test.ts', 'c.test.ts'] })
75+
76+
expect(files.map(normalizeFilename)).toMatchInlineSnapshot(`
77+
[
78+
"<process-cwd>/fixtures/pool/a.test.ts",
79+
"<process-cwd>/fixtures/pool/b.test.ts",
80+
"<process-cwd>/fixtures/pool/c.test.ts",
81+
"<process-cwd>/fixtures/pool/print-testfiles.test.ts",
82+
]
83+
`)
84+
})
85+
86+
async function getConfig<T = SerializedConfig>(options: Partial<TestUserConfig>, cliOptions: Partial<TestUserConfig> = {}): Promise<T> {
87+
let config: T | undefined
5688

5789
await runVitest({
5890
root: './fixtures/pool',
@@ -66,3 +98,8 @@ async function getConfig(options: Partial<TestUserConfig>, cliOptions: Partial<T
6698
assert(config)
6799
return config
68100
}
101+
102+
function normalizeFilename(filename: string) {
103+
return normalize(filename)
104+
.replace(normalize(process.cwd()), '<process-cwd>')
105+
}

0 commit comments

Comments
 (0)