diff --git a/packages/vitest/src/node/reporters/benchmark/table/index.ts b/packages/vitest/src/node/reporters/benchmark/table/index.ts index 751e2431717a..a7fa9fae5f05 100644 --- a/packages/vitest/src/node/reporters/benchmark/table/index.ts +++ b/packages/vitest/src/node/reporters/benchmark/table/index.ts @@ -1,7 +1,10 @@ import c from 'picocolors' +import type { TaskResultPack } from '@vitest/runner' import type { UserConsoleLog } from '../../../../types/general' import { BaseReporter } from '../../base' -import { type TableRendererOptions, createTableRenderer } from './tableRender' +import { getFullName } from '../../../../utils' +import { getStateSymbol } from '../../renderers/utils' +import { type TableRendererOptions, createTableRenderer, renderTree } from './tableRender' export class TableReporter extends BaseReporter { renderer?: ReturnType @@ -30,6 +33,25 @@ export class TableReporter extends BaseReporter { } } + onTaskUpdate(packs: TaskResultPack[]) { + if (this.isTTY) + return + for (const pack of packs) { + const task = this.ctx.state.idMap.get(pack[0]) + if (task && task.type === 'suite' && task.result?.state && task.result?.state !== 'run') { + // 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')) { + let title = ` ${getStateSymbol(task)} ${getFullName(task, c.dim(' > '))}` + if (task.result.duration != null && task.result.duration > this.ctx.config.slowTestThreshold) + title += c.yellow(` ${Math.round(task.result.duration)}${c.dim('ms')}`) + this.ctx.logger.log(title) + this.ctx.logger.log(renderTree(benches, this.rendererOptions, 1, true)) + } + } + } + } + async onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) { await this.stopListRender() this.ctx.logger.log() diff --git a/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts b/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts index ee7b17c48be3..ceeac1327e6f 100644 --- a/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts +++ b/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts @@ -100,7 +100,7 @@ function renderBenchmark(task: Benchmark, tasks: Task[]): string { ].join(' ') } -function renderTree(tasks: Task[], options: TableRendererOptions, level = 0): string { +export function renderTree(tasks: Task[], options: TableRendererOptions, level = 0, shallow = false): string { const output: string[] = [] let idx = 0 @@ -151,7 +151,7 @@ function renderTree(tasks: Task[], options: TableRendererOptions, level = 0): st } } - if (task.type === 'suite' && task.tasks.length > 0) { + if (!shallow && task.type === 'suite' && task.tasks.length > 0) { if (task.result?.state) output.push(renderTree(task.tasks, options, level + 1)) } diff --git a/test/benchmark/fixtures/basic/base.bench.ts b/test/benchmark/fixtures/basic/base.bench.ts index 9d2fc8851478..872f214c7f79 100644 --- a/test/benchmark/fixtures/basic/base.bench.ts +++ b/test/benchmark/fixtures/basic/base.bench.ts @@ -38,22 +38,30 @@ describe('timeout', () => { teardown() { }, + ...benchOptions }) bench('timeout75', async () => { await timeout(75) - }) + }, benchOptions) bench('timeout50', async () => { await timeout(50) - }) + }, benchOptions) bench('timeout25', async () => { await timeout(25) - }) + }, benchOptions) // TODO: move to failed tests // test('reduce', () => { // expect(1 - 1).toBe(2) // }) }) + +const benchOptions = { + time: 0, + iterations: 3, + warmupIterations: 0, + warmupTime: 0, +} diff --git a/test/benchmark/test/reporter.test.ts b/test/benchmark/test/reporter.test.ts index 60ec650a3dd3..0b13331645be 100644 --- a/test/benchmark/test/reporter.test.ts +++ b/test/benchmark/test/reporter.test.ts @@ -8,3 +8,22 @@ it('summary', async () => { expect(result.stdout).not.toContain('NaNx') expect(result.stdout.split('BENCH Summary')[1].replaceAll(/\d/g, '?')).toMatchSnapshot() }) + +it('non-tty', async () => { + const root = pathe.join(import.meta.dirname, '../fixtures/basic') + const result = await runVitest({ root }, ['base.bench.ts'], 'benchmark') + const lines = result.stdout.split('\n').slice(3).slice(0, 10) + const expected = `\ + ✓ base.bench.ts > sort + name + · normal + · reverse + ✓ base.bench.ts > timeout + name + · timeout100 + · timeout75 + · timeout50 + · timeout25 +` + expect(lines).toMatchObject(expected.trim().split('\n').map(s => expect.stringContaining(s))) +})