How can I wait for a condition?

74,216

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);
}
Share:
74,216
Muratso
Author by

Muratso

Updated on February 09, 2021

Comments

  • Muratso
    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
    Raphaël over 9 years
    I 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 of ptor in the above code). This is not a direct answer to the question but I though it might be helpful.
  • Ali Motevallian
    Ali Motevallian almost 9 years
    I 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
    asherrard almost 9 years
    I 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
    napu over 8 years
    This one worked well with Protractor version 2.5.1 on a non-Angular site