Skip to content

Commit f7bfb71

Browse files
committed
fix(expect): handle async errors in expect.soft
1 parent 657e83f commit f7bfb71

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

packages/expect/src/utils.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,19 @@ export function recordAsyncExpect(
7373
return promise
7474
}
7575

76+
function handleTestError(test: Test, err: unknown) {
77+
test.result ||= { state: 'fail' }
78+
test.result.state = 'fail'
79+
test.result.errors ||= []
80+
test.result.errors.push(processError(err))
81+
}
82+
7683
export function wrapAssertion(
7784
utils: Chai.ChaiUtils,
7885
name: string,
79-
fn: (this: Chai.AssertionStatic & Assertion, ...args: any[]) => void,
86+
fn: (this: Chai.AssertionStatic & Assertion, ...args: any[]) => void | Promise<void>,
8087
) {
81-
return function (this: Chai.AssertionStatic & Assertion, ...args: any[]): void {
88+
return function (this: Chai.AssertionStatic & Assertion, ...args: any[]): void | Promise<void> {
8289
// private
8390
if (name !== 'withTest') {
8491
utils.flag(this, '_name', name)
@@ -95,13 +102,18 @@ export function wrapAssertion(
95102
}
96103

97104
try {
98-
return fn.apply(this, args)
105+
const result = fn.apply(this, args)
106+
107+
if (result && typeof result === 'object' && result instanceof Promise) {
108+
return result.catch((err) => {
109+
handleTestError(test, err)
110+
})
111+
}
112+
113+
return result
99114
}
100115
catch (err) {
101-
test.result ||= { state: 'fail' }
102-
test.result.state = 'fail'
103-
test.result.errors ||= []
104-
test.result.errors.push(processError(err))
116+
handleTestError(test, err)
105117
}
106118
}
107119
}

test/cli/fixtures/expect-soft/expects/soft.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { expect, test } from 'vitest'
22

33
interface CustomMatchers<R = unknown> {
4+
toBeAsync: (expected: unknown) => Promise<R>;
45
toBeDividedBy(divisor: number): R
56
}
67

@@ -9,6 +10,12 @@ declare module 'vitest' {
910
}
1011

1112
expect.extend({
13+
toBeAsync: async function (received, expected) {
14+
return {
15+
pass: received === expected,
16+
message: () => `expected ${received} to be ${expected} (asynchronously)`,
17+
};
18+
},
1219
toBeDividedBy(received, divisor) {
1320
const pass = received % divisor === 0
1421
if (pass) {
@@ -62,6 +69,12 @@ test('with expect.extend', () => {
6269
expect(5).toEqual(6)
6370
})
6471

72+
test('promise with expect.extend', async () => {
73+
await expect.soft(1 + 1).toBeAsync(3);
74+
await expect.soft(1 + 2).toBeAsync(3);
75+
await expect.soft(2 + 2).toBeAsync(3);
76+
});
77+
6578
test('passed', () => {
6679
expect.soft(1).toEqual(1)
6780
expect(10).toEqual(10)

test/cli/test/expect-soft.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ describe('expect.soft', () => {
4040
expect.soft(stderr).toContain('AssertionError: expected 5 to deeply equal 6')
4141
})
4242

43+
test('promise with expect.extend', async () => {
44+
const { stderr } = await run()
45+
expect.soft(stderr).toContain('Error: expected 2 to be 3')
46+
expect.soft(stderr).toContain('Error: expected 4 to be 3')
47+
})
48+
4349
test('passed', async () => {
4450
const { stdout } = await run()
4551
expect.soft(stdout).toContain('soft.test.ts > passed')

0 commit comments

Comments
 (0)