Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 15 additions & 3 deletions docs/api/advanced/test-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ You can only create a specification by calling [`createSpecification`](/api/adva
```ts
const specification = project.createSpecification(
resolve('./example.test.ts'),
[20, 40], // optional test lines
{
testLines: [20, 40],
testNamePattern: /hello world/,
testIds: ['1223128da3_0_0_0', '1223128da3_0_0'],
} // optional test filters
)
```

`createSpecification` expects resolved module ID. It doesn't auto-resolve the file or check that it exists on the file system.
`createSpecification` expects resolved module identifier. It doesn't auto-resolve the file or check that it exists on the file system.

## taskId

Expand Down Expand Up @@ -40,7 +44,7 @@ Instance of [`TestModule`](/api/advanced/test-module) associated with the specif
The [`pool`](/config/#pool) in which the test module will run.

::: danger
It's possible to have multiple pools in a single test project with [`poolMatchGlob`](/config/#poolmatchglob) and [`typecheck.enabled`](/config/#typecheck-enabled). This means it's possible to have several specifications with the same `moduleId` but different `pool`. In Vitest 4, the project will only support a single pool, and this property will be removed.
It's possible to have multiple pools in a single test project with [`typecheck.enabled`](/config/#typecheck-enabled). This means it's possible to have several specifications with the same `moduleId` but different `pool`. In later versions, the project will only support a single pool.
:::

## testLines
Expand Down Expand Up @@ -70,6 +74,14 @@ describe('a group of tests', () => { // [!code error]
```
:::

## testNamePattern <Version>4.1.0</Version> {#testnamepattern}

A regexp that matches the name of the test in this module. This value will override the global [`testNamePattern`](/config/testnamepattern) option if it's set.

## testIds <Version>4.1.0</Version> {#testids}

The ids of tasks inside of this specification to run.

## toJSON

```ts
Expand Down
5 changes: 4 additions & 1 deletion packages/runner/src/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export async function collectTests(
{ 'code.file.path': filepath },
async () => {
const testLocations = typeof spec === 'string' ? undefined : spec.testLocations
const testNamePattern = typeof spec === 'string' ? undefined : spec.testNamePattern
const testIds = typeof spec === 'string' ? undefined : spec.testIds

const file = createFileTask(filepath, config.root, config.name, runner.pool, runner.viteEnvironment)
setFileContext(file, Object.create(null))
Expand Down Expand Up @@ -108,8 +110,9 @@ export async function collectTests(
const hasOnlyTasks = someTasksAreOnly(file)
interpretTaskModes(
file,
config.testNamePattern,
testNamePattern ?? config.testNamePattern,
testLocations,
testIds,
hasOnlyTasks,
false,
config.allowOnly,
Expand Down
2 changes: 2 additions & 0 deletions packages/runner/src/types/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export interface VitestRunnerConfig {
export interface FileSpecification {
filepath: string
testLocations: number[] | undefined
testNamePattern: RegExp | undefined
testIds: string[] | undefined
}

export type VitestRunnerImportSource = 'collect' | 'setup'
Expand Down
6 changes: 5 additions & 1 deletion packages/runner/src/utils/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function interpretTaskModes(
file: Suite,
namePattern?: string | RegExp,
testLocations?: number[] | undefined,
testIds?: string[] | undefined,
onlyMode?: boolean,
parentIsOnly?: boolean,
allowOnly?: boolean,
Expand Down Expand Up @@ -50,7 +51,7 @@ export function interpretTaskModes(

let hasLocationMatch = parentMatchedWithLocation
// Match test location against provided locations, only run if present
// in `testLocations`. Note: if `includeTaskLocations` is not enabled,
// in `testLocations`. Note: if `includeTaskLocation` is not enabled,
// all test will be skipped.
if (testLocations !== undefined && testLocations.length !== 0) {
if (t.location && testLocations?.includes(t.location.line)) {
Expand All @@ -70,6 +71,9 @@ export function interpretTaskModes(
if (namePattern && !getTaskFullName(t).match(namePattern)) {
t.mode = 'skip'
}
if (testIds && !testIds.includes(t.id)) {
t.mode = 'skip'
}
}
else if (t.type === 'suite') {
if (t.mode === 'skip') {
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/api/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { ViteDevServer } from 'vite'
import type { WebSocket } from 'ws'
import type { Vitest } from '../node/core'
import type { TestCase, TestModule } from '../node/reporters/reported-tasks'
import type { TestSpecification } from '../node/spec'
import type { TestSpecification } from '../node/test-specification'
import type { Reporter } from '../node/types/reporter'
import type { LabelColor, ModuleGraphData, UserConsoleLog } from '../types/general'
import type {
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/node/ast-collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ function createFileTask(
file,
options.testNamePattern,
undefined,
undefined,
hasOnly,
false,
options.allowOnly,
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/cache/files.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Stats } from 'node:fs'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import fs from 'node:fs'
import { relative } from 'pathe'

Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/cli/cli-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { InlineConfig as ViteInlineConfig, UserConfig as ViteUserConfig } f
import type { environments } from '../../integrations/env'
import type { Vitest, VitestOptions } from '../core'
import type { TestModule, TestSuite } from '../reporters/reported-tasks'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import type { UserConfig, VitestEnvironment, VitestRunMode } from '../types/config'
import { mkdirSync, writeFileSync } from 'node:fs'
import { dirname, isAbsolute, relative, resolve } from 'pathe'
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { CliOptions } from './cli/cli-api'
import type { VitestFetchFunction } from './environments/fetchModule'
import type { ProcessPool } from './pool'
import type { TestModule } from './reporters/reported-tasks'
import type { TestSpecification } from './spec'
import type { TestSpecification } from './test-specification'
import type { ResolvedConfig, TestProjectConfiguration, UserConfig, VitestRunMode } from './types/config'
import type { CoverageProvider, ResolvedCoverageOptions } from './types/coverage'
import type { Reporter } from './types/reporter'
Expand Down
9 changes: 7 additions & 2 deletions packages/vitest/src/node/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ContextTestEnvironment } from '../types/worker'
import type { Vitest } from './core'
import type { PoolTask } from './pools/types'
import type { TestProject } from './project'
import type { TestSpecification } from './spec'
import type { TestSpecification } from './test-specification'
import type { BuiltinPool, ResolvedConfig } from './types/config'
import * as nodeos from 'node:os'
import { isatty } from 'node:tty'
Expand Down Expand Up @@ -147,7 +147,12 @@ export function createPool(ctx: Vitest): ProcessPool {

taskGroup.push({
context: {
files: specs.map(spec => ({ filepath: spec.moduleId, testLocations: spec.testLines })),
files: specs.map(spec => ({
filepath: spec.moduleId,
testLocations: spec.testLines,
testNamePattern: spec.testNamePattern,
testIds: spec.testIds,
})),
invalidates,
providedContext: project.getProvidedContext(),
workerId: workerId++,
Expand Down
6 changes: 4 additions & 2 deletions packages/vitest/src/node/pools/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Traces } from '../../utils/traces'
import type { Vitest } from '../core'
import type { ProcessPool } from '../pool'
import type { TestProject } from '../project'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import type { BrowserProvider } from '../types/browser'
import crypto from 'node:crypto'
import * as nodeos from 'node:os'
Expand Down Expand Up @@ -62,11 +62,13 @@ export function createBrowserPool(vitest: Vitest): ProcessPool {

const runWorkspaceTests = async (method: 'run' | 'collect', specs: TestSpecification[]) => {
const groupedFiles = new Map<TestProject, FileSpecification[]>()
for (const { project, moduleId, testLines } of specs) {
for (const { project, moduleId, testLines, testIds, testNamePattern } of specs) {
const files = groupedFiles.get(project) || []
files.push({
filepath: moduleId,
testLocations: testLines,
testIds,
testNamePattern,
})
groupedFiles.set(project, files)
}
Expand Down
7 changes: 4 additions & 3 deletions packages/vitest/src/node/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ProvidedContext } from '../types/general'
import type { OnTestsRerunHandler, Vitest } from './core'
import type { VitestFetchFunction } from './environments/fetchModule'
import type { GlobalSetupFile } from './globalSetup'
import type { TestSpecificationOptions } from './test-specification'
import type { ParentProjectBrowser, ProjectBrowser } from './types/browser'
import type {
ProjectName,
Expand Down Expand Up @@ -35,7 +36,7 @@ import { MocksPlugins } from './plugins/mocks'
import { WorkspaceVitestPlugin } from './plugins/workspace'
import { getFilePoolName } from './pool'
import { VitestResolver } from './resolver'
import { TestSpecification } from './spec'
import { TestSpecification } from './test-specification'
import { createViteServer } from './vite'

export class TestProject {
Expand Down Expand Up @@ -144,15 +145,15 @@ export class TestProject {
*/
public createSpecification(
moduleId: string,
locations?: number[] | undefined,
locationsOrOptions?: number[] | TestSpecificationOptions | undefined,
/** @internal */
pool?: string,
): TestSpecification {
return new TestSpecification(
this,
moduleId,
pool || getFilePoolName(this),
locations,
locationsOrOptions,
)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/reporters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { File, Task, TestAnnotation } from '@vitest/runner'
import type { SerializedError } from '@vitest/utils'
import type { TestError, UserConsoleLog } from '../../types/general'
import type { Vitest } from '../core'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import type { Reporter, TestRunEndReason } from '../types/reporter'
import type { TestCase, TestCollection, TestModule, TestModuleState, TestResult, TestSuite, TestSuiteState } from './reported-tasks'
import { performance } from 'node:perf_hooks'
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/reporters/default.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SerializedError } from '@vitest/utils'
import type { Vitest } from '../core'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import type { TestRunEndReason } from '../types/reporter'
import type { BaseOptions } from './base'
import type { ReportedHookContext, TestCase, TestModule } from './reported-tasks'
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/reporters/summary.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Vitest } from '../core'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import type { Reporter } from '../types/reporter'
import type { ReportedHookContext, TestCase, TestModule } from './reported-tasks'
import c from 'tinyrainbow'
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/sequencers/BaseSequencer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Vitest } from '../core'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import type { TestSequencer } from './types'
import { slash } from '@vitest/utils/helpers'
import { relative, resolve } from 'pathe'
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/sequencers/RandomSequencer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'
import { shuffle } from '@vitest/utils/helpers'
import { BaseSequencer } from './BaseSequencer'

Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/sequencers/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Awaitable } from '@vitest/utils'
import type { Vitest } from '../core'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'

export interface TestSequencer {
/**
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/specifications.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Vitest } from './core'
import type { TestProject } from './project'
import type { TestSpecification } from './spec'
import type { TestSpecification } from './test-specification'
import { existsSync } from 'node:fs'
import { join, relative, resolve } from 'pathe'
import pm from 'picomatch'
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/test-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { UserConsoleLog } from '../types/general'
import type { Vitest } from './core'
import type { TestProject } from './project'
import type { ReportedHookContext, TestCase, TestCollection, TestModule } from './reporters/reported-tasks'
import type { TestSpecification } from './spec'
import type { TestSpecification } from './test-specification'
import type { TestRunEndReason } from './types/reporter'
import assert from 'node:assert'
import { createHash } from 'node:crypto'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,59 @@ import type { Pool } from './types/config'
import { generateFileHash } from '@vitest/runner/utils'
import { relative } from 'pathe'

export interface TestSpecificationOptions {
testNamePattern?: RegExp
testIds?: string[]
testLines?: number[]
}

export class TestSpecification {
/**
* The task ID associated with the test module.
* The task id associated with the test module.
*/
public readonly taskId: string
/**
* The test project that the module belongs to.
*/
public readonly project: TestProject
/**
* The ID of the module in the Vite module graph. It is usually an absolute file path.
* The id of the module in the Vite module graph. It is usually an absolute file path.
*/
public readonly moduleId: string
/**
* The current test pool. It's possible to have multiple pools in a single test project with `poolMatchGlob` and `typecheck.enabled`.
* @experimental In Vitest 4, the project will only support a single pool and this property will be removed.
* The current test pool. It's possible to have multiple pools in a single test project with `typecheck.enabled`.
* @experimental In later versions, the project will only support a single pool.
*/
public readonly pool: Pool
/**
* Line numbers of the test locations to run.
*/
public readonly testLines: number[] | undefined
/**
* Regular expression pattern to filter test names.
*/
public readonly testNamePattern: RegExp | undefined
/**
* The ids of tasks inside of this specification to run.
*/
public readonly testIds: string[] | undefined

/**
* This class represents a test suite for a test module within a single project.
* @internal
*/
constructor(
project: TestProject,
moduleId: string,
pool: Pool,
testLines?: number[] | undefined,
testLinesOrOptions?: number[] | TestSpecificationOptions | undefined,
) {
const name = project.config.name
const projectName = project.config.name
const hashName = pool !== 'typescript'
? name
: name
? projectName
: projectName
// https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/typecheck/collect.ts#L58
? `${name}:__typecheck__`
? `${projectName}:__typecheck__`
: '__typecheck__'
this.taskId = generateFileHash(
relative(project.config.root, moduleId),
Expand All @@ -48,11 +66,18 @@ export class TestSpecification {
this.project = project
this.moduleId = moduleId
this.pool = pool
this.testLines = testLines
if (Array.isArray(testLinesOrOptions)) {
this.testLines = testLinesOrOptions
}
else if (testLinesOrOptions && typeof testLinesOrOptions === 'object') {
this.testLines = testLinesOrOptions.testLines
this.testNamePattern = testLinesOrOptions.testNamePattern
this.testIds = testLinesOrOptions.testIds
}
}

/**
* Test module associated with the specification.
* Test module associated with the specification. This will be `undefined` if tests have not been run yet.
*/
get testModule(): TestModule | undefined {
const task = this.project.vitest.state.idMap.get(this.taskId)
Expand All @@ -69,7 +94,12 @@ export class TestSpecification {
root: this.project.config.root,
},
this.moduleId,
{ pool: this.pool, testLines: this.testLines },
{
pool: this.pool,
testLines: this.testLines,
testIds: this.testIds,
testNamePattern: this.testNamePattern,
},
]
}
}
2 changes: 1 addition & 1 deletion packages/vitest/src/node/types/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { UserConsoleLog } from '../../types/general'
import type { Vitest } from '../core'
import type { TestProject } from '../project'
import type { ReportedHookContext, TestCase, TestModule, TestSuite } from '../reporters/reported-tasks'
import type { TestSpecification } from '../spec'
import type { TestSpecification } from '../test-specification'

export type TestRunEndReason = 'passed' | 'interrupted' | 'failed'

Expand Down
Loading
Loading