diff --git a/src/jsc/ConsoleObject.rs b/src/jsc/ConsoleObject.rs index 29152e29c5cf..a6b799836954 100644 --- a/src/jsc/ConsoleObject.rs +++ b/src/jsc/ConsoleObject.rs @@ -502,13 +502,13 @@ fn message_with_type_and_level_( let mut table_printer = TablePrinter::init(global, level, tabular_data, properties)?; table_printer.value_formatter.indent += u32::from(default_indent); - if enable_colors { - let _ = table_printer.print_table::(writer); + let printed = if enable_colors { + table_printer.print_table::(writer) } else { - let _ = table_printer.print_table::(writer); - } + table_printer.print_table::(writer) + }; let _ = writer.flush(); - return Ok(()); + return printed; } } diff --git a/test/js/bun/console/console-table.test.ts b/test/js/bun/console/console-table.test.ts index 32fee910127d..038e89b788bc 100644 --- a/test/js/bun/console/console-table.test.ts +++ b/test/js/bun/console/console-table.test.ts @@ -363,3 +363,60 @@ console.log("calls=" + calls);`, expect({ stdout, stderr, exitCode }).toEqual({ stdout: box("1") + "calls=1\n", stderr: "", exitCode: 0 }); }); }); + +// Reading a cell runs user code (getters, Proxy traps, custom inspect). An +// exception thrown there must surface from console.table itself, exactly as +// it does from Bun.inspect.table, rather than being swallowed by the printer. +describe("console.table propagates exceptions thrown while reading cells", () => { + test("a throwing getter on a row", () => { + const boom = new Error("getter boom"); + const row = {}; + Object.defineProperty(row, "x", { + get() { + throw boom; + }, + enumerable: true, + }); + expect(() => console.table([row])).toThrow(boom); + }); + + test("a throwing Proxy trap on the tabular data", () => { + const boom = new Error("proxy boom"); + const data = new Proxy( + { a: 1 }, + { + ownKeys() { + throw boom; + }, + }, + ); + expect(() => console.table(data)).toThrow(boom); + }); + + test("a throwing custom inspect in a cell", () => { + const boom = new Error("inspect boom"); + const cell = { + [Bun.inspect.custom]() { + throw boom; + }, + }; + expect(() => console.table([{ x: cell }])).toThrow(boom); + }); + + test("nothing is printed and the error is uncaught in a script", async () => { + await using proc = Bun.spawn({ + cmd: [ + bunExe(), + "-e", + `console.table([{ get x() { throw new Error("table getter boom"); } }]); +console.log("unreachable");`, + ], + env: bunEnv, + stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + expect(stdout).toBe(""); + expect(stderr).toContain("table getter boom"); + expect(exitCode).toBe(1); + }); +});