mirror of
https://github.com/vitest-dev/vitest.git
synced 2025-12-08 18:26:03 +00:00
feat: allow a custom note when calling ctx.skip() dynamically (#6805)
This commit is contained in:
parent
8d179afcc7
commit
697c35c52d
@ -67,9 +67,9 @@ export function createTestContext<T extends Test | Custom>(
|
||||
|
||||
context.task = test
|
||||
|
||||
context.skip = () => {
|
||||
context.skip = (note?: string) => {
|
||||
test.pending = true
|
||||
throw new PendingError('test is skipped; abort execution', test)
|
||||
throw new PendingError('test is skipped; abort execution', test, note)
|
||||
}
|
||||
|
||||
context.onTestFailed = (fn) => {
|
||||
|
||||
@ -4,7 +4,7 @@ export class PendingError extends Error {
|
||||
public code = 'VITEST_PENDING'
|
||||
public taskId: string
|
||||
|
||||
constructor(public message: string, task: TaskBase) {
|
||||
constructor(public message: string, task: TaskBase, public note: string | undefined) {
|
||||
super(message)
|
||||
this.taskId = task.id
|
||||
}
|
||||
|
||||
@ -257,7 +257,7 @@ export async function runTest(test: Test | Custom, runner: VitestRunner): Promis
|
||||
// skipped with new PendingError
|
||||
if (test.pending || test.result?.state === 'skip') {
|
||||
test.mode = 'skip'
|
||||
test.result = { state: 'skip' }
|
||||
test.result = { state: 'skip', note: test.result?.note }
|
||||
updateTask(test, runner)
|
||||
setCurrentTest(undefined)
|
||||
return
|
||||
@ -336,6 +336,7 @@ export async function runTest(test: Test | Custom, runner: VitestRunner): Promis
|
||||
function failTask(result: TaskResult, err: unknown, diffOptions: DiffOptions | undefined) {
|
||||
if (err instanceof PendingError) {
|
||||
result.state = 'skip'
|
||||
result.note = err.note
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -147,6 +147,8 @@ export interface TaskResult {
|
||||
* `repeats` option is set. This number also contains `retryCount`.
|
||||
*/
|
||||
repeatCount?: number
|
||||
/** @private */
|
||||
note?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@ -611,7 +613,7 @@ export interface TaskContext<Task extends Custom | Test = Custom | Test> {
|
||||
* Mark tests as skipped. All execution after this call will be skipped.
|
||||
* This function throws an error, so make sure you are not catching it accidentally.
|
||||
*/
|
||||
skip: () => void
|
||||
skip: (note?: string) => void
|
||||
}
|
||||
|
||||
export type ExtendedContext<T extends Custom | Test> = TaskContext<T> &
|
||||
|
||||
@ -144,7 +144,8 @@ function renderTree(
|
||||
}
|
||||
|
||||
if (task.mode === 'skip' || task.mode === 'todo') {
|
||||
suffix += ` ${c.dim(c.gray('[skipped]'))}`
|
||||
const note = task.result?.note || 'skipped'
|
||||
suffix += ` ${c.dim(c.gray(`[${note}]`))}`
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@ -119,14 +119,27 @@ export class TestCase extends ReportedTaskImplementation {
|
||||
return undefined
|
||||
}
|
||||
const state = result.state === 'fail'
|
||||
? 'failed'
|
||||
? 'failed' as const
|
||||
: result.state === 'pass'
|
||||
? 'passed'
|
||||
: 'skipped'
|
||||
? 'passed' as const
|
||||
: 'skipped' as const
|
||||
if (state === 'skipped') {
|
||||
return {
|
||||
state,
|
||||
note: result.note,
|
||||
errors: undefined,
|
||||
} satisfies TestResultSkipped
|
||||
}
|
||||
if (state === 'passed') {
|
||||
return {
|
||||
state,
|
||||
errors: result.errors as TestError[] | undefined,
|
||||
} satisfies TestResultPassed
|
||||
}
|
||||
return {
|
||||
state,
|
||||
errors: result.errors as TestError[] | undefined,
|
||||
} as TestResult
|
||||
errors: (result.errors || []) as TestError[],
|
||||
} satisfies TestResultFailed
|
||||
}
|
||||
|
||||
/**
|
||||
@ -441,6 +454,10 @@ export interface TestResultSkipped {
|
||||
* Skipped tests have no errors.
|
||||
*/
|
||||
errors: undefined
|
||||
/**
|
||||
* A custom note.
|
||||
*/
|
||||
note: string | undefined
|
||||
}
|
||||
|
||||
export interface TestDiagnostic {
|
||||
|
||||
@ -43,6 +43,9 @@ export class VerboseReporter extends DefaultReporter {
|
||||
` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`,
|
||||
)
|
||||
}
|
||||
if (task.result?.note) {
|
||||
title += c.dim(c.gray(` [${task.result.note}]`))
|
||||
}
|
||||
this.ctx.logger.log(title)
|
||||
if (task.result.state === 'fail') {
|
||||
task.result.errors?.forEach((error) => {
|
||||
|
||||
@ -40,6 +40,7 @@ export class StateManager {
|
||||
task.mode = 'skip'
|
||||
task.result ??= { state: 'skip' }
|
||||
task.result.state = 'skip'
|
||||
task.result.note = _err.note
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
5
test/cli/fixtures/skip-note/basic.test.ts
Normal file
5
test/cli/fixtures/skip-note/basic.test.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { test } from 'vitest';
|
||||
|
||||
test('my skipped test', ctx => {
|
||||
ctx.skip('custom message')
|
||||
})
|
||||
30
test/cli/test/skip-note.test.ts
Normal file
30
test/cli/test/skip-note.test.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import type { TestCase } from 'vitest/node'
|
||||
import { resolve } from 'node:path'
|
||||
import { expect, test } from 'vitest'
|
||||
import { runVitest } from '../../test-utils'
|
||||
|
||||
const root = resolve(import.meta.dirname, '../fixtures/skip-note')
|
||||
|
||||
test.for([
|
||||
{ reporter: 'default', isTTY: true },
|
||||
{ reporter: 'verbose', isTTY: false },
|
||||
])('can leave a note when skipping in the $reporter reporter', async ({ reporter, isTTY }) => {
|
||||
const { ctx, stdout, stderr } = await runVitest({
|
||||
root,
|
||||
reporters: [
|
||||
[reporter, { isTTY }],
|
||||
],
|
||||
})
|
||||
|
||||
expect(stderr).toBe('')
|
||||
expect(stdout).toContain('my skipped test [custom message]')
|
||||
|
||||
expect(ctx).toBeDefined()
|
||||
const testTask = ctx!.state.getFiles()[0].tasks[0]
|
||||
const test = ctx!.state.getReportedEntity(testTask) as TestCase
|
||||
const result = test.result()
|
||||
expect(result).toEqual({
|
||||
state: 'skipped',
|
||||
note: 'custom message',
|
||||
})
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user