2

I'm still very much learning node, js, sinon, proxyquire, etc.

I have a module that uses the google-geocode module (https://github.com/bigmountainideas/google-geocoder) and I am struggling to write a test to stub it.

This all boils down I think to how you set it up. In time.js I do as follows as per google-geocoder documentation:

var geocoder = require('google-geocoder');

  ...

module.exports = function(args, callback) {
  var geo = geocoder({ key: some-thing });
  geo.find('new york', function(err, response) { ... });
}

I'm trying to test as follows but I get the error:

  TypeError: geo.find is not a function
   at run (cmdsUser/time.js:x:x)
   at Context.<anonymous> (tests/cmdsUser/time-test.js:x:x)

time-test.js:

var time;
var findStub;

before(function () {
  findStub = sinon.stub()
  time = proxyquire('./../../cmdsUser/time',{ 'google-geocoder': { find: findStub } } );
});

describe('Demo test', function() {
  it('Test 1', function(done){
    findStub.withArgs('gobbledegook').yields(null, { this-is: { an-example: 'invalid' } });

    time(['gobbledegook'], function(err, response) {
      expect(response).to.equals('No result for gobbledegook');
      done();
    });
  });
});

I am a little confused. Many thanks.

s27840
  • 367
  • 1
  • 5
  • 14

1 Answers1

0

google-geocode's exports seem to be formatted as:

{
    function() {
        [...]
        // Will return an instance of GeoCoder
    }
    GeoCoder: {
        [...]
        __proto__: {
            find: function() {
                // Replace me!
            }
        }
    },
    GeoPlace: [...]
}

proxyquire seems to replace the function that returns the instance even when wrapping find in an object with the key "GeoCoder" which brings you closer to the solution by actually assigning a method find to the correct object. I made a test project to try to learn the best way to overcome this and I felt kinda stuck. But since you were callThru'ing before, you might as well do proxyquire's dirty work then pass the stubbed version of the dependency instead.

before(function() {
    // Stub, as you were before
    findStub = sinon.stub()
    // Require the module yourself to stub
    stubbedDep = require('google-geocoder')
    // Override the method with the extact code used in the source
    stubbedDep.GeoCoder.prototype.find = findStub
    // Pass the stubbed version into proxyquire
    test = proxyquire('./test.js', { 'google-geocoder': stubbedDep });
});

I really hope there's a better way to do what you'd like. I believe class' constructors act in a similar manner and that makes me think others have a similar issue (see issues below). You should probably join that conversation or another on that repo and post an answer back here for others if this is still an active project of yours over a half a year later with no response.

Issues: #136, #144, #178

evelynhathaway
  • 1,670
  • 14
  • 18