diff --git a/packages/browser/src/client/tester/runner.ts b/packages/browser/src/client/tester/runner.ts index faddbcb9f090..48dfe4dfe593 100644 --- a/packages/browser/src/client/tester/runner.ts +++ b/packages/browser/src/client/tester/runner.ts @@ -156,7 +156,8 @@ export function createBrowserRunner( } onTaskFinished = async (task: Task) => { - const lastErrorContext = task.result?.errors?.at(-1)?.context + // check custom matcher metadata in JestExtendError + const lastErrorContext = task.result?.errors?.at(-1)?.__vitest_error_context__ if ( this.config.browser.screenshotFailures && document.body.clientHeight > 0 diff --git a/packages/expect/src/jest-extend.ts b/packages/expect/src/jest-extend.ts index cc5d313177e6..8857f4357a70 100644 --- a/packages/expect/src/jest-extend.ts +++ b/packages/expect/src/jest-extend.ts @@ -64,12 +64,18 @@ function getMatcherState( } } +interface VitestErrorContext { + assertionName: string + meta?: object +} + class JestExtendError extends Error { constructor( message: string, public actual?: any, public expected?: any, - public context?: { assertionName: string; meta?: object }, + /** @internal */ + public __vitest_error_context__?: VitestErrorContext, ) { super(message) } diff --git a/packages/vitest/src/node/printError.ts b/packages/vitest/src/node/printError.ts index 300d132acb09..bea106916d85 100644 --- a/packages/vitest/src/node/printError.ts +++ b/packages/vitest/src/node/printError.ts @@ -283,6 +283,7 @@ const skipErrorProperties = new Set([ 'VITEST_TEST_NAME', 'VITEST_TEST_PATH', '__vitest_rollup_error__', + '__vitest_error_context__', ...Object.getOwnPropertyNames(Error.prototype), ...Object.getOwnPropertyNames(Object.prototype), ]) diff --git a/test/cli/test/expect-extend.test.ts b/test/cli/test/expect-extend.test.ts new file mode 100644 index 000000000000..c5acb35bfe1a --- /dev/null +++ b/test/cli/test/expect-extend.test.ts @@ -0,0 +1,56 @@ +import { expect, test } from 'vitest' +import { runInlineTests } from '../../test-utils' + +// JestExtendError's internal context property shouldn't show up as "Serialized Error" +test('expect.extend error message', async () => { + const result = await runInlineTests({ + './basic.test.js': ` +import { expect, test } from 'vitest'; + +expect.extend({ + toMyEqual(actual, expected) { + const pass = actual === expected; + return { pass, message: () => 'my matcher failed', actual, expected }; + }, +}); + +test('fail', () => { + expect(123).toMyEqual(456); +}); +`, + }, { + reporters: 'verbose', + }) + expect(result.stderr).toMatchInlineSnapshot(` + " + ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL basic.test.js > fail + Error: my matcher failed + + - Expected + + Received + + - 456 + + 123 + + ❯ basic.test.js:12:15 + 10| + 11| test('fail', () => { + 12| expect(123).toMyEqual(456); + | ^ + 13| }); + 14| + + ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ + + " + `) + expect(result.testTree()).toMatchInlineSnapshot(` + { + "basic.test.js": { + "fail": "failed", + }, + } + `) +})