2

I am trying to test an xmpp chat application, and having some difficulties testing the results of asynchronous operations. The test is trying to remove a contact from your roster (contact list), and driver.wait does not seem to be resolving when the promise if fulfilled. The test passes, but it waits for 11 secs (allScriptsTimeout in protractor.conf) before finishing the wait, then takes another 11 secs in the .then after evaluating the expect statement before the browser window closes. Here's the code, problems start at driver.wait() block:

describe("When adding a contact to the roster", function() {
  var jid = "testyeti@yeti.dslab.ad.adp.com";
  var searchString = "yeti";
  var editBtnId = jid + "_cog";
  var plusBtnId = jid + "_add";
  var searchId = "yeti-searchInput";
  beforeEach(function() {
    browser.get('/');
  });
  var addOrRemove = function(callbackWhenDone) {
    expect(element(by.css('.yeti-contactList')).isPresent()).toBe(true);
    var driver = browser.driver;
    driver.manage().timeouts().implicitlyWait(10000).then(function() {
      //wait for the roster to load async
      expect(element(by.css('.yeti-rosterRight')).isPresent()).toBeTruthy();
    });
    var cog = element(by.id(editBtnId));
    cog.isPresent()
      .then(function(itIsThere) {
        if (itIsThere) {
          //remove this person from the roster if they are there
          console.log(jid + " was in roster. Removing...");
          //click the button to edit contact properites
          cog.click();
          //click to remove from roster
          element(by.id('RemoveExisting')).click();
          //click to confirm remove
          element(by.id('SureRemove')).click();
          //here's where things get interesting...
          var deferred = protractor.promise.defer();
          driver.wait(function() {
              var poll = function() {
                //check if the element is present until it gets removed
                element(by.id(editBtnId)).isPresent().then(function(isPresent) {
                  console.log("(in promise.then) element isPresent? " + isPresent);
                  // isPresent is true if the server hasn't yet returned with a 
                  // response to remove contact
                  // we need isPresent to be false before eval of expect statement below
                  if (!isPresent) {
                    deferred.fulfill(true);
                    return deferred.promise;
                  } else {
                    //check again
                    poll();
                  }
                });
                return deferred.promise;
              };
              poll();
              return deferred.promise;
              //tried the return statement below without the poll() wrapper, but
              // isPresent().then() returned true (server hasn't responded yet)
              //and it never entered if statement to resolve the promise that
              // driver is waiting on
              //return deferred.promise;
            }, 5000, "\nTimed out waiting for element to not be present\n")
            .then(function() {
              //they were successfully removed from the roster and the view was updated
              expect(element(by.id(editBtnId)).isPresent()).toBeFalsy();
            });
        } else {
          //add this person to the roster if they are not there
          ...more unrelated code...
        }
      });
  };

  it('Successfully adds or removes a known user', function() {
    addOrRemove.call(this);
  });
});

console output:

testyeti@yeti.dslab.ad.adp.com was in roster. Removing...
(in promise.then) element isPresent? true
(in promise.then) element isPresent? true
(in promise.then) element isPresent? true
(in promise.then) element isPresent? false <-(this takes 11 secs to show up)
Eval expect <- (this also takes 11 secs to show up)
. <- (green dot, test passed)

Here's my second attempt. A lot simpler, but test doesn't pass (final expect fails):

driver.wait(function() {
    var condition = false;
    element(by.id(editBtnId)).isPresent().then(function(isPresent) {
        condition = isPresent;
    });
    console.log("returning " + (!condition));
    return !condition;
}, 10000, "timed out").then(function() {
    //they were successfully removed from the roster and the view was updated
    expect(element(by.id(editBtnId)).isPresent()).toBeFalsy();
});

Any clue what's going on here? Any help would be GREATLY appreciated, I have been stuck on this one for quite some time...

thorn0
  • 9,362
  • 3
  • 68
  • 96

1 Answers1

3

The reason why

(in promise.then) element isPresent? false <-(this takes 11 secs to show up)

Is because you're setting a very high implicit wait:

driver.manage().timeouts().implicitlyWait(10000)

As detailed here that has the advantage of waiting up to that time to find an element but with the disadvantage of waiting all that time on negative tests like

expect(element(by.id(editBtnId)).isPresent()).toBeFalsy();

You're probably using implicit wait because your test fails sometimes when it doesn't properly wait for the element? I have this issue when testing non-angular pages because Protractor doesn't know how to wait for the page to be fully loaded so you can use with custom function waitReady() that browser.wait for elements ready:

expect(element(by.css('.yeti-rosterRight')).waitReady()).toBeTruthy();

First integrate this snippet in your code: https://gist.github.com/elgalu/2939aad2b2e31418c1bb

Community
  • 1
  • 1
Leo Gallucci
  • 16,355
  • 12
  • 77
  • 110