Skip to content

Commit 3af3741

Browse files
committed
fix: run tests in configs that are not part of the workspace
1 parent d6a7041 commit 3af3741

File tree

4 files changed

+107
-68
lines changed

4 files changed

+107
-68
lines changed

src/api.ts

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as vscode from 'vscode'
33
import { log } from './log'
44
import type { SerializedTestSpecification, VitestEvents, VitestRPC } from './api/rpc'
55
import type { VitestPackage } from './api/pkg'
6-
import { showVitestError } from './utils'
6+
import { createVitestWorkspaceFile, noop, showVitestError } from './utils'
77
import type { VitestProcess } from './api/types'
88
import { createVitestTerminalProcess } from './api/terminal'
99
import { getConfig } from './config'
@@ -257,21 +257,79 @@ function createQueuedHandler<T>(resolver: (value: T[]) => Promise<void>) {
257257
}
258258
}
259259

260-
export async function resolveVitestAPI(packages: VitestPackage[]) {
261-
const promises = packages.map(async (pkg) => {
262-
const config = getConfig(pkg.folder)
263-
if (config.cliArguments && !pkg.arguments) {
264-
pkg.arguments = `vitest ${config.cliArguments}`
265-
}
266-
const vitest = config.shellType === 'terminal'
267-
? await createVitestTerminalProcess(pkg)
268-
: await createVitestProcess(pkg)
269-
return new VitestFolderAPI(pkg, vitest)
260+
export async function resolveVitestAPI(workspaceConfigs: VitestPackage[], configs: VitestPackage[]) {
261+
const usedConfigs = new Set<string>()
262+
const workspacePromises = workspaceConfigs.map(pkg => createVitestFolderAPI(usedConfigs, pkg))
263+
const apis = await Promise.all(workspacePromises)
264+
const configsToResolve = configs.filter((pkg) => {
265+
return !pkg.configFile || pkg.workspaceFile || !usedConfigs.has(pkg.configFile)
270266
})
271-
const apis = await Promise.all(promises)
267+
268+
const maximumConfigs = getConfig().maximumConfigs ?? 3
269+
270+
if (configsToResolve.length > maximumConfigs) {
271+
const warningMessage = [
272+
'Vitest found multiple config files.',
273+
`The extension will use only the first ${maximumConfigs} due to performance concerns.`,
274+
'Consider using a workspace configuration to group your configs or increase',
275+
'the limit via "vitest.maximumConfigs" option.',
276+
].join(' ')
277+
278+
const folders = Array.from(new Set(configsToResolve.map(c => c.folder)))
279+
const allConfigs = [...configsToResolve]
280+
// remove all but the first 3
281+
const discardedConfigs = configsToResolve.splice(maximumConfigs)
282+
283+
if (folders.every(f => getConfig(f).disableWorkspaceWarning !== true)) {
284+
vscode.window.showWarningMessage(
285+
warningMessage,
286+
'Create vitest.workspace.js',
287+
'Disable notification',
288+
).then((result) => {
289+
if (result === 'Create vitest.workspace.js')
290+
createVitestWorkspaceFile(allConfigs).catch(noop)
291+
292+
if (result === 'Disable notification') {
293+
folders.forEach((folder) => {
294+
const rootConfig = vscode.workspace.getConfiguration('vitest', folder)
295+
rootConfig.update('disableWorkspaceWarning', true)
296+
})
297+
}
298+
})
299+
}
300+
else {
301+
log.info(warningMessage)
302+
log.info(`Discarded config files: ${discardedConfigs.map(x => x.workspaceFile || x.configFile).join(', ')}`)
303+
}
304+
}
305+
306+
// one by one because it's possible some of them have "workspace:" -- the configs are already sorted by priority
307+
for (const pkg of configsToResolve) {
308+
if (pkg.configFile && usedConfigs.has(pkg.configFile)) {
309+
continue
310+
}
311+
312+
const api = await createVitestFolderAPI(usedConfigs, pkg)
313+
apis.push(api)
314+
}
315+
272316
return new VitestAPI(apis)
273317
}
274318

319+
async function createVitestFolderAPI(usedConfigs: Set<string>, pkg: VitestPackage) {
320+
const config = getConfig(pkg.folder)
321+
if (config.cliArguments && !pkg.arguments) {
322+
pkg.arguments = `vitest ${config.cliArguments}`
323+
}
324+
const vitest = config.shellType === 'terminal'
325+
? await createVitestTerminalProcess(pkg)
326+
: await createVitestProcess(pkg)
327+
vitest.configs.forEach((config) => {
328+
usedConfigs.add(config)
329+
})
330+
return new VitestFolderAPI(pkg, vitest)
331+
}
332+
275333
export interface ResolvedMeta {
276334
rpc: VitestRPC
277335
process: VitestProcess

src/api/pkg.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,22 @@ function validateVitestPkg(showWarning: boolean, pkgJsonPath: string, pkg: any)
108108
return true
109109
}
110110

111-
export async function resolveVitestPackages(showWarning: boolean): Promise<VitestPackage[]> {
112-
// try to resolve configs first
113-
const vitest = await resolveVitestPackagesViaConfigs(showWarning)
114-
// if no viable configs found, try to resolve via package.json
115-
if (!vitest.meta.length && !vitest.warned) {
111+
export async function resolveVitestPackages(showWarning: boolean): Promise<{ configs: VitestPackage[]; workspaces: VitestPackage[] }> {
112+
// TODO: update "warned" logic
113+
const [workspaceConfigs, configs] = await Promise.all([
114+
resolveVitestWorkspaceConfigs(showWarning),
115+
resolveVitestConfigs(showWarning),
116+
])
117+
if (!workspaceConfigs.meta.length && !configs.meta.length) {
116118
const pkg = await resolveVitestPackagesViaPackageJson(showWarning)
117119
if (!pkg.meta.length && !pkg.warned)
118-
return resolveVitestWorkspacePackages(showWarning).meta
119-
return pkg.meta
120+
return { configs: resolveVitestWorkspacePackages(showWarning).meta, workspaces: [] }
121+
return { configs: pkg.meta, workspaces: [] }
122+
}
123+
return {
124+
workspaces: workspaceConfigs.meta,
125+
configs: configs.meta,
120126
}
121-
return vitest.meta
122127
}
123128

124129
function resolveVitestWorkspacePackages(showWarning: boolean) {
@@ -213,7 +218,7 @@ export async function resolveVitestPackagesViaPackageJson(showWarning: boolean):
213218
}
214219
}
215220

216-
export async function resolveVitestPackagesViaConfigs(showWarning: boolean): Promise<{ meta: VitestPackage[]; warned: boolean }> {
221+
async function resolveVitestWorkspaceConfigs(showWarning: boolean) {
217222
const config = getConfig()
218223
const userWorkspace = config.workspaceConfig
219224
const rootConfig = config.rootConfig
@@ -226,7 +231,6 @@ export async function resolveVitestPackagesViaConfigs(showWarning: boolean): Pro
226231
: await vscode.workspace.findFiles(workspaceGlob, config.configSearchPatternExclude)
227232

228233
let warned = false
229-
230234
if (vitestWorkspaces.length) {
231235
// if there is a workspace config, use it as root
232236
const meta = resolvePackagUniquePrefixes(vitestWorkspaces.map((config) => {
@@ -247,6 +251,17 @@ export async function resolveVitestPackagesViaConfigs(showWarning: boolean): Pro
247251
warned,
248252
}
249253
}
254+
return {
255+
meta: [],
256+
warned,
257+
}
258+
}
259+
260+
async function resolveVitestConfigs(showWarning: boolean) {
261+
const config = getConfig()
262+
const rootConfig = config.rootConfig
263+
264+
let warned = false
250265

251266
if (rootConfig)
252267
log.info('[API] Using user root config:', rootConfig)

src/extension.ts

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { TestRunner } from './runner/runner'
99
import { TestTree } from './testTree'
1010
import { configGlob, workspaceGlob } from './constants'
1111
import { log } from './log'
12-
import { createVitestWorkspaceFile, debounce, noop, showVitestError } from './utils'
12+
import { debounce, showVitestError } from './utils'
1313
import { resolveVitestPackages } from './api/pkg'
1414
import { TestFile, getTestData } from './testTreeData'
1515
import { TagsManager } from './tagsManager'
@@ -72,59 +72,21 @@ class VitestExtension {
7272
this.runners.forEach(runner => runner.dispose())
7373
this.runners = []
7474

75-
const vitest = await resolveVitestPackages(showWarning)
75+
const { workspaces, configs } = await resolveVitestPackages(showWarning)
7676

7777
if (cancelToken?.isCancellationRequested) {
7878
return
7979
}
8080

81-
if (!vitest.length) {
81+
if (!workspaces.length && !configs.length) {
8282
log.error('[API]', 'Failed to start Vitest: No vitest config files found')
8383
this.testController.items.delete(this.loadingTestItem.id)
8484

8585
await this.api?.dispose()
8686
return
8787
}
8888

89-
const configFiles = vitest.filter(x => x.configFile && !x.workspaceFile)
90-
91-
const maximumConfigs = getConfig().maximumConfigs ?? 3
92-
93-
if (configFiles.length > maximumConfigs) {
94-
const warningMessage = [
95-
'Vitest found multiple config files.',
96-
`The extension will use only the first ${maximumConfigs} due to performance concerns.`,
97-
'Consider using a workspace configuration to group your configs or increase',
98-
'the limit via "vitest.maximumConfigs" option.',
99-
].join(' ')
100-
101-
// remove all but the first 3
102-
const discardedConfigs = vitest.splice(maximumConfigs)
103-
104-
if (configFiles.every(c => getConfig(c.folder).disableWorkspaceWarning !== true)) {
105-
vscode.window.showWarningMessage(
106-
warningMessage,
107-
'Create vitest.workspace.js',
108-
'Disable notification',
109-
).then((result) => {
110-
if (result === 'Create vitest.workspace.js')
111-
createVitestWorkspaceFile(configFiles).catch(noop)
112-
113-
if (result === 'Disable notification') {
114-
configFiles.forEach((c) => {
115-
const rootConfig = vscode.workspace.getConfiguration('vitest', c.folder)
116-
rootConfig.update('disableWorkspaceWarning', true)
117-
})
118-
}
119-
})
120-
}
121-
else {
122-
log.info(warningMessage)
123-
log.info(`Discarded config files: ${discardedConfigs.map(x => x.workspaceFile || x.configFile).join(', ')}`)
124-
}
125-
}
126-
127-
const folders = new Set(vitest.map(x => x.folder))
89+
const folders = new Set([...workspaces, ...configs].map(x => x.folder))
12890
this.testTree.reset(Array.from(folders))
12991

13092
const previousRunProfiles = this.runProfiles
@@ -137,7 +99,7 @@ class VitestExtension {
13799
return
138100
}
139101

140-
this.api = await resolveVitestAPI(vitest)
102+
this.api = await resolveVitestAPI(workspaces, configs)
141103

142104
this.api.onUnexpectedExit((code) => {
143105
if (code) {

src/worker/init.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { pathToFileURL } from 'node:url'
2-
import type { UserConfig } from 'vitest/node'
2+
import type { UserConfig, WorkspaceProject } from 'vitest/node'
33
import { VSCodeReporter } from './reporter'
44
import type { WorkerMeta } from './types'
55
import { normalizeDriveLetter } from './utils'
@@ -87,11 +87,15 @@ export async function initVitest(meta: WorkerMeta, options?: UserConfig) {
8787
},
8888
)
8989
await vitest.report('onInit', vitest)
90-
const configs = vitest.projects.map(p => p.server.config.configFile).filter(c => c != null)
90+
const configs = ([
91+
// @ts-expect-error -- getRootProject in Vitest 3.0
92+
'getRootProject' in vitest ? vitest.getRootProject() : vitest.getCoreWorkspaceProject(),
93+
...vitest.projects,
94+
] as WorkspaceProject[]).map(p => p.server.config.configFile).filter(c => c != null)
9195
return {
9296
vitest,
9397
reporter,
94-
configs,
98+
configs: Array.from(new Set(configs)),
9599
meta,
96100
}
97101
}

0 commit comments

Comments
 (0)