Skip to content

Commit 874a121

Browse files
authored
feat(api): make spec into a class instead of a tuple (#6355)
1 parent e03683c commit 874a121

File tree

12 files changed

+134
-50
lines changed

12 files changed

+134
-50
lines changed

packages/browser/src/node/index.ts

-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ export async function createBrowserServer(
1616
) {
1717
const server = new BrowserServer(project, '/')
1818

19-
const root = project.config.root
20-
21-
await project.ctx.packageInstaller.ensureInstalled('@vitest/browser', root)
22-
2319
const configPath = typeof configFile === 'string' ? configFile : false
2420

2521
const vite = await createServer({

packages/vitest/src/api/setup.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,14 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) {
102102
return ctx.state.getUnhandledErrors()
103103
},
104104
async getTestFiles() {
105-
const spec = await ctx.globTestFiles()
106-
return spec.map(([project, file, options]) => [
105+
const spec = await ctx.globTestSpecs()
106+
return spec.map(spec => [
107107
{
108-
name: project.config.name,
109-
root: project.config.root,
108+
name: spec.project.config.name,
109+
root: spec.project.config.root,
110110
},
111-
file,
112-
options,
111+
spec.moduleId,
112+
{ pool: spec.pool },
113113
])
114114
},
115115
},

packages/vitest/src/node/core.ts

+26-19
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import { WebSocketReporter } from '../api/setup'
1717
import type { SerializedCoverageConfig } from '../runtime/config'
1818
import type { SerializedSpec } from '../runtime/types/utils'
1919
import type { ArgumentsType, OnServerRestartHandler, ProvidedContext, UserConsoleLog } from '../types/general'
20-
import { createPool, getFilePoolName } from './pool'
2120
import type { ProcessPool, WorkspaceSpec } from './pool'
21+
import { createPool, getFilePoolName } from './pool'
2222
import { createBenchmarkReporters, createReporters } from './reporters/utils'
2323
import { StateManager } from './state'
2424
import { resolveConfig } from './config/resolveConfig'
@@ -437,7 +437,7 @@ export class Vitest {
437437
}
438438
}
439439

440-
private async getTestDependencies([project, filepath]: WorkspaceSpec, deps = new Set<string>()) {
440+
private async getTestDependencies(spec: WorkspaceSpec, deps = new Set<string>()) {
441441
const addImports = async (project: WorkspaceProject, filepath: string) => {
442442
if (deps.has(filepath)) {
443443
return
@@ -459,8 +459,8 @@ export class Vitest {
459459
}))
460460
}
461461

462-
await addImports(project, filepath)
463-
deps.delete(filepath)
462+
await addImports(spec.project.workspaceProject, spec.moduleId)
463+
deps.delete(spec.moduleId)
464464

465465
return deps
466466
}
@@ -531,18 +531,18 @@ export class Vitest {
531531
for (const project of this.projects) {
532532
if (project.isTestFile(file)) {
533533
const pool = getFilePoolName(project, file)
534-
specs.push([project, file, { pool }])
534+
specs.push(project.createSpec(file, pool))
535535
}
536536
if (project.isTypecheckFile(file)) {
537-
specs.push([project, file, { pool: 'typescript' }])
537+
specs.push(project.createSpec(file, 'typescript'))
538538
}
539539
}
540540
specs.forEach(spec => this.ensureSpecCached(spec))
541541
return specs
542542
}
543543

544544
async initializeGlobalSetup(paths: WorkspaceSpec[]) {
545-
const projects = new Set(paths.map(([project]) => project))
545+
const projects = new Set(paths.map(spec => spec.project.workspaceProject))
546546
const coreProject = this.getCoreWorkspaceProject()
547547
if (!projects.has(coreProject)) {
548548
projects.add(coreProject)
@@ -566,16 +566,16 @@ export class Vitest {
566566
async runFiles(specs: WorkspaceSpec[], allTestsRun: boolean) {
567567
await this.initializeDistPath()
568568

569-
const filepaths = specs.map(([, file]) => file)
569+
const filepaths = specs.map(spec => spec.moduleId)
570570
this.state.collectPaths(filepaths)
571571

572572
await this.report('onPathsCollected', filepaths)
573573
await this.report('onSpecsCollected', specs.map(
574-
([project, file, options]) =>
574+
spec =>
575575
[{
576-
name: project.config.name,
577-
root: project.config.root,
578-
}, file, options] satisfies SerializedSpec,
576+
name: spec.project.config.name,
577+
root: spec.project.config.root,
578+
}, spec.moduleId, { pool: spec.pool }] satisfies SerializedSpec,
579579
))
580580

581581
// previous run
@@ -618,7 +618,7 @@ export class Vitest {
618618
})()
619619
.finally(async () => {
620620
// can be duplicate files if different projects are using the same file
621-
const files = Array.from(new Set(specs.map(([, p]) => p)))
621+
const files = Array.from(new Set(specs.map(spec => spec.moduleId)))
622622
const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun })
623623

624624
await this.report('onFinished', this.state.getFiles(files), this.state.getUnhandledErrors(), coverage)
@@ -638,7 +638,7 @@ export class Vitest {
638638
async collectFiles(specs: WorkspaceSpec[]) {
639639
await this.initializeDistPath()
640640

641-
const filepaths = specs.map(([, file]) => file)
641+
const filepaths = specs.map(spec => spec.moduleId)
642642
this.state.collectPaths(filepaths)
643643

644644
// previous run
@@ -709,7 +709,7 @@ export class Vitest {
709709
else { this.configOverride.project = pattern }
710710

711711
this.projects = this.resolvedProjects.filter(p => p.getName() === pattern)
712-
const files = (await this.globTestFiles()).map(([, file]) => file)
712+
const files = (await this.globTestSpecs()).map(spec => spec.moduleId)
713713
await this.rerunFiles(files, 'change project filter')
714714
}
715715

@@ -1083,28 +1083,35 @@ export class Vitest {
10831083
}
10841084

10851085
public async getTestFilepaths() {
1086-
return this.globTestFiles().then(files => files.map(([, file]) => file))
1086+
return this.globTestSpecs().then(specs => specs.map(spec => spec.moduleId))
10871087
}
10881088

1089-
public async globTestFiles(filters: string[] = []) {
1089+
public async globTestSpecs(filters: string[] = []) {
10901090
const files: WorkspaceSpec[] = []
10911091
await Promise.all(this.projects.map(async (project) => {
10921092
const { testFiles, typecheckTestFiles } = await project.globTestFiles(filters)
10931093
testFiles.forEach((file) => {
10941094
const pool = getFilePoolName(project, file)
1095-
const spec: WorkspaceSpec = [project, file, { pool }]
1095+
const spec = project.createSpec(file, pool)
10961096
this.ensureSpecCached(spec)
10971097
files.push(spec)
10981098
})
10991099
typecheckTestFiles.forEach((file) => {
1100-
const spec: WorkspaceSpec = [project, file, { pool: 'typescript' }]
1100+
const spec = project.createSpec(file, 'typescript')
11011101
this.ensureSpecCached(spec)
11021102
files.push(spec)
11031103
})
11041104
}))
11051105
return files
11061106
}
11071107

1108+
/**
1109+
* @deprecated use globTestSpecs instead
1110+
*/
1111+
public async globTestFiles(filters: string[] = []) {
1112+
return this.globTestSpecs(filters)
1113+
}
1114+
11081115
private ensureSpecCached(spec: WorkspaceSpec) {
11091116
const file = spec[1]
11101117
const specs = this._cachedSpecs.get(file) || []

packages/vitest/src/node/pool.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,23 @@ import { createVmThreadsPool } from './pools/vmThreads'
99
import type { WorkspaceProject } from './workspace'
1010
import { createTypecheckPool } from './pools/typecheck'
1111
import { createVmForksPool } from './pools/vmForks'
12+
import type { WorkspaceSpec as _WorkspaceSpec } from './spec'
13+
14+
export type WorkspaceSpec = _WorkspaceSpec & [
15+
/**
16+
* @deprecated use spec.project instead
17+
*/
18+
project: WorkspaceProject,
19+
/**
20+
* @deprecated use spec.moduleId instead
21+
*/
22+
file: string,
23+
/**
24+
* @deprecated use spec.pool instead
25+
*/
26+
options: { pool: Pool },
27+
]
1228

13-
export type WorkspaceSpec = [project: WorkspaceProject, testFile: string, options: { pool: Pool }]
1429
export type RunWithFiles = (
1530
files: WorkspaceSpec[],
1631
invalidates?: string[]

packages/vitest/src/node/pools/forks.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,19 @@ export function createForksPool(
166166
}
167167

168168
const workspaceMap = new Map<string, WorkspaceProject[]>()
169-
for (const [project, file] of specs) {
169+
for (const spec of specs) {
170+
const file = spec.moduleId
171+
const project = spec.project.workspaceProject
170172
const workspaceFiles = workspaceMap.get(file) ?? []
171173
workspaceFiles.push(project)
172174
workspaceMap.set(file, workspaceFiles)
173175
}
174176

175177
const singleFork = specs.filter(
176-
([project]) => project.config.poolOptions?.forks?.singleFork,
178+
spec => spec.project.config.poolOptions?.forks?.singleFork,
177179
)
178180
const multipleForks = specs.filter(
179-
([project]) => !project.config.poolOptions?.forks?.singleFork,
181+
spec => !spec.project.config.poolOptions?.forks?.singleFork,
180182
)
181183

182184
if (multipleForks.length) {

packages/vitest/src/node/pools/threads.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ export function createThreadsPool(
170170
}
171171

172172
const singleThreads = specs.filter(
173-
([project]) => project.config.poolOptions?.threads?.singleThread,
173+
spec => spec.project.config.poolOptions?.threads?.singleThread,
174174
)
175175
const multipleThreads = specs.filter(
176-
([project]) => !project.config.poolOptions?.threads?.singleThread,
176+
spec => !spec.project.config.poolOptions?.threads?.singleThread,
177177
)
178178

179179
if (multipleThreads.length) {

packages/vitest/src/node/pools/typecheck.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,20 @@ export function createTypecheckPool(ctx: Vitest): ProcessPool {
100100
}
101101

102102
async function collectTests(specs: WorkspaceSpec[]) {
103-
const specsByProject = groupBy(specs, ([project]) => project.getName())
103+
const specsByProject = groupBy(specs, spec => spec.project.name)
104104
for (const name in specsByProject) {
105-
const project = specsByProject[name][0][0]
106-
const files = specsByProject[name].map(([_, file]) => file)
107-
const checker = await createWorkspaceTypechecker(project, files)
105+
const project = specsByProject[name][0].project
106+
const files = specsByProject[name].map(spec => spec.moduleId)
107+
const checker = await createWorkspaceTypechecker(project.workspaceProject, files)
108108
checker.setFiles(files)
109109
await checker.collectTests()
110-
ctx.state.collectFiles(project, checker.getTestFiles())
110+
ctx.state.collectFiles(project.workspaceProject, checker.getTestFiles())
111111
await ctx.report('onCollected')
112112
}
113113
}
114114

115115
async function runTests(specs: WorkspaceSpec[]) {
116-
const specsByProject = groupBy(specs, ([project]) => project.getName())
116+
const specsByProject = groupBy(specs, spec => spec.project.name)
117117
const promises: Promise<void>[] = []
118118

119119
for (const name in specsByProject) {

packages/vitest/src/node/sequencers/BaseSequencer.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class BaseSequencer implements TestSequencer {
2121
const shardEnd = shardSize * index
2222
return [...files]
2323
.map((spec) => {
24-
const fullPath = resolve(slash(config.root), slash(spec[1]))
24+
const fullPath = resolve(slash(config.root), slash(spec.moduleId))
2525
const specPath = fullPath?.slice(config.root.length)
2626
return {
2727
spec,
@@ -37,8 +37,8 @@ export class BaseSequencer implements TestSequencer {
3737
public async sort(files: WorkspaceSpec[]): Promise<WorkspaceSpec[]> {
3838
const cache = this.ctx.cache
3939
return [...files].sort((a, b) => {
40-
const keyA = `${a[0].getName()}:${relative(this.ctx.config.root, a[1])}`
41-
const keyB = `${b[0].getName()}:${relative(this.ctx.config.root, b[1])}`
40+
const keyA = `${a.project.name}:${relative(this.ctx.config.root, a.moduleId)}`
41+
const keyB = `${b.project.name}:${relative(this.ctx.config.root, b.moduleId)}`
4242

4343
const aState = cache.getFileTestResults(keyA)
4444
const bState = cache.getFileTestResults(keyB)

packages/vitest/src/node/spec.ts

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type { TestProject } from './reported-workspace-project'
2+
import type { Pool } from './types/pool-options'
3+
import type { WorkspaceProject } from './workspace'
4+
5+
export class WorkspaceSpec {
6+
// backwards compatibility
7+
/**
8+
* @deprecated
9+
*/
10+
public readonly 0: WorkspaceProject
11+
/**
12+
* @deprecated
13+
*/
14+
public readonly 1: string
15+
/**
16+
* @deprecated
17+
*/
18+
public readonly 2: { pool: Pool }
19+
20+
public readonly project: TestProject
21+
public readonly moduleId: string
22+
public readonly pool: Pool
23+
// public readonly location: WorkspaceSpecLocation | undefined
24+
25+
constructor(
26+
workspaceProject: WorkspaceProject,
27+
moduleId: string,
28+
pool: Pool,
29+
// location?: WorkspaceSpecLocation | undefined,
30+
) {
31+
this[0] = workspaceProject
32+
this[1] = moduleId
33+
this[2] = { pool }
34+
this.project = workspaceProject.testProject
35+
this.moduleId = moduleId
36+
this.pool = pool
37+
// this.location = location
38+
}
39+
40+
/**
41+
* for backwards compatibility
42+
* @deprecated
43+
*/
44+
*[Symbol.iterator]() {
45+
yield this.project.workspaceProject
46+
yield this.moduleId
47+
yield this.pool
48+
}
49+
}
50+
51+
// interface WorkspaceSpecLocation {
52+
// start: number
53+
// end: number
54+
// }

packages/vitest/src/node/workspace.ts

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import { CoverageTransform } from './plugins/coverageTransform'
3939
import { serializeConfig } from './config/serializeConfig'
4040
import type { Vitest } from './core'
4141
import { TestProject } from './reported-workspace-project'
42+
import { WorkspaceSpec } from './spec'
43+
import type { WorkspaceSpec as DeprecatedWorkspaceSpec } from './pool'
4244

4345
interface InitializeProjectOptions extends UserWorkspaceConfig {
4446
workspaceConfigPath: string
@@ -151,6 +153,10 @@ export class WorkspaceProject {
151153
}
152154
}
153155

156+
public createSpec(moduleId: string, pool: string): DeprecatedWorkspaceSpec {
157+
return new WorkspaceSpec(this, moduleId, pool) as DeprecatedWorkspaceSpec
158+
}
159+
154160
async initializeGlobalSetup() {
155161
if (this._globalSetups) {
156162
return

packages/vitest/src/utils/test-helpers.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export async function groupFilesByEnv(
3030
files: Array<WorkspaceSpec>,
3131
) {
3232
const filesWithEnv = await Promise.all(
33-
files.map(async ([project, file]) => {
33+
files.map(async (spec) => {
34+
const file = spec.moduleId
35+
const project = spec.project.workspaceProject
3436
const code = await fs.readFile(file, 'utf-8')
3537

3638
// 1. Check for control comments in the file

test/core/test/sequencers.test.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { Vitest } from 'vitest'
1+
import type { Vitest, WorkspaceProject } from 'vitest/node'
22
import { describe, expect, test, vi } from 'vitest'
3-
import type { WorkspaceProject } from 'vitest/node'
43
import { RandomSequencer } from '../../../packages/vitest/src/node/sequencers/RandomSequencer'
54
import { BaseSequencer } from '../../../packages/vitest/src/node/sequencers/BaseSequencer'
6-
import type { WorkspaceSpec } from '../../../packages/vitest/src/node/pool'
5+
import { WorkspaceSpec } from '../../../packages/vitest/src/node/spec'
6+
import type { WorkspaceSpec as DeprecatedWorkspaceSpec } from '../../../packages/vitest/src/node/pool'
77

88
function buildCtx() {
99
return {
@@ -19,14 +19,16 @@ function buildCtx() {
1919

2020
function buildWorkspace() {
2121
return {
22-
getName: () => 'test',
22+
testProject: {
23+
name: 'test',
24+
},
2325
} as any as WorkspaceProject
2426
}
2527

2628
const workspace = buildWorkspace()
2729

2830
function workspaced(files: string[]) {
29-
return files.map(file => [workspace, file, { pool: 'forks' }] satisfies WorkspaceSpec)
31+
return files.map(file => new WorkspaceSpec(workspace, file, 'forks')) as DeprecatedWorkspaceSpec[]
3032
}
3133

3234
describe('base sequencer', () => {

0 commit comments

Comments
 (0)