Legumebo_Magezfeld Legumebo_Magezfeld - 28 days ago 10
AngularJS Question

angular protractor: driver.wait and .then taking allScriptsTimeout time to return

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...

Answer

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