Sinon: Stub and spy does not work on public module functions if one calls another

Created on 9 Feb 2018  路  5Comments  路  Source: sinonjs/sinon

Hello.

I met some strange sinon behaviour with stubs and spies.
I will try to present you my test case.

For example I have a simple module (my-module.js) with two public functions.
It is important. Function foo calls another public function bar.

module.exports = {foo, bar};

function foo() {
    console.log('foo');
    return bar();
}

function bar() {
    console.log('bar');
}

Alson I have a simple unit test for this module. I want to test that bar was called on foo call.

const sinon = require('sinon');
const chai = require('chai');
const myModule = require('./my-module');

chai.use(require('sinon-chai'));

const expect = chai.expect;

describe('test', () => {
    const sandbox = sinon.createSandbox();

    afterEach(() => sandbox.restore());

    it('simple test', () => {
        sandbox.stub(myModule, 'bar');

        myModule.foo();

        expect(myModule.bar).to.be.calledOnce;
    });
});
  • Sinon version : 4.2.2
  • Environment : NodeJS v9.3.0
  • Example URL :
  • Other libraries you are using: mocha, chai (expect), sinon-chai, chai-as-promised

What did you expect to happen?

In my opinion this test should be passed

What actually happens

Test fails on assertion. bar - is true sinon stub but it was not called any time.

How to reproduce

Make simple project with given files and run test



Really long code sample or stacktrace
AssertionError: expected bar to have been called exactly once, but it was called 0 times

Most helpful comment

This is not so strange. JS ES6 Syntax in your export is fooling you. By stubbing the bar export you overwrite the exported symbol, but not the internal function reference which is bound by a closure in foo. Sinon can't do this. You would need DI or proxyquire to accomplish this.

All 5 comments

This is not so strange. JS ES6 Syntax in your export is fooling you. By stubbing the bar export you overwrite the exported symbol, but not the internal function reference which is bound by a closure in foo. Sinon can't do this. You would need DI or proxyquire to accomplish this.

Had the same problem, the solution is to avoid using function and export const instead.
Like so:

export const myFunc = () => {}
// Or with old CommonJS syntax
exports.myFunc = () => {}

The difference is that when you define function myFunc () {} it becomes encapsulated inside of module function (that wraps the module internally when using Node or after build using WebPack). But when you do export const myFunc = then you just add a property to a module object, which can be mocked.

Also when you do export function myFunc ... it will possibly lead to same problem if you are using Babel/TypeScript, because it will still be compiled to same function myFunc ...; export myFunc

Man, this is frustratingly subtle behavior when working with Typescript. I just ran across this, and it adds to the list of constant reminders that transpilation is perhaps, a bit too magical!

How can I export each public method with export const? if this is the case in typescript

We are trying to keep the GitHub issues list tidy and focused on bugs and feature discussions. The last question is a usage question; please post it to StackOverflow and tag it with sinon, so the bigger community can help answer your questions.

Was this page helpful?
0 / 5 - 0 ratings