Skip to content

Commit

Permalink
feat: allow a custom note when calling ctx.skip() dynamically (#6805)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va authored Nov 13, 2024
1 parent 8d179af commit 697c35c
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 11 deletions.
4 changes: 2 additions & 2 deletions packages/runner/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/runner/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion packages/runner/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
4 changes: 3 additions & 1 deletion packages/runner/src/types/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ export interface TaskResult {
* `repeats` option is set. This number also contains `retryCount`.
*/
repeatCount?: number
/** @private */
note?: string
}

/**
Expand Down Expand Up @@ -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> &
Expand Down
3 changes: 2 additions & 1 deletion packages/vitest/src/node/reporters/renderers/listRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
27 changes: 22 additions & 5 deletions packages/vitest/src/node/reporters/reported-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

/**
Expand Down Expand Up @@ -441,6 +454,10 @@ export interface TestResultSkipped {
* Skipped tests have no errors.
*/
errors: undefined
/**
* A custom note.
*/
note: string | undefined
}

export interface TestDiagnostic {
Expand Down
3 changes: 3 additions & 0 deletions packages/vitest/src/node/reporters/verbose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/node/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export class StateManager {
task.mode = 'skip'
task.result ??= { state: 'skip' }
task.result.state = 'skip'
task.result.note = _err.note
}
return
}
Expand Down
5 changes: 5 additions & 0 deletions test/cli/fixtures/skip-note/basic.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test } from 'vitest';

test('my skipped test', ctx => {
ctx.skip('custom message')
})
30 changes: 30 additions & 0 deletions test/cli/test/skip-note.test.ts
Original file line number Diff line number Diff line change
@@ -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',
})
})

0 comments on commit 697c35c

Please sign in to comment.