Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 37 additions & 8 deletions src/runtime/test_runner/pretty_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,11 @@ impl<'w, W: bun_io::Write> WrappedWriter<'w, W> {
use bun_io::AsFmt;

impl<'a> Formatter<'a> {
/// Older versions stored these line breaks at every depth, so snapshots keep them. Only a failure message counts its output.
fn has_snapshot_line_breaks(&self) -> bool {
self.indent == 0 || self.output_length.is_none()
}

pub(crate) fn write_indent<W: bun_io::Write>(&self, writer: &mut W) -> bun_io::Result<()> {
let indent = self.indent.min(32);
let buf = [b' '; 64];
Expand Down Expand Up @@ -1156,6 +1161,7 @@ impl<'a> Formatter<'a> {
writer.write_all(b"String {}");
return Ok(());
}
let line_breaks = self.has_snapshot_line_breaks();
if self.indent == 0 && str.len > 0 {
writer.write_all(b"\n");
}
Expand All @@ -1176,8 +1182,14 @@ impl<'a> Formatter<'a> {
}
}
self.reset_line();
writer.write_all(b"}\n");
self.indent = self.indent.saturating_sub(1);
if line_breaks {
// In a snapshot the closing brace of a nested String object has no indentation.
writer.write_all(b"}\n");
} else {
let _ = self.write_indent(writer.ctx);
writer.write_all(b"}");
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
return Ok(());
}

Expand All @@ -1193,7 +1205,7 @@ impl<'a> Formatter<'a> {

let mut has_newline = false;

if str.index_of_any(b"\n\r").is_some() {
if str.index_of_any(b"\n\r").is_some() && self.has_snapshot_line_breaks() {
Comment thread
robobun marked this conversation as resolved.
Resolved
has_newline = true;
writer.write_all(b"\n");
}
Expand Down Expand Up @@ -1736,7 +1748,7 @@ impl<'a> Formatter<'a> {
writer.write_all(b"[native code]");
}
Tag::Promise => {
if self.good_time_for_a_new_line() {
if self.has_snapshot_line_breaks() && self.good_time_for_a_new_line() {
writer.write_all(b"\n");
let _ = self.write_indent(writer.ctx);
}
Expand Down Expand Up @@ -1791,7 +1803,12 @@ impl<'a> Formatter<'a> {
return Ok(());
}

writer.print(format_args!("\n{} {{\n", map_name));
let line_breaks = self.has_snapshot_line_breaks();
if line_breaks {
writer.print(format_args!("\n{} {{\n", map_name));
} else {
writer.print(format_args!("{} {{\n", map_name));
}
{
self.indent += 1;
// hoist global_this (Copy &ref) before iter mutably
Expand All @@ -1815,7 +1832,9 @@ impl<'a> Formatter<'a> {
}
let _ = self.write_indent(writer.ctx);
writer.write_all(b"}");
writer.write_all(b"\n");
if line_breaks {
writer.write_all(b"\n");
}
}
Tag::Set => {
let length_value = value
Expand All @@ -1830,7 +1849,11 @@ impl<'a> Formatter<'a> {
let prev_quote_strings = self.quote_strings;
self.quote_strings = true;

let _ = self.write_indent(writer.ctx);
let line_breaks = self.has_snapshot_line_breaks();
if line_breaks {
// A snapshot also has the indentation of a nested Set before its name.
let _ = self.write_indent(writer.ctx);
}

let set_name: &str =
if value.js_type() == JSType::WeakSet { "WeakSet" } else { "Set" };
Expand All @@ -1841,7 +1864,11 @@ impl<'a> Formatter<'a> {
return Ok(());
}

writer.print(format_args!("\n{} {{\n", set_name));
if line_breaks {
writer.print(format_args!("\n{} {{\n", set_name));
} else {
writer.print(format_args!("{} {{\n", set_name));
}
{
self.indent += 1;
let global = self.global_this;
Expand All @@ -1862,7 +1889,9 @@ impl<'a> Formatter<'a> {
}
let _ = self.write_indent(writer.ctx);
writer.write_all(b"}");
writer.write_all(b"\n");
if line_breaks {
writer.write_all(b"\n");
}
}
Tag::JSON => {
let str = value.json_stringify(self.global_this, self.indent)?;
Expand Down
6 changes: 6 additions & 0 deletions test/js/bun/test/expect-extend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,12 @@ describe("MatcherContext", () => {
expect(Bun.stripANSI(utils.diff(Symbol("a"), Symbol("b")))).toBe("Expected: Symbol(a)\nReceived: Symbol(b)");
});

test("diff prints a Set inside an object on the line of its key", () => {
expect(Bun.stripANSI(utils.diff({ s: new Set([1]) }, { s: new Set([2]) }))).toContain(
'\n "s": Set {\n- 1,\n+ 2,\n },\n',
);
});

test("diff rethrows an error thrown while printing a value", () => {
const thrown = new Error("from the trap");
const value = new Proxy(
Expand Down
15 changes: 15 additions & 0 deletions test/js/bun/test/printing/diffexample.fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,18 @@ test.skipIf(!Bun.enableANSIColors)("mix of whitespace-only and non-whitespace-on
`);
}
});

test("the output of a subprocess in an object", () => {
const received = { stdout: "hello\n", stderr: "warn: x\n", exitCode: 1 };
expect(received).toEqual({ stdout: "hello\n", stderr: "", exitCode: 0 });
});

test("a Set and a Map in an object", () => {
const received = { s: new Set([1, 2]), m: new Map([["a", 1]]), a: 1 };
expect(received).toEqual({ s: new Set([1, 3]), m: new Map([["a", 2]]), a: 1 });
});

test("a Set and a Map in an array", () => {
const received = [new Set([1, 2]), new Map([["a", 1]]), 1];
expect(received).toEqual([new Set([1, 3]), new Map([["a", 2]]), 1]);
});
Loading
Loading