Skip to content

Commit ec9d7c9

Browse files
authored
fix: resolve cwd correctly when initiating projects (#5582)
1 parent e40f992 commit ec9d7c9

File tree

8 files changed

+55
-48
lines changed

8 files changed

+55
-48
lines changed

packages/vitest/src/node/core.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -315,31 +315,30 @@ export class Vitest {
315315

316316
const cwd = process.cwd()
317317

318-
const projects: (() => Promise<WorkspaceProject>)[] = []
318+
const projects: WorkspaceProject[] = []
319319

320320
try {
321321
// we have to resolve them one by one because CWD should depend on the project
322322
for (const filepath of filteredWorkspaces) {
323323
if (this.server.config.configFile === filepath) {
324324
const project = await this.createCoreProject()
325-
projects.push(() => Promise.resolve(project))
325+
projects.push(project)
326326
continue
327327
}
328328
const dir = filepath.endsWith('/') ? filepath.slice(0, -1) : dirname(filepath)
329329
if (isMainThread)
330330
process.chdir(dir)
331-
// this just resolves the config, later we also wait when the server is resolved,
332-
// but we can do that in parallel because it doesn't depend on process.cwd()
333-
// this is strictly a performance optimization so we don't need to wait for server to start
334-
projects.push(await initializeProject(filepath, this, { workspaceConfigPath, test: cliOverrides }))
331+
projects.push(
332+
await initializeProject(filepath, this, { workspaceConfigPath, test: cliOverrides }),
333+
)
335334
}
336335
}
337336
finally {
338337
if (isMainThread)
339338
process.chdir(cwd)
340339
}
341340

342-
const projectPromises: Promise<() => Promise<WorkspaceProject>>[] = []
341+
const projectPromises: Promise<WorkspaceProject>[] = []
343342

344343
projectsOptions.forEach((options, index) => {
345344
// we can resolve these in parallel because process.cwd() is not changed
@@ -349,14 +348,10 @@ export class Vitest {
349348
if (!projects.length && !projectPromises.length)
350349
return [await this.createCoreProject()]
351350

352-
const resolvedProjectsReceivers = [
351+
const resolvedProjects = await Promise.all([
353352
...projects,
354353
...await Promise.all(projectPromises),
355-
]
356-
// we need to wait when the server is resolved, we can do that in parallel
357-
const resolvedProjects = await Promise.all(
358-
resolvedProjectsReceivers.map(receiver => receiver()),
359-
)
354+
])
360355
const names = new Set<string>()
361356

362357
for (const project of resolvedProjects) {

packages/vitest/src/node/workspace.ts

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { deepMerge } from '../utils'
1212
import type { Typechecker } from '../typecheck/typechecker'
1313
import type { BrowserProvider } from '../types/browser'
1414
import { getBrowserProvider } from '../integrations/browser'
15-
import { createDefer } from '../public/utils'
1615
import { isBrowserEnabled, resolveConfig } from './config'
1716
import { WorkspaceVitestPlugin } from './plugins/workspace'
1817
import { createViteServer } from './vite'
@@ -40,40 +39,22 @@ export async function initializeProject(workspacePath: string | number, ctx: Vit
4039
: workspacePath.endsWith('/') ? workspacePath : dirname(workspacePath)
4140
)
4241

43-
return new Promise<() => Promise<WorkspaceProject>>((resolve, reject) => {
44-
const resolution = createDefer<WorkspaceProject>()
45-
let configResolved = false
46-
const config: ViteInlineConfig = {
47-
...options,
48-
root,
49-
logLevel: 'error',
50-
configFile,
51-
// this will make "mode": "test" | "benchmark" inside defineConfig
52-
mode: options.test?.mode || options.mode || ctx.config.mode,
53-
plugins: [
54-
{
55-
name: 'vitest:workspace:resolve',
56-
configResolved() {
57-
configResolved = true
58-
resolve(() => resolution)
59-
},
60-
},
61-
...options.plugins || [],
62-
WorkspaceVitestPlugin(project, { ...options, root, workspacePath }),
63-
],
64-
}
42+
const config: ViteInlineConfig = {
43+
...options,
44+
root,
45+
logLevel: 'error',
46+
configFile,
47+
// this will make "mode": "test" | "benchmark" inside defineConfig
48+
mode: options.test?.mode || options.mode || ctx.config.mode,
49+
plugins: [
50+
...options.plugins || [],
51+
WorkspaceVitestPlugin(project, { ...options, root, workspacePath }),
52+
],
53+
}
6554

66-
createViteServer(config)
67-
.then(() => resolution.resolve(project))
68-
.catch((err) => {
69-
if (configResolved)
70-
resolution.reject(err)
71-
else
72-
reject(err)
73-
})
55+
await createViteServer(config)
7456

75-
return project
76-
})
57+
return project
7758
}
7859

7960
export class WorkspaceProject {

test/workspaces/cwdPlugin.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import type { Plugin } from 'vite'
2+
3+
export function cwdPlugin(name: string): Plugin

test/workspaces/cwdPlugin.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @ts-check
2+
3+
export function cwdPlugin(name) {
4+
return {
5+
name: `vitest:test:workspace-${name}`,
6+
configResolved() {
7+
process.env[`${name}_CWD_CONFIG`] = process.cwd()
8+
},
9+
configureServer() {
10+
process.env[`${name}_CWD_SERVER`] = process.cwd()
11+
},
12+
}
13+
}

test/workspaces/globalTest.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export async function teardown() {
3333
try {
3434
assert.ok(results.success)
3535
assert.equal(results.numTotalTestSuites, 28)
36-
assert.equal(results.numTotalTests, 30)
37-
assert.equal(results.numPassedTests, 30)
36+
assert.equal(results.numTotalTests, 31)
37+
assert.equal(results.numPassedTests, 31)
3838

3939
const shared = results.testResults.filter((r: any) => r.name.includes('space_shared/test.spec.ts'))
4040

test/workspaces/space_1/test/env-injected.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { resolve } from 'node:path'
12
import { expect, test } from 'vitest'
23

34
declare global {
@@ -23,3 +24,13 @@ test('env variable is assigned', () => {
2324
expect(process.env.CONFIG_LOCAL).toBe('local')
2425
expect(process.env.CONFIG_OVERRIDE).toBe('local')
2526
})
27+
28+
test('cwd is resolved correctly', () => {
29+
const spaceRoot = resolve(import.meta.dirname, '..')
30+
const rootPath = resolve(spaceRoot, '..')
31+
32+
expect(process.env.ROOT_CWD_CONFIG).toBe(rootPath)
33+
expect(process.env.ROOT_CWD_SERVER).toBe(rootPath)
34+
expect(process.env.SPACE_2_CWD_CONFIG).toBe(spaceRoot)
35+
expect(process.env.SPACE_2_CWD_SERVER).toBe(spaceRoot)
36+
})

test/workspaces/space_1/vite.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { defineProject } from 'vitest/config'
2+
import { cwdPlugin } from '../cwdPlugin'
23

34
export default defineProject({
45
envPrefix: ['VITE_', 'CUSTOM_'],
6+
plugins: [cwdPlugin('SPACE_2')],
57
define: {
68
__DEV__: 'true',
79
},

test/workspaces/vitest.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { defineConfig } from 'vitest/config'
2+
import { cwdPlugin } from './cwdPlugin.js'
23

34
if (process.env.TEST_WATCH) {
45
// Patch stdin on the process so that we can fake it to seem like a real interactive terminal and pass the TTY checks
@@ -8,6 +9,7 @@ if (process.env.TEST_WATCH) {
89

910
export default defineConfig({
1011
envPrefix: ['VITE_', 'CUSTOM_', 'ROOT_'],
12+
plugins: [cwdPlugin('ROOT')],
1113
test: {
1214
coverage: {
1315
enabled: true,

0 commit comments

Comments
 (0)