Skip to content

What should console.assert(false, { a: 1 }) print? #226

Description

@jcbhmr

gist of it: which one of these is the "right" way?
image
image

nodejs/node#49680
mdn/content#29172

it seems from the spec https://console.spec.whatwg.org/#assert that it all gets funneled to Logger() which unfurls all that data stuff the same way regardless of which console.* method was used but then again MDN says this:
image
as cited here nodejs/node#49680
https://developer.mozilla.org/en-US/docs/Web/API/console/assert

...soooo yeah I opened this issue to hopefully get someone who knows how to read specs to clarify which way is the "spec way" or if I'm misunderstanding something 🤷‍♂️😵

Activity

  1. domfarolino commented on Sep 19, 2023

    @domfarolino
    Member

    Can you clarify your question? Which output is unexpected for you, and why?

  2. terinjokes commented on Sep 19, 2023

    @terinjokes
    Collaborator

    If I'm reading the screenshots and the linked Node.js issue correctly, the unexpected output is "[object Object]" from Node.js converting all data elements to string.

    My understanding of the spec is the object {hello: "world"} would get passed as a member of args (eg, ["Assertion failed", {hello: "world"}]) to Printer, which is implementation defined. Converting a POJO to the string "[object Object]" is certainly a valid way of being implementation defined, but I wouldn't judge it "to be maximally useful and informative."

  3. jcbhmr commented on Sep 19, 2023

    @jcbhmr
    Author

    @domfarolino Specifically my question is this: Which output is the "correct" one? Assertion failed: [object Object] or Assertion failed: ▶ { hello: 'world' } ?

    Or, more generally, which of these is "correct" according to the spec?

    image
    image

    My confusion comes from reading the spec and surmising this sorta equivalence:

    console.assert(false, {a:1}, {b:2}) // is sorta like
    console.log("Assertion failed", {a:1}, {b:2})
    
    console.assert(false, "it failed %o", {b:2}) // is sorta like
    console.log("Assertion failed" + ": " + "it failed %o", {b:2})

    but that Node.js seems to do the "Assertion failed: " + data[0] all the time instead of only if it's a string.
    https://github.com/nodejs/node/blob/cd97e28860d109e1576e05b4b79692aa013a4e6e/lib/internal/console/constructor.js#L435

    // nodejs essentially ALWAYS does this even if its an object:
    console.assert(false, {a:1}, {b:2}) // is sorta like
    console.log("Assertion failed: " + {a:1}, {b:2})

    Working as expected/documented.
    Yes, I'm pretty sure.

    nodejs/node#49680

    but the spec says:
    image

    so looking for a more authoritative whatwg/console answer on which one (Node.js vs Chrome/Firefox) is the more "correct" implementation ❤

  4. terinjokes commented on Sep 19, 2023

    @terinjokes
    Collaborator

    I'd argue, as above, that both are correct. How any arguments, outside of specifiers, are printed is implementation defined, so [object Object] is equally correct as {"hello": "world"}. I don't think MDN's language is technically wrong (a string, of some sort, is printed), but it also implies behavior that isn't in the specification, and isn't found in their description of other logging methods.

    I would expect, in most environments, objects printed in assert in a similar fashion to how they're printed in the other logging methods. However, as it's implementation defined, they may chose not to.

  5. jcbhmr commented on Sep 19, 2023

    @jcbhmr
    Author

    I found an edge case that exemplifies Node.js' implementation as having some kind of bug:

    console.assert(false, Symbol())
    // THROWS! becase `Assertion failed: ${Symbol()}` will fail

    from this line: https://github.com/nodejs/node/blob/cd97e28860d109e1576e05b4b79692aa013a4e6e/lib/internal/console/constructor.js#L435
    switched the Node.js issue to focus on that instead nodejs/node#49680

    and I've also changed my MDN issue to focus on improving the wording on a bunch of the console methods. mdn/content#29172

  6. jcbhmr commented on Sep 19, 2023

    @jcbhmr
    Author

    @terinjokes Yep! You answered my question! ❤️ Thanks for clarifying the implementation-defined nature of the printing and explaining the spec logic for me. 👍

  7. terinjokes commented on Sep 19, 2023

    @terinjokes
    Collaborator

    The fact that Node.js prints [object Object] only for the first object is curious. Without reviewing the code it suggests to me that it's converting the second parameter to a string either to concatenate with the "Assertion failed" message, or to check for specifiers (or both), neither of which would be following this standard.

  8. jcbhmr commented on Sep 19, 2023

    @jcbhmr
    Author

    Yep! Here's the relevant bit:

      assert(expression, ...args) {
        if (!expression) {
          args[0] = `Assertion failed${args.length === 0 ? '' : `: ${args[0]}`}`;
          // The arguments will be formatted in warn() again
          ReflectApply(this.warn, this, args);
        }
      },

    https://github.com/nodejs/node/blob/cd97e28860d109e1576e05b4b79692aa013a4e6e/lib/internal/console/constructor.js#L435

    Note that it always treats args[0] as a format string (coercing it) which is why ${Symbol()} throws.

    I've chosen to focus on that particular edge case to try and exemplify how the implementation could be improved in nodejs/node#49680

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions