Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dist
.vite-node
ltex*
.DS_Store
.zed
bench/test/*/*/
**/bench.json
**/browser/browser.json
Expand All @@ -35,4 +36,4 @@ test/browser/html/
test/core/html/
.vitest-attachments
explainFiles.txt
.vitest-dump
.vitest-dump
25 changes: 21 additions & 4 deletions packages/vitest/src/node/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function createPool(ctx: Vitest): ProcessPool {

const sorted = await sequencer.sort(specs)
const environments = await getSpecificationsEnvironments(specs)
const groups = groupSpecs(sorted)
const groups = groupSpecs(sorted, environments)

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

function groupSpecs(specs: TestSpecification[]) {
// Test files are passed to test runner one at a time, except Typechecker.
// TODO: Should non-isolated test files be passed to test runner all at once?
function groupSpecs(specs: TestSpecification[], environments: Awaited<ReturnType<typeof getSpecificationsEnvironments>>) {
// Test files are passed to test runner one at a time, except for Typechecker or when "--maxWorker=1 --no-isolate"
type SpecsForRunner = TestSpecification[]

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

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

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

// Non-isolated single worker can receive all files at once
if (isolate === false && maxWorkers === 1) {
const previous = groups[order].specs[0]?.[0]

if (previous && previous.project.name === spec.project.name) {
const env = environments.get(spec)
const previousEnv = environments.get(previous)

if (
env?.name === previousEnv?.name
&& JSON.stringify(env?.options) === JSON.stringify(previousEnv?.options)
Comment thread
AriPerkkio marked this conversation as resolved.
Outdated
) {
return groups[order].specs[0].push(spec)
}
}
}

groups[order].specs.push([spec])
})

Expand Down
3 changes: 3 additions & 0 deletions test/config/fixtures/pool/a.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { test } from "vitest"

test("a", () => { })
3 changes: 3 additions & 0 deletions test/config/fixtures/pool/b.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { test } from "vitest"

test("b", () => { })
3 changes: 3 additions & 0 deletions test/config/fixtures/pool/c.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { test } from "vitest"

test("c", () => { })
6 changes: 6 additions & 0 deletions test/config/fixtures/pool/print-testfiles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { test } from 'vitest'

test('print config', () => {
// @ts-expect-error -- internal
console.log(JSON.stringify(globalThis.__vitest_worker__.ctx.files.map(file => file.filepath)))
})
43 changes: 40 additions & 3 deletions test/config/test/pool.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { SerializedConfig } from 'vitest'
import type { TestUserConfig } from 'vitest/node'
import { normalize } from 'pathe'
import { assert, describe, expect, test } from 'vitest'
import { runVitest } from '../../test-utils'
import { runVitest, StableTestFileOrderSorter } from '../../test-utils'

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

async function getConfig(options: Partial<TestUserConfig>, cliOptions: Partial<TestUserConfig> = {}) {
let config: SerializedConfig | undefined
test('isolated single worker pool receives single testfile at once', async () => {
const files = await getConfig<string[]>({
maxWorkers: 1,
isolate: true,
sequence: { sequencer: StableTestFileOrderSorter },
}, { include: ['print-testfiles.test.ts', 'a.test.ts', 'b.test.ts', 'c.test.ts'] })

expect(files.map(normalizeFilename)).toMatchInlineSnapshot(`
[
"<process-cwd>/fixtures/pool/print-testfiles.test.ts",
]
`)
})

test('non-isolated single worker pool receives all testfiles at once', async () => {
const files = await getConfig<string[]>({
maxWorkers: 1,
isolate: false,
sequence: { sequencer: StableTestFileOrderSorter },
}, { include: ['print-testfiles.test.ts', 'a.test.ts', 'b.test.ts', 'c.test.ts'] })

expect(files.map(normalizeFilename)).toMatchInlineSnapshot(`
[
"<process-cwd>/fixtures/pool/a.test.ts",
"<process-cwd>/fixtures/pool/b.test.ts",
"<process-cwd>/fixtures/pool/c.test.ts",
"<process-cwd>/fixtures/pool/print-testfiles.test.ts",
]
`)
})

async function getConfig<T = SerializedConfig>(options: Partial<TestUserConfig>, cliOptions: Partial<TestUserConfig> = {}): Promise<T> {
let config: T | undefined

await runVitest({
root: './fixtures/pool',
Expand All @@ -66,3 +98,8 @@ async function getConfig(options: Partial<TestUserConfig>, cliOptions: Partial<T
assert(config)
return config
}

function normalizeFilename(filename: string) {
return normalize(filename)
.replace(normalize(process.cwd()), '<process-cwd>')
}
Loading