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
[FEATURE] Can't see cause or aggregate details for uncaught errors #1000
Comments
I'm noting that this is probably related to tapjs/stack-utils#61, which has a whole ton of discussion about cause formatting in general. It's probably the place to go to discuss specifics on that mark! (See also jestjs/jest#11935.) But I'm keeping this issue around as tracking for other ways to integrate custom or Node.js-built-in error tracing for tap itself. |
I've done some digging in the source to try to get more familiar with basically how tap works and where changes would be needed, and the give-away (after digging in the reporter code) is that the reporter is most certainly parsing the tap results, with no extra "magic" after the fact to generate new information, so the core test runner is responsible (which generates tap output) is responsible for stack tracing. Specifically, the function we've gotta look at is I'm not sure what the ideal solution would be for embedding information that isn't a plain stack trace into the results here. I guess the good thing is that YAML Diagnostic blocks aren't standardized? So we can choose to add completely new information here, without altering the existing expected contents of Personally, seeing as it's a structured YAML object anyway, I think we should basically allow recursive details here, exactly the same as the current flat shape is reported, just without Of course, all this means that as-is, tap's error reporting for result details is handled by Actually, if
I'm definitely inclined more towards the second approach, because it keeps I might give implementing all of this a shot, since implementation-wise it doesn't sound dreadfully complicated (recursion in TypeScript isn't that hard, right!?), and would be a fun project to get familiar with tap's internals — even if any of this is out of scope for tap or some totally different approach is selected. But no guarantees I'll get anywhere with my code! 👾 |
We did it! We still need to do test cases, and probably some extra-detail adjustments (it doesn't display the error type, nor any Also some checking against Node.js to make sure everything is, in fact, working precisely as intended (that's where we're pulling the essential appearance, "42 lines matching cause trace" messaging, and a chunk of implementation code from). |
Is there an existing issue for this?
Have you read the
CONTRIBUTING
guide on posting issues, andCODE_OF_CONDUCT
?Description
To aid in debugging without necessitating futzing around with Chrome-style
debugger
statements, several infrastructural parts of my code wrap uncaught errors with supplemental details by creating errors withcause
.In practice we use a custom (and not-so-appropriately named)
showAggregate
function to display causes and aggregate errors in a nice, compact tree, for example below:Node.js already tries to accommodate errors with
cause
and aggregate errors, too, as below:Tap doesn't, though! All I get is details about the top-level error.
This is problematic for a few reasons, but the biggest is that — provided a simple cause chain, with no aggregate errors — I don't get any information about the bottom error. That's where the code actually failed (since it's an uncaught error). Of course, I hardly get any of the surrounding context I've added through errors with
cause
; I get the very top layer (since it's the top-level error object that tap considers), but that's it.Of course, if any layers are aggregate errors, the overall structure really is important — it's not just supplemental context anymore, but describing possibly multiple errors that went wrong. For proper debugging, I need access to not just one of them (or the top layer) but the whole structure.
In practice I've worked around this by temporarily editing the test file, wrapping the line of code that eventually throws the error in debugging boilerplate:
It works, but it's super inconvenient.
I can think of three ways to make this better on tap's part:
cause
and aggregate errors. This is probably an involved process — I don't know how much tap is built on Node's own error reporting, but if its implementation is highly customized/hand-made, it could require a lot of work to approximate or take inspiration from Node's error handling.There's also a big question of what to do with the code context that tap provides, which is genuinely super helpful, but completely fails for errors-with-cause or aggregate errors — providing only code context for the top-level (and generally supplemental) error. But obviously displaying code context for every error in a chain would get very unwieldy. (You could argue that this is why tap only shows the code context for the top line in an error trace!)
On my part there are probably nicer ways to get around this, for example by handling uncaught errors in general (
unhandledRejection
) or by putting specific error-handling code into a helper function that wraps my tests. (I already have one for snapshot tests, but most of my unit tests just use the top-levelt.test()
function directly, so those would take some not-so-nice refactoring).But I'm pretty sure workarounds I'd code on my end wouldn't be able to integrate nicely into tap's own error reporting; I basically only have the option to spit text into stdout/stderr and manually correlate it to the actual test that failed, in tap's summary, once all my tests have evaluated.
Although this gets in the way, it's not like tap is doing anything wrong here — it just doesn't specially report uncaught errors with
cause
and aggregate errors. So I've filed making any sorts of related improvements as a feature request! And I'd love to find out that actually there are ways to handle this better right now, too, but figured I'd summarize the situation anyway.Example
Simple reproduction code with only a plain
cause
chain, no aggregate errors:Note that the code context for the bottom error is around
return new TypeError("Division by zero, ma'am?");
, but the context tap provides is aroundthrow new Error("Oh dear in relation(fakeRelation)", {
. tap also doesn't give me any way to figure out the trace or even message for that bottom-level error, nor any of the errors in-between.Edit: Yay, issue #1000! 🥳
The text was updated successfully, but these errors were encountered: