Search code examples
node.jsunit-testingsinonrewire

How to mockup a constant defined in another file using sinon and rewire?


I'm a beginner with JS tests and I'm having issues when I try to mockup the value of a constant in the file I need to test.

I have the following file

// index.js
const { MultiAccounts } = require('../../some.js')

const MultiAccountInstance = new MultiAccounts();
...

const syncEvents = () => Promise.try(() => {
    // ...
    return MultiAccountInstance.all()
       .then((accounts) => // ...); // ==> it throws the exception here Cannot read property 'then' of undefined
});

module.exports = syncEvents;

So, I will like to mockup the MultiAccountInstance constant. I had been trying using Simon and rewire, but with the following script I'm having it throws the exception here Cannot read property 'then' of undefined exception in the script above.

//index.test.js
const rewire = require('rewire');
const indexRewired = rewire('.../../index/js');

describe('testing sync events', () => {
    let fakeMultiAccountInstance, MultiAccountInstanceReverter;
    let accounts;

    beforeEach(() => {
        accounts = [{id: 1}, {id: 2}];
        fakeMultiAccountInstance = {};
        fakeMultiAccountInstance.all = () => Promise.resolve(accounts);

        MultiAccountInstanceReverter = indexRewired.__set__('MultiAccountInstance', fakeMultiAccountInstance);
    });

    afterEach(() => {
        MultiAccountInstanceReverter();
    });

    it('testing', ()=> {
        const spy = sinon.stub(fakeMultiAccountInstance, 'all');
        return indexRewired().then((resp) => {
            spy.restore();
            expect(spy).to.have.been.calledWith({someParams: true});
        });
    })
});

How can I achieve this?. I also tried using stubs, but I'm having the error that the MultiAccountInstance.all is not a function

it's something like this

//index.test.js
const rewire = require('rewire');
const indexRewired = rewire('.../../index/js');

describe('testing sync events', () => {
    let stubMultiAccountInstance, MultiAccountInstanceReverter;
    let accounts;

    beforeEach(() => {
        accounts = [{id: 1}, {id: 2}];

        stubMultiAccountInstance= sinon.stub().returns({
          all: () => Promise.resolve(accounts), // also tried with sinon.stub().resolves(accounts)
        });

        MultiAccountInstanceReverter = indexRewired.__set__('MultiAccountInstance', stubMultiAccountInstance);
    });

    afterEach(() => {
        stubMultiAccountInstance.reset();
        MultiAccountInstanceReverter();
    });

    it('testing', ()=> {
        return indexRewired().then((resp) => {
            expect(stubMultiAccountInstance).to.have.been.calledWith({someParams: true});
        });
    })
});

Do you know what am I doing wrong?


Solution

  • Here is the unit test solution:

    index.js:

    const { MultiAccounts } = require('./some.js');
    const Promise = require('bluebird');
    
    let MultiAccountInstance = new MultiAccounts();
    
    const syncEvents = () =>
      Promise.try(() => {
        return MultiAccountInstance.all().then((accounts) => console.log(accounts));
      });
    
    module.exports = syncEvents;
    

    some.js:

    function MultiAccounts() {
      async function all() {}
    
      return {
        all,
      };
    }
    
    module.exports = { MultiAccounts };
    

    index.test.js:

    const sinon = require('sinon');
    const rewire = require('rewire');
    const Promise = require('bluebird');
    
    describe('61659908', () => {
      afterEach(() => {
        sinon.restore();
      });
      it('should pass', async () => {
        const promiseTrySpy = sinon.spy(Promise, 'try');
        const logSpy = sinon.spy(console, 'log');
        const indexRewired = rewire('./');
        const accounts = [{ id: 1 }, { id: 2 }];
        const fakeMultiAccountInstance = {
          all: sinon.stub().resolves(accounts),
        };
        indexRewired.__set__('MultiAccountInstance', fakeMultiAccountInstance);
        await indexRewired();
        sinon.assert.calledOnce(fakeMultiAccountInstance.all);
        sinon.assert.calledWith(logSpy, [{ id: 1 }, { id: 2 }]);
        sinon.assert.calledOnce(promiseTrySpy);
      });
    });
    

    unit test results with coverage report:

      61659908
    [ { id: 1 }, { id: 2 } ]
        ✓ should pass (54ms)
    
    
      1 passing (62ms)
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |     100 |      100 |      80 |     100 |                   
     index.js |     100 |      100 |     100 |     100 |                   
     some.js  |     100 |      100 |      50 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------