Skip to content
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

Core: Exclude or grey internal frames from stack traces in TAP reporter #1789

Merged
merged 1 commit into from
Jul 27, 2024

Conversation

Krinkle
Copy link
Member

@Krinkle Krinkle commented Jul 27, 2024

Internal frames are those from qunit.js, or Node.js runtime.

  • Remove any internal frames from the top of the stack.
  • Grey out later internal frames anywhere in the stack.

This change is applied to the TAP reporter, which the QUnit CLI uses by default. The benefit of trimming initial qunit.js internal frames also benefits use of the TAP reporter in browser environments.

This change inspired by an upcoming change, which converts our fake "No tests" test failure into a normal error. When we emitted it as a fake test, it benefitted from QUnit.stack() trimming qunit.js frames, thus guanteeing the stack to start at the QUnit.test() call, skipping the first few frames, and anything after the user code is also by definition not of interest.

For generic errors, we weren't doing this yet. And, while we don't have a clean anchor point like QUnit.test() for uncaught errors, we can do better than dumping it all to the console. We can still safely trim the first frames that are internal. Removing later ones is likely to cause confusion (by wrongly suggesting that A>C when it is actually A>B>C). We can color those in grey, similar to what Node.js's own error formatter does by default.

Example

Using node bin/qunit.js test/cli/fixtures/async-module-error.js as example. The stack trace now starts at the test suite file, skipping qunit.js itself as first two frames. This is similar to what the HTML Reporter has done for years for stack traces under assertions (rather than global errors).

Before (3.0.0-alpha.1)
Screenshot

After (3.0.0-alpha.3)
Screenshot

Internal frames are those from qunit.js, or Node.js runtime.

* Remove any internal frames from the top of the stack.
* Grey out later internal frames anywhere in the stack.

This change is applied to the TAP reporter, which the QUnit CLI uses
by default.
@Krinkle Krinkle force-pushed the clean-cli-err-stack branch from bd67758 to 228c073 Compare July 27, 2024 21:03
@Krinkle Krinkle merged commit 9fed286 into main Jul 27, 2024
21 checks passed
@Krinkle Krinkle deleted the clean-cli-err-stack branch July 27, 2024 21:06
Krinkle added a commit to Krinkle/qunit that referenced this pull request Jul 27, 2024
* Remove hacky re-entrance from
  ProcessingQueue.done() -> test() + advance() -> done(),
  existed only for this purpose.

  This also removes the need for the 99aee51 workaround, which
  avoided a crash by infinite loop.

* Remove unused internal `test` injection to ProcessingQueue,
  existed only for this purpose.

* Remove "omit stack trace" logic in test.js,
  existed only for this purpose. To keep output for the "No tests"
  error similarly clean and distraction-free, the TAP reporter
  treats error stack traces with a similar cleaner since
  qunitjs#1789.

* Remove unused internal `validTest` mechanism
  existed only for this purpose.

  This was originally impossible to trigger externally because it
  required setting `validTest` to a private symbol. In QUnit 1.16
  this was simplified as part of commit 3f08a1a, to take any
  boolean true value to ease some implementation details, however it
  remained internal in purpose. A search today for `/validTest:/`
  and `/validTest = /` over public GitHub-hosted repositories, shows
  that (fortunatley) nobody has started relying on this. I found only
  copies of QUnit itself.

As a nice side-effect, fixtures like async-module-error.tap.txt
now no longer display a useless "No tests" after an uncaught error
that already bailed the test run. This happened previously because
errors are not tests, and so technically there was no test. No that
"No tests" is itself considered a bail out, TAP absorbs this after
the first error, just like it alreayd does for other cascading
errors.
Krinkle added a commit that referenced this pull request Jul 27, 2024
* Remove hacky re-entrance from
  ProcessingQueue.done() -> test() + advance() -> done(),
  existed only for this purpose.

  This also removes the need for the 99aee51 workaround, which
  avoided a crash by infinite loop.

* Remove unused internal `test` injection to ProcessingQueue,
  existed only for this purpose.

* Remove "omit stack trace" logic in test.js,
  existed only for this purpose. To keep output for the "No tests"
  error similarly clean and distraction-free, the TAP reporter
  treats error stack traces with a similar cleaner since
  #1789.

* Remove unused internal `validTest` mechanism
  existed only for this purpose.

  This was originally impossible to trigger externally because it
  required setting `validTest` to a private symbol. In QUnit 1.16
  this was simplified as part of commit 3f08a1a, to take any
  boolean true value to ease some implementation details, however it
  remained internal in purpose. A search today for `/validTest:/`
  and `/validTest = /` over public GitHub-hosted repositories, shows
  that (fortunatley) nobody has started relying on this. I found only
  copies of QUnit itself.

As a nice side-effect, fixtures like async-module-error.tap.txt
now no longer display a useless "No tests" after an uncaught error
that already bailed the test run. This happened previously because
errors are not tests, and so technically there was no test. No that
"No tests" is itself considered a bail out, TAP absorbs this after
the first error, just like it alreayd does for other cascading
errors.

Closes #1790.
Krinkle added a commit to Krinkle/qunit that referenced this pull request Aug 7, 2024
Follows-up qunitjs#1789, which applied
this to traces under uncaught errors. We now apply the same to traces
under assertion failures as well.

(TODO: Split into separate commit)

Omit noisy and confusing actual:null,expected:undefined from TAP
output. This is prevented in HtmlReporter due to hasOwn check, but
this check fails in TAP because it uses testEnd.errors instead of
QUnit.log(). And, in Test.js#logAssertion, where originally expected
is allowed to be unset, it gets forged in the call to testReport
in order to satisfy the API. Indeed, js-reporters never allowed for
unset actual/expected.

Fix this by instead deciding to skip rendering if both are strictly
equal to the value of undefined, which I believe cannot be useful
information. However, for that to be true, we have to change
`actual:null` to `actual:undefined` in pushFailure(). Otherwise,
it can easily be a genuine diff.
Krinkle added a commit that referenced this pull request Aug 7, 2024
Follows-up #1789, which applied
this to traces under uncaught errors. We now apply this clean up to
traces under assertion failures as well.
Krinkle added a commit that referenced this pull request Aug 9, 2024
Follows-up #1789, which applied
this to traces under uncaught errors. We now apply this clean up to
traces under assertion failures as well.

Closes #1795.
Krinkle added a commit that referenced this pull request Jan 18, 2025
…port)

Cherry-picked from 9fed286 (3.0.0-dev):

> Core: Exclude or grey internal frames from stack traces in TAP reporter
> Internal frames are those from qunit.js, or Node.js runtime.
>
> * Remove any internal frames from the top of the stack.
> * Grey out later internal frames anywhere in the stack.
>
> This change is applied to the TAP reporter, which the QUnit CLI uses
> by default.
>
> Ref #1789.

Cherry-picked from 95105aa (3.0.0-dev):

> Fix fragile code in stracktrace.js that previously worked only because
> of Babel transformations masking a violation of the Temporal Dead Zone
> between `const fileName` and the functions it uses to compute that
> value.
@Krinkle Krinkle added this to the 2.x release milestone Jan 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant