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 }}
+
+
+ Expected Fail
+
+
+ {{ explorerTree.summary.testsExpectedFail }}
+
+
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,
]