From 6e6ea38e69e6c204750f1933c81d6ef67933117d Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sat, 4 Oct 2025 03:11:21 +0000 Subject: [PATCH 1/3] fix(test): remove quotes from string variables in test.each MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #23206 When using test.each with object syntax and $variable interpolation, string values were being quoted (e.g., "apple" instead of apple). This didn't match the behavior of %s formatting or Jest's behavior. The fix checks if the value is a primitive string and uses toString() instead of the formatter with quote_strings=true. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/bun.js/test/jest.zig | 14 +++++++++++--- test/regression/issue/23206.test.ts | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 test/regression/issue/23206.test.ts diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 521c3d064d43..1b41acadd098 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -384,9 +384,17 @@ pub fn formatLabel(globalThis: *JSGlobalObject, label: string, function_args: [] const var_path = label[var_start..var_end]; const value = try function_args[0].getIfPropertyExistsFromPath(globalThis, bun.String.init(var_path).toJS(globalThis)); if (!value.isEmptyOrUndefinedOrNull()) { - var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; - defer formatter.deinit(); - bun.handleOom(list.writer().print("{}", .{value.toFmt(&formatter)})); + // For primitive strings, use toString() to avoid adding quotes + // This matches Jest's behavior (https://github.com/jestjs/jest/issues/7689) + if (value.isString()) { + const owned_slice = try value.toSliceOrNull(globalThis); + defer owned_slice.deinit(); + bun.handleOom(list.appendSlice(owned_slice.slice())); + } else { + var formatter = jsc.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true }; + defer formatter.deinit(); + bun.handleOom(list.writer().print("{}", .{value.toFmt(&formatter)})); + } idx = var_end; continue; } diff --git a/test/regression/issue/23206.test.ts b/test/regression/issue/23206.test.ts new file mode 100644 index 000000000000..9b8cc5a16f6d --- /dev/null +++ b/test/regression/issue/23206.test.ts @@ -0,0 +1,19 @@ +// https://github.com/oven-sh/bun/issues/23206 +import { test, expect } from "bun:test"; + +test.each([ + "apple", + "banana" +])("fruit #%# is %s", fruit => { + // Test name should be "fruit #0 is apple" and "fruit #1 is banana" + expect(["apple", "banana"]).toContain(fruit); +}); + +test.each([ + { name: "apple" }, + { name: "banana" } +])("fruit #%# is $name", fruit => { + // Test name should be "fruit #0 is apple" and "fruit #1 is banana" + // NOT "fruit #0 is "apple"" and "fruit #1 is "banana"" + expect(["apple", "banana"]).toContain(fruit.name); +}); From 78f5f19dae46a937702e267f7e73cb2d72f9571c Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 12:52:38 +0000 Subject: [PATCH 2/3] [autofix.ci] apply automated fixes --- test/regression/issue/23206.test.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/test/regression/issue/23206.test.ts b/test/regression/issue/23206.test.ts index 9b8cc5a16f6d..09e16fbef813 100644 --- a/test/regression/issue/23206.test.ts +++ b/test/regression/issue/23206.test.ts @@ -1,18 +1,12 @@ // https://github.com/oven-sh/bun/issues/23206 -import { test, expect } from "bun:test"; +import { expect, test } from "bun:test"; -test.each([ - "apple", - "banana" -])("fruit #%# is %s", fruit => { +test.each(["apple", "banana"])("fruit #%# is %s", fruit => { // Test name should be "fruit #0 is apple" and "fruit #1 is banana" expect(["apple", "banana"]).toContain(fruit); }); -test.each([ - { name: "apple" }, - { name: "banana" } -])("fruit #%# is $name", fruit => { +test.each([{ name: "apple" }, { name: "banana" }])("fruit #%# is $name", fruit => { // Test name should be "fruit #0 is apple" and "fruit #1 is banana" // NOT "fruit #0 is "apple"" and "fruit #1 is "banana"" expect(["apple", "banana"]).toContain(fruit.name); From f5d72a78aa58284edc54be9cfd478856324a338f Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Mon, 6 Oct 2025 08:15:00 +0000 Subject: [PATCH 3/3] fix: flush output before exit and update test expectations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After merging main, several tests were failing due to: 1. Output not being flushed before Global.exit() calls 2. AGENT env var causing test names to not be printed 3. Test expectations needing updates for fixed test.each string quote behavior Changes: - Add Output.flush() before Global.exit() in Arguments.zig and test_command.zig - Set AGENT=0 in runTest() to ensure test names are printed - Update test expectations to match new behavior (strings without quotes) - Delete useless test/regression/issue/23206.test.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/cli/Arguments.zig | 3 +++ src/cli/test_command.zig | 1 + test/cli/test/bun-test.test.ts | 26 +++++++++++++------------- test/regression/issue/23206.test.ts | 13 ------------- 4 files changed, 17 insertions(+), 26 deletions(-) delete mode 100644 test/regression/issue/23206.test.ts diff --git a/src/cli/Arguments.zig b/src/cli/Arguments.zig index 4b55ba744616..773b2e5d9d01 100644 --- a/src/cli/Arguments.zig +++ b/src/cli/Arguments.zig @@ -414,6 +414,7 @@ pub fn parse(allocator: std.mem.Allocator, ctx: Command.Context, comptime cmd: C if (timeout_ms.len > 0) { ctx.test_options.default_timeout_ms = std.fmt.parseInt(u32, timeout_ms, 10) catch { Output.prettyErrorln("error: Invalid timeout: \"{s}\"", .{timeout_ms}); + Output.flush(); Global.exit(1); }; } @@ -478,11 +479,13 @@ pub fn parse(allocator: std.mem.Allocator, ctx: Command.Context, comptime cmd: C if (bail.len > 0) { ctx.test_options.bail = std.fmt.parseInt(u32, bail, 10) catch |e| { Output.prettyErrorln("error: --bail expects a number: {s}", .{@errorName(e)}); + Output.flush(); Global.exit(1); }; if (ctx.test_options.bail == 0) { Output.prettyErrorln("error: --bail expects a number greater than 0", .{}); + Output.flush(); Global.exit(1); } } else { diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig index 28c11d2bba1f..7d3bf10cbcae 100644 --- a/src/cli/test_command.zig +++ b/src/cli/test_command.zig @@ -929,6 +929,7 @@ pub const CommandLineReporter = struct { if (this.summary().fail == this.jest.bail) { this.printSummary(); Output.prettyError("\nBailed out after {d} failure{s}\n", .{ this.jest.bail, if (this.jest.bail == 1) "" else "s" }); + Output.flush(); Global.exit(1); } }, diff --git a/test/cli/test/bun-test.test.ts b/test/cli/test/bun-test.test.ts index c462bdfaf487..4724d1052bd8 100644 --- a/test/cli/test/bun-test.test.ts +++ b/test/cli/test/bun-test.test.ts @@ -951,8 +951,8 @@ describe("bun test", () => { `, }); - expect(stderr).toContain('"fs" module > has $method'); - expect(stderr).toContain('"path" module > has $method'); + expect(stderr).toContain("fs module > has $method"); + expect(stderr).toContain("path module > has $method"); expect(stderr).toContain("2 pass"); }); @@ -976,8 +976,8 @@ describe("bun test", () => { `, }); - expect(stderr).toContain('(pass) user "john_doe" age 30 active true'); - expect(stderr).toContain('(pass) user "jane_smith" age 25 active false'); + expect(stderr).toContain("(pass) user john_doe age 30 active true"); + expect(stderr).toContain("(pass) user jane_smith age 25 active false"); expect(stderr).toContain("2 pass"); }); @@ -1027,8 +1027,8 @@ describe("bun test", () => { `, }); - expect(stderr).toContain('(pass) "Alice" from "NYC"'); - expect(stderr).toContain('(pass) "Bob" from "LA"'); + expect(stderr).toContain("(pass) Alice from NYC"); + expect(stderr).toContain("(pass) Bob from LA"); expect(stderr).toContain("2 pass"); }); @@ -1056,8 +1056,8 @@ describe("bun test", () => { `, }); - expect(stderr).toContain('(pass) first user is "Alice"'); - expect(stderr).toContain('(pass) first user is "Carol"'); + expect(stderr).toContain("(pass) first user is Alice"); + expect(stderr).toContain("(pass) first user is Carol"); expect(stderr).toContain("2 pass"); }); @@ -1085,9 +1085,9 @@ describe("bun test", () => { `, }); - expect(stderr).toContain('"underscore"'); - expect(stderr).toContain('"dollar"'); - expect(stderr).toContain('"mix"'); + expect(stderr).toContain("underscore"); + expect(stderr).toContain("dollar"); + expect(stderr).toContain("mix"); expect(stderr).toContain("$123invalid"); expect(stderr).toContain("$hasdash"); expect(stderr).toContain("$hasspace"); @@ -1118,7 +1118,7 @@ describe("bun test", () => { `, }); - expect(stderr).toContain('First user: "Alice" with tag: "admin"'); + expect(stderr).toContain("First user: Alice with tag: admin"); }); test("handles missing properties gracefully", () => { @@ -1460,7 +1460,7 @@ function runTest({ const { stderr, exitCode } = spawnSync({ cwd, cmd: [bunExe(), "test", ...args], - env: { ...bunEnv, ...env }, + env: { ...bunEnv, AGENT: "0", ...env }, stderr: "pipe", stdout: "ignore", }); diff --git a/test/regression/issue/23206.test.ts b/test/regression/issue/23206.test.ts deleted file mode 100644 index 09e16fbef813..000000000000 --- a/test/regression/issue/23206.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -// https://github.com/oven-sh/bun/issues/23206 -import { expect, test } from "bun:test"; - -test.each(["apple", "banana"])("fruit #%# is %s", fruit => { - // Test name should be "fruit #0 is apple" and "fruit #1 is banana" - expect(["apple", "banana"]).toContain(fruit); -}); - -test.each([{ name: "apple" }, { name: "banana" }])("fruit #%# is $name", fruit => { - // Test name should be "fruit #0 is apple" and "fruit #1 is banana" - // NOT "fruit #0 is "apple"" and "fruit #1 is "banana"" - expect(["apple", "banana"]).toContain(fruit.name); -});