diff --git a/packages/ui/client/components/dashboard/TestsEntry.vue b/packages/ui/client/components/dashboard/TestsEntry.vue index 76825c216f29..7be0fe7bcc90 100644 --- a/packages/ui/client/components/dashboard/TestsEntry.vue +++ b/packages/ui/client/components/dashboard/TestsEntry.vue @@ -47,6 +47,18 @@ function toggleFilter(type: 'success' | 'failed' | 'skipped' | 'total') { {{ explorerTree.summary.testsFailed }} + + + + i.result?.state === 'pass' ? acc + 1 : acc, 0) + const passed = tasks.reduce((acc, i) => { + // Exclude expected failures from passed count + if (i.result?.state === 'pass' && i.type === 'test' && i.fails) { + return acc + } + return i.result?.state === 'pass' ? acc + 1 : acc + }, 0) const failed = tasks.reduce((acc, i) => i.result?.state === 'fail' ? acc + 1 : acc, 0) const skipped = tasks.reduce((acc, i) => i.mode === 'skip' ? acc + 1 : acc, 0) const todo = tasks.reduce((acc, i) => i.mode === 'todo' ? acc + 1 : acc, 0) + const expectedFail = tasks.reduce((acc, i) => { + // Count tests that are marked as .fails and passed (which means they failed as expected) + if (i.result?.state === 'pass' && i.type === 'test' && i.fails) { + return acc + 1 + } + return acc + }, 0) return ( [ failed ? c.bold(c.red(`${failed} failed`)) : null, passed ? c.bold(c.green(`${passed} passed`)) : null, + expectedFail ? c.cyan(`${expectedFail} expected fail`) : null, skipped ? c.yellow(`${skipped} skipped`) : null, todo ? c.gray(`${todo} todo`) : null, ] diff --git a/packages/vitest/src/node/reporters/summary.ts b/packages/vitest/src/node/reporters/summary.ts index bbbf7860ec9c..736d7812e6ae 100644 --- a/packages/vitest/src/node/reporters/summary.ts +++ b/packages/vitest/src/node/reporters/summary.ts @@ -21,6 +21,7 @@ interface Counter { failed: number skipped: number todo: number + expectedFail: number } interface SlowTask { @@ -208,7 +209,13 @@ export class SummaryReporter implements Reporter { const result = test.result() if (result?.state === 'passed') { - this.tests.passed++ + // Check if this is an expected failure (test.fails && passed) + if (test.options.fails) { + this.tests.expectedFail++ + } + else { + this.tests.passed++ + } } else if (result?.state === 'failed') { this.tests.failed++ @@ -349,7 +356,7 @@ export class SummaryReporter implements Reporter { } function emptyCounters(): Counter { - return { completed: 0, passed: 0, failed: 0, skipped: 0, todo: 0, total: 0 } + return { completed: 0, passed: 0, failed: 0, skipped: 0, todo: 0, expectedFail: 0, total: 0 } } function getStateString(entry: Counter) { @@ -357,6 +364,7 @@ function getStateString(entry: Counter) { [ entry.failed ? c.bold(c.red(`${entry.failed} failed`)) : null, c.bold(c.green(`${entry.passed} passed`)), + entry.expectedFail ? c.cyan(`${entry.expectedFail} expected fail`) : null, entry.skipped ? c.yellow(`${entry.skipped} skipped`) : null, entry.todo ? c.gray(`${entry.todo} todo`) : null, ]