Fix console.trace coloring + more tests

This commit is contained in:
Ben Grant
2025-05-28 11:50:58 -07:00
parent cda77ab831
commit 20baa2ca2c
6 changed files with 180 additions and 15 deletions

View File

@@ -248,7 +248,7 @@ fn messageWithTypeAndLevel_(
writer.writeAll("undefined\n") catch {};
if (message_type == .Trace) {
writeTrace(Writer, writer, global);
writeTrace(Writer, writer, global, enable_colors);
buffered_writer.flush() catch {};
}
}
@@ -668,7 +668,7 @@ pub const TablePrinter = struct {
}
};
pub fn writeTrace(comptime Writer: type, writer: Writer, global: *JSGlobalObject) void {
pub fn writeTrace(comptime Writer: type, writer: Writer, global: *JSGlobalObject, enable_ansi_colors: bool) void {
var holder = ZigException.Holder.init();
var vm = VirtualMachine.get();
defer holder.deinit(vm);
@@ -688,20 +688,14 @@ pub fn writeTrace(comptime Writer: type, writer: Writer, global: *JSGlobalObject
false,
);
if (Output.enable_ansi_colors_stderr)
VirtualMachine.printStackTrace(
switch (enable_ansi_colors) {
inline else => |color| VirtualMachine.printStackTrace(
Writer,
writer,
exception.stack,
true,
) catch {}
else
VirtualMachine.printStackTrace(
Writer,
writer,
exception.stack,
false,
) catch {};
color,
) catch {},
}
}
pub const FormatOptions = struct {

View File

@@ -2390,7 +2390,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
Output.flush();
if (!globalThis.hasException()) {
JSC.ConsoleObject.writeTrace(@TypeOf(&writer), &writer, globalThis);
JSC.ConsoleObject.writeTrace(@TypeOf(&writer), &writer, globalThis, Output.enable_ansi_colors_stderr);
}
Output.flush();
}

View File

@@ -578,7 +578,7 @@ describe("stdio", () => {
expect(writeFn).toHaveBeenCalledTimes(1);
});
it.todo(`console uses overridden process.${stream} in worker`, async () => {
it(`console uses overridden process.${stream} in worker`, async () => {
const worker = new Worker(
/* js */ `
import { Writable } from "node:stream";
@@ -600,6 +600,58 @@ describe("stdio", () => {
expect(await resultPromise).toBe("[wrapped] hello\n");
});
});
describe("console", () => {
it("all functions are captured", async () => {
const worker = new Worker(
/* js */ `
console.assert();
console.assert(false);
// TODO: https://github.com/oven-sh/bun/issues/19953
// this should be "Assertion failed: should be true," not "should be true"
// but we still want to make sure it is captured in workers
console.assert(false, "should be true");
console.debug("debug");
console.error("error");
console.info("info");
console.log("log");
console.table([{ a: 5 }]);
// TODO: https://github.com/oven-sh/bun/issues/19952
// this goes to the wrong place but we still want to make sure it is captured in workers
console.trace("trace");
console.warn("warn");
`,
{ eval: true, stdout: true, stderr: true },
);
// normalize the random blob URL and lines and columns from internal modules
const stdout = (await readToEnd(worker.stdout))
.replace(/blob:[0-9a-f\-]{36}/, "blob:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
.replaceAll(/\(\d+:\d+\)$/gm, "(line:col)");
const stderr = await readToEnd(worker.stderr);
expect(stdout).toBe(`debug
info
log
┌───┬───┐
│ │ a │
├───┼───┤
│ 0 │ 5 │
└───┴───┘
trace
at blob:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:15:17
at loadAndEvaluateModule (line:col)
at asyncFunctionResume (line:col)
at promiseReactionJobWithoutPromiseUnwrapAsyncContext (line:col)
at promiseReactionJob (line:col)
`);
expect(stderr).toBe(`Assertion failed
Assertion failed
should be true
error
warn
`);
});
});
});
describe("getHeapSnapshot", () => {

View File

@@ -0,0 +1,41 @@
import { Writable } from "node:stream";
class WrapStream extends Writable {
#base;
#message;
constructor(base, message) {
super();
this.#base = base;
this.#message = message;
}
_write(chunk, encoding, callback) {
const string = chunk.toString("utf8");
this.#base.write(`[${this.#message}] ${string}`, "utf8", callback);
}
}
if (Bun.isMainThread) {
process.stdout = new WrapStream(process.stdout, "parent process.stdout");
process.stderr = new WrapStream(process.stderr, "parent process.stderr");
new Worker(import.meta.filename);
} else {
process.stdout = new WrapStream(process.stdout, "worker process.stdout");
process.stderr = new WrapStream(process.stderr, "worker process.stderr");
console.assert();
console.assert(false);
// TODO: https://github.com/oven-sh/bun/issues/19953
// this should be "Assertion failed: should be true," not "should be true"
// but we still want to make sure it is not in workers
console.assert(false, "should be true");
console.debug("debug");
console.error("error");
console.info("info");
console.log("log");
console.table([{ a: 5 }]);
// TODO: https://github.com/oven-sh/bun/issues/19952
// this goes to the wrong place but we still want to make sure it is not in workers
console.trace("trace");
console.warn("warn");
}

View File

@@ -0,0 +1,26 @@
import { Writable } from "node:stream";
class WrapStream extends Writable {
#base;
#message;
constructor(base, message) {
super();
this.#base = base;
this.#message = message;
}
_write(chunk, encoding, callback) {
const string = chunk.toString("utf8");
this.#base.write(`[${this.#message}] ${string}`, "utf8", callback);
}
}
if (Bun.isMainThread) {
process.stdout = new WrapStream(process.stdout, "parent process.stdout");
process.stderr = new WrapStream(process.stderr, "parent process.stderr");
new Worker(import.meta.filename);
} else {
process.stdout.write("stdout");
process.stderr.write("stderr");
}

View File

@@ -296,6 +296,58 @@ describe("web worker", () => {
expect(err.error).toBe(null);
});
});
describe("stdio", () => {
test("process stdio in worker does not go to process stdio in parent", async () => {
const proc = Bun.spawn({
cmd: [bunExe(), "worker-fixture-process-stdio.js"],
env: bunEnv,
cwd: __dirname,
stdout: "pipe",
stderr: "pipe",
});
await proc.exited;
expect(proc.exitCode).toBe(0);
const stdout = await new Response(proc.stdout).text();
const stderr = await new Response(proc.stderr).text();
expect(stdout).toBe("stdout");
expect(stderr).toBe("stderr");
});
test("console functions in worker do not go to process stdio in worker or parent", async () => {
const proc = Bun.spawn({
cmd: [bunExe(), "worker-fixture-console.js"],
env: bunEnv,
cwd: __dirname,
stdout: "pipe",
stderr: "pipe",
});
await proc.exited;
expect(proc.exitCode).toBe(0);
// normalize lines and columns from internal modules
const stdout = (await new Response(proc.stdout).text()).replaceAll(/\(\d+:\d+\)$/gm, "(line:col)");
const stderr = await new Response(proc.stderr).text();
expect(stdout).toBe(`debug
info
log
┌───┬───┐
│ │ a │
├───┼───┤
│ 0 │ 5 │
└───┴───┘
trace
at ${__dirname}/worker-fixture-console.js:39:11
at loadAndEvaluateModule (line:col)
`);
expect(stderr).toBe(`Assertion failed
Assertion failed
should be true
error
warn
`);
});
});
});
// TODO: move to node:worker_threads tests directory