Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How might I check if any mocha tests failed from within an after block?

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.

like image 678
hurrymaplelad Avatar asked Feb 26 '14 04:02

hurrymaplelad


Video Answer


2 Answers

I found answer to this question here

afterEach(function() {
  if (this.currentTest.state == 'failed') {
    // ...
  }
});
like image 197
nilesh Avatar answered Oct 17 '22 08:10

nilesh


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.

like image 35
Louis Avatar answered Oct 17 '22 10:10

Louis