Email Test Automation With Mailtrap
Make no mistake, testing email remains a productive use of your time. However, automation can make it use less of your time.
Join the DZone community and get the full member experience.
Join For FreeIn most of the applications that we use today, the use of email continues to be an important part of many of the main functionalities that these systems offer us. Whether it's to register as users, recover a password, receive reports, invoices, flight reservations, accommodations, or anything else, sending emails is something that is still closely linked to the core functionality of many systems.
On the other hand, email is something that has been around for a long time. This is why we often overlook tests where sending emails is involved, either because of the complexity of the task or because we assume that there will be no errors. However, there are certain scenarios where it is advisable to perform some minimal tests. For example, some elements that you should want to check might be:
The proper format and design of the body of the mail.
The correct use and replacement of template fields.
That files are correctly attached.
Correctly sending user activation links or resetting passwords.
That recipients and senders are generated correctly.
Failures in any of the above elements can lead to serious security errors or a significant deterioration of the brand image in the eyes of customers.
Automated Testing for Email Sending
Mocking
When performing unit tests of the functionality in which the sending of emails intervenes, the most common is the use of some mocking framework that simulates these interactions (Mmockito, Moq, Sinon, etc.). Thanks to this we will be able to verify that our system fulfills the suitable functional specifications and behaves correctly before certain situations of error without the need to make real mailings.
Integration Tests or E2E
Although we start from a good base of unit tests, when we deal with the automation of integration tests, the management of emails is not always an issue that is easily automatable as it raises several points to take into account:
What accounts will receive the emails
What type of server receives the emails (IMAP, POP3, etc.)
Whether you have access/credentials for the accounts that will receive the emails.
How a user can filter the emails they interested in controlling.
Sending flow control or test synchronization.
These are just a few examples of the difficulties of automating testing when email is part of it.
For this type of situations, Mailtrap can be very useful.
Mailtrap
Mailtrap's developers define it as a "fake SMTP testing server." In other words, they provide a service in the cloud that behaves like a real SMTP server, but does not send the emails to the final recipient. Instead, it stores them so that the corresponding verifications can be carried out.
To do this, in our system, we will have to indicate that Mailtrap is used as an SMTP server for sending mail. This connection data can be found in our user account. They even provide us with the right snippet for the most common languages.
Once we have our system configured so that the sending of emails is done through Mailtrap, how can we automate our tests? It is at this point where Mailtrap makes it really easy since it exposes an API through which we can access the appropriate mailbox to consult and operate on the emails that are on the server.
MailTrap API
All documentation concerning the Mailtrap API can be consulted online.
The fact that we can use an API to consult the mail is a great advantage for its simplicity, cleanliness, and the expressiveness that brings to the tests.
Thanks to the Mailtrap API, we will be able to read the incoming mails, eliminate them, check attachments, etc.
Example
In this link, you can see an example of a program that uses Mailtrap to send emails and the corresponding tests that verify that the mail has actually been sent.
Sending Mail
this.app.route('/').post(async (req, res) => {
const message = Object.assign({}, req.body);
Mail.from = message.from;
Mail.to = message.to;
Mail.subject = message.subject;
Mail.message = message.message;
const result = await Mail.sendMail();
console.log(result);
res.status(200).json({
result,
});
});
On the server, there is a simple method that sends emails:
const transporter = nodemailer.createTransport({
host: config.host,
port: config.port,
secure: false,
auth: {
user: config.user,
pass: config.password,
},
tls: { rejectUnauthorized: false },
});
console.log(mailOptions);
await transporter.sendMail(mailOptions).then((info) => {
console.log(info);
result = 'Envio OK';
}).catch((err) => {
console.log(err);
result = err.response;
});
return result;
When sending mail, the "Mail.ts" class, through the nodemailer library, is in charge of sending mail using the appropriate Mailtrap configuration.
Integration Test
A possible automatic test to check the correct functioning of sending emails is also possible
Before each test deletes all the emails from an mailbox:
beforeEach((done) => {
console.log('Clean Inbox');
const cleanInbox = {
url: mailtrapUrl + 'inboxes/' + inboxId + '/clean',
headers: {
'Api-Token': apiToken
}
};
function callback(error, response, body) {
console.log('Empty Inbox');
expect(response.statusCode).toBe(200);
done();
}
api.patch(cleanInbox, callback);
});
The test is based on sending an email with a specific subject (based on the timestamp) and the subsequent verification that in Mailtrap, there is indeed an email with the same subject.
it('Send mail from app', (done) => {
let timestamp = new Date();
//Adding timestamp will help us to check if email was recieved
let subjectText = "SendTest_" + timestamp.valueOf();
let body = {
from: 'TestMail@test.com',
to: 'fran@test.com',
subject: subjectText,
message: 'Send Test'
};
//Our app will send the email
request(app.app)
.post('/')
.send(body)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200) //Check our server response
.end(() => {
console.log("Email sent");
//Once server send email check mailtrap
api.get(getEmailsEndPoint, checkMail);
});
const getEmailsEndPoint = {
url: mailtrapUrl + 'inboxes/' + inboxId + '/messages',
headers: {
'Api-Token': apiToken
},
};
let checkMail = function callback(error, response, body) {
const info = JSON.parse(body);
expect(response.statusCode).toBe(200);
//Check subject
expect(info[0].subject).toBe(subjectText);
done();
}
});
Instructions to start the project
- During development, we use both
npm run watch-ts
(recompiles application on source changes) andnpm run watch-node
(restarts application on recompilation).- One terminal:
npm run watch-ts
- Another terminal:
npm run watch-node
- One terminal:
npm run build-ts
only compiles the application.npm run serve
(npm run start
) only starts the application.npm run test
run the tests "Send an email" and "Verification."
The complete example is available on GitHub.
Published at DZone with permission of Francisco Moreno. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments