Search code examples
mocha.jskarma-runnerkarma-mocha

How to use Mocha require option in Karma


I've been trying to use the mocha require option:

mocha mytest.js --require myglobals.js

But I don't know how to do it from karma. The idea is to run karma start and it will automatically require myglobals.js.

Is that possible to do it from within karma.conf.js or somehow else?

Maybe I'm not using karma/mocha in the right way.

My idea is:

  • I want to have unit/integration tests for both the client (react) and the server (node/express)
  • I want to just run karma start and both client and server tests are tested
  • I found very useful to have the following file pre-required, in order to avoid requiring some things in all tests:

myglobals.js:

const chai = require('chai');

// Load Chai assertions
global.expect = chai.expect;
global.assert = chai.assert;
chai.should();

// Load Sinon
global.sinon = require('sinon');

// Initialize Chai plugins
chai.use(require('sinon-chai'));
chai.use(require('chai-as-promised'));
chai.use(require('chai-things'));

For the server side I've made it work using the command:

mocha mytest.js --require myglobals.js

But still, I wanted to keep it running under the npm run test (which calls karma start) instead of creating another npm run test:server command.

Furthermore, I wanted to do the same on the client. I'm using webpack there as a preprocessor.

Any ideas if it is possible to accomplish that? Or maybe I'm in the wrong way?


Solution

  • Short Answer

    Mocha in the browser does not support an equivalent of the --require option, but you do not need it. You can just load whatever you need ahead of your tests listing the files you want to load in files in front of your test files. Or if you use a loader like RequireJS, write a test-main.js that loads the modules you would load with --require first, and then load your test files.

    Long Answer

    If you look at Mocha's code you'll see that the only place --require is used is in the bin/_mocha file. This option is not passed further into the Mocha code but is immediately used to load the requested modules:

    requires.forEach(function(mod) {
      require(mod);
    });
    

    When you run Mocha in the browser, none of this code is run, and if you look in the rest of the Mocha code you won't find a similar facility anywhere else. Why?

    Because it would serve no purpose. The --require option is very useful at the command line. Without it, the only way to load modules before Mocha loads the test files would be to either write custom code to start Mocha or put the necessary require calls at the start of every single test file.

    In the browser, if you do not use a module loader, you can just load the code you'd load using --require by putting the script elements that load them in front of the script elements that load your tests. In Karma, this means putting these files earlier in the list of files you have in your karma.conf.js. Or if you use RequireJS, for instance, you write test-main.js so that the loading is done in two phases: one that loads the modules you'd load through --require on the command-line, and a second that loads your test files. It could be something like:

    const allTestFiles = [];
    const TEST_REGEXP = /test\/test.*\.js$/i;
    
    Object.keys(window.__karma__.files).forEach((file) => {
      if (TEST_REGEXP.test(file)) {
        const normalizedTestModule = file.replace(/^\/base\/|\.js$/g, "");
        allTestFiles.push(normalizedTestModule);
      }
    });
    
    require.config({
      baseUrl: "/base",
      paths: {
         ...
      },
    });
    
    // This guarantees that "a", "b", "c" loads before any other module
    require(["a", "b", "c", ...], () => {
      require(allTestFiles, window.__karma__.start);
    });