Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot run Mocha.js in synchronous mode

I am testing stored procedures with mocha running in a nodejs instance. I have this test skeleton:

var chai              = require('chai'),
    MyReporter        = require("../MyReporter.js"),
    chokidar          = require('chokidar'),
    expect            = chai.expect,
    should            = chai.should,
    assert            = chai.assert;

var Mocha = require('mocha');
amochai = new Mocha({
   bail: false, 
   debug: true
});

amochai.addFile("mytest_v1.js");

function runMocha(callback) {
    amochai.run(function () {
    callback();
  });
}

watcher.on('change', function(path, stats) {
      runMocha(function () {});
}

Problem: My tests are always run in an asynchronous mode, although all my tests are written like this:

describe('Mysql stored procedures', function(){ 
   describe('Add this data', function(){
      it('-- Should return this information', function(){ 
         // asserts
      });
   });
});

There is no done() callback, I mean nowhere, so, as it is mentioned everywhere that mocha.js is synchronous by default, what could be the reason why my code is running in a asynchronous mode ?

PATCH

To patch my problem, I had to use before() and check my tests state, but this becomes a nightmare to maintain.

like image 851
Alain Avatar asked Dec 16 '22 03:12

Alain


1 Answers

You are running operations that are asynchronous in your synchronous mocha tests.

Saying a Mocha test is "synchronous" is ambiguous. It could mean:

  • The operation tested by the test happens synchronously.
  • Mocha handles the test in a synchronous way.

The two are not equivalent. One does not entail the other. By default Mocha handles all tests synchronously. We can make it handle a test asynchronously but adding a parameter to the callback we pass to it (or its equivalent in other test interfaces). (Later versions of Mocha eventually added another way to make Mocha handle a test asynchronously: return a promise. But I'm going to use callbacks for the following examples.) So we can have 4 combinations of synchronicity:

  • Operation synchronous, Mocha test synchronous.

    it("reads foo", function () {
        fs.readFileSync("foo");
        // ssert what we want to assert.
    });
    

    No problem.

  • Operation synchronous, Mocha test asynchronous.

    it("reads foo", function (done) {
        fs.readFileSync("foo");
        // Assert what we want to assert.
        done();
    });
    

    It is pointless to have the Mocha test be asynchronous, but no problem.

  • Operation asynchronous, Mocha test asynchronous.

    it("reads foo", function (done) {
        fs.readFile("foo", function () {
            // Assert what we want to assert.
            done();
        });
    });
    

    No problem.

  • Operation asynchronous, Mocha test synchronous.

    it("reads foo", function () {
        fs.readFile("foo", function () {
            // Assert what we want to assert.
        });
    });
    

    This is a problem. Mocha will return right away from the test callback and call it successful (assuming fs.readFile does not raise an exeption). The asynchronous operation will still be scheduled and the call back may still be called later. One important point here: Mocha does not have the power to make the operations it tests synchronous. So making the Mocha test synchronous has no effect on the operations in the test. If they are asynchronous, they will remain asynchronous, no matter what we tell Mocha.

This last case, in your system would cause the execution of the stored procedures to be queued with the DB system. If this queuing happens without error, Mocha finishes right away. Then if there is a file change, your watcher launches another Mocha run and more operations are queued, etc.

like image 156
Louis Avatar answered Jan 02 '23 13:01

Louis