Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kicking off mocha describes in parallel

I want to be able to have all my describe statements in Mocha get kicked off in parallel. Can someone help me figure out how to do that?

like image 385
Fizz Avatar asked Feb 21 '15 03:02

Fizz


4 Answers

You can't do this directly with mocha because it creates a list of it() callbacks and invokes them in order. mocha-parallel-tests can do this if you're willing to move your describes into separate .js files. To convince yourself, install it somewhere and invoke it with a short --slow so it reports each time:

laptop:/tmp/delme$ npm install mocha-parallel-tests
laptop:/tmp/delme$ cd node_modules/mocha-parallel-tests
laptop:/tmp/delme/node_modules/mocha-parallel-tests$ ./bin/mocha-parallel-tests test/parallel/tests --timeout 10000 --slow 100

You will see that it ran three (very simple) tests suites in the time it took to run the longest.

If your tests don't depend on side-effects of earlier tests, you can make them all asynchronous. A simple way to do this is to initiate the stuff that takes a while before the describe and use the regular mocha apparatus to evaluate it. Here, I create a bunch of promises which take a while to resolve and then iterate through the tests again, examining their results in a .then() function:

var expect = require("chai").expect;

var SlowTests = [
  { name: "a" , time: 250 },
  { name: "b" , time: 500 },
  { name: "c" , time: 750 },
  { name: "d" , time:1000 },
  { name: "e" , time:1250 },
  { name: "f" , time:1500 }
];

SlowTests.forEach(function (test) {
  test.promise = takeAWhile(test.time);
});

describe("SlowTests", function () {
  // mocha defaults to 2s timeout. change to 5s with: this.timeout(5000);
  SlowTests.forEach(function (test) {
    it("should pass '" + test.name + "' in around "+ test.time +" mseconds.",
       function (done) {
         test.promise.then(function (res) {
           expect(res).to.be.equal(test.time);
           done();
         }).catch(function (err) {
           done(err);
         });
       });
  });
});

function takeAWhile (time) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(time);
    }, time);
  });
}
(Save this as foo.js and invoke with mocha foo.js.)

Meta I disagree with the assertion that tests should be primarily be synchronous. before and after pragmas are easier but it's rare that one test invalidates all remaining tests. All discouraging asynchronous tests does is discourage extensive testing of network tasks.

like image 122
ericP Avatar answered Oct 07 '22 12:10

ericP


Mocha does not support what you are trying to do out of the box. It runs tests sequentially. This has a big advantage when dealing with an unhandled exception: Mocha can be sure that it happened in the test that it is currently running. So it ascribes the exception to the current test. It is certainly possible to support parallel testing but it would complicate Mocha quite a bit.

And I tend to agree with David's comment. I would not do it. At the level at which Mocha usually operates, parallelism does not seem to me particularly desirable. Where I have used test parallelism before is at the level of running end-to-end suites. For instance, run a suite against Firefox in Windows 8.1 while at the same time running the same suite against Chrome in Linux.

like image 44
Louis Avatar answered Oct 07 '22 12:10

Louis


Just to update this question, Mocha version 8+ now natively supports parallel runs. You can use the --parallel flag to run your tests in parallel.

Parallel tests should work out-of-the box for many use cases. However, you must be aware of some important implications of the behavior

1 thing to note, some reporters don't currently support this execution (mocha-junit-reporter for example)

like image 4
Rob C Avatar answered Oct 07 '22 12:10

Rob C


If you are using karma to start your tests, you can use karma-parallel to split up your tests across multiple browser instances. It runs specs in different browser instances in parallel and is very simple and easy to install:

npm i karma-parallel

and then add the 'parallel' to the frameworks list in karma.conf.js

module.exports = function(config) {
  config.set({
    frameworks: ['parallel', 'mocha']
  });
};

karma-parallel

Disclosure: I am the author

like image 1
Joel Jeske Avatar answered Oct 07 '22 12:10

Joel Jeske