Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetching values from email in protractor test case

I need to test a protractor test case in which a user signs up, receives an email, goes to the link provided in the email and fills up his/her details in activation signup form.

The problem is how can I get the redeem token from the email. My email has a link to the activation page which has the auth token like following:

http://127.0.0.1:3000/#/signup/redeem/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJlOTRhYzY3MC1kYTNlLTQyYTUtODVkZS02NDU4ZjVmZGMwYjAiLCJzdWIiOiJ0ZXN0QGNvZWYuY28iLCJpYXQiOjE0Mjc0OTM5MDMsImV4cCI6MTQyODA5ODcwM30.

But how do I fetch that token so that I can build the url or how can I click that button in my email so that I can complete the flow ? I am using mailcatcher to simulate email.

like image 597
Ashish Gaur Avatar asked Mar 27 '15 22:03

Ashish Gaur


2 Answers

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:

  1. Install mail-listener2:

    npm install mail-listener2 --save-dev
    
  2. 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();
    }, 
    
  3. Create a helper getLastEmail() function which would wait for an email 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;
    };
    
  4. 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);
    
             });
        });
    });
    
like image 72
alecxe Avatar answered Nov 03 '22 10:11

alecxe


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!

like image 7
Ashish Gaur Avatar answered Nov 03 '22 10:11

Ashish Gaur