3

How would I stub the following module with proxyquire and sinon:

var email = require("emailjs").server.connect.send();

I did the following, but its not working, because when I try to trigger an error within send() it still sends the email.

sendMailStub = sinon.stub(email, "send");    
testedModule = proxyquire('../index.js', {
                'email': {
                    'server': {
                        'send': sendMailStub
                        }
                    }
            });

And also tried:

testedModule = proxyquire('../index.js', {
            email: {send: sendMailStub}
        });

This is the full test so far, which fails:

var chai = require('chai');
var sinonChai = require("sinon-chai");
var sinon = require('sinon');
chai.use(sinonChai);
var proxyquire = require('proxyquire');
var testedModule;
var expect = chai.expect;



describe('invoicer', function () {

    var nock = require('nock');

    var ResponseOptions = {
        username: "Peter Pan",
        user_address_line_1: "Never Never Land",
        user_address_line_2: "Tree-house 99",
        user_post_code: "E4 9BY",
        delivery_address_line_1: "Hook's Boat",
        delivery_address_line_2: "Dock 69",
        delivery_post_code: "SE2 4C",
        order_number: "234234234",
        order_date: "20/12/2090",
        dispatch_date: "20/12/2090",
        items: [
            {
                product_name: "Fairy Dust",
                brand: "Airy fairy",
                quantity: 5,
                total: 2000
            },
            {
                product_name: "Pirate Sword",
                brand: "Pirate's Bay",
                quantity: 8,
                total: 2000
            }
        ],
        grand_total: 4000,
        user_email: "peter@flyaway.com"
    }

    var mailOptions = {
        text: "Hello World"
    }

    var scope = nock("http://somewhere.com")
        .get("/orders")
        .reply(200, ResponseOptions);

    var sendStub, readFileStub, url, contextDoneSpy, obj, connectStub;

    before(function () {

        readFileStub = sinon.stub();
        sendStub = sinon.stub().withArgs(mailOptions).callsArgWith(1, null, contextDoneSpy);
        connectStub = sinon.stub().returns({
            send: sendStub
        });

        testedModule = proxyquire('../index', {
            'fs': {readFile: readFileStub},
            'emailjs': {
                'server': {
                    'connect': connectStub
                }
            }
        });

        url = "http://somewhere.com/orders";
        contextDoneSpy = sinon.spy();
        obj = {
            user: 'AKIAJMHSJRRYGKTE4TOQ',
            password: 'Ag3Nkpej8dxZ4DwYz2in/x8kUhN7Lh/BqXImB0+i+DWy',
            host: "email-smtp.eu-west-1.amazonaws.com",
            port: 587,
            tls: true,
            ssl: false
        }

        readFileStub.withArgs('./email.html').callsArgWith(1, null, 'file1');

        connectStub();
    });

    it("readFile and successful context.done were called", function (done) {
        testedModule.Invoicer(url, obj, { done: function () {
            contextDoneSpy.apply(null, arguments);
            expect(readFileStub).has.been.called;
            expect(contextDoneSpy).to.have.been.called;
            done();
        }});

    });
});
hyprstack
  • 4,043
  • 6
  • 46
  • 89

1 Answers1

7

Let's first fix the line where your described emailjs using the its documentation

require("emailjs").server.connect({
  /* Required server options */
}).send(function (err, message) {
  // This a function with a callback node convention signature
});

connect is a function and should receive some parameters, moreover send doesn't return any thing, basically call a callback

Proxyquire requires to use the same module name, so email should be emailjs, on the other hand you're wrong assigning the stub in proxiquire, it should be

connectStub = sinon.stub().returns(sendStub);
sendMailStub = sinon.stub(email, "send");    
testedModule = proxyquire('../index.js', {
            'emailjs': {
                'server': {
                    'connect': connectStub
                }
        });
Ivan Fraixedes
  • 550
  • 3
  • 12
  • when I run the test it returns `TypeError: Object # has no method 'connect'` – hyprstack Apr 29 '15 at 10:21
  • @hyprstack you can also stub `connect` than create a function and return the the object, then you'll be able to check the calls to `connect` – Ivan Fraixedes Apr 29 '15 at 18:44
  • I updated my question with my full test. However I am getting the following error: `1) invoicer "before all" hook: TypeError: Should wrap property of object` – hyprstack Apr 29 '15 at 21:57
  • No really sure, but it seems that the lines of code inside `before` throw an error, you should look for what is wrong inside – Ivan Fraixedes Apr 30 '15 at 09:39
  • Its the line where `sendMailStub = sinon.stub(emailjs, 'send');` The same error happens if I try to stub `connect` – hyprstack Apr 30 '15 at 09:54
  • You may have a clash between require `emailjs` in your test and call proxiquire with `emailjs` after and the same with `fs`; I think that you don't need them in your test so don't require them just stub them in proxiquire – Ivan Fraixedes Apr 30 '15 at 12:55
  • You're right about that. I was stubbing them before `proxyquire`, that's why I was getting that error, instead of having them: `readFileStub = sinon.stub(); sendStub = sinon.stub();` But it is still not stubbing emailjs. I have updated my question with my latest test – hyprstack Apr 30 '15 at 13:54
  • Instead it is returning an error `Error: timeout of 2000ms execeeded` – hyprstack Apr 30 '15 at 14:13
  • I think the problem might be that `connect` is not a function. How would one get around that issue? – hyprstack Apr 30 '15 at 15:33
  • This is the error it returns now: `Uncaught TypeError: Property 'connect' of object # is not a function` – hyprstack Apr 30 '15 at 15:44
  • True. I should actually be `connectStub = sinon.stub().returns({ send: sendStub });` – hyprstack Apr 30 '15 at 19:38