Repository navigation
console: print String.prototype as {} and Object.create(String.prototype) as String {} #47575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
da9ef23
1cb972d
20f194e
e6782c2
095a203
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2203,13 +2203,22 @@ pub mod formatter { | |
| use jsc::JSType as T; | ||
| let tag = match js_type { | ||
| T::ErrorInstance => TagPayload::Error, | ||
| // JSC makes these three prototypes boxed values (#8627). `cell` selects string colouring. | ||
| T::DerivedStringObject | T::NumberObject | T::BooleanObject | ||
| if crate::cpp::Bun__isStringNumberOrBooleanPrototype(value) => | ||
| { | ||
| return Ok(TagResult { | ||
| tag: TagPayload::Object, | ||
| cell: T::Object, | ||
| }); | ||
| } | ||
| T::NumberObject => TagPayload::Double, | ||
| T::DerivedArray | ||
| | T::Array | ||
| | T::DirectArguments | ||
| | T::ScopedArguments | ||
| | T::ClonedArguments => TagPayload::Array, | ||
| T::DerivedStringObject | T::String | T::StringObject => TagPayload::String, | ||
| T::String | T::StringObject => TagPayload::String, | ||
| T::RegExpObject => TagPayload::String, | ||
| T::Symbol => TagPayload::Symbol, | ||
| T::BooleanObject => TagPayload::Boolean, | ||
|
|
@@ -3166,6 +3175,10 @@ pub mod formatter { | |
| ) -> JsResult<Option<bun_core::String>> { | ||
| let name_str = value.get_class_name(global_this)?; | ||
| if !name_str.eq_ascii(b"Object") { | ||
| // Node prints `String.prototype`, `Number.prototype` and `Boolean.prototype` as `{}`. | ||
| if crate::cpp::Bun__isStringNumberOrBooleanPrototype(value) { | ||
| return Ok(None); | ||
| } | ||
| return Ok(Some(name_str)); | ||
| } else if value.get_prototype(global_this)?.eql_value(JSValue::NULL) { | ||
| return Ok(Some(bun_core::String::static_("[Object: null prototype]"))); | ||
|
|
@@ -5366,7 +5379,8 @@ pub mod formatter { | |
| i: 0, | ||
| }; | ||
|
|
||
| if ordered_properties { | ||
| // Only the other walk leaves out the built-in methods of `String.prototype` and its two siblings. | ||
| if ordered_properties && !crate::cpp::Bun__isStringNumberOrBooleanPrototype(value) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 nit (optional): callers passing Why this was flaggedA program adds enumerable keys to Number.prototype in non-alphabetical order (test/js/bun/util/inspect.test.js:1627-1630 does Verification: Acknowledged in diff: test/js/bun/util/inspect.test.js:1645 pins
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not change this. The reasons:
To honour |
||
| value.for_each_property_ordered( | ||
| global_this, | ||
| (&raw mut iter).cast::<c_void>(), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -939,6 +939,51 @@ test("error inline snapshots", () => { | |
| }).toThrowErrorMatchingInlineSnapshot(`"😊"`); | ||
| }); | ||
|
|
||
| // The snapshot printer has a property walk of its own. console.log prints the three prototypes as `{}` (#8627). | ||
| test("String.prototype, Number.prototype, Boolean.prototype and boxed values", () => { | ||
| class N extends Number {} | ||
| const withKeys = (value: object) => | ||
| Object.defineProperty(Object.assign(value, { b: 1, a: 2 }), "hidden", { value: 3 }); | ||
| expect(String.prototype).toMatchInlineSnapshot(`String {}`); | ||
| expect(Number.prototype).toMatchInlineSnapshot(` | ||
| Number { | ||
| "toExponential": [Function: toExponential], | ||
| "toFixed": [Function: toFixed], | ||
| "toLocaleString": [Function: toLocaleString], | ||
| "toPrecision": [Function: toPrecision], | ||
| "toString": [Function: toString], | ||
| "valueOf": [Function: valueOf], | ||
| } | ||
| `); | ||
| expect(Boolean.prototype).toMatchInlineSnapshot(` | ||
| Boolean { | ||
| "toString": [Function: toString], | ||
| "valueOf": [Function: valueOf], | ||
| } | ||
| `); | ||
| expect(withKeys(new Number(1))).toMatchInlineSnapshot(` | ||
| Number { | ||
| "a": 2, | ||
| "b": 1, | ||
| "hidden": 3, | ||
| } | ||
| `); | ||
| expect(withKeys(new Boolean(true))).toMatchInlineSnapshot(` | ||
| Boolean { | ||
| "a": 2, | ||
| "b": 1, | ||
| "hidden": 3, | ||
| } | ||
| `); | ||
| expect(withKeys(new N(1))).toMatchInlineSnapshot(` | ||
| N { | ||
| "a": 2, | ||
| "b": 1, | ||
| "hidden": 3, | ||
| } | ||
| `); | ||
|
Comment on lines
+947
to
+984
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 nit (optional): maintainers get inline snapshots that certify the snapshot printer's divergence from Jest and that pass unchanged on the base branch. The block at test/js/bun/test/snapshot-tests/snapshots/snapshot.test.ts:947-984 pins Why this was flaggedA later change makes the snapshot printer in src/runtime/test_runner/pretty_format.rs:2307 list only own enumerable keys, matching Jest's pretty-format and the console output this PR introduces. The inline snapshots at test/js/bun/test/snapshot-tests/snapshots/snapshot.test.ts:948-957 and :964-984 then fail, because they pin the built-in DontEnum methods of Verification: nit. The new test block runs against the snapshot printer, which this PR does not touch, so the inline snapshots pin pre-existing behaviour rather than anything the PR changes.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept this block. It is there for #46729, not for the code that this PR changes.
You are right that each assertion passes on the base branch, and that the text is not what Jest prints. That is the text that #46729 promises to keep. The same contract is why I did not change the ordered walk in the If a maintainer prefers to keep that contract in #46729 only, I will drop the block. |
||
| }); | ||
|
|
||
| test("snapshot numbering", () => { | ||
| function fails() { | ||
| throw new Error("snap"); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.