13
describe('some tests', function () {
  /*
   * Run some tests...
   */
})

after(function () {
  failures = ? // <--- what goes here?
  console.log(failures + " tests failed!")
})

I'd use this to keep chromedriver's browser open if a test failed, and to report success or failure to sauce labs.

Mocha's Runner and Reporters have the info I'm looking for as stats but I'm not sure how to get to them from within a test file.

hurrymaplelad
  • 26,645
  • 10
  • 56
  • 76

2 Answers2

9

I found answer to this question here

afterEach(function() {
  if (this.currentTest.state == 'failed') {
    // ...
  }
});
Community
  • 1
  • 1
nilesh
  • 14,131
  • 7
  • 65
  • 79
  • 2
    The OP is not asking how to determine in an `afterEach` hook whether the test that executed just before it failed. The OP is asking how to determine in an `after` hook if *any* test after which the `after` hook is run failed. – Louis Mar 11 '15 at 23:18
  • 1
    oops sorry didn't realize it. hopefully this will help someone like me who was looking for `afterEach` solution. – nilesh Mar 11 '15 at 23:49
  • 3
    It's easy enough to put this code in the `afterEach` hook, set a flag, and check that flag in the `after` hook. – bmacnaughton Apr 14 '18 at 22:34
  • If you use `suite` and `test` instead of `describe` and `it`, this won't work. But there is a solution: https://stackoverflow.com/questions/58661128/how-to-check-in-the-teardown-method-of-mocha-tdd-if-the-current-test-failed – hardfork Nov 01 '19 at 14:47
6

After a quick check of the code, I believe there is no way for code in after to have access to the runner or the reporters. However, there's a way to get the state of the tests at run time:

describe("blah", function () {

    it("blah", function () {
        throw new Error("blah");
    });

    after(function (){
        var failed = false;
        var tests = this.test.parent.tests;
        for(var i = 0, limit = tests.length; !failed && i < limit; ++i)
            failed = tests[i].state === "failed";
        if (failed)
            console.log("FAILED");
    });
});

Look at the line var tests = this.test.parent.tests. I believe that this.test seems to be a test object associated with the after call. The value of this.test.parent is the suite object associated with the top level describe. And the value of this.test.parent.tests is the list of tests in that suite. So the code there goes through each test, and detects whether the test is in the "failed" state.

None of the variables used in the code above are marked as private (by use of a leading underscore in the name). At the same time, there are no guarantees that future versions of Mocha will use the exact same structure.

All test failures are exceptions so to catch hook failures, I'd wrap the hook with code that detects exceptions. This is a proof-of-concept that shows how it could be done (and I've moved some of the code in the previous example into a has_failed function):

var hook_failure = false;
function make_wrapper(f) {
    return function wrapper() {
        try {
            f.apply(this, arguments);
        }
        catch (e) {
            hook_failure = true;
            throw e;
        }
    };
}

function has_failed(it) {
    var failed = false;
    var tests = it.test.parent.tests;
    for(var i = 0, limit = tests.length; !failed && i < limit; ++i)
        failed = tests[i].state === "failed";
    return failed;
}

describe("blah", function () {

    before(make_wrapper(function () {
        throw new Error("yikes!");
    }));

    it("blah", function () {
        throw new Error("q");
    });

    after(function (){
        var failed = has_failed(this);
        if (failed)
            console.log(this.test.parent.title + " FAILED");
    });
});

after(function () {
    if (hook_failure)
        console.log("HOOK FAILURE");
});

In the example above I use the wrapper method and the method of scanning tests in after. However, it would be possible to only use wrappers throughout for hooks and tests.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • thanks for the investigation. WD uses a [similar strategy](https://github.com/admc/wd/blob/91993b7f1c71bbca976ccb6111fb75e8c2a03eeb/test/e2e/basic-specs.js#L26), tracking failures per test, but hooks cause trouble. An error in a before block doesn't result in any failed tests objects, they're just [skipped](https://github.com/visionmedia/mocha/blob/master/lib/runner.js#L224), even though the runner records a failure. Any ideas for catching hook failures as well? – hurrymaplelad Feb 26 '14 at 22:46