Fetching values from email in protractor test case
This is something I've solved recently. Hope the solution would also apply for your use-case.
Prerequisites:
mail-listener2
package- understanding of the concept of
promises
Step by step instructions:
-
Install
mail-listener2
:npm install mail-listener2 --save-dev
-
In your protractor config initialize Mail Listener and make it available globally:
onPrepare: function () { var MailListener = require("mail-listener2"); // here goes your email connection configuration var mailListener = new MailListener({ username: "imap-username", password: "imap-password", host: "imap-host", port: 993, // imap port tls: true, tlsOptions: { rejectUnauthorized: false }, mailbox: "INBOX", // mailbox to monitor searchFilter: ["UNSEEN", "FLAGGED"], // the search filter being used after an IDLE notification has been retrieved markSeen: true, // all fetched email willbe marked as seen and not fetched next time fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`, mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib. attachments: true, // download attachments as they are encountered to the project directory attachmentOptions: { directory: "attachments/" } // specify a download directory for attachments }); mailListener.start(); mailListener.on("server:connected", function(){ console.log("Mail listener initialized"); }); global.mailListener = mailListener; }), onCleanUp: function () { mailListener.stop(); },
-
Create a helper
getLastEmail()
function which would wait for anemail
to be retrieved:function getLastEmail() { var deferred = protractor.promise.defer(); console.log("Waiting for an email..."); mailListener.on("mail", function(mail){ deferred.fulfill(mail); }); return deferred.promise; };
-
Example test case:
describe("Sample test case", function () { beforeEach(function () { browser.get("/#login"); browser.waitForAngular(); }); it("should login with a registration code sent to an email", function () { element(by.id("username")).sendKeys("MyUserName"); element(by.id("password")).sendKeys("MyPassword"); element(by.id("loginButton")).click(); browser.controlFlow().await(getLastEmail()).then(function (email) { expect(email.subject).toEqual("New Registration Code"); expect(email.headers.to).toEqual("[email protected]"); // extract registration code from the email message var pattern = /Registration code is: (\w+)/g; var regCode = pattern.exec(email.text)[1]; console.log(regCode); }); }); });
The solution I implemented was using mailcatcher API, if you scroll down a bit you'll find the following about the API:
A fairly RESTful URL schema means you can download a list of messages in JSON from /messages, each message's metadata with /messages/:id.json, and then the pertinent parts with /messages/:id.html and /messages/:id.plain for the default HTML and plain text version, /messages/:id/:cid for individual attachments by CID, or the whole message with /messages/:id.source.
So we first fetched the whole json response, parse it and fetch the latest email id:
// Returns the last email id
function(emails, user) {
var email, recipient;
for(var i = emails.length - 1; i >= 0; i--) {
email = emails[i];
for(var j = 0; j < email.recipients.length ; j++) {
recipient = email.recipients[j];
if(recipient == "<"+user+">") {
return email.id;
}
}
}
};
using that email id we can get the body of the email by hitting /messages/:id.plain
(of course there are more variants like fetching the email source code or email rendered html, we only needed the message) then we can just parse the body to fetch what we want, following is the code:
browser.driver.get(mailcatcherUrl+"/messages");
browser.driver.findElement(by.tagName('body')).getText().then(function(response) {
var emails, lastEmailId, partialTokens ;
emails = JSON.parse(response);
lastEmailId = getLastEmailId(emails, user);
browser.driver.get(mailcatcherUrl+"/messages/"+lastEmailId+".plain");
browser.driver.findElement(by.tagName('body')).getText().then(function(lastEmail) {
// use latestEmail to get what you want.
});
});
And Cheers!