3

In my code, I have:

function handleMessage() {
  const twilio = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
  let recordings = twilio.recordings(foundConference.RecordingSid);
  console.log('recordings', recordings);
  return recordings.remove();
}

And in my stub, I have:

const sinon = require('sinon');
const twilio = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);

exports.twilioRecordings = () => {
  console.log('about to stub', twilio.recordings);
  sinon.stub(twilio, 'recordings').returns('here');
  console.log('finished stub', twilio.recordings);

  return;
};

However, it doesn't actually create a stubbed function. It's still using the original recordings function. What am I doing wrong?

Shamoon
  • 41,293
  • 91
  • 306
  • 570

1 Answers1

6

Twilio npm package returns a function which creates a new object on every call, it's not a singleton. So your stubbed twilio instance is scoped to the test only.

Also twilio.recordings (as all other properties though) is defined through the getter function in prototype, so they are read only:

Object.defineProperty(Twilio.prototype,
  'recordings', {
  get: function() {
    return this.api.account.recordings;
  }
});

So, stubbing actual twilio instance have no effect. Except if you change the instance's prototype, but I don't think it worth doing for just unit testing.

I'd suggest you to refactor your code to put twilio initialization into separate method:

function getTwilio() {
   return require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
}

Next your hangleMessage will look like:

function handleMessage() {
  const twilio = this.getTwilio();
  const recordings = twilio.recordings(...);
  ...
}

And next, in your test you can stub getTwilio() to return stub:

const twilioStub = {
    recordings: sinon.stub(),
    remove: sinon.stub()
}
sinon.stub(myAwesomeModule, 'getTwilio').returns(twilioStub);

You also can consider using mock-require package:

const sinon = require('sinon');
const mock = require('mock-require');
mock('twilio', () => ({
  recordings: sinon.stub(),
}));

Here is a question about how-to mock dependencies, there might be other helpful libraries to stub required module.

Hope it helps.

Alejandro
  • 5,834
  • 1
  • 19
  • 36