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

Report skipped tests upon beforeEach hook failure #4233

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

juergba
Copy link
Contributor

@juergba juergba commented Apr 21, 2020

Description

required: #4221

describe("parent suite", function() {
    beforeEach(function() {
      throw new Error("this is a failure in a beforeEach hook");
    });
  
    it("test 1", function() { });
    it("test 2", function() { });
  
    describe("inner suite", function() {
      it("test 3", function() { });
    });
})

Before: a failing beforeEach hook ignores the three tests completely.

parent suite
    1) "before each" hook for "test 1"

0 passing (14ms)
1 failing

1) parent suite
     "before each" hook for "test 1":
   Error: this is a failure in a beforeEach hook
   [...]

After:

parent suite
    1) "before each" hook for "test 1"
    - test 1
    - test 2
    inner suite
      - test 3

0 / 3 passing (20ms)
3 skipped
1 failing

1) parent suite
     "before each" hook for "test 1":
   Error: this is a failure in a beforeEach hook
   [...]

Description of the Change

  • add a new event EVENT_TEST_SKIPPED
  • add a new test.state: skipped
  • beforeEach hook: each skipped test is reported and summerised in the epilogue. The output is very similar to pending test cases, but in color red.
  • there are no changes to the hook pattern, skipped tests will not be executed.
  • adapt reporter JSON-STREAM, LIST, TAP and XUNIT

Applicable issues

#1955
#1815

@juergba juergba added block status: needs review a maintainer should (re-)review this pull request type: cleanup a refactor area: reporters involving a specific reporter semver-major implementation requires increase of "major" version number; "breaking changes" area: usability concerning user experience or interface labels Apr 21, 2020
@coveralls
Copy link

coveralls commented Apr 21, 2020

Coverage Status

Coverage increased (+0.1%) to 93.211% when pulling bb10ce9 on juergba/beforeEach into 400bf9b on master.

@juergba juergba force-pushed the juergba/beforeEach branch 2 times, most recently from 7caf4f7 to da95e71 Compare April 29, 2020 08:04
@juergba juergba removed the status: needs review a maintainer should (re-)review this pull request label Apr 29, 2020
@juergba juergba marked this pull request as ready for review April 30, 2020 14:48
@juergba juergba requested a review from a team April 30, 2020 14:48
@juergba juergba self-assigned this Apr 30, 2020
@juergba juergba added the status: needs review a maintainer should (re-)review this pull request label Apr 30, 2020
Copy link
Contributor

@boneskull boneskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, this is great. tests look good too. I don't see any major technical issues, and I think this is a good idea in general. mainly I'm concerned about the mismatch between our terminology and function names, as I've commented here. looking forward to your thoughts

@@ -449,9 +447,73 @@ setTimeout(function() {
}, 5000);
```

### Failing Hooks

Upon a failing "before all", "before each" or "after each" hook, all remaining tests in the current suite and also its nested suites will be skipped. Skipped tests are included in the test results and marked as **skipped**. A skipped test is not considered a failed test.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so we're differentiating between "skipped" and "pending"... I know these two concepts have been conflated.


describe('inner', function() {
before(function() {
// will be skipped
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's important to show (somehow) that order matters. In this case, the outer "before all" hook is run before the inner "before all" hook. If, instead, the inner hook threw, what would happen?

## Pending Tests

"Pending"--as in "someone should write these test cases eventually"--test-cases are simply those _without_ a callback:
"Pending" - as in "someone should write these test cases eventually" - test-cases are simply those _without_ a callback:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an "EM DASH"? Ideally we should have something like smartypants that translates -- to . Maybe revert this?

@@ -462,7 +524,9 @@ describe('Array', function() {
});
```

Pending tests will be included in the test results, and marked as pending. A pending test is not considered a failed test.
By appending `.skip()`, you may also tell Mocha to ignore a test: [inclusive tests](#inclusive-tests).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion:

By appending `.skip()`, you may also tell Mocha to [ignore a test](#inclusive-tests).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait... I'm confused now. this.skip() means "test is pending", not "test is skipped"?

I think we could be more clear here. For your consideration:

  • Maybe we can, instead, make this.skip() report a test as skipped, and this.pending() report a test as pending. The behavior would be roughly similar (the test wouldn't get run), but the test would not be displayed as "pending" unless the user called this.pending() instead of this.skip() (likewise for describe.skip()/describe.pending()/it.skip()/it.pending()). This would be less of a breaking change than just trying to rename skip() to pending().
  • Maybe instead of calling them "skipped tests", as you introduce above, we can just use a different word. "Omitted" tests, maybe?
  • This may be a good place to update the terminology we use elsewhere re: "inclusive" (it.skip()) and "exclusive" (it.only()) tests. Those terms always felt vague to me. Instead of "inclusive", we could say "omitted", and instead of "exclusive", we could say "selected" or "picked" or something.

Copy link
Contributor Author

@juergba juergba May 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current situation (incl. this PR) is:

  • pending: set by the user
    • test without callback: it('some test')
    • static: it.skip() or describe.skip()
    • conditional: this.skip()
  • skipped: test not run because of a failing hook

I haven't changed anything on the first item pending. This mismatch between our terminology and function is an old problem. We could replace label pending by label skipped, but this would break a few third-party tools, reporters, ...
I certainly don't want to rename/add a new this.pending().
And the pending part is out of this PR's scope.

The second label skipped is new and is about failing hooks. We could rename it to "omitted" or "dropped" or whatever. Eg. Cypress and Mochawesome are using skipped for tests omitted by failing hooks. That's why I have chosen skipped. But yes, it is confusing.

We need two independent labels: pending (or we rename it to skipped) and a new one for hook-failed-omitted tests. So I need to know which name to chose.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit of brainstorm:

My thoughts are, when I mark a test not to run, I want Mocha to ignore it, to disable it, to skip it, to omit it.

If it's skipped because of hook-failed, Mocha is skipping it, leaving out, or the test was unrun, unused, benched, called off, unprepared, dropped, withdrawn, canceled, halted. And some of this could apply to the previous case as well.

I think my favorites so far for hook-failed-omitted are called off, canceled, halted. I think called off even best.

It could be interesting to amass a large number of these potential labels, and run a survey through users of Mocha to see how well they feel each of those words describes (from 1 to 10) those two cases. Not to base our choice on our opinion alone.

@@ -1641,7 +1705,7 @@ mocha.setup({
### Browser-specific Option(s)

Browser Mocha supports many, but not all [cli options](#command-line-usage).
To use a [cli option](#command-line-usage) that contains a "-", please convert the option to camel-case, (eg. `check-leaks` to `checkLeaks`).
To use a [cli option](#command-line-usage) that contains a "-", please convert the option to camel-case, (e.g. `check-leaks` to `checkLeaks`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if (err || test.isPending()) {
if (test.isPending()) {
if (self.forbidPending) {
self.fail(test, new Error('Pending test forbidden'), true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably be an error with a code as in lib/errors.js

@@ -726,8 +747,9 @@ Runner.prototype.runSuite = function(suite, fn) {
}

this.emit(constants.EVENT_SUITE_BEGIN, (this.suite = suite));
suite.started = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have any more booleans on Suite like this, we should consider a state prop instead


function next(errSuite) {
function nextSuite(errSuite) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -840,7 +852,7 @@ Runner.prototype.uncaught = function(err) {

runnable.clearTimeout();

if (runnable.isFailed()) {
if (runnable.isFailed() || runnable.isSkipped()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls update the debug statement here

@@ -62,6 +62,7 @@ function Suite(title, parentContext, isRoot) {
this.suites = [];
this.tests = [];
this.pending = false;
this.skipped = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, so, if it's not possible to have this.pending && this.skipped === true, then we should use a state

@JoshuaKGoldberg
Copy link
Member

JoshuaKGoldberg commented Mar 1, 2024

Per #1815 (comment), marking this and #4221 as status: blocked for now. We can take a deeper look once we've gone through some smaller changes first.

@JoshuaKGoldberg JoshuaKGoldberg added the status: blocked Waiting for something else to be resolved label Mar 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: reporters involving a specific reporter area: usability concerning user experience or interface semver-major implementation requires increase of "major" version number; "breaking changes" status: blocked Waiting for something else to be resolved
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants