From 132c73363bb3912e21539b937a7204673f12adeb Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Fri, 13 Feb 2026 08:27:34 +0000 Subject: [PATCH] fix(test): use "Received value" instead of "Expected value" in error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `expect()` receives a non-function for `.toThrow()` or a non-mock for mock matchers, the error message said "Expected value must be..." which is ambiguous — in testing terminology, "expected" refers to the matcher argument while "received" refers to the value passed to `expect()`. This aligns with Jest's behavior. Closes #26996 Co-Authored-By: Claude --- src/bun.js/test/expect.zig | 6 +-- src/bun.js/test/expect/toContainKey.zig | 2 +- src/bun.js/test/expect/toHaveBeenCalled.zig | 2 +- .../test/expect/toHaveBeenCalledOnce.zig | 2 +- .../test/expect/toHaveBeenCalledTimes.zig | 2 +- .../test/expect/toHaveBeenLastCalledWith.zig | 2 +- .../test/expect/toHaveLastReturnedWith.zig | 2 +- .../test/expect/toHaveNthReturnedWith.zig | 2 +- src/bun.js/test/expect/toHaveReturnedWith.zig | 2 +- test/regression/issue/26996.test.ts | 41 +++++++++++++++++++ 10 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 test/regression/issue/26996.test.ts diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index ffa8303115..54add05edd 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -554,7 +554,7 @@ pub const Expect = struct { return .{ value, return_value_from_function }; } - return globalThis.throw("Expected value must be a function", .{}); + return globalThis.throw("Received value must be a function", .{}); } var return_value: JSValue = .zero; @@ -2002,7 +2002,7 @@ pub const mock = struct { if (!returns.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function: {f}", .{value.toFmt(&formatter)}); } return try returns.arrayIterator(globalThis); @@ -2015,7 +2015,7 @@ pub const mock = struct { } var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function with returns: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function with returns: {f}", .{value.toFmt(&formatter)}); } pub fn jestMockReturnObject_value(globalThis: *JSGlobalObject, value: bun.jsc.JSValue) bun.JSError!JSValue { return (try value.get(globalThis, "value")) orelse .js_undefined; diff --git a/src/bun.js/test/expect/toContainKey.zig b/src/bun.js/test/expect/toContainKey.zig index 0121e85c8a..c7f274ebbf 100644 --- a/src/bun.js/test/expect/toContainKey.zig +++ b/src/bun.js/test/expect/toContainKey.zig @@ -22,7 +22,7 @@ pub fn toContainKey( const not = this.flags.not; if (!value.isObject()) { - return globalThis.throwInvalidArguments("Expected value must be an object\nReceived: {f}", .{value.toFmt(&formatter)}); + return globalThis.throwInvalidArguments("Received value must be an object\nReceived: {f}", .{value.toFmt(&formatter)}); } var pass = try value.hasOwnPropertyValue(globalThis, expected); diff --git a/src/bun.js/test/expect/toHaveBeenCalled.zig b/src/bun.js/test/expect/toHaveBeenCalled.zig index a4113d1f04..6b14b8a36a 100644 --- a/src/bun.js/test/expect/toHaveBeenCalled.zig +++ b/src/bun.js/test/expect/toHaveBeenCalled.zig @@ -15,7 +15,7 @@ pub fn toHaveBeenCalled(this: *Expect, globalThis: *JSGlobalObject, callframe: * if (!calls.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function: {f}", .{value.toFmt(&formatter)}); } const calls_length = try calls.getLength(globalThis); diff --git a/src/bun.js/test/expect/toHaveBeenCalledOnce.zig b/src/bun.js/test/expect/toHaveBeenCalledOnce.zig index dbb20dac0c..d816866089 100644 --- a/src/bun.js/test/expect/toHaveBeenCalledOnce.zig +++ b/src/bun.js/test/expect/toHaveBeenCalledOnce.zig @@ -11,7 +11,7 @@ pub fn toHaveBeenCalledOnce(this: *Expect, globalThis: *JSGlobalObject, callfram if (!calls.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function: {f}", .{value.toFmt(&formatter)}); } const calls_length = try calls.getLength(globalThis); diff --git a/src/bun.js/test/expect/toHaveBeenCalledTimes.zig b/src/bun.js/test/expect/toHaveBeenCalledTimes.zig index 5b0db03aba..d8258cb986 100644 --- a/src/bun.js/test/expect/toHaveBeenCalledTimes.zig +++ b/src/bun.js/test/expect/toHaveBeenCalledTimes.zig @@ -13,7 +13,7 @@ pub fn toHaveBeenCalledTimes(this: *Expect, globalThis: *JSGlobalObject, callfra if (!calls.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function: {f}", .{value.toFmt(&formatter)}); } if (arguments.len < 1 or !arguments[0].isUInt32AsAnyInt()) { diff --git a/src/bun.js/test/expect/toHaveBeenLastCalledWith.zig b/src/bun.js/test/expect/toHaveBeenLastCalledWith.zig index 488a42916e..1e9c2c2e7e 100644 --- a/src/bun.js/test/expect/toHaveBeenLastCalledWith.zig +++ b/src/bun.js/test/expect/toHaveBeenLastCalledWith.zig @@ -26,7 +26,7 @@ pub fn toHaveBeenLastCalledWith(this: *Expect, globalThis: *JSGlobalObject, call if (!lastCallValue.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function with calls: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function with calls: {f}", .{value.toFmt(&formatter)}); } if (try lastCallValue.getLength(globalThis) != arguments.len) { diff --git a/src/bun.js/test/expect/toHaveLastReturnedWith.zig b/src/bun.js/test/expect/toHaveLastReturnedWith.zig index 82b7230a61..f6633af4bd 100644 --- a/src/bun.js/test/expect/toHaveLastReturnedWith.zig +++ b/src/bun.js/test/expect/toHaveLastReturnedWith.zig @@ -13,7 +13,7 @@ pub fn toHaveLastReturnedWith(this: *Expect, globalThis: *JSGlobalObject, callfr if (!returns.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function: {f}", .{value.toFmt(&formatter)}); } const calls_count = @as(u32, @intCast(try returns.getLength(globalThis))); diff --git a/src/bun.js/test/expect/toHaveNthReturnedWith.zig b/src/bun.js/test/expect/toHaveNthReturnedWith.zig index 5ba76d46a0..74704c1343 100644 --- a/src/bun.js/test/expect/toHaveNthReturnedWith.zig +++ b/src/bun.js/test/expect/toHaveNthReturnedWith.zig @@ -21,7 +21,7 @@ pub fn toHaveNthReturnedWith(this: *Expect, globalThis: *JSGlobalObject, callfra if (!returns.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function: {f}", .{value.toFmt(&formatter)}); } const calls_count = @as(u32, @intCast(try returns.getLength(globalThis))); diff --git a/src/bun.js/test/expect/toHaveReturnedWith.zig b/src/bun.js/test/expect/toHaveReturnedWith.zig index c8aac164a5..0e67f04e0f 100644 --- a/src/bun.js/test/expect/toHaveReturnedWith.zig +++ b/src/bun.js/test/expect/toHaveReturnedWith.zig @@ -13,7 +13,7 @@ pub fn toHaveReturnedWith(this: *Expect, globalThis: *JSGlobalObject, callframe: if (!returns.jsType().isArray()) { var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; defer formatter.deinit(); - return globalThis.throw("Expected value must be a mock function: {f}", .{value.toFmt(&formatter)}); + return globalThis.throw("Received value must be a mock function: {f}", .{value.toFmt(&formatter)}); } const calls_count = @as(u32, @intCast(try returns.getLength(globalThis))); diff --git a/test/regression/issue/26996.test.ts b/test/regression/issue/26996.test.ts new file mode 100644 index 0000000000..d73fb1ddc3 --- /dev/null +++ b/test/regression/issue/26996.test.ts @@ -0,0 +1,41 @@ +import { expect, test } from "bun:test"; + +// https://github.com/oven-sh/bun/issues/26996 +// Error messages should say "Received value" (the value passed to expect()), +// not "Expected value" (which refers to the matcher argument in testing terminology). + +test("toThrow on non-function says 'Received value'", () => { + try { + expect(123).toThrow(Error); + throw new Error("should not reach here"); + } catch (e: any) { + expect(e.message).toBe("Received value must be a function"); + } +}); + +test("toHaveBeenCalled on non-mock says 'Received value'", () => { + try { + expect(123).toHaveBeenCalled(); + throw new Error("should not reach here"); + } catch (e: any) { + expect(e.message).toContain("Received value must be a mock function"); + } +}); + +test("toHaveBeenCalledTimes on non-mock says 'Received value'", () => { + try { + expect(123).toHaveBeenCalledTimes(1); + throw new Error("should not reach here"); + } catch (e: any) { + expect(e.message).toContain("Received value must be a mock function"); + } +}); + +test("toContainKey on non-object says 'Received value'", () => { + try { + expect(123).toContainKey("foo"); + throw new Error("should not reach here"); + } catch (e: any) { + expect(e.message).toContain("Received value must be an object"); + } +});