/* eslint-disable global-require */ import request from 'request'; import nconf from 'nconf'; import nodemailer from 'nodemailer'; import Bluebird from 'bluebird'; import requireAgain from 'require-again'; import logger from '../../../../../website/server/libs/api-v3/logger'; import { TAVERN_ID } from '../../../../../website/server/models/group'; function defer () { let resolve; let reject; let promise = new Bluebird((resolveParam, rejectParam) => { resolve = resolveParam; reject = rejectParam; }); return { resolve, reject, promise, }; } function getUser () { return { _id: 'random _id', auth: { local: { username: 'username', email: 'email@email', }, facebook: { emails: [{ value: 'email@facebook', }], displayName: 'fb display name', }, }, profile: { name: 'profile name', }, preferences: { emailNotifications: { unsubscribeFromAll: false, }, }, }; } describe('emails', () => { let pathToEmailLib = '../../../../../website/server/libs/api-v3/email'; describe('sendEmail', () => { it('can send an email using the default transport', () => { let sendMailSpy = sandbox.stub().returns(defer().promise); sandbox.stub(nodemailer, 'createTransport').returns({ sendMail: sendMailSpy, }); let attachEmail = requireAgain(pathToEmailLib); attachEmail.send(); expect(sendMailSpy).to.be.calledOnce; }); it('logs errors', (done) => { let deferred = defer(); let sendMailSpy = sandbox.stub().returns(deferred.promise); sandbox.stub(nodemailer, 'createTransport').returns({ sendMail: sendMailSpy, }); sandbox.stub(logger, 'error'); let attachEmail = requireAgain(pathToEmailLib); attachEmail.send(); expect(sendMailSpy).to.be.calledOnce; deferred.reject(); // wait for unhandledRejection event to fire setTimeout(() => { expect(logger.error).to.be.calledOnce; done(); }, 20); }); }); describe('getUserInfo', () => { it('returns an empty object if no field request', () => { let attachEmail = requireAgain(pathToEmailLib); let getUserInfo = attachEmail.getUserInfo; expect(getUserInfo({}, [])).to.be.empty; }); it('returns correct user data', () => { let attachEmail = requireAgain(pathToEmailLib); let getUserInfo = attachEmail.getUserInfo; let user = getUser(); let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); expect(data).to.have.property('name', user.profile.name); expect(data).to.have.property('email', user.auth.local.email); expect(data).to.have.property('_id', user._id); expect(data).to.have.property('canSend', true); }); it('returns correct user data [facebook users]', () => { let attachEmail = requireAgain(pathToEmailLib); let getUserInfo = attachEmail.getUserInfo; let user = getUser(); delete user.profile.name; delete user.auth.local; let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); expect(data).to.have.property('name', user.auth.facebook.displayName); expect(data).to.have.property('email', user.auth.facebook.emails[0].value); expect(data).to.have.property('_id', user._id); expect(data).to.have.property('canSend', true); }); it('has fallbacks for missing data', () => { let attachEmail = requireAgain(pathToEmailLib); let getUserInfo = attachEmail.getUserInfo; let user = getUser(); delete user.profile.name; delete user.auth.local.email; delete user.auth.facebook; let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']); expect(data).to.have.property('name', user.auth.local.username); expect(data).not.to.have.property('email'); expect(data).to.have.property('_id', user._id); expect(data).to.have.property('canSend', true); }); }); describe('getGroupUrl', () => { it('returns correct url if group is the tavern', () => { let getGroupUrl = require(pathToEmailLib).getGroupUrl; expect(getGroupUrl({_id: TAVERN_ID, type: 'guild'})).to.eql('/#/options/groups/tavern'); }); it('returns correct url if group is a guild', () => { let getGroupUrl = require(pathToEmailLib).getGroupUrl; expect(getGroupUrl({_id: 'random _id', type: 'guild'})).to.eql('/#/options/groups/guilds/random _id'); }); it('returns correct url if group is a party', () => { let getGroupUrl = require(pathToEmailLib).getGroupUrl; expect(getGroupUrl({_id: 'random _id', type: 'party'})).to.eql('party'); }); }); describe('sendTxnEmail', () => { beforeEach(() => { sandbox.stub(request, 'post'); }); afterEach(() => { sandbox.restore(); }); it('can send a txn email to one recipient', () => { sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); let attachEmail = requireAgain(pathToEmailLib); let sendTxnEmail = attachEmail.sendTxn; let emailType = 'an email type'; let mailingInfo = { name: 'my name', email: 'my@email', }; sendTxnEmail(mailingInfo, emailType); expect(request.post).to.be.calledWith(sinon.match({ json: { data: { emailType: sinon.match.same(emailType), to: sinon.match((value) => { return Array.isArray(value) && value[0].name === mailingInfo.name; }, 'matches mailing info array'), }, }, })); }); it('does not send email if address is missing', () => { sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); let attachEmail = requireAgain(pathToEmailLib); let sendTxnEmail = attachEmail.sendTxn; let emailType = 'an email type'; let mailingInfo = { name: 'my name', // email: 'my@email', }; sendTxnEmail(mailingInfo, emailType); expect(request.post).not.to.be.called; }); it('uses getUserInfo in case of user data', () => { sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); let attachEmail = requireAgain(pathToEmailLib); let sendTxnEmail = attachEmail.sendTxn; let emailType = 'an email type'; let mailingInfo = getUser(); sendTxnEmail(mailingInfo, emailType); expect(request.post).to.be.calledWith(sinon.match({ json: { data: { emailType: sinon.match.same(emailType), to: sinon.match(val => val[0]._id === mailingInfo._id), }, }, })); }); it('sends email with some default variables', () => { sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true); let attachEmail = requireAgain(pathToEmailLib); let sendTxnEmail = attachEmail.sendTxn; let emailType = 'an email type'; let mailingInfo = { name: 'my name', email: 'my@email', }; let variables = [1, 2, 3]; sendTxnEmail(mailingInfo, emailType, variables); expect(request.post).to.be.calledWith(sinon.match({ json: { data: { variables: sinon.match((value) => { return value[0].name === 'BASE_URL'; }, 'matches variables'), personalVariables: sinon.match((value) => { return value[0].rcpt === mailingInfo.email && value[0].vars[0].name === 'RECIPIENT_NAME' && value[0].vars[1].name === 'RECIPIENT_UNSUB_URL'; }, 'matches personal variables'), }, }, })); }); }); });