3

I am learning sinon currently. My codes:

const bluebird = require('bluebird');
const sinon = require('sinon');
const sinonTest = require('sinon-test')(sinon);

sinon.test = sinonTest;

describe('xxx', function _test() {
  this.timeout(2000);
  it('should', sinon.test(function() {
    return new bluebird.Promise( (resolve, reject) => {
      try {
        console.log('123');
        resolve();
      } catch ( err ) {
        reject(err);
      };      
    })
    .then( () => console.log('456') )
    .delay(100)
    .then( () => console.log('789') )
    .then(function() {
    })
  }));
});

output:

xxx
    123
    456

Why the above code times out and stuck in delay? Thanks

UPDATE

const bluebird = require('bluebird');
const sinon = require('sinon');
const sinonTest = require('sinon-test')(sinon);

sinon.test = sinonTest;

describe('xxx', function _test() {
  this.timeout(2000);
  it('should', sinon.test(function() {
    return bluebird
    .delay(100)
    .then( () => console.log('789') );
  }));
});

Output:

 Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves

UPDATE

Thanks @Louis. Setting useFakeTimers works fine.

But I am just confused. Why in my project, there are no problems with the existing tests where useFakeTimers set to true by default? If useFakeTimers set true, promise delay cannot be used in sinonTest()?

By the way, I had this problem when upgrading sinon from 1.17.6 to 2.4.1. Thanks

BAE
  • 8,550
  • 22
  • 88
  • 171

1 Answers1

1

By default the sandboxes that Sinon creates have their configuration set so that the sandbox configuration option useFakeTimers is true. (Search for defaultConfig in this documentation page.)

This means that while the sandbox is in effect, the clock appears to be stopped, and Bluebird's delay never resolves. You tell sinon-test to create sandboxes without fake timers by passing a 2nd parameter when you configure it. This 2nd parameter is actually a configuration object for Sinon sandboxes:

const sinonTest = require('sinon-test')(sinon,
                                        { useFakeTimers: false });

I have not tried it, but from eyeballing the code, it looks like you could use multiple configurations at the same time if you need some tests to use fake timers and some to not use fake timers:

const sinonTest = require('sinon-test');
const wrapper = sinonTest(sinon, { useFakeTimers: false });
const wrapperWithTimers = sinonTest(sinon);

You just need to use the right wrapper for the needs of the test.


You added the question:

But I am just confused. Why in my project, there are no problems with the existing tests where useFakeTimers set to true by default? If useFakeTimers set true, promise delay cannot be used in sinonTest()?

By default useFakeTimers is true, but that won't cause a problem unless you have code that depends on the clock moving forward to work properly. I have many test suites where I use sandboxes and where I did not take care to turn off the fake timers and they work fine. Fake timers do not generally prevent asynchronous functions from running. If you do fs.readFile while the sandbox is in effect, for instance, it should work just fine. It just affects functions that depend on the clock, like setTimeout, setInterval and Date.

Bluebird's delay method is affected because it calls setTimeout.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • if `{ useFakeTimers: false }` set, `delay` will not work? – BAE Aug 23 '17 at 20:55
  • I take the code in your question, plop it in a new file, edit to add the 2nd parameter `{ useFakeTimers: false }`, install the required packages and run Mocha and it work. I get all the `console.log` outputs and there is no time out. It worked when I did it before writing my answer and it works now. You must be doing something wrong. – Louis Aug 23 '17 at 21:00
  • yes. it is working now. You solved several questions of mine. Thanks. But I am just confused. Why in my project, there are no problems with the existing tests where `useFakeTimers` not set? – BAE Aug 23 '17 at 21:01
  • @BAE I had answered your last question in comments but I removed the comments and edited my answer to add the information there. – Louis Aug 23 '17 at 23:41
  • so, `delay` cannot be used inside `it()`, but can be used insize `before()` and `after()`? I used a lots of `delay` in my previous tests where `useFakeTimers` set to true. – BAE Aug 24 '17 at 00:09
  • It seems that I only used `delay` in `after` and `before`. not sure – BAE Aug 24 '17 at 00:16
  • @BAE The code that runs in the `before/beforeEach` hooks runs before the sandbox that is established by your call to `sinon.test` and the code that runs in the `after/afterEach` hooks runs after the sandbox is destroyed. So it is not affected by the sandbox you create for the test. – Louis Aug 24 '17 at 10:40
  • so, `useFakeTimers` only affect `it()`, not `before()`? – BAE Aug 24 '17 at 13:15