Mail listener ocassionally fails to authenticate

1.3k views Asked by At

The Problem:

We have multiple tests where we need to actually check the test user's email as a test case step. This is used for two factor authentication and email notification tests.

At the moment, we use the solution provided here which is based on the mail-listener2 node package. Here is the configuration that we use:

email: {
    username: "user email here",
    password: "user password here",
    host: "smtp server address here",
    port: 993,
    tls: true,
    mailbox: "Inbox",
    markSeen: true
},

We initialize the mail listener in the Protractor config inside the onPrepare() function:

var MailListener = require("mail-listener2");
var mailListener = new MailListener(config.email);

mailListener.start();

mailListener.on("server:connected", function(){
    console.log("Mail listener initialized");
});

global.mailListener = mailListener;

The problem is - in about 10% of the times, the mail listener fails with the following error message:

Timed out while authenticating with server

The Question:

What can cause the problem and what can we do to make the mail listener work? Also, would it be possible to retry authenticating on a failure?

2

There are 2 answers

2
cnishina On BEST ANSWER

This is an async problem. Your mail listener is trying to check for an event "server:connected". Since this is asynchronous, this may or may not happen in time. What you should try to do is wrap this it in a promise and resolve after the event "server:connected".

onPrepare: {
  return new Promise((resolve, reject) => {
    var MailListener = require("mail-listener2");
    var mailListener = new MailListener(config.email);

    mailListener.start();

    mailListener.on("server:connected", function(){
      console.log("Mail listener initialized");
      resolve();
    });

    // if you run into an error on connecting to the server,
    // maybe reject the promise here.
    mailListener.on("error", (err) => {
      reject(err);
    });

    global.mailListener = mailListener;
  });
}
0
alecxe On

@cnishina's answer helped a lot. We've taken it a bit further and added the "retry" part to retry mail listener N times in case it fails:

this.configureMailListener = function (mailListener, maxRetries, deferred) {
    var self = this;

    if (!deferred) {
        deferred = protractor.promise.defer();
    }

    mailListener.start();

    mailListener.on("server:connected", function() {
        console.log("Mail listener initialized.");
        deferred.fulfill();
    });

    mailListener.on("error", function (err) {
        if (maxRetries > 0) {
            console.log("Mail listener failed to initialize. Retrying...");

            setTimeout(function () {
                mailListener.removeAllListeners();
                mailListener.stop();

                self.configureMailListener(mailListener, maxRetries - 1, deferred);
            }, 1000);
        } else {
            console.log("Mail listener failed to initialize.");
            deferred.reject(err);
        }
    });
    return deferred.promise;
};

Usage, add this to onPrepare():

onPrepare: function () {
    // configure email listener
    var MailListener = require("mail-listener2");
    var config = require("../config/config");
    var mailListener = new MailListener(config.email);

    global.mailListener = mailListener;

    return helpers.configureMailListener(mailListener, 5);  // attempt to initialize mail-listener 5 times
},