How can I wait for a condition?
Solution 1
I had the same problem you were having for the longest time while using protractor. In my e2e test I start in a non angular app, then get into an angular portion, then get back out to a non angular portion. Made things tricky. The key is to understand promises and how they work. Here's some examples of my real world code in a functioning e2e test. Hoping this gives you an idea of how to structure your tests. Probably some bad practice in this code, please feel free to improve upon this, but I know that it works, maybe not the best way.
To get to angular I use
var ptor;
var events = require('events');
var eventEmitter = new events.EventEmitter();
var secondClick = require('./second-click');
beforeEach(function () {
browser.driver.get('http://localhost:8080/');
},10000);
it("should start the test", function () {
describe("starting", function () {
it("should find the link and start the test", function(){
var elementToFind = by.linkText('Start'); //what element we are looking for
browser.driver.isElementPresent(elementToFind).then(function(isPresent){
expect(isPresent).toBe(true); //the test, kind of redundant but it helps pass or fail
browser.driver.findElement(elementToFind).then(function(start){
start.click().then(function(){ //once we've found the element and its on the page click it!! :)
ptor = protractor.getInstance(); //pass down protractor and the events to other files so we can emit events
secondClick(eventEmitter, ptor); //this is your callback to keep going on to other actions or test in another file
});
});
});
});
});
},60000);
While in angular this code works
describe("type in a message ", function(){
it("should find and type in a random message", function(){
var elementToFind = by.css('form textarea.limited');
browser.driver.isElementPresent(elementToFind).then(function(isPresent){
element(elementToFind).sendKeys(randomSentence).then(function(){
console.log("typed in random message");
continueOn();
});
});
});
},15000);
After exiting angular
browser.driver.wait(function(){
console.log("polling for a firstName to appear");
return browser.driver.isElementPresent(by.name('firstName')).then(function(el){
return el === true;
});
}).
then(function(){
somefunctionToExecute()
});
Hope that gives some guidance and helps you out!
Solution 2
Protractor 1.7.0
has also introduced a new feature: Expected Conditions.
There are several predefined conditions to explicitly wait for. In case you want to wait for an element to become present:
var EC = protractor.ExpectedConditions;
var e = element(by.id('xyz'));
browser.wait(EC.presenceOf(e), 10000);
expect(e.isPresent()).toBeTruthy();
See also:
Solution 3
I finally find out...
var waitLoading = by.css('#loading.loader-state-hidden');
browser.wait(function() {
return ptor.isElementPresent(waitLoading);
}, 8000);
expect(ptor.isElementPresent(waitLoading)).toBeTruthy();
var openContact = by.xpath("//a[@href='#/contacts']");
element(openContact).click();
With this protractor could wait for that element until it loading page disappears. Thanks for those who tried to help XD.
Solution 4
browser.driver.wait(function() {
return browser.driver.isElementPresent(by.xpath("//a[@href='#/contacts']"));
});
This works for me too (without the timeout param)..
for more information, see http://angular.github.io/protractor/#/api?view=webdriver.WebDriver.prototype.wait
Solution 5
Thanks to answers above, this was my simplified and updated usage
function waitFor (selector) {
return browser.wait(function () {
return browser.isElementPresent(by.css(selector));
}, 50000);
}
Muratso
Updated on February 09, 2021Comments
-
Muratso over 3 years
I'm new on protractor, and I'm trying to implement an e2e test. I don't know if this is the right way to do this, but... The page that I want to test is not a full angular page based, so... I'm having some trouble.
On my first spec I have:
describe('should open contact page', function() { var ptor = protractor.getInstance(); beforeEach(function(){ var Login = require('./util/Login'); new Login(ptor); });
I have created this Login class, but after login I want to open the contact page, but protractor immediately try to find element before the page is fully loaded.
I've tried to use:
browser.driver.wait(function() { expect(browser.findElement(by.xpath("//a[@href='#/contacts']")).isDisplayed()); ptor.findElement(by.xpath("//a[@href='#/contacts']")).click(); });
But it doesn't work... it always try to find the element before the page loads. I tried this one too:
browser.driver.wait(function() { expect(ptor.isElementPresent(by.xpath("//a[@href='#/contacts']"))); ptor.findElement(by.xpath("//a[@href='#/contacts']")).click(); });
I'm able to do that using
browser.sleep();
but I don't think that is a good option. Any idea? On my login class I have:ptor.ignoreSynchronization = true;
How can I wait for this
@href='#/contacts
before protractor tries to click on it? -
Raphaël over 9 yearsI was looking to use this to test a custom angular flash message content. But protractor seems unable to get the corresponding DOM element. I resolved the issue by using selenium driver instead of protractor (e.g. use
browser.driver
instead ofptor
in the above code). This is not a direct answer to the question but I though it might be helpful. -
Ali Motevallian almost 9 yearsI guess you still do not know promises very well. If you return from within first .then, you can chain other .then calls so that you get a flat structure.
-
asherrard almost 9 yearsI wish someone would have told me that a year ago when I wrote this ha! Thank you @AliMotevallian I haven't written anything with the newer version of protractor, I'd like to revisit it and clean up the code for the new versions and hopefully make it a lot simpler.
-
napu over 8 yearsThis one worked well with Protractor version 2.5.1 on a non-Angular site