diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 54a0f3c74670..71ace259fb72 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -152,6 +152,7 @@ export class Vitest { const testsFilesList = await this.globTestFiles() const checker = new Typechecker(this, testsFilesList) checker.onParseEnd(async ({ files, sourceErrors }) => { + await this.report('onCollected', files) await this.report('onFinished', files) if (sourceErrors.length && !this.config.typecheck.ignoreSourceErrors) { process.exitCode = 1 @@ -166,13 +167,15 @@ export class Vitest { }) checker.onParseStart(async () => { await this.report('onInit', this) - this.logger.log(c.cyan('Typechecking...')) // TODO show list of test files? + await this.report('onCollected', checker.getTestFiles()) }) checker.onWatcherRerun(async () => { const { files } = checker.getResult() await this.report('onWatcherRerun', files.map(f => f.filepath), 'File change detected. Triggering rerun.') - this.logger.log(c.cyan('Typechecking...')) // TODO show list of test files? + await checker.collectTests() + await this.report('onCollected', checker.getTestFiles()) }) + await checker.collectTests() await checker.start() } diff --git a/packages/vitest/src/node/reporters/default.ts b/packages/vitest/src/node/reporters/default.ts index 2947033432ed..1a2fa9b93bf0 100644 --- a/packages/vitest/src/node/reporters/default.ts +++ b/packages/vitest/src/node/reporters/default.ts @@ -1,5 +1,5 @@ import c from 'picocolors' -import type { UserConsoleLog } from '../../types' +import type { File, UserConsoleLog } from '../../types' import { BaseReporter } from './base' import type { ListRendererOptions } from './renderers/listRenderer' import { createListRenderer } from './renderers/listRenderer' @@ -18,11 +18,13 @@ export class DefaultReporter extends BaseReporter { super.onWatcherStart() } - onCollected() { + onCollected(files?: File[]) { if (this.isTTY) { this.rendererOptions.logger = this.ctx.logger this.rendererOptions.showHeap = this.ctx.config.logHeapUsage - const files = this.ctx.state.getFiles(this.watchFilters) + this.rendererOptions.mode = this.mode + if (!files) + files = this.ctx.state.getFiles(this.watchFilters) if (!this.renderer) this.renderer = createListRenderer(files, this.rendererOptions).start() else diff --git a/packages/vitest/src/node/reporters/renderers/listRenderer.ts b/packages/vitest/src/node/reporters/renderers/listRenderer.ts index ec4c2593a9a0..d1e94013ea94 100644 --- a/packages/vitest/src/node/reporters/renderers/listRenderer.ts +++ b/packages/vitest/src/node/reporters/renderers/listRenderer.ts @@ -1,8 +1,8 @@ import c from 'picocolors' import cliTruncate from 'cli-truncate' import stripAnsi from 'strip-ansi' -import type { Benchmark, BenchmarkResult, SuiteHooks, Task } from '../../../types' -import { clearInterval, getTests, notNullish, setInterval } from '../../../utils' +import type { Benchmark, BenchmarkResult, SuiteHooks, Task, VitestRunMode } from '../../../types' +import { clearInterval, getTests, getTypecheckTests, isTypecheckTest, notNullish, setInterval } from '../../../utils' import { F_RIGHT } from '../../../utils/figures' import type { Logger } from '../../logger' import { getCols, getHookStateSymbol, getStateSymbol } from './utils' @@ -11,6 +11,7 @@ export interface ListRendererOptions { renderSucceed?: boolean logger: Logger showHeap: boolean + mode: VitestRunMode } const DURATION_LONG = 300 @@ -95,8 +96,10 @@ export function renderTree(tasks: Task[], options: ListRendererOptions, level = if (task.type === 'test' && task.result?.retryCount && task.result.retryCount > 1) suffix += c.yellow(` (retry x${task.result.retryCount})`) - if (task.type === 'suite') - suffix += c.dim(` (${getTests(task).length})`) + if (task.type === 'suite' && !isTypecheckTest(task)) { + const tests = options.mode === 'typecheck' ? getTypecheckTests(task) : getTests(task) + suffix += c.dim(` (${tests.length})`) + } if (task.mode === 'skip' || task.mode === 'todo') suffix += ` ${c.dim(c.gray('[skipped]'))}` diff --git a/packages/vitest/src/typescript/parser.ts b/packages/vitest/src/typescript/parser.ts index 010753f0e0ba..ef3644131400 100644 --- a/packages/vitest/src/typescript/parser.ts +++ b/packages/vitest/src/typescript/parser.ts @@ -34,6 +34,8 @@ export class Typechecker { sourceErrors: [], } + private _tests: Record | null = {} + private tmpConfigPath?: string constructor(protected ctx: Vitest, protected files: string[]) {} @@ -50,28 +52,37 @@ export class Typechecker { this._onWatcherRerun = fn } - protected async collectTests(filepath: string): Promise { + protected async collectFileTests(filepath: string): Promise { return collectTests(this.ctx, filepath) } - protected async prepareResults(output: string) { - const typeErrors = await this.parseTscLikeOutput(output) - const testFiles = new Set(this.files) - - const sourceDefinitions = (await Promise.all( - this.files.map(filepath => this.collectTests(filepath)), + public async collectTests() { + const tests = (await Promise.all( + this.files.map(filepath => this.collectFileTests(filepath)), )).reduce((acc, data) => { if (!data) return acc acc[data.filepath] = data return acc }, {} as Record) + this._tests = tests + return tests + } + + protected async prepareResults(output: string) { + const typeErrors = await this.parseTscLikeOutput(output) + const testFiles = new Set(this.files) + + let tests = this._tests + + if (!tests) + tests = await this.collectTests() const sourceErrors: TypeCheckError[] = [] const files: File[] = [] testFiles.forEach((path) => { - const { file, definitions, map, parsed } = sourceDefinitions[path] + const { file, definitions, map, parsed } = tests![path] const errors = typeErrors.get(path) files.push(file) if (!errors) @@ -189,10 +200,9 @@ export class Typechecker { return if (output.includes('File change detected') && !rerunTriggered) { this._onWatcherRerun?.() - this._result = { - sourceErrors: [], - files: [], - } + this._result.sourceErrors = [] + this._result.files = [] + this._tests = null // test structure migh've changed rerunTriggered = true } if (/Found \w+ errors*. Watching for/.test(output)) { @@ -214,4 +224,11 @@ export class Typechecker { public getResult() { return this._result } + + public getTestFiles() { + return Object.values(this._tests || {}).map(({ file }) => ({ + ...file, + result: undefined, + })) + } } diff --git a/packages/vitest/src/utils/tasks.ts b/packages/vitest/src/utils/tasks.ts index 0bbad101c019..0479f6e07fd1 100644 --- a/packages/vitest/src/utils/tasks.ts +++ b/packages/vitest/src/utils/tasks.ts @@ -10,6 +10,10 @@ export function getTests(suite: Arrayable): (Test | Benchmark | TypeCheck) return toArray(suite).flatMap(s => isAtomTest(s) ? [s] : s.tasks.flatMap(c => isAtomTest(c) ? [c] : getTests(c))) } +export function isTypecheckTest(suite: Task): suite is Suite { + return TYPECHECK_SUITE in suite +} + export function getTypecheckTests(suite: Arrayable): Suite[] { return toArray(suite).flatMap((s) => { if (s.type !== 'suite')