mocha: The same test suite won't run twice when using mocha programmatically

When trying to execute a test suite twice, using the programmatic approach, the second time it should be executed it isn’t found. This is especially annoying when trying to execute the same test with differing configuration.

Minimal Example (the test/test.js file contains a suite with a single always-passing test):

var Mocha = require('mocha');

function runMocha(callback) {
    var mocha = new Mocha();

    mocha.addFile('test/test.js');

    mocha.run(function () {
        callback();
    });
}

runMocha(function () {
    runMocha(function () {});
});

The first time mocha is run it will execute the test, the second time it will not.

The cause for this is that the second time it is required in mocha.js, the file is already cached and won’t be executed. The only solution I was able to find is deleting the cached file from require.cache, but that doesn’t look like good practice to me at all.

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Reactions: 7
  • Comments: 27 (2 by maintainers)

Commits related to this issue

Most upvoted comments

So I definitely had to solve this problem at least once before, yet tonight I could not remember how, so here is an example to assist my future self (or anyone else 😃 ):

function runMochaTests() {
    Object.keys( require.cache ).forEach( function( file ) {
        delete require.cache[ file ];
    } );

    var mocha = new Mocha();

    mocha.addFile( 'run_test.js' );

    mocha.run();
}

Its ugly, but you should be able to call runMochaTests() multiple times.

Deleting the cache right after running require() seems to do nicely. I suspect it’s very racy but I’ve been able to run the test hundreds of time in parallel.

let mocha = new Mocha({});

mocha.suite.on('require', function (global, file) {
    delete require.cache[file];
});

//TODO: add files to suite & do things

mocha.run();

How do I run tests more than once?

var Mocha = require('mocha');
var mocha = new Mocha({});
mocha.addFile('test.js');
mocha.run();

setTimeout(function() {
    mocha.run();
},1000);

Output is something like:

  suite
    √ test


  1 passing (11ms)



  suite
    1) test


  0 passing (16ms)
  1 failing

  1) suite test:
     TypeError: Cannot read property 'call' of undefined
      at callFn (node_modules\mocha\lib\runnable.js:334:20)
      at Test.Runnable.run (node_modules\mocha\lib\runnable.js:327:7)
      at Runner.runTest (node_modules\mocha\lib\runner.js:429:10)
      at node_modules\mocha\lib\runner.js:535:12
      at next (node_modules\mocha\lib\runner.js:349:14)
      at node_modules\mocha\lib\runner.js:359:7
      at next (node_modules\mocha\lib\runner.js:285:14)
      at Immediate.<anonymous> (node_modules\mocha\lib\runner.js:327:5)

If anyone comes across this post and is trying to run mocha tests in your browser, here is what I did to reset the tests after mocha.run()

const resetTests = () => {
  mocha.suite.suites = []
  let testSpecs = document.getElementById('testSpecs')
  if (testSpecs) testSpecs.remove()
  testSpecs = document.createElement('script')
  testSpecs.src = '/questions-specs/testSpecs.js'
  testSpecs.async = true
  testSpecs.id = 'testSpecs'
  document.body.appendChild(testSpecs)
}

setTimeout(resetTests, 1000)

Faced the same issue, and options above have not worked for me. I just created a helper MochaRunner class and now I can rerun the same tests.

// Usage
const runner1 = new MochaRunner();
const runner2 = new MochaRunner();

runner1.run(['test1.js', 'test2.js']).then(() => {
   runner1.cleanup();
});

runner2.run(['test1.js']).then(() => {
   runner2.cleanup();
})

and in both cases test1.js will be run!

P.S. Hope it will help to someone 😉

I almost lost all of my hair. The issue is stated at the bottom of the ‘angelo’ npm module description, https://www.npmjs.com/package/angelo.

The test files are being loaded with a require, which is being cached. A simple fix would be to remove the test files cached after each run. I wouldn’t consider this hacky.

For my own quick workaround, I’m just calling delete require.cache[testFileName] before addFile(testFileName).

Hello.

The solution from @traviswimer is not working. My mocha tests are running only once. I can not debug it. I dont now solution.

Deleting the require.cache did not work for me. Spawning a child process did. For my use case, here was the before and after: BEOFRE:

const testFile = (filename, reporter) => {
    if (filename.includes('.test.js')) {
        const output = [];
        const mocha = new Mocha({ reporter: reporter });
        delete require.cache[filename]
        mocha.addFile(filename);

        return new Promise((resolve, reject) => {
            mocha.run(failures => {
                resolve(failures);
            })
        })
    }
};

AFTER:

const spawn = require('child-process-promise').spawn;

const testFile = (filename, reporter) => {
    if (filename.includes('.test.js')) {
        const output = [];
        const promise = spawn('mocha', ['-R', reporter, filename], {stdio: "inherit"})

        return new Promise((resolve, reject) => {
            promise
                .then(() => resolve(0))
                .catch((err) => {resolve(1) })
        })
    }
};