6

I have a section of code that is using node-sync like so:

function funcA() {
  return new Promise(function(resolve, reject) {
    Sync(function () {
      return funcB.sync();
    }, function (err, result) {
      if(err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
}

This code is tested using mocha+chai:

it("should return array", function() {
  return funcA().then(function(result) {
    expect(result).to.be.an.instanceof(Array);
  });
});

It worked just fine couple of months ago, but now this test always times out:

Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

What I've tried so far:

  • using done() instead of returning a promise
  • replacing node-sync with synchronize.js
  • increasing timeout

What I found out, is that expect(... part of this test is, in fact, being called, but only after mocha kills the test. No matter what timeout interval is currently set, expect(.. is being called always ~20 milliseconds after I get Error: timeout message.

I fixed the issue by adding setInterval(function(){}, 10) on the top of the test file. I'd like to know why this worked and if there is some better way to fix that?

[EDIT] It looks like this is a node-version specific issue. Test fails on 0.12.4 but runs correctly on 0.10.38 .

[EDIT] Actual code is available here.

2
  • 1
    Seems very odd.. i can reproduce it but can't figure out what the issue is. might be a long shot but maybe dig into node-sync , see these github tickets here and here Commented Jun 10, 2015 at 0:46
  • btw it's typically best practice (imho) to not run code asynchronously in a test. I know you're attempting to run this block sync, but maybe try the chai-as-promised module so you can remove the done Commented Jun 10, 2015 at 0:47

3 Answers 3

2
+50

Based on your code, I am assuming that your funcB function is running code in a synchronous way.

So when I create funcB in this way:

function funcB() {
  return [1, 2, 3];
}

And run the test, Mocha shows an error:

Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

But if I convert the funcB in asynchronus function as this:

function funcB(cb) {
  process.nextTick(function () {
    cb(null, [1, 2, 3]);
  });
}

Mocha runs the test without any problem:

✓ should return an array


So my complete code that runs ok (the funcB commented is the one that will cause the error) is this:

// install dependencies
// npm install promise
// npm install sync
var Promise = require('promise');
var assert = require('assert');
var Sync = require('sync');

function funcA() {
  return new Promise(function (resolve, reject) {
    Sync(function () {
      return funcB.sync();
    }, function (err, result) {
      if (err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
  });
}

// function funcB() {
//   return [1, 2, 3];
// }

function funcB(cb) {
  process.nextTick(function () {
    cb(null, [1, 2, 3]);
  });
}

it("should return an array", function(done) {
  return funcA().then(
    function (result) {
      console.log(result);
      assert.equal(Array.isArray(result), true);
      done();
    }
  );
});

So I am opinion I think that the misuse of the sync method (using it on synchronous functions) created by sync library is the one that is causing this problem.

Sign up to request clarification or add additional context in comments.

2 Comments

Hey Wilson! Thank you for this, but it is still a hack and it doesn't answer why this happens. I'm guessing that my use of setInterval serves exact same purpose as your nextTick hack. It seems that node goes "asleep" and needs to be woken up by nextTick or setInterval. The question is, why this happens and if that's a node issue, Sync issue or an expected behaviour? I'd love to get to the bottom of this.
Maybe I am wrong but reasoning from the doc of the method that says: "sync() method simply turns any asynchronous function to synchronous one" so calling this method from a sync function like funcB, to me could be potentially the source of the bug.
1

You may just be missing the done() callback:

it("should return array", function(done) {
    funcA().then(function(result) {
        expect(result).to.be.an.instanceof(Array);
        done();
    });
});

http://mochajs.org/#asynchronous-code

1 Comment

Hey, thanks for suggestion - as mentioned in question I already tried done(). Also, returning a promise should work just fine (in fact you linked to the very section in mocha docs where this is described). My issue seems to be node-version related.
1

You can use a timeout parameter for mocha executable.

For example, if you want a 500 milliseconds timeout, just change your package.json to:

"scripts": {
    "test": "mocha specs --timeout 500 --require specs/helpers/chai.js"
},

And maybe your promise is being rejected, so you have to call done using catch method.

it("should return array", function(done) {
    return funcA().then(function(result) {
        expect(result).to.be.an.instanceof(Array);
        done();
    }).catch(done);
});

This would also help you debug eventual errors that might happen in your promise code.

3 Comments

Hey! As mentioned in the question, I've tried increasing timeout - the test fails always right after the timeout (no matter what the timeout value is). Having catch is a good tip, but this test doesn't fail, it times out.
@KonradDzwinel Hmm.. It seems you're trying to test a code with promises that does everything in the same process. Try changing setTimeout() to process.nextTick(); and check if it still works. Also, can you send the code of the method you're trying to test?
Hey! Whole thing is available here. Tests pass on node 0.10 but fail on 0.12. I will try changing setInterval to nextTick later on. My guess is that it will work - the question is why I have to trigger next tick manually in node 0.12?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.