Смыкая функцию электронной почты в nodejs

У меня есть функция почтовой программы, которую я создал, и пытаюсь укрепить покрытие. Попытка протестировать его части оказалась сложной, особенно эта mailer.smtpTransport.sendMail

var nodemailer = require('nodemailer')

var mailer = {}

mailer.smtpTransport = nodemailer.createTransport('SMTP', {
    'service': 'Gmail',
    'auth': {
        'XOAuth2': {
            'user': '[email protected]',
            'clientId': 'googleClientID',
            'clientSecret': 'superSekrit',
            'refreshToken': '1/refreshYoSelf'
        }
    }
})
var mailOptions = {
    from: 'Some Admin <[email protected]>',
}

mailer.verify = function(email, hash) {
    var emailhtml = 'Welcome to TestCo. <a href="'+hash+'">Click this '+hash+'</a>'
    var emailtxt = 'Welcome to TestCo. This  is your hash: '+hash
    mailOptions.to = email
    mailOptions.subject = 'Welcome to TestCo!'
    mailOptions.html = emailhtml
    mailOptions.text = emailtxt
    mailer.smtpTransport.sendMail(mailOptions, function(error, response){
        if(error) {
            console.log(error)

        } else {
            console.log('Message sent: '+response.message)
        }
    })
}

Я не уверен, как пройти тестирование, в частности, чтобы моя функция mailer.smtpTransport.sendMail передавала правильные параметры без фактической отправки электронной почты. Я пытаюсь использовать https://github.com/whatser/mock-nodemailer/tree/master, но я, вероятно, ошибаюсь. Должен ли я издеваться над методом?

var _ = require('lodash')
var should = require('should')
var nodemailer = require('nodemailer')
var mockMailer = require('./helpers/mock-nodemailer')
var transport = nodemailer.createTransport('SMTP', '')

var mailer = require('../../../server/lib/account/mailer')

describe('Mailer', function() {
    describe('.verify()', function() {
        it('sends a verify email with a hashto an address when invoked', function(done) {
            var email ={
                'to': '[email protected]',
                'html': 'Welcome to Testco. <a href="bleh">Click this bleh</a>',
                'text': 'Welcome to Testco. This  is your hash: bleh',
                'subject': 'Welcome to Testco!'
            }

            mockMailer.expectEmail(function(sentEmail) {
            return _.isEqual(email, sentEmail)
            }, done)
            mailer.verify('[email protected]','bleh')
            transport.sendMail(email, function() {})
    })
})

Ответы

Ответ 1

Вы можете использовать транспортный уровень "Stub" в вашем тесте вместо SMTP.

var stubMailer = require("nodemailer").createTransport("Stub"),
    options = {
        from: "[email protected]",
        to: "[email protected]m",
        text: "My Message!"
    };

   stubMailer.sendMail(options, function(err, response){
     var message = response.message;
   })

Итак, в этом случае "message" будет электронным письмом в текстовом формате. Что-то вроде этого:

MIME-Version: 1.0
X-Mailer: Nodemailer (0.3.43; +http://www.nodemailer.com/)
Date: Fri, 25 Feb 2014 11:11:48 GMT
Message-Id: <[email protected]>
From: [email protected]
To: [email protected]
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

My Message!

Дополнительные примеры см. в наборе тестов nodemailer: https://github.com/andris9/Nodemailer/blob/master/test/nodemailer-test.js

Ответ 2

expectEmail просто подключается к транспортному уровню и ожидает, что вы будете идентифицировать электронную почту (верните true, если это письмо, которое вы ожидаете), просмотрев содержимое sentEmail.

В этом случае return sentEmail.to === '[email protected]' должно быть достаточно.

Имейте в виду, однако, этот модуль был разработан в среде, где тесты выполняются в произвольном порядке и одновременно. Вы должны рандомизировать ваши данные в значительной степени, чтобы предотвратить столкновения и ложные срабатывания. Кстати, мы используем что-то вроде: var to = Date.now().toString(36) + Faker.Internet.email();

Ответ 3

Этот пример хорошо работает для меня

======== myfile.js ========

// SOME CODE HERE

transporter.sendMail(mailOptions, (err, info) => {
  // PROCESS RESULT HERE
});

======== myfile.spec.js (файл модульного теста) ========

const sinon = require('sinon');
const nodemailer = require('nodemailer');
const sandbox = sinon.sandbox.create();

describe('XXX', () => {
  afterEach(function() {
    sandbox.restore();
  });

  it('XXX', done => {
    const transport = {
      sendMail: (data, callback) => {
        const err = new Error('some error');
        callback(err, null);
      }
    };
    sandbox.stub(nodemailer, 'createTransport').returns(transport);

    // CALL FUNCTION TO TEST

    // EXPECT RESULT
  });
});

Ответ 4

Вы можете напрямую высмеять функцию sendMail, но не ясно, как получить к ней доступ из тестов. Экземпляр Mailer возвращается при создании транспорта, поэтому вам нужно напрямую импортировать этот класс в свой тест.

const Mailer = require('nodemailer/lib/mailer')

Затем вы можете высмеять или заглушить метод sendMail на прототипе обычным способом. Используя Жасмин, вы можете сделать это следующим образом:

beforeEach(function () {
  spyOn(Mailer.prototype, 'sendMail').and.callFake(function (mailOptions, cb) {
    cb(null, true)
  })
})

CallFake гарантирует, что обратный вызов sendMail все еще выполняется, чтобы вам нужно было проверить, что произойдет дальше. Вы можете легко имитировать ошибку, передав первый аргумент в cb: cb(new Error('Email failed'))

Теперь, когда макет настроен, вы можете проверить, что все работает по назначению:

expect(Mailer.prototype.sendMail).toHaveBeenCalled()