diff --git a/packages/runner/src/collect.ts b/packages/runner/src/collect.ts index 8dd17a95cde9..ce7b2301d667 100644 --- a/packages/runner/src/collect.ts +++ b/packages/runner/src/collect.ts @@ -60,7 +60,7 @@ export async function collectTests( mergeHooks(fileHooks, getHooks(defaultTasks)) for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) { - if (c.type === 'test' || c.type === 'suite') { + if (c.type === 'test' || c.type === 'custom' || c.type === 'suite') { file.tasks.push(c) } else if (c.type === 'collector') { diff --git a/packages/runner/src/run.ts b/packages/runner/src/run.ts index c06aaf5bdacf..0972a45cc321 100644 --- a/packages/runner/src/run.ts +++ b/packages/runner/src/run.ts @@ -2,6 +2,7 @@ import type { Awaitable } from '@vitest/utils' import type { DiffOptions } from '@vitest/utils/diff' import type { FileSpec, VitestRunner } from './types/runner' import type { + Custom, File, HookCleanupCallback, HookListener, @@ -176,7 +177,7 @@ async function callCleanupHooks(cleanups: HookCleanupCallback[]) { ) } -export async function runTest(test: Test, runner: VitestRunner): Promise { +export async function runTest(test: Test | Custom, runner: VitestRunner): Promise { await runner.onBeforeRunTask?.(test) if (test.mode !== 'run') { @@ -470,7 +471,7 @@ export async function runSuite(suite: Suite, runner: VitestRunner): Promise async function runSuiteChild(c: Task, runner: VitestRunner) { - if (c.type === 'test') { + if (c.type === 'test' || c.type === 'custom') { return limitMaxConcurrency(() => runTest(c, runner)) } else if (c.type === 'suite') { diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index 6f0d255f0432..a59423a0b887 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -1,6 +1,7 @@ import type { FixtureItem } from './fixture' import type { VitestRunner } from './types/runner' import type { + Custom, CustomAPI, File, Fixtures, @@ -293,7 +294,7 @@ function createSuiteCollector( each?: boolean, suiteOptions?: TestOptions, ) { - const tasks: (Test | Suite | SuiteCollector)[] = [] + const tasks: (Test | Custom | Suite | SuiteCollector)[] = [] const factoryQueue: (Test | Suite | SuiteCollector)[] = [] let suite: Suite diff --git a/packages/runner/src/test-state.ts b/packages/runner/src/test-state.ts index af1d5b04157f..6e7bd01957ea 100644 --- a/packages/runner/src/test-state.ts +++ b/packages/runner/src/test-state.ts @@ -1,11 +1,11 @@ -import type { Test } from './types/tasks.ts' +import type { Custom, Test } from './types/tasks.ts' -let _test: Test | undefined +let _test: Test | Custom | undefined -export function setCurrentTest(test: T | undefined): void { +export function setCurrentTest(test: T | undefined): void { _test = test } -export function getCurrentTest(): T { +export function getCurrentTest(): T { return _test as T } diff --git a/packages/runner/src/types/runner.ts b/packages/runner/src/types/runner.ts index a8571f7415b1..9fb34109303f 100644 --- a/packages/runner/src/types/runner.ts +++ b/packages/runner/src/types/runner.ts @@ -1,5 +1,6 @@ import type { DiffOptions } from '@vitest/utils/diff' import type { + Custom, ExtendedContext, File, SequenceHooks, @@ -90,7 +91,7 @@ export interface VitestRunner { /** * When the task has finished running, but before cleanup hooks are called */ - onTaskFinished?: (test: Test) => unknown + onTaskFinished?: (test: Test | Custom) => unknown /** * Called after result and state are set. */ diff --git a/packages/runner/src/types/tasks.ts b/packages/runner/src/types/tasks.ts index 3ac9666774b6..3fbfbff43128 100644 --- a/packages/runner/src/types/tasks.ts +++ b/packages/runner/src/types/tasks.ts @@ -234,7 +234,7 @@ export interface Custom extends TaskPopulated { context: TaskContext & ExtraContext & TestContext } -export type Task = Test | Suite | File +export type Task = Test | Suite | Custom | File /** * @deprecated Vitest doesn't provide `done()` anymore @@ -578,6 +578,8 @@ export interface SuiteCollector { test: TestAPI tasks: ( | Suite + // TODO: remove in Vitest 3 + | Custom | Test | SuiteCollector )[] diff --git a/packages/runner/src/utils/tasks.ts b/packages/runner/src/utils/tasks.ts index 3cd7515d935c..b1071ca8bb2e 100644 --- a/packages/runner/src/utils/tasks.ts +++ b/packages/runner/src/utils/tasks.ts @@ -1,19 +1,19 @@ -import type { Suite, Task, Test } from '../types/tasks' +import type { Custom, Suite, Task, Test } from '../types/tasks' import { type Arrayable, toArray } from '@vitest/utils' /** * @deprecated use `isTestCase` instead */ -export function isAtomTest(s: Task): s is Test { +export function isAtomTest(s: Task): s is Test | Custom { return isTestCase(s) } -export function isTestCase(s: Task): s is Test { - return s.type === 'test' +export function isTestCase(s: Task): s is Test | Custom { + return s.type === 'test' || s.type === 'custom' } -export function getTests(suite: Arrayable): Test[] { - const tests: Test[] = [] +export function getTests(suite: Arrayable): (Test | Custom)[] { + const tests: (Test | Custom)[] = [] const arraySuites = toArray(suite) for (const s of arraySuites) { if (isTestCase(s)) { diff --git a/packages/ui/client/components/views/ViewReport.vue b/packages/ui/client/components/views/ViewReport.vue index d3fdc802bdea..050e25635ce6 100644 --- a/packages/ui/client/components/views/ViewReport.vue +++ b/packages/ui/client/components/views/ViewReport.vue @@ -19,7 +19,7 @@ function collectFailed(task: Task, level: number): LeveledTask[] { return [] } - if (task.type === 'test') { + if (task.type === 'test' || task.type === 'custom') { return [{ ...task, level }] } else { diff --git a/packages/ui/client/composables/explorer/collector.ts b/packages/ui/client/composables/explorer/collector.ts index 86dd7ce630ba..ad049e21a7ae 100644 --- a/packages/ui/client/composables/explorer/collector.ts +++ b/packages/ui/client/composables/explorer/collector.ts @@ -1,7 +1,7 @@ -import type { File, Task, TaskResultPack, Test } from '@vitest/runner' +import type { Custom, File, Task, TaskResultPack, Test } from '@vitest/runner' import type { Arrayable } from '@vitest/utils' import type { CollectFilteredTests, CollectorInfo, Filter, FilteredTests } from '~/composables/explorer/types' -import { isTestCase } from '@vitest/runner/utils/tasks' +import { isAtomTest } from '@vitest/runner/utils' import { toArray } from '@vitest/utils' import { hasFailedSnapshot } from '@vitest/ws-client' import { client, findById } from '~/composables/client' @@ -460,12 +460,12 @@ export function collectTestsTotalData( return filesSummary } -function* testsCollector(suite: Arrayable): Generator { +function* testsCollector(suite: Arrayable): Generator { const arraySuites = toArray(suite) let s: Task for (let i = 0; i < arraySuites.length; i++) { s = arraySuites[i] - if (isTestCase(s)) { + if (isAtomTest(s)) { yield s } else { diff --git a/packages/ui/client/composables/explorer/types.ts b/packages/ui/client/composables/explorer/types.ts index 0544676b9d91..2e55175a6fb3 100644 --- a/packages/ui/client/composables/explorer/types.ts +++ b/packages/ui/client/composables/explorer/types.ts @@ -25,7 +25,7 @@ export interface RootTreeNode extends TaskTreeNode { tasks: FileTreeNode[] } -export type TaskTreeNodeType = 'file' | 'suite' | 'test' +export type TaskTreeNodeType = 'file' | 'suite' | 'test' | 'custom' export interface UITaskTreeNode extends TaskTreeNode { type: TaskTreeNodeType @@ -42,6 +42,11 @@ export interface TestTreeNode extends UITaskTreeNode { type: 'test' } +export interface CustomTestTreeNode extends UITaskTreeNode { + fileId: string + type: 'custom' +} + export interface ParentTreeNode extends UITaskTreeNode { children: Set tasks: UITaskTreeNode[] diff --git a/packages/ui/client/composables/explorer/utils.ts b/packages/ui/client/composables/explorer/utils.ts index dede3a7815b0..65f1229fd7c3 100644 --- a/packages/ui/client/composables/explorer/utils.ts +++ b/packages/ui/client/composables/explorer/utils.ts @@ -1,5 +1,6 @@ import type { File, Task } from '@vitest/runner' import type { + CustomTestTreeNode, FileTreeNode, ParentTreeNode, SuiteTreeNode, @@ -12,12 +13,12 @@ import { explorerTree } from '~/composables/explorer/index' import { openedTreeItemsSet } from '~/composables/explorer/state' import { getProjectNameColor, isSuite as isTaskSuite } from '~/utils/task' -export function isTestNode(node: UITaskTreeNode): node is TestTreeNode { - return node.type === 'test' +export function isTestNode(node: UITaskTreeNode): node is TestTreeNode | CustomTestTreeNode { + return node.type === 'test' || node.type === 'custom' } -export function isRunningTestNode(node: UITaskTreeNode): node is TestTreeNode { - return node.mode === 'run' && (node.type === 'test') +export function isRunningTestNode(node: UITaskTreeNode): node is TestTreeNode | CustomTestTreeNode { + return node.mode === 'run' && (node.type === 'test' || node.type === 'custom') } export function isFileNode(node: UITaskTreeNode): node is FileTreeNode { @@ -160,7 +161,7 @@ export function createOrUpdateNode( indent: node.indent + 1, duration, state: task.result?.state, - } as TestTreeNode + } as TestTreeNode | CustomTestTreeNode } else { taskNode = { diff --git a/packages/vitest/src/node/reporters/dot.ts b/packages/vitest/src/node/reporters/dot.ts index 718c81a326cd..ee0206221ca9 100644 --- a/packages/vitest/src/node/reporters/dot.ts +++ b/packages/vitest/src/node/reporters/dot.ts @@ -1,4 +1,4 @@ -import type { File, TaskResultPack, TaskState, Test } from '@vitest/runner' +import type { Custom, File, TaskResultPack, TaskState, Test } from '@vitest/runner' import type { Vitest } from '../core' import { getTests } from '@vitest/runner/utils' import c from 'tinyrainbow' @@ -78,7 +78,7 @@ class DotSummary extends TaskParser { } } - onTestStart(test: Test) { + onTestStart(test: Test | Custom) { if (this.finishedTests.has(test.id)) { return } @@ -86,7 +86,7 @@ class DotSummary extends TaskParser { this.tests.set(test.id, test.mode || 'run') } - onTestFinished(test: Test) { + onTestFinished(test: Test | Custom) { if (this.finishedTests.has(test.id)) { return } diff --git a/packages/vitest/src/node/reporters/reported-tasks.ts b/packages/vitest/src/node/reporters/reported-tasks.ts index cd918e7bfbd4..973570d6c4f4 100644 --- a/packages/vitest/src/node/reporters/reported-tasks.ts +++ b/packages/vitest/src/node/reporters/reported-tasks.ts @@ -1,4 +1,5 @@ import type { + Custom as RunnerCustomCase, Task as RunnerTask, Test as RunnerTestCase, File as RunnerTestFile, @@ -55,7 +56,7 @@ class ReportedTaskImplementation { export class TestCase extends ReportedTaskImplementation { #fullName: string | undefined - declare public readonly task: RunnerTestCase + declare public readonly task: RunnerTestCase | RunnerCustomCase public readonly type = 'test' /** @@ -78,7 +79,7 @@ export class TestCase extends ReportedTaskImplementation { */ public readonly parent: TestSuite | TestModule - protected constructor(task: RunnerTestCase, project: TestProject) { + protected constructor(task: RunnerTestCase | RunnerCustomCase, project: TestProject) { super(task, project) this.name = task.name @@ -404,7 +405,7 @@ export interface TaskOptions { } function buildOptions( - task: RunnerTestCase | RunnerTestFile | RunnerTestSuite, + task: RunnerTestCase | RunnerCustomCase | RunnerTestFile | RunnerTestSuite, ): TaskOptions { return { each: task.each, diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index 9646c2ac5bb4..25030392d4a7 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -1,4 +1,4 @@ -import type { File, Test } from '@vitest/runner' +import type { Custom, File, Test } from '@vitest/runner' import type { Vitest } from '../core' import type { Reporter } from '../types/reporter' import type { HookOptions } from './task-parser' @@ -169,7 +169,7 @@ export class SummaryReporter extends TaskParser implements Reporter { stats.hook.visible = false } - onTestStart(test: Test) { + onTestStart(test: Test | Custom) { // Track slow running tests only on verbose mode if (!this.options.verbose) { return @@ -200,7 +200,7 @@ export class SummaryReporter extends TaskParser implements Reporter { stats.tests.set(test.id, slowTest) } - onTestFinished(test: Test) { + onTestFinished(test: Test | Custom) { const stats = this.getTestStats(test) if (!stats) { @@ -262,7 +262,7 @@ export class SummaryReporter extends TaskParser implements Reporter { } } - private getTestStats(test: Test) { + private getTestStats(test: Test | Custom) { const file = test.file let stats = this.runningTests.get(file.id) diff --git a/packages/vitest/src/node/reporters/task-parser.ts b/packages/vitest/src/node/reporters/task-parser.ts index 54d517ec962f..3859594dc44a 100644 --- a/packages/vitest/src/node/reporters/task-parser.ts +++ b/packages/vitest/src/node/reporters/task-parser.ts @@ -1,4 +1,4 @@ -import type { File, Task, TaskResultPack, Test } from '@vitest/runner' +import type { Custom, File, Task, TaskResultPack, Test } from '@vitest/runner' import type { Vitest } from '../core' import { getTests } from '@vitest/runner/utils' @@ -19,8 +19,8 @@ export class TaskParser { onHookStart(_options: HookOptions) {} onHookEnd(_options: HookOptions) {} - onTestStart(_test: Test) {} - onTestFinished(_test: Test) {} + onTestStart(_test: Test | Custom) {} + onTestFinished(_test: Test | Custom) {} onTestFilePrepare(_file: File) {} onTestFileFinished(_file: File) {} @@ -29,8 +29,8 @@ export class TaskParser { const startingTestFiles: File[] = [] const finishedTestFiles: File[] = [] - const startingTests: Test[] = [] - const finishedTests: Test[] = [] + const startingTests: (Test | Custom)[] = [] + const finishedTests: (Test | Custom)[] = [] const startingHooks: HookOptions[] = [] const endingHooks: HookOptions[] = [] @@ -54,7 +54,7 @@ export class TaskParser { } } - if (task?.type === 'test') { + if (task?.type === 'test' || task?.type === 'custom') { if (task.result?.state === 'run') { startingTests.push(task) } diff --git a/packages/vitest/src/public/index.ts b/packages/vitest/src/public/index.ts index 6a02c1759f6d..f37053248b03 100644 --- a/packages/vitest/src/public/index.ts +++ b/packages/vitest/src/public/index.ts @@ -161,7 +161,7 @@ export type Suite = Suite_ export type File = File_ /** @deprecated use `RunnerTestCase` instead */ export type Test = Test_ -/** @deprecated do not use `Custom`, use `RunnerTestCase` instead */ +/** @deprecated use `RunnerCustomCase` instead */ export type Custom = Custom_ /** @deprecated use `RunnerTask` instead */ export type Task = Task_