From 45e8ca8702fef90d5d0d9d44ab8abc639be6824e Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 19 Nov 2024 11:13:16 +0100 Subject: [PATCH 01/16] feat(runner): add "queued" state --- packages/runner/src/collect.ts | 2 ++ packages/runner/src/types/tasks.ts | 3 ++- packages/runner/src/utils/collect.ts | 2 +- packages/vitest/src/runtime/runners/benchmark.ts | 2 +- packages/vitest/src/runtime/runners/test.ts | 2 +- packages/vitest/src/typecheck/collect.ts | 4 ++-- packages/vitest/src/typecheck/typechecker.ts | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/runner/src/collect.ts b/packages/runner/src/collect.ts index 8dd17a95cde9..691b0d8a2d8b 100644 --- a/packages/runner/src/collect.ts +++ b/packages/runner/src/collect.ts @@ -4,6 +4,7 @@ import { toArray } from '@vitest/utils' import { processError } from '@vitest/utils/error' import { collectorContext } from './context' import { getHooks, setHooks } from './map' +import { updateTask } from './run' import { runSetupFiles } from './setup' import { clearCollectorContext, @@ -34,6 +35,7 @@ export async function collectTests( const file = createFileTask(filepath, config.root, config.name, runner.pool) file.shuffle = config.sequence.shuffle + updateTask(file, runner) runner.onCollectStart?.(file) clearCollectorContext(filepath, runner) diff --git a/packages/runner/src/types/tasks.ts b/packages/runner/src/types/tasks.ts index db53a597d28b..9a970ce2a924 100644 --- a/packages/runner/src/types/tasks.ts +++ b/packages/runner/src/types/tasks.ts @@ -2,7 +2,7 @@ import type { Awaitable, ErrorWithDiff } from '@vitest/utils' import type { FixtureItem } from '../fixture' import type { ChainableFunction } from '../utils/chain' -export type RunMode = 'run' | 'skip' | 'only' | 'todo' +export type RunMode = 'run' | 'skip' | 'only' | 'todo' | 'queued' export type TaskState = RunMode | 'pass' | 'fail' export interface TaskBase { @@ -23,6 +23,7 @@ export interface TaskBase { * - **only**: only this task and other tasks with `only` mode will run * - **todo**: task is marked as a todo, alias for `skip` * - **run**: task will run or already ran + * - **queued**: task will start running next */ mode: RunMode /** diff --git a/packages/runner/src/utils/collect.ts b/packages/runner/src/utils/collect.ts index f492cc5c789b..15aa2fe0bfb7 100644 --- a/packages/runner/src/utils/collect.ts +++ b/packages/runner/src/utils/collect.ts @@ -172,7 +172,7 @@ export function createFileTask( id: generateHash(`${path}${projectName || ''}`), name: path, type: 'suite', - mode: 'run', + mode: 'queued', filepath, tasks: [], meta: Object.create(null), diff --git a/packages/vitest/src/runtime/runners/benchmark.ts b/packages/vitest/src/runtime/runners/benchmark.ts index d3d2a0be9fb1..59aa7ac7dc64 100644 --- a/packages/vitest/src/runtime/runners/benchmark.ts +++ b/packages/vitest/src/runtime/runners/benchmark.ts @@ -35,7 +35,7 @@ async function runBenchmarkSuite(suite: Suite, runner: NodeBenchmarkRunner) { const benchmarkGroup: Benchmark[] = [] const benchmarkSuiteGroup = [] for (const task of suite.tasks) { - if (task.mode !== 'run') { + if (task.mode !== 'run' && task.mode !== 'queued') { continue } diff --git a/packages/vitest/src/runtime/runners/test.ts b/packages/vitest/src/runtime/runners/test.ts index 54c46adf3d08..0003d0193a09 100644 --- a/packages/vitest/src/runtime/runners/test.ts +++ b/packages/vitest/src/runtime/runners/test.ts @@ -93,7 +93,7 @@ export class VitestTestRunner implements VitestRunner { test.mode = 'skip' } - if (test.mode !== 'run') { + if (test.mode !== 'run' && test.mode !== 'queued') { return } diff --git a/packages/vitest/src/typecheck/collect.ts b/packages/vitest/src/typecheck/collect.ts index 4b1ae34ddfa1..075c739c1823 100644 --- a/packages/vitest/src/typecheck/collect.ts +++ b/packages/vitest/src/typecheck/collect.ts @@ -1,4 +1,4 @@ -import type { File, Suite, Test } from '@vitest/runner' +import type { File, RunMode, Suite, Test } from '@vitest/runner' import type { Node } from 'estree' import type { RawSourceMap } from 'vite-node' import type { TestProject } from '../node/project' @@ -32,7 +32,7 @@ interface LocalCallDefinition { end: number name: string type: 'suite' | 'test' - mode: 'run' | 'skip' | 'only' | 'todo' + mode: RunMode task: ParsedSuite | ParsedFile | ParsedTest } diff --git a/packages/vitest/src/typecheck/typechecker.ts b/packages/vitest/src/typecheck/typechecker.ts index 5b8710ee59d5..b52b255cbc1e 100644 --- a/packages/vitest/src/typecheck/typechecker.ts +++ b/packages/vitest/src/typecheck/typechecker.ts @@ -112,7 +112,7 @@ export class Typechecker { if ('tasks' in task) { markTasks(task.tasks) } - if (!task.result?.state && task.mode === 'run') { + if (!task.result?.state && (task.mode === 'run' || task.mode === 'queued')) { task.result = { state: 'pass', } From effe144237e270980923d08ebe82321c4c5b2d13 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 19 Nov 2024 11:17:24 +0100 Subject: [PATCH 02/16] chore: cleanup --- packages/vitest/src/node/reporters/reported-tasks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vitest/src/node/reporters/reported-tasks.ts b/packages/vitest/src/node/reporters/reported-tasks.ts index cd918e7bfbd4..b671769041cf 100644 --- a/packages/vitest/src/node/reporters/reported-tasks.ts +++ b/packages/vitest/src/node/reporters/reported-tasks.ts @@ -400,7 +400,7 @@ export interface TaskOptions { shuffle: boolean | undefined retry: number | undefined repeats: number | undefined - mode: 'run' | 'only' | 'skip' | 'todo' + mode: 'run' | 'only' | 'skip' | 'todo' | 'queued' } function buildOptions( From ee333b0f5333408f5d210fb50f564e10c5ffb61c Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 19 Nov 2024 11:35:22 +0100 Subject: [PATCH 03/16] chore: cleanup --- packages/vitest/src/node/reporters/json.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vitest/src/node/reporters/json.ts b/packages/vitest/src/node/reporters/json.ts index 1b46c62bd2ab..ea6737dd29f8 100644 --- a/packages/vitest/src/node/reporters/json.ts +++ b/packages/vitest/src/node/reporters/json.ts @@ -26,6 +26,7 @@ const StatusMap: Record = { run: 'pending', skip: 'skipped', todo: 'todo', + queued: 'pending', } export interface JsonAssertionResult { From 5403c98bc713c85b152f5b8c05ffd46ecaeaaa1c Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 19 Nov 2024 15:22:11 +0100 Subject: [PATCH 04/16] fix: more "queued" checks --- packages/runner/src/run.ts | 4 ++-- packages/runner/src/types/tasks.ts | 2 +- packages/runner/src/utils/collect.ts | 6 +++--- packages/vitest/src/node/cli/cli-api.ts | 4 ++-- packages/vitest/src/node/reporters/base.ts | 3 ++- packages/vitest/src/node/reporters/benchmark/table/index.ts | 3 ++- packages/vitest/src/node/reporters/json.ts | 6 +++--- packages/vitest/src/node/reporters/renderers/utils.ts | 2 +- packages/vitest/src/node/reporters/reported-tasks.ts | 4 ++-- packages/vitest/src/node/reporters/task-parser.ts | 6 +++--- packages/vitest/src/node/reporters/verbose.ts | 1 + 11 files changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/runner/src/run.ts b/packages/runner/src/run.ts index 44c1baf3b189..8c35b9f88006 100644 --- a/packages/runner/src/run.ts +++ b/packages/runner/src/run.ts @@ -196,7 +196,7 @@ async function callCleanupHooks(cleanups: HookCleanupCallback[]) { export async function runTest(test: Test, runner: VitestRunner): Promise { await runner.onBeforeRunTask?.(test) - if (test.mode !== 'run') { + if (test.mode !== 'run' && test.mode !== 'queued') { return } @@ -458,7 +458,7 @@ export async function runSuite(suite: Suite, runner: VitestRunner): Promise i.mode !== 'run')) { + if (suite.mode === 'run' || suite.mode === 'queued') { + if (suite.tasks.length && suite.tasks.every(i => i.mode !== 'run' && i.mode !== 'queued')) { suite.mode = 'skip' } } @@ -115,7 +115,7 @@ export function someTasksAreOnly(suite: Suite): boolean { function skipAllTasks(suite: Suite) { suite.tasks.forEach((t) => { - if (t.mode === 'run') { + if (t.mode === 'run' || t.mode === 'queued') { t.mode = 'skip' if (t.type === 'suite') { skipAllTasks(t) diff --git a/packages/vitest/src/node/cli/cli-api.ts b/packages/vitest/src/node/cli/cli-api.ts index a0fb736c518c..11f40f41e104 100644 --- a/packages/vitest/src/node/cli/cli-api.ts +++ b/packages/vitest/src/node/cli/cli-api.ts @@ -257,7 +257,7 @@ function forEachSuite(tasks: Task[], callback: (suite: Suite) => void) { export function formatCollectedAsJSON(files: File[]) { return files.map((file) => { - const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'only') + const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'queued' || test.mode === 'only') return tests.map((test) => { const result: any = { name: getNames(test).slice(1).join(' > '), @@ -276,7 +276,7 @@ export function formatCollectedAsJSON(files: File[]) { export function formatCollectedAsString(files: File[]) { return files.map((file) => { - const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'only') + const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'queued' || test.mode === 'only') return tests.map((test) => { const name = getNames(test).join(' > ') if (test.file.projectName) { diff --git a/packages/vitest/src/node/reporters/base.ts b/packages/vitest/src/node/reporters/base.ts index 71df7bf40885..046dea29f7dc 100644 --- a/packages/vitest/src/node/reporters/base.ts +++ b/packages/vitest/src/node/reporters/base.ts @@ -75,7 +75,8 @@ export abstract class BaseReporter implements Reporter { if ( !('filepath' in task) || !task.result?.state - || task.result?.state === 'run') { + || task.result?.state === 'run' + || task.result?.state === 'queued') { return } diff --git a/packages/vitest/src/node/reporters/benchmark/table/index.ts b/packages/vitest/src/node/reporters/benchmark/table/index.ts index 2ae1ae61fa62..f7ab74f3422d 100644 --- a/packages/vitest/src/node/reporters/benchmark/table/index.ts +++ b/packages/vitest/src/node/reporters/benchmark/table/index.ts @@ -76,12 +76,13 @@ export class TableReporter extends BaseReporter { && task.type === 'suite' && task.result?.state && task.result?.state !== 'run' + && task.result?.state !== 'queued' ) { // render static table when all benches inside single suite are finished const benches = task.tasks.filter(t => t.meta.benchmark) if ( benches.length > 0 - && benches.every(t => t.result?.state !== 'run') + && benches.every(t => t.result?.state !== 'run' && t.result?.state !== 'queued') ) { let title = ` ${getStateSymbol(task)} ${getFullName( task, diff --git a/packages/vitest/src/node/reporters/json.ts b/packages/vitest/src/node/reporters/json.ts index ea6737dd29f8..f77f354a82f2 100644 --- a/packages/vitest/src/node/reporters/json.ts +++ b/packages/vitest/src/node/reporters/json.ts @@ -96,7 +96,7 @@ export class JsonReporter implements Reporter { const numFailedTestSuites = suites.filter(s => s.result?.state === 'fail').length const numPendingTestSuites = suites.filter( - s => s.result?.state === 'run' || s.mode === 'todo', + s => s.result?.state === 'run' || s.result?.state === 'queued' || s.mode === 'todo', ).length const numPassedTestSuites = numTotalTestSuites - numFailedTestSuites - numPendingTestSuites @@ -105,7 +105,7 @@ export class JsonReporter implements Reporter { ).length const numPassedTests = tests.filter(t => t.result?.state === 'pass').length const numPendingTests = tests.filter( - t => t.result?.state === 'run' || t.mode === 'skip' || t.result?.state === 'skip', + t => t.result?.state === 'run' || t.result?.state === 'queued' || t.mode === 'skip' || t.result?.state === 'skip', ).length const numTodoTests = tests.filter(t => t.mode === 'todo').length const testResults: Array = [] @@ -155,7 +155,7 @@ export class JsonReporter implements Reporter { } satisfies JsonAssertionResult }) - if (tests.some(t => t.result?.state === 'run')) { + if (tests.some(t => t.result?.state === 'run' || t.result?.state === 'queued')) { this.ctx.logger.warn( 'WARNING: Some tests are still running when generating the JSON report.' + 'This is likely an internal bug in Vitest.' diff --git a/packages/vitest/src/node/reporters/renderers/utils.ts b/packages/vitest/src/node/reporters/renderers/utils.ts index 9aa777a08d84..a8f057dba45e 100644 --- a/packages/vitest/src/node/reporters/renderers/utils.ts +++ b/packages/vitest/src/node/reporters/renderers/utils.ts @@ -163,7 +163,7 @@ export function getStateSymbol(task: Task) { return pending } - if (task.result.state === 'run') { + if (task.result.state === 'run' || task.result.state === 'queued') { if (task.type === 'suite') { return pointer } diff --git a/packages/vitest/src/node/reporters/reported-tasks.ts b/packages/vitest/src/node/reporters/reported-tasks.ts index b671769041cf..6e980d535e40 100644 --- a/packages/vitest/src/node/reporters/reported-tasks.ts +++ b/packages/vitest/src/node/reporters/reported-tasks.ts @@ -113,7 +113,7 @@ export class TestCase extends ReportedTaskImplementation { */ public result(): TestResult | undefined { const result = this.task.result - if (!result || result.state === 'run') { + if (!result || result.state === 'run' || result.state === 'queued') { return undefined } const state = result.state === 'fail' @@ -163,7 +163,7 @@ export class TestCase extends ReportedTaskImplementation { public diagnostic(): TestDiagnostic | undefined { const result = this.task.result // startTime should always be available if the test has properly finished - if (!result || result.state === 'run' || !result.startTime) { + if (!result || result.state === 'run' || result.state === 'queued' || !result.startTime) { return undefined } const duration = result.duration || 0 diff --git a/packages/vitest/src/node/reporters/task-parser.ts b/packages/vitest/src/node/reporters/task-parser.ts index 54d517ec962f..a9cc5b1e13b4 100644 --- a/packages/vitest/src/node/reporters/task-parser.ts +++ b/packages/vitest/src/node/reporters/task-parser.ts @@ -39,7 +39,7 @@ export class TaskParser { const task = this.ctx.state.idMap.get(pack[0]) if (task?.type === 'suite' && 'filepath' in task && task.result?.state) { - if (task?.result?.state === 'run') { + if (task?.result?.state === 'run' || task?.result?.state === 'queued') { startingTestFiles.push(task) } else { @@ -55,7 +55,7 @@ export class TaskParser { } if (task?.type === 'test') { - if (task.result?.state === 'run') { + if (task.result?.state === 'run' || task.result?.state === 'queued') { startingTests.push(task) } else if (task.result?.hooks?.afterEach !== 'run') { @@ -65,7 +65,7 @@ export class TaskParser { if (task?.result?.hooks) { for (const [hook, state] of Object.entries(task.result.hooks)) { - if (state === 'run') { + if (state === 'run' || state === 'queued') { startingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type }) } else { diff --git a/packages/vitest/src/node/reporters/verbose.ts b/packages/vitest/src/node/reporters/verbose.ts index dff3fbf168b1..8b2c03f6a974 100644 --- a/packages/vitest/src/node/reporters/verbose.ts +++ b/packages/vitest/src/node/reporters/verbose.ts @@ -20,6 +20,7 @@ export class VerboseReporter extends DefaultReporter { && task.type === 'test' && task.result?.state && task.result?.state !== 'run' + && task.result?.state !== 'queued' ) { let title = ` ${getStateSymbol(task)} ` if (task.file.projectName) { From 6ca6de781bae5df7b8cb8a8da55290ad15b85f0f Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 19 Nov 2024 15:24:33 +0100 Subject: [PATCH 05/16] chore: cleanup --- packages/vitest/src/node/reporters/task-parser.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/vitest/src/node/reporters/task-parser.ts b/packages/vitest/src/node/reporters/task-parser.ts index a9cc5b1e13b4..7ff04f178f76 100644 --- a/packages/vitest/src/node/reporters/task-parser.ts +++ b/packages/vitest/src/node/reporters/task-parser.ts @@ -81,7 +81,6 @@ export class TaskParser { startingTestFiles.forEach(file => this.onTestFilePrepare(file)) startingTests.forEach(test => this.onTestStart(test)) - startingHooks.forEach(hook => this.onHookStart(hook), - ) + startingHooks.forEach(hook => this.onHookStart(hook)) } } From dcb9530a2e5a0c7bbdb661ceae178d9104743289 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 19 Nov 2024 15:44:08 +0100 Subject: [PATCH 06/16] fix: disable reporters during collection --- packages/vitest/src/node/core.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 2da9761b8760..38c5e7efb512 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -391,7 +391,15 @@ export class Vitest { return { tests: [], errors: [] } } - await this.collectFiles(files) + const reporters = this.reporters + this.reporters = [] + + try { + await this.collectFiles(files) + } + finally { + this.reporters = reporters + } return { tests: this.state.getFiles(), From 2b418f19a79c4e4281682a12285b4aae65047c18 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 19 Nov 2024 16:26:54 +0100 Subject: [PATCH 07/16] chore: update mode to run after collected --- packages/runner/src/collect.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/runner/src/collect.ts b/packages/runner/src/collect.ts index 691b0d8a2d8b..6e3fb21564d0 100644 --- a/packages/runner/src/collect.ts +++ b/packages/runner/src/collect.ts @@ -109,6 +109,10 @@ export async function collectTests( config.allowOnly, ) + if (file.mode === 'queued') { + file.mode = 'run' + } + files.push(file) } From 3e6d36612195a863964de30877ecd483d9beaa9f Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 9 Dec 2024 17:02:48 +0100 Subject: [PATCH 08/16] feat: add onQueued event --- packages/browser/src/client/tester/runner.ts | 4 ++++ packages/browser/src/node/rpc.ts | 4 ++++ packages/browser/src/node/types.ts | 1 + packages/runner/src/collect.ts | 2 -- packages/vitest/src/node/pools/rpc.ts | 4 ++++ packages/vitest/src/node/reporters/default.ts | 4 ++++ packages/vitest/src/node/reporters/summary.ts | 4 ++++ packages/vitest/src/node/types/reporter.ts | 1 + packages/vitest/src/runtime/runners/index.ts | 6 ++++++ packages/vitest/src/types/rpc.ts | 1 + 10 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/browser/src/client/tester/runner.ts b/packages/browser/src/client/tester/runner.ts index 40ff4501b2c5..449e0ac6c360 100644 --- a/packages/browser/src/client/tester/runner.ts +++ b/packages/browser/src/client/tester/runner.ts @@ -104,6 +104,10 @@ export function createBrowserRunner( } } + onCollectStart = (file: File) => { + return rpc().onQueued(file) + } + onCollected = async (files: File[]): Promise => { files.forEach((file) => { file.prepareDuration = state.durations.prepare diff --git a/packages/browser/src/node/rpc.ts b/packages/browser/src/node/rpc.ts index 0147438cddb9..8733dd78312f 100644 --- a/packages/browser/src/node/rpc.ts +++ b/packages/browser/src/node/rpc.ts @@ -75,6 +75,10 @@ export function setupBrowserRpc(server: BrowserServer) { } ctx.state.catchError(error, type) }, + async onQueued(file) { + ctx.state.collectFiles(project, [file]) + await ctx.report('onQueued', file) + }, async onCollected(files) { ctx.state.collectFiles(project, files) await ctx.report('onCollected', files) diff --git a/packages/browser/src/node/types.ts b/packages/browser/src/node/types.ts index 91ed6c8c605d..df3837bcdadc 100644 --- a/packages/browser/src/node/types.ts +++ b/packages/browser/src/node/types.ts @@ -6,6 +6,7 @@ export interface WebSocketBrowserHandlers { resolveSnapshotPath: (testPath: string) => string resolveSnapshotRawPath: (testPath: string, rawPath: string) => string onUnhandledError: (error: unknown, type: string) => Promise + onQueued: (file: RunnerTestFile) => void onCollected: (files?: RunnerTestFile[]) => Promise onTaskUpdate: (packs: TaskResultPack[]) => void onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void diff --git a/packages/runner/src/collect.ts b/packages/runner/src/collect.ts index 6e3fb21564d0..25cc9017c321 100644 --- a/packages/runner/src/collect.ts +++ b/packages/runner/src/collect.ts @@ -4,7 +4,6 @@ import { toArray } from '@vitest/utils' import { processError } from '@vitest/utils/error' import { collectorContext } from './context' import { getHooks, setHooks } from './map' -import { updateTask } from './run' import { runSetupFiles } from './setup' import { clearCollectorContext, @@ -35,7 +34,6 @@ export async function collectTests( const file = createFileTask(filepath, config.root, config.name, runner.pool) file.shuffle = config.sequence.shuffle - updateTask(file, runner) runner.onCollectStart?.(file) clearCollectorContext(filepath, runner) diff --git a/packages/vitest/src/node/pools/rpc.ts b/packages/vitest/src/node/pools/rpc.ts index 4c41417fdae8..cbc103b00832 100644 --- a/packages/vitest/src/node/pools/rpc.ts +++ b/packages/vitest/src/node/pools/rpc.ts @@ -78,6 +78,10 @@ export function createMethodsRPC(project: TestProject, options: MethodsOptions = ctx.state.collectPaths(paths) return ctx.report('onPathsCollected', paths) }, + onQueued(file) { + ctx.state.collectFiles(project, [file]) + return ctx.report('onQueued', file) + }, onCollected(files) { ctx.state.collectFiles(project, files) return ctx.report('onCollected', files) diff --git a/packages/vitest/src/node/reporters/default.ts b/packages/vitest/src/node/reporters/default.ts index 5ac02191fcab..306f2530b208 100644 --- a/packages/vitest/src/node/reporters/default.ts +++ b/packages/vitest/src/node/reporters/default.ts @@ -28,6 +28,10 @@ export class DefaultReporter extends BaseReporter { } } + onQueued(file: File) { + this.summary?.onQueued(file) + } + onInit(ctx: Vitest) { super.onInit(ctx) this.summary?.onInit(ctx, { verbose: this.verbose }) diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index 9646c2ac5bb4..a8734d21e5e2 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -87,6 +87,10 @@ export class SummaryReporter extends TaskParser implements Reporter { }) } + onQueued(file: File) { + this.onTestFilePrepare(file) + } + onPathsCollected(paths?: string[]) { this.suites.total = (paths || []).length } diff --git a/packages/vitest/src/node/types/reporter.ts b/packages/vitest/src/node/types/reporter.ts index efd8304d33c8..b3855e31abe8 100644 --- a/packages/vitest/src/node/types/reporter.ts +++ b/packages/vitest/src/node/types/reporter.ts @@ -7,6 +7,7 @@ export interface Reporter { onInit?: (ctx: Vitest) => void onPathsCollected?: (paths?: string[]) => Awaitable onSpecsCollected?: (specs?: SerializedTestSpecification[]) => Awaitable + onQueued?: (file: File) => Awaitable onCollected?: (files?: File[]) => Awaitable onFinished?: ( files: File[], diff --git a/packages/vitest/src/runtime/runners/index.ts b/packages/vitest/src/runtime/runners/index.ts index 2ac31beba3c7..66d0494fce74 100644 --- a/packages/vitest/src/runtime/runners/index.ts +++ b/packages/vitest/src/runtime/runners/index.ts @@ -68,6 +68,12 @@ export async function resolveTestRunner( return p } + const originalOnCollectStart = testRunner.onCollectStart + testRunner.onCollectStart = async (file) => { + await rpc().onQueued(file) + await originalOnCollectStart?.call(testRunner, file) + } + const originalOnCollected = testRunner.onCollected testRunner.onCollected = async (files) => { const state = getWorkerState() diff --git a/packages/vitest/src/types/rpc.ts b/packages/vitest/src/types/rpc.ts index 5fd1f45c7687..cbdbbd9ef815 100644 --- a/packages/vitest/src/types/rpc.ts +++ b/packages/vitest/src/types/rpc.ts @@ -39,6 +39,7 @@ export interface RuntimeRPC { onPathsCollected: (paths: string[]) => void onUserConsoleLog: (log: UserConsoleLog) => void onUnhandledError: (err: unknown, type: string) => void + onQueued: (file: File) => void onCollected: (files: File[]) => Promise onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void onTaskUpdate: (pack: TaskResultPack[]) => Promise From 753456bfd4144728eebfc8a893c5de2e81bac62e Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 9 Dec 2024 17:20:16 +0100 Subject: [PATCH 09/16] test: add a test for queue --- test/reporters/fixtures/long-loading-task.test.ts | 5 +++++ test/reporters/tests/default.test.ts | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 test/reporters/fixtures/long-loading-task.test.ts diff --git a/test/reporters/fixtures/long-loading-task.test.ts b/test/reporters/fixtures/long-loading-task.test.ts new file mode 100644 index 000000000000..11aa80554e53 --- /dev/null +++ b/test/reporters/fixtures/long-loading-task.test.ts @@ -0,0 +1,5 @@ +import { test } from 'vitest' + +await new Promise(r => setTimeout(r, 500)) + +test('works') diff --git a/test/reporters/tests/default.test.ts b/test/reporters/tests/default.test.ts index 23b3dcafedf5..afe64830d61d 100644 --- a/test/reporters/tests/default.test.ts +++ b/test/reporters/tests/default.test.ts @@ -70,6 +70,20 @@ describe('default reporter', async () => { expect(result.stderr).not.toContain(`status: 'not found'`) }) + test('prints queued tests as soon as they are added', async () => { + const { stdout, vitest } = await runVitest({ + include: ['fixtures/long-loading-task.test.ts'], + reporters: [['default', { isTTY: true, summary: true }]], + config: 'fixtures/vitest.config.ts', + watch: true, + }) + + await vitest.waitForStdout('❯ fixtures/long-loading-task.test.ts 0/0') + await vitest.waitForStdout('Waiting for file changes...') + + expect(stdout).toContain('✓ fixtures/long-loading-task.test.ts (1 test)') + }) + test('prints skipped tests by default when a single file is run', async () => { const { stdout } = await runVitest({ include: ['fixtures/all-passing-or-skipped.test.ts'], From 7ad8ffde00e9777e46cc4af33e5da4e9aa066616 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 11 Dec 2024 11:13:02 +0100 Subject: [PATCH 10/16] fix: correctly count total tests and add [queued] label --- packages/vitest/src/node/reporters/summary.ts | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index a8734d21e5e2..33cff9732097 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -1,6 +1,7 @@ import type { File, Test } from '@vitest/runner' import type { Vitest } from '../core' import type { Reporter } from '../types/reporter' +import type { TestModule } from './reported-tasks' import type { HookOptions } from './task-parser' import { getTests } from '@vitest/runner/utils' import c from 'tinyrainbow' @@ -87,8 +88,8 @@ export class SummaryReporter extends TaskParser implements Reporter { }) } - onQueued(file: File) { - this.onTestFilePrepare(file) + onTestModuleQueued(module: TestModule) { + this.onTestFilePrepare(module.task) } onPathsCollected(paths?: string[]) { @@ -115,7 +116,18 @@ export class SummaryReporter extends TaskParser implements Reporter { } onTestFilePrepare(file: File) { - if (this.allFinishedTests.has(file.id) || this.runningTests.has(file.id)) { + if (this.allFinishedTests.has(file.id)) { + return + } + + if (this.runningTests.has(file.id)) { + const stats = this.runningTests.get(file.id)! + // if there are no tests, it means the test was queued but not collected + if (!stats.total) { + const total = getTests(file).length + this.tests.total += total + stats.total = total + } return } @@ -307,7 +319,9 @@ export class SummaryReporter extends TaskParser implements Reporter { c.bold(c.yellow(` ${F_POINTER} `)) + formatProjectName(testFile.projectName) + testFile.filename - + c.dim(` ${testFile.completed}/${testFile.total}`), + + (!testFile.completed && !testFile.total + ? '[queued]' + : c.dim(` ${testFile.completed}/${testFile.total}`)), ) const slowTasks = [ From 696df4a130c82b84000af4a218b6df0415a82d1f Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 11 Dec 2024 11:28:52 +0100 Subject: [PATCH 11/16] refactor: rename onQueued to onTestModuleQueued --- packages/browser/src/node/rpc.ts | 5 +++-- packages/vitest/src/node/pools/rpc.ts | 4 +++- packages/vitest/src/node/reporters/default.ts | 5 +++-- packages/vitest/src/node/types/reporter.ts | 3 ++- test/reporters/tests/default.test.ts | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/browser/src/node/rpc.ts b/packages/browser/src/node/rpc.ts index 8733dd78312f..71f12893d534 100644 --- a/packages/browser/src/node/rpc.ts +++ b/packages/browser/src/node/rpc.ts @@ -1,5 +1,5 @@ import type { ErrorWithDiff } from 'vitest' -import type { BrowserCommandContext, ResolveSnapshotPathHandlerContext } from 'vitest/node' +import type { BrowserCommandContext, ResolveSnapshotPathHandlerContext, TestModule } from 'vitest/node' import type { WebSocket } from 'ws' import type { BrowserServer } from './server' import type { WebSocketBrowserEvents, WebSocketBrowserHandlers } from './types' @@ -77,7 +77,8 @@ export function setupBrowserRpc(server: BrowserServer) { }, async onQueued(file) { ctx.state.collectFiles(project, [file]) - await ctx.report('onQueued', file) + const testModule = ctx.state.getReportedEntity(file) as TestModule + await ctx.report('onTestModuleQueued', testModule) }, async onCollected(files) { ctx.state.collectFiles(project, files) diff --git a/packages/vitest/src/node/pools/rpc.ts b/packages/vitest/src/node/pools/rpc.ts index cbc103b00832..11ea6518a9a0 100644 --- a/packages/vitest/src/node/pools/rpc.ts +++ b/packages/vitest/src/node/pools/rpc.ts @@ -1,6 +1,7 @@ import type { RawSourceMap } from 'vite-node' import type { RuntimeRPC } from '../../types/rpc' import type { TestProject } from '../project' +import type { TestModule } from '../reporters/reported-tasks' import type { ResolveSnapshotPathHandlerContext } from '../types/config' import { mkdir, writeFile } from 'node:fs/promises' import { join } from 'pathe' @@ -80,7 +81,8 @@ export function createMethodsRPC(project: TestProject, options: MethodsOptions = }, onQueued(file) { ctx.state.collectFiles(project, [file]) - return ctx.report('onQueued', file) + const testModule = ctx.state.getReportedEntity(file) as TestModule + return ctx.report('onTestModuleQueued', testModule) }, onCollected(files) { ctx.state.collectFiles(project, files) diff --git a/packages/vitest/src/node/reporters/default.ts b/packages/vitest/src/node/reporters/default.ts index 306f2530b208..76181ec27f6c 100644 --- a/packages/vitest/src/node/reporters/default.ts +++ b/packages/vitest/src/node/reporters/default.ts @@ -1,6 +1,7 @@ import type { File, TaskResultPack } from '@vitest/runner' import type { Vitest } from '../core' import type { BaseOptions } from './base' +import type { TestModule } from './reported-tasks' import { BaseReporter } from './base' import { SummaryReporter } from './summary' @@ -28,8 +29,8 @@ export class DefaultReporter extends BaseReporter { } } - onQueued(file: File) { - this.summary?.onQueued(file) + onTestModuleQueued(file: TestModule) { + this.summary?.onTestModuleQueued(file) } onInit(ctx: Vitest) { diff --git a/packages/vitest/src/node/types/reporter.ts b/packages/vitest/src/node/types/reporter.ts index b3855e31abe8..1d152baabc64 100644 --- a/packages/vitest/src/node/types/reporter.ts +++ b/packages/vitest/src/node/types/reporter.ts @@ -1,4 +1,5 @@ import type { File, TaskResultPack } from '@vitest/runner' +import type { TestModule } from 'vitest/node' import type { SerializedTestSpecification } from '../../runtime/types/utils' import type { Awaitable, UserConsoleLog } from '../../types/general' import type { Vitest } from '../core' @@ -7,7 +8,7 @@ export interface Reporter { onInit?: (ctx: Vitest) => void onPathsCollected?: (paths?: string[]) => Awaitable onSpecsCollected?: (specs?: SerializedTestSpecification[]) => Awaitable - onQueued?: (file: File) => Awaitable + onTestModuleQueued?: (file: TestModule) => Awaitable onCollected?: (files?: File[]) => Awaitable onFinished?: ( files: File[], diff --git a/test/reporters/tests/default.test.ts b/test/reporters/tests/default.test.ts index afe64830d61d..52eb3e23fdbb 100644 --- a/test/reporters/tests/default.test.ts +++ b/test/reporters/tests/default.test.ts @@ -78,7 +78,7 @@ describe('default reporter', async () => { watch: true, }) - await vitest.waitForStdout('❯ fixtures/long-loading-task.test.ts 0/0') + await vitest.waitForStdout('❯ fixtures/long-loading-task.test.ts [queued]') await vitest.waitForStdout('Waiting for file changes...') expect(stdout).toContain('✓ fixtures/long-loading-task.test.ts (1 test)') From 45a433f94322a926fc3e0f6e0efaffa0065c0786 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 11 Dec 2024 11:42:22 +0100 Subject: [PATCH 12/16] fix: oops --- packages/vitest/src/node/types/reporter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vitest/src/node/types/reporter.ts b/packages/vitest/src/node/types/reporter.ts index 1d152baabc64..d45d6bf376a4 100644 --- a/packages/vitest/src/node/types/reporter.ts +++ b/packages/vitest/src/node/types/reporter.ts @@ -1,8 +1,8 @@ import type { File, TaskResultPack } from '@vitest/runner' -import type { TestModule } from 'vitest/node' import type { SerializedTestSpecification } from '../../runtime/types/utils' import type { Awaitable, UserConsoleLog } from '../../types/general' import type { Vitest } from '../core' +import type { TestModule } from '../reporters/reported-tasks' export interface Reporter { onInit?: (ctx: Vitest) => void From 190ce3ac27b19f92fe8628015dca86f94750f904 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 11 Dec 2024 11:49:30 +0100 Subject: [PATCH 13/16] chore: cleanup --- packages/vitest/src/node/reporters/summary.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index 33cff9732097..fae380bb9e20 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -320,7 +320,7 @@ export class SummaryReporter extends TaskParser implements Reporter { + formatProjectName(testFile.projectName) + testFile.filename + (!testFile.completed && !testFile.total - ? '[queued]' + ? ' [queued]' : c.dim(` ${testFile.completed}/${testFile.total}`)), ) From d7aaf8265b4476c0f146b5c8f8856379a94c4dcf Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 11 Dec 2024 12:33:08 +0100 Subject: [PATCH 14/16] chore: dim queued --- packages/vitest/src/node/reporters/summary.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index fae380bb9e20..567005a85bdb 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -319,9 +319,9 @@ export class SummaryReporter extends TaskParser implements Reporter { c.bold(c.yellow(` ${F_POINTER} `)) + formatProjectName(testFile.projectName) + testFile.filename - + (!testFile.completed && !testFile.total + + c.dim(!testFile.completed && !testFile.total ? ' [queued]' - : c.dim(` ${testFile.completed}/${testFile.total}`)), + : ` ${testFile.completed}/${testFile.total}`), ) const slowTasks = [ From 3649ee2a7435ff230e7c73540f4f04c34fecadca Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 11 Dec 2024 14:57:01 +0100 Subject: [PATCH 15/16] fix: move the stats check --- packages/vitest/src/node/reporters/summary.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index 567005a85bdb..2e43e9c6e87f 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -116,10 +116,6 @@ export class SummaryReporter extends TaskParser implements Reporter { } onTestFilePrepare(file: File) { - if (this.allFinishedTests.has(file.id)) { - return - } - if (this.runningTests.has(file.id)) { const stats = this.runningTests.get(file.id)! // if there are no tests, it means the test was queued but not collected @@ -131,6 +127,10 @@ export class SummaryReporter extends TaskParser implements Reporter { return } + if (this.allFinishedTests.has(file.id)) { + return + } + const total = getTests(file).length this.tests.total += total From f91a5f75ba0496587281f9908e5313f26a62d690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Tue, 17 Dec 2024 15:32:54 +0200 Subject: [PATCH 16/16] fix: report preparation for running tests that skipped `'run'` phase but reported 'queue' --- packages/vitest/src/node/reporters/summary.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index 2e43e9c6e87f..97488cc97410 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -282,7 +282,7 @@ export class SummaryReporter extends TaskParser implements Reporter { const file = test.file let stats = this.runningTests.get(file.id) - if (!stats) { + if (!stats || stats.total === 0) { // It's possible that that test finished before it's preparation was even reported this.onTestFilePrepare(test.file) stats = this.runningTests.get(file.id)!