From 5836160f7e9264fa898f71ca0fd384f0406e2834 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 27 Feb 2023 10:00:41 -0300 Subject: [PATCH] Rebase and changing repeated log in terminal --- packages/runner/src/run.ts | 131 ++++++++++-------- packages/runner/src/suite.ts | 2 +- packages/runner/src/types/tasks.ts | 10 +- packages/vitest/src/node/reporters/json.ts | 4 +- .../node/reporters/renderers/listRenderer.ts | 3 + .../src/node/reporters/renderers/utils.ts | 2 - packages/vitest/src/typecheck/collect.ts | 2 +- test/core/test/repeats.test.ts | 6 +- 8 files changed, 94 insertions(+), 66 deletions(-) diff --git a/packages/runner/src/run.ts b/packages/runner/src/run.ts index e816f14d6224..72d7953d35de 100644 --- a/packages/runner/src/run.ts +++ b/packages/runner/src/run.ts @@ -107,7 +107,7 @@ const callCleanupHooks = async (cleanups: HookCleanupCallback[]) => { export async function runTest(test: Test, runner: VitestRunner) { await runner.onBeforeRunTest?.(test) - if (test.mode !== 'run') + if (test.mode !== 'run' && test.mode !== 'repeats') return if (test.result?.state === 'fail') { @@ -125,7 +125,7 @@ export async function runTest(test: Test, runner: VitestRunner) { setCurrentTest(test) - const retry = test.retry || 1 + const retry = test.mode === 'repeats' ? test.repeats! : test.retry || 1 for (let retryCount = 0; retryCount < retry; retryCount++) { let beforeEachCleanups: HookCleanupCallback[] = [] try { @@ -147,7 +147,10 @@ export async function runTest(test: Test, runner: VitestRunner) { await runner.onAfterTryTest?.(test, retryCount) - test.result.state = 'pass' + if (test.mode === 'run') + test.result.state = 'pass' + else if (test.mode === 'repeats' && retry === retryCount) + test.result.state = 'pass' } catch (e) { failTask(test.result, e) @@ -164,6 +167,9 @@ export async function runTest(test: Test, runner: VitestRunner) { if (test.result.state === 'pass') break + if (test.mode === 'repeats' && test.result.state === 'fail') + break + // update retry info updateTask(test, runner) } @@ -240,68 +246,83 @@ export async function runSuite(suite: Suite, runner: VitestRunner) { suite.result.state = 'todo' } else { - try { - beforeAllCleanups = await callSuiteHook(suite, suite, 'beforeAll', runner, [suite]) + let retry = suite.repeats - if (runner.runSuite) { - await runner.runSuite(suite) - } - else { - for (let tasksGroup of partitionSuiteChildren(suite)) { - if (tasksGroup[0].concurrent === true) { - const mutex = limit(runner.config.maxConcurrency) - await Promise.all(tasksGroup.map(c => mutex(() => runSuiteChild(c, runner)))) - } - else { - const { sequence } = runner.config - if (sequence.shuffle || suite.shuffle) { - // run describe block independently from tests - const suites = tasksGroup.filter(group => group.type === 'suite') - const tests = tasksGroup.filter(group => group.type === 'test') - const groups = shuffle([suites, tests], sequence.seed) - tasksGroup = groups.flatMap(group => shuffle(group, sequence.seed)) + for (let retryCount = 0; retryCount < retry!; retryCount++) { + if (suite.mode !== 'repeats') + retry = 1 + try { + beforeAllCleanups = await callSuiteHook(suite, suite, 'beforeAll', runner, [suite]) + + if (runner.runSuite) { + await runner.runSuite(suite) + } + else { + for (let tasksGroup of partitionSuiteChildren(suite)) { + if (tasksGroup[0].concurrent === true) { + const mutex = limit(runner.config.maxConcurrency) + await Promise.all(tasksGroup.map(c => mutex(() => runSuiteChild(c, runner)))) + } + else { + const { sequence } = runner.config + if (sequence.shuffle || suite.shuffle) { + // run describe block independently from tests + const suites = tasksGroup.filter(group => group.type === 'suite') + const tests = tasksGroup.filter(group => group.type === 'test') + const groups = shuffle([suites, tests], sequence.seed) + tasksGroup = groups.flatMap(group => shuffle(group, sequence.seed)) + } + for (const c of tasksGroup) + await runSuiteChild(c, runner) } - for (const c of tasksGroup) - await runSuiteChild(c, runner) } } } - } - catch (e) { - failTask(suite.result, e) - } - } - - try { - await callSuiteHook(suite, suite, 'afterAll', runner, [suite]) - await callCleanupHooks(beforeAllCleanups) - } - catch (e) { - failTask(suite.result, e) - } + catch (e) { + failTask(suite.result, e) + } - suite.result.duration = now() - start + try { + if (suite.mode !== 'repeats') + await callSuiteHook(suite, suite, 'afterAll', runner, [suite]) + else if (suite.mode === 'repeats' && retry === retryCount) + await callSuiteHook(suite, suite, 'afterAll', runner, [suite]) + await callCleanupHooks(beforeAllCleanups) + } + catch (e) { + failTask(suite.result, e) + } - if (suite.mode === 'run') { - if (!hasTests(suite)) { - suite.result.state = 'fail' - if (!suite.result.error) { - const error = processError(new Error(`No test found in suite ${suite.name}`)) - suite.result.error = error - suite.result.errors = [error] + if (suite.mode === 'run') { + if (!hasTests(suite)) { + suite.result.state = 'fail' + if (!suite.result.error) { + const error = processError(new Error(`No test found in suite ${suite.name}`)) + suite.result.error = error + suite.result.errors = [error] + } + } + else if (hasFailed(suite)) { + suite.result.state = 'fail' + } + else { + suite.result.state = 'pass' + } } - } - else if (hasFailed(suite)) { - suite.result.state = 'fail' - } - else { - suite.result.state = 'pass' - } - } - await runner.onAfterRunSuite?.(suite) + updateTask(suite, runner) - updateTask(suite, runner) + suite.result.duration = now() - start + + await runner.onAfterRunSuite?.(suite) + + if (suite.result.state === 'pass') + break + + if (suite.mode === 'repeats' && suite.result.state === 'fail') + break + } + } } async function runSuiteChild(c: Task, runner: VitestRunner) { diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index a26698201b8f..178c15f5829a 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -103,7 +103,7 @@ function createSuiteCollector(name: string, factory: SuiteFactory = () => { }, m id: '', name, type: 'custom', - mode: self.only ? 'only' : self.skip ? 'skip' : self.todo ? 'todo' : 'run', + mode: self.only ? 'only' : self.skip ? 'skip' : self.todo ? 'todo' : self.repeats ? 'repeats' : 'run', } tasks.push(task) return task diff --git a/packages/runner/src/types/tasks.ts b/packages/runner/src/types/tasks.ts index 7c306e6d1e7e..ae02285c5a2b 100644 --- a/packages/runner/src/types/tasks.ts +++ b/packages/runner/src/types/tasks.ts @@ -16,6 +16,7 @@ export interface TaskBase { result?: TaskResult retry?: number meta?: any + repeats?: number } export interface TaskCustom extends TaskBase { @@ -35,6 +36,7 @@ export interface TaskResult { htmlError?: string hooks?: Partial> retryCount?: number + repeatCount?: number } export type TaskResultPack = [id: string, result: TaskResult | undefined] @@ -161,7 +163,11 @@ export interface TestOptions { * @default 1 */ retry?: number - + /** + * How many times the test will repeat. + * + * @default 5 + */ repeats?: number } @@ -172,7 +178,7 @@ export type TestAPI = ChainableTestAPI & { } type ChainableSuiteAPI = ChainableFunction< - 'concurrent' | 'only' | 'skip' | 'todo' | 'shuffle', + 'concurrent' | 'only' | 'skip' | 'todo' | 'shuffle' | 'repeats', [name: string, factory?: SuiteFactory, options?: number | TestOptions], SuiteCollector, { diff --git a/packages/vitest/src/node/reporters/json.ts b/packages/vitest/src/node/reporters/json.ts index 59d832475332..6bfd83eaf15e 100644 --- a/packages/vitest/src/node/reporters/json.ts +++ b/packages/vitest/src/node/reporters/json.ts @@ -10,7 +10,7 @@ import { parseStacktrace } from '../../utils/source-map' // the following types are extracted from the Jest repository (and simplified) // the commented-out fields are the missing ones -type Status = 'passed' | 'failed' | 'skipped' | 'pending' | 'todo' | 'disabled' | 'repeated' +type Status = 'passed' | 'failed' | 'skipped' | 'pending' | 'todo' | 'disabled' type Milliseconds = number interface Callsite { line: number; column: number } const StatusMap: Record = { @@ -20,7 +20,7 @@ const StatusMap: Record = { run: 'pending', skip: 'skipped', todo: 'todo', - repeats: 'repeated', + repeats: 'pending', } interface FormattedAssertionResult { diff --git a/packages/vitest/src/node/reporters/renderers/listRenderer.ts b/packages/vitest/src/node/reporters/renderers/listRenderer.ts index 8f9b9afcc2d6..71f36c6ddc94 100644 --- a/packages/vitest/src/node/reporters/renderers/listRenderer.ts +++ b/packages/vitest/src/node/reporters/renderers/listRenderer.ts @@ -107,6 +107,9 @@ export function renderTree(tasks: Task[], options: ListRendererOptions, level = if (task.mode === 'skip' || task.mode === 'todo') suffix += ` ${c.dim(c.gray('[skipped]'))}` + if (task.mode === 'repeats') + suffix += ` ${c.dim(c.gray('[repeated]'))}` + if (task.result?.duration != null) { if (task.result.duration > DURATION_LONG) suffix += c.yellow(` ${Math.round(task.result.duration)}${c.dim('ms')}`) diff --git a/packages/vitest/src/node/reporters/renderers/utils.ts b/packages/vitest/src/node/reporters/renderers/utils.ts index 37adb0ea22a4..bb31e14ec173 100644 --- a/packages/vitest/src/node/reporters/renderers/utils.ts +++ b/packages/vitest/src/node/reporters/renderers/utils.ts @@ -103,13 +103,11 @@ export function getStateString(tasks: Task[], name = 'tests', showTotal = true) const failed = tasks.filter(i => i.result?.state === 'fail') const skipped = tasks.filter(i => i.mode === 'skip') const todo = tasks.filter(i => i.mode === 'todo') - const repeated = tasks.filter(i => i.mode === 'repeats') return [ failed.length ? c.bold(c.red(`${failed.length} failed`)) : null, passed.length ? c.bold(c.green(`${passed.length} passed`)) : null, skipped.length ? c.yellow(`${skipped.length} skipped`) : null, - repeated.length ? c.yellow(`${repeated.length} repeated`) : null, todo.length ? c.gray(`${todo.length} todo`) : null, ].filter(Boolean).join(c.dim(' | ')) + (showTotal ? c.gray(` (${tasks.length})`) : '') } diff --git a/packages/vitest/src/typecheck/collect.ts b/packages/vitest/src/typecheck/collect.ts index 365262f35a4b..6d3f8222b675 100644 --- a/packages/vitest/src/typecheck/collect.ts +++ b/packages/vitest/src/typecheck/collect.ts @@ -83,7 +83,7 @@ export async function collectTests(ctx: Vitest, filepath: string): Promise { +describe('testing it/test', () => { const result = [1, 1, 1, 1, 1, 2, 2, 2] // repeats 5 times by default test.repeats('test 1', () => { @@ -26,13 +26,13 @@ describe('repeat tests', () => { const describeNumbers: number[] = [] -describe.repeats('repeat tests', () => { +describe.repeats('testing describe 1', () => { test('test 1', () => { describeNumbers.push(1) }) }) -describe.repeats('repeat tests', () => { +describe.repeats('testing describe 2', () => { test('test 2', () => { describeNumbers.push(2) })