diff --git a/expect/_build_message.ts b/expect/_build_message.ts index 4678a46eb106..d0671f267b6f 100644 --- a/expect/_build_message.ts +++ b/expect/_build_message.ts @@ -49,3 +49,38 @@ export function buildNotEqualErrorMessage( const msgPrefix = msg ? `${msg}: ` : ""; return `${msgPrefix}Expected actual: ${actualString} not to be: ${expectedString}.`; } + +export function buildToMatchObjectErrorMessage( + actual: T, + expected: T, + options: EqualErrorMessageOptions = {}, +): string { + const { formatter = format, msg } = options; + const msgPrefix = msg ? `${msg}: ` : ""; + const actualString = formatter(actual); + const expectedString = formatter(expected); + + let message = `${msgPrefix}expect(received).toMatchObject(expected)`; + + const stringDiff = isString(actual) && isString(expected); + const diffResult = stringDiff + ? diffStr(actual, expected) + : diff(actualString.split("\n"), expectedString.split("\n")); + const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n"); + message = `${message}\n${diffMsg}`; + + return message; +} + +export function buildNotToMatchObjectErrorMessage( + actual: T, + expected: T, + options: EqualErrorMessageOptions = {}, +): string { + const { formatter = format, msg } = options; + const actualString = formatter(actual); + const expectedString = formatter(expected); + + const msgPrefix = msg ? `${msg}: ` : ""; + return `${msgPrefix}expect(received).not.toMatchObject(expected)\n\nExpected: not ${expectedString}\nReceived: ${actualString}`; +} diff --git a/expect/_matchers.ts b/expect/_matchers.ts index 3c74bf0b7047..f98d754698cc 100644 --- a/expect/_matchers.ts +++ b/expect/_matchers.ts @@ -27,7 +27,8 @@ import { } from "./_utils.ts"; import { buildEqualErrorMessage, - buildNotEqualErrorMessage, + buildNotToMatchObjectErrorMessage, + buildToMatchObjectErrorMessage, } from "./_build_message.ts"; import { escapeStringForJs, @@ -595,7 +596,10 @@ export function toMatchObject( const triggerError = () => { if (context.isNot) { - const defaultMessage = buildNotEqualErrorMessage(received, expected); + const defaultMessage = buildNotToMatchObjectErrorMessage( + received, + expected, + ); throw new AssertionError( context.customMessage ? `${context.customMessage}: ${defaultMessage}` @@ -603,7 +607,7 @@ export function toMatchObject( ); } else { const subset = getObjectSubset(received, expected, context.customTesters); - const defaultMessage = buildEqualErrorMessage(subset, expected); + const defaultMessage = buildToMatchObjectErrorMessage(subset, expected); throw new AssertionError( context.customMessage ? `${context.customMessage}: ${defaultMessage}` diff --git a/expect/_to_match_object_test.ts b/expect/_to_match_object_test.ts index 8b58b360a21f..d357974bd1dd 100644 --- a/expect/_to_match_object_test.ts +++ b/expect/_to_match_object_test.ts @@ -121,6 +121,11 @@ Deno.test("expect().toMatchObject() throws the correct error messages", () => { () => expect({ a: 1 }).toMatchObject({ a: 2 }), AssertionError, ); + // The matcher name must appear in the message, not a generic equality + // phrase such as "Values are not equal." which misleads users into + // thinking strict equality was checked. + assertMatch(e.message, /expect\(received\)\.toMatchObject\(expected\)/); + assertNotMatch(e.message, /Values are not equal/); assertNotMatch(e.message, /not to be/); } { @@ -128,7 +133,12 @@ Deno.test("expect().toMatchObject() throws the correct error messages", () => { () => expect({ a: 1 }).not.toMatchObject({ a: 1 }), AssertionError, ); - assertMatch(e.message, /not to be/); + assertMatch( + e.message, + /expect\(received\)\.not\.toMatchObject\(expected\)/, + ); + assertNotMatch(e.message, /Values are equal/); + assertNotMatch(e.message, /Expected actual: .* not to be:/); } });