Skip to content

Commit

Permalink
major code rewrite
Browse files Browse the repository at this point in the history
* rewrite using modern ES syntax
* update tests to handle more test cases
* add peerDependencies for nodemailer and express-handlebars
  • Loading branch information
yads committed Mar 6, 2023
1 parent b1ab0fa commit cfc846b
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 145 deletions.
14 changes: 14 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict';

module.exports = {
singleQuote: true,
overrides: [
{
files: '*.hbs',
options: {
singleQuote: false,
parser: 'glimmer',
},
},
],
};
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ npm install nodemailer-express-handlebars
# Usage
```javascript
//reference the plugin
var hbs = require('nodemailer-express-handlebars');
const hbs = require('nodemailer-express-handlebars');
//attach the plugin to the nodemailer transporter
transporter.use('compile', hbs(options));
//send mail with options
var mail = {
const mail = {
from: 'from@domain.com',
to: 'to@domain.com',
subject: 'Test',
Expand All @@ -24,6 +24,20 @@ var mail = {
}
transporter.sendMail(mail);
```

You can send a multipart html and text email by setting the `text_template` option on a mail message.
```javascript
const mail = {
from: 'from@domain.com',
to: 'to@domain.com',
subject: 'Test',
template: 'email',
text_template: 'text',
context: {
name: 'Name'
}
}
```
## Plugin Options
The plugin expects the following options:
* __viewEngine (required)__ either the express-handlebars view engine instance or [options for the view engine](https://github.com/express-handlebars/express-handlebars#configuration-and-defaults)
Expand Down
60 changes: 34 additions & 26 deletions lib/generator.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,47 @@
'use strict';

var path = require('path'),
handlebars = require('express-handlebars');
const path = require('path');
const handlebars = require('express-handlebars');

var TemplateGenerator = function(opts) {
var viewEngine = opts.viewEngine || {};
class TemplateGenerator {
constructor(opts) {
let viewEngine = opts.viewEngine || {};
if (!viewEngine.renderView) {
viewEngine = handlebars.create(viewEngine);
viewEngine = handlebars.create(viewEngine);
}
this.viewEngine = viewEngine;
this.viewPath = opts.viewPath;
this.extName = opts.extName || '.handlebars';
};
}

TemplateGenerator.prototype.render = function render(mail, cb) {
if (mail.data.html) return cb();
async render(mail) {
if (mail.data.html) {
return;
}

let templatePath = path.join(
this.viewPath,
mail.data.template + this.extName
);
let textTemplatePath = '';
if (mail.data.text_template) {
textTemplatePath = path.join(
this.viewPath,
mail.data.text_template + this.extName
);
}

var templatePath = path.join(this.viewPath, mail.data.template + this.extName);
var textTemplatePath='';
if (!!mail.data.text_template) {
textTemplatePath=path.join(this.viewPath, mail.data.text_template + this.extName);
mail.data.html = await this.viewEngine.renderView(
templatePath,
mail.data.context
);
if (mail.data.text_template) {
mail.data.text = await this.viewEngine.renderView(
textTemplatePath,
mail.data.context
);
}
var viewEngine=this.viewEngine;
this.viewEngine.renderView(templatePath, mail.data.context, function(err, body) {
if (err) return cb(err);
mail.data.html = body;
if(!mail.data.text_template)cb();
else{
viewEngine.renderView(textTemplatePath, mail.data.context, function(err, body) {
if (err) return cb(err);
mail.data.text = body;
cb();
});
}
});
};
}
}

module.exports = TemplateGenerator;
21 changes: 13 additions & 8 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
'use strict';
const TemplateGenerator = require('./generator');

var TemplateGenerator = require('./generator');
module.exports = function (options) {
const generator = new TemplateGenerator(options);

module.exports = function(options) {
var generator = new TemplateGenerator(options);
return async (mail, cb) => {
try {
await generator.render(mail);
} catch (err) {
return cb(err);
}

cb();
};
};

return function(mail, cb) {
generator.render(mail, cb);
};
};
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
"url": "https://github.com/yads/nodemailer-express-handlebars"
},
"license": "MIT",
"dependencies": {
"express-handlebars": "^6.0.0"
"peerDependencies": {
"express-handlebars": ">= 6.0.0",
"nodemailer": ">= 6.0.0"
},
"devDependencies": {
"chai": "^4.1.2",
"express-handlebars": "^6.0.0",
"mocha": "^10.0.0",
"nodemailer": "^6.4.6",
"nodemailer-stub-transport": "^1.1.0"
"nodemailer": "^6.4.6"
},
"engines": {
"node": "14.* || 16.* || >= 18"
Expand Down
202 changes: 115 additions & 87 deletions test/tests/index.js
Original file line number Diff line number Diff line change
@@ -1,106 +1,134 @@
'use strict';

var should = require('chai').should();
var nodemailerExpressHandlebars = require('../..'),
nodemailer = require('nodemailer'),
transport = require('nodemailer-stub-transport'),
handlebars = require('express-handlebars'),
path = require('path');

describe('when view engine passed', function() {

var sut,
mail,
transporter,
viewEngine;

beforeEach(function() {
transporter = nodemailer.createTransport(transport());
viewEngine = handlebars.create({
partialsDir: 'partials/',
defaultLayout: false
});
sut = nodemailerExpressHandlebars({
viewEngine: viewEngine,
viewPath: path.resolve(__dirname, '../views')
});
transporter.use('compile', sut);
mail = {
from: 'from@domain.com',
to: 'to@domain.com',
subject: 'Test',
template: 'email',
context: {
name: 'Name'
}
};
const { expect } = require('chai');
const nodemailerExpressHandlebars = require('../..'),
nodemailer = require('nodemailer'),
handlebars = require('express-handlebars'),
path = require('path');

describe('when view engine passed', function () {
let sut, mail, transporter, viewEngine;

beforeEach(function () {
transporter = nodemailer.createTransport({
streamTransport: true,
buffer: true,
});
viewEngine = handlebars.create({
partialsDir: path.resolve(__dirname, '../views/partials/'),
defaultLayout: false,
});
sut = nodemailerExpressHandlebars({
viewEngine: viewEngine,
viewPath: path.resolve(__dirname, '../views'),
});
transporter.use('compile', sut);
mail = {
from: 'from@domain.com',
to: 'to@domain.com',
subject: 'Test',
template: 'email',
context: {
name: 'Name',
},
};
});

it('should handle errors', function (done) {
viewEngine.renderView = () => {
throw 'Rendering Error';
};

transporter.sendMail(mail, (err, info) => {
expect(err).to.eq('Rendering Error');
done();
});
});

it('should set html on email', function(done) {
it('should set html on email', function (done) {
transporter.sendMail(mail, (err, info) => {
if (err) return done(err);

transporter.sendMail(mail, function(err, info) {
if (err) return done(err);
const body = info.message.toString();
expect(body).to.contain('<h1>This is a test</h1>');
expect(body).to.contain('Name');
done();
});
});

var body = info.response.toString();
body.should.contain('<h1>This is a test</h1>');
body.should.contain('Name');
done();
});
it('should not overwrite existing html entry', function (done) {
const html = (mail.html = '<h1>hardcoded</h1>');
transporter.sendMail(mail, (err, info) => {
if (err) return done(err);

const body = info.message.toString();
expect(body).to.contain(html);
done();
});
});

it('should not overwrite existing html entry', function(done) {

var html = mail.html = '<h1>hardcoded</h1>';
transporter.sendMail(mail, function(err, info) {
if (err) return done(err);
it('should handle text_template', function (done) {
mail.text_template = 'text';
transporter.sendMail(mail, (err, info) => {
if (err) return done(err);

var body = info.response.toString();
body.should.contain(html);
done();
});
const body = info.message.toString();
expect(body).to.contain('<h1>This is a test</h1>');
expect(body).to.contain('Name');
expect(body).to.contain('Text email');

done();
});
});
});

it('should handle view and partials', function (done) {
mail.template = 'with_partial';
transporter.sendMail(mail, (err, info) => {
if (err) return done(err);

describe('when options passed', function() {

var sut,
mail,
transporter;

beforeEach(function() {
transporter = nodemailer.createTransport(transport());
sut = nodemailerExpressHandlebars({
viewEngine: {
partialsDir: 'partials/',
defaultLayout: false
},
viewPath: path.resolve(__dirname, '../views')
});
transporter.use('compile', sut);
mail = {
from: 'from@domain.com',
to: 'to@domain.com',
subject: 'Test',
template: 'email',
context: {
name: 'Name'
}
};
const body = info.message.toString();
expect(body).to.contain('<h1>Header</h1>');
expect(body).to.contain('Email content');
done();
});
});
});

it('should set html on email', function(done) {

transporter.sendMail(mail, function(err, info) {
if (err) return done(err);

var body = info.response.toString();
body.should.contain('<h1>This is a test</h1>');
body.should.contain('Name');
done();
});
describe('when options passed', function () {
var sut, mail, transporter;

beforeEach(function () {
transporter = nodemailer.createTransport({
streamTransport: true,
buffer: true,
});
sut = nodemailerExpressHandlebars({
viewEngine: {
partialsDir: path.resolve(__dirname, '../views/partials/'),
defaultLayout: false,
},
viewPath: path.resolve(__dirname, '../views'),
});
transporter.use('compile', sut);
mail = {
from: 'from@domain.com',
to: 'to@domain.com',
subject: 'Test',
template: 'email',
context: {
name: 'Name',
},
};
});

it('should set html on email', function (done) {
transporter.sendMail(mail, (err, info) => {
if (err) return done(err);

const body = info.message.toString();
expect(body).to.contain('<h1>This is a test</h1>');
expect(body).to.contain('Name');
done();
});
});
});
1 change: 1 addition & 0 deletions test/views/partials/header.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Header</h1>
2 changes: 2 additions & 0 deletions test/views/text.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Text email
{{name}}
2 changes: 2 additions & 0 deletions test/views/with_partial.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{{> header}}
Email content
Loading

0 comments on commit cfc846b

Please sign in to comment.