Bubble Trouble Bubble Trouble - 1 year ago 41
Node.js Question

How to write sinon tests where third part api's are concerned

I am attempting to test geocode.js which has only one function :

// geocode.js

const googleApiClient = require('@google/maps').createClient({
key: CONFIG.googleApis.key
});

const poll = zipcode => {

return new Promise((resolve, reject) => {

googleApiClient.geocode({
address: zipcode
}, function(err, response) {
resolve(response.json.results); // This is line 22
});

});

};

module.exports = {poll}


so i have setup my mocha environment and installed sinon. I can't figure out how to stub the googleApiClient functionality.

I don't actually want to make any kind of external call during the test.

//geocode.spec.js
describe('geocode', function(){
before(function(){

//HOW DO I STUB googleApiClient ?
sinon.stub ...

})

});

Answer Source

It's a bit of a PITA, because createClient returns a plain object each time, and not a class that you can stub.

Nonetheless, I came up with this:

const chai   = require('chai');
const expect = chai.expect;
const sinon  = require('sinon');

// This allows us to `expect` on Sinon properties.
chai.use(require('sinon-chai'));

// Load the Google Maps module.
const googleMaps = require('@google/maps');

// Create a dummy client.
const googleApiClient = googleMaps.createClient({ key : 'foo' });

// Stub `googleMaps.createClient` so it always returns the dummy client.
let createClientStub = sinon.stub(googleMaps, 'createClient').returns(googleApiClient);

// Load the code to be tested. This has to be done _after_ stubbing `createClient`.
const poll = require('./geocode.js').poll;

// The test.
describe('geocode', function(){
  let stub;

  // For each test, stub the `geocode` function.
  beforeEach(function() {
    stub = sinon.stub(googleApiClient, 'geocode');
  });

  // After each test, restore it to its original.
  afterEach(function() {
    stub.restore();
  });

  it('should call `googleApiClient.geocode` with the correct zipcode', function() {
    // This means that `googleApiClient.geocode()` will call the first function
    // argument that it gets passed, which is the callback function that
    // resolves the promise.
    stub.yields();

    // Now we call the function under test, pass it a zipcode, and check if 
    // googleApiClient.geocode() got called with the correct argument.
    const ZIPCODE = '90210';
    return poll(ZIPCODE).then(zipcode => {
      expect(stub).to.be.calledWith({ address: ZIPCODE });
    });
  });

});
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download