How do I use Gently to stub a method of an object that is not immediately exposed by a module?

Problem

I'm using the AWS SDK for NodeJS.

I've got a module (moduleFoo) set up like this:

if (global.GENTLY) { require = GENTLY.hijack(require); }

var aws = require("aws-sdk"),
    ec2;

exports.initEC2Client = function () {
    ec2 = new aws.EC2();
};

exports.doSomething = function () {
    var params;

    // params gets populated here...

    ec2.Client.describeInstances(params, function (err, data) {
        // logic!
    }
}

I'm trying to stub out the describeInstances method.

I know I can stub the EC2 class by doing:

gently.stub("aws-sdk", "EC2");

and I can create a fake instance of that by stubbing its constructor, as per the Gently docs:

var ec2Stub = gently.stub("aws-sdk", "EC2"),
    ec2;

gently.expect(ec2Stub, "new", function () {
    ec2 = this;
});

moduleFoo.initEC2Client();

At this point I get stuck. What I need to do is to stub out a method of an object belonging to ec2. Is there a way to approach this using Gently?

Problem courtesy of: Andrey

Solution

I discovered the answer after having typed out the entire question, just before pressing submit.

I solved it by initialising Client as an empty object and then stubbing the describeInstances method on it:

var ec2Stub = gently.stub("aws-sdk", "EC2"),
    ec2;

gently.expect(ec2Stub, "new", function () {
    ec2 = this;
});

moduleFoo.initEC2Client();

ec2.Client = {};

gently.expect(ec2.Client, "describeInstances", function (params, callback) {
    // assert `params` is populated ok
    callback();
})

moduleFoo.doSomething();

gently.verify(); // throws no error
Solution courtesy of: Andrey

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.