Protractor : How to wait for page complete after click a button?

JasmineProtractorWait

Jasmine Problem Overview


In a test spec, I need to click a button on a web page, and wait for the new page completely loaded.

emailEl.sendKeys('jack');
passwordEl.sendKeys('123pwd');
	    
btnLoginEl.click();

// ...Here need to wait for page complete... How?

ptor.waitForAngular();
expect(ptor.getCurrentUrl()).toEqual(url + 'abc#/efg');
	    	

Jasmine Solutions


Solution 1 - Jasmine

Depending on what you want to do, you can try:

browser.waitForAngular();

or

btnLoginEl.click().then(function() {
  // do some stuff 
}); 

to solve the promise. It would be better if you can do that in the beforeEach.

NB: I noticed that the expect() waits for the promise inside (i.e. getCurrentUrl) to be solved before comparing.

Solution 2 - Jasmine

I just had a look at the source - Protractor is waiting for Angular only in a few cases (like when element.all is invoked, or setting / getting location).

So Protractor won't wait for Angular to stabilise after every command.

Also, it looks like sometimes in my tests I had a race between Angular digest cycle and click event, so sometimes I have to do:

elm.click();
browser.driver.sleep(1000);
browser.waitForAngular();

using sleep to wait for execution to enter AngularJS context (triggered by click event).

Solution 3 - Jasmine

You don't need to wait. Protractor automatically waits for angular to be ready and then it executes the next step in the control flow.

Solution 4 - Jasmine

With Protractor, you can use the following approach

var EC = protractor.ExpectedConditions;
// Wait for new page url to contain newPageName
browser.wait(EC.urlContains('newPageName'), 10000);

So your code will look something like,

emailEl.sendKeys('jack');
passwordEl.sendKeys('123pwd');

btnLoginEl.click();

var EC = protractor.ExpectedConditions;
// Wait for new page url to contain efg
ptor.wait(EC.urlContains('efg'), 10000);

expect(ptor.getCurrentUrl()).toEqual(url + 'abc#/efg');

Note: This may not mean that new page has finished loading and DOM is ready. The subsequent 'expect()' statement will ensure Protractor waits for DOM to be available for test.

Reference: Protractor ExpectedConditions

Solution 5 - Jasmine

In this case, you can used:

Page Object:

    waitForURLContain(urlExpected: string, timeout: number) {
        try {
            const condition = browser.ExpectedConditions;
            browser.wait(condition.urlContains(urlExpected), timeout);
        } catch (e) {
            console.error('URL not contain text.', e);
        };
    }

Page Test:

page.waitForURLContain('abc#/efg', 30000);

Solution 6 - Jasmine

I typically just add something to the control flow, i.e.:

it('should navigate to the logfile page when attempting ' +
   'to access the user login page, after logging in', function() {
  userLoginPage.login(true);
  userLoginPage.get();
  logfilePage.expectLogfilePage();
});

logfilePage:

function login() {
  element(by.buttonText('Login')).click();

  // Adding this to the control flow will ensure the resulting page is loaded before moving on
  browser.getLocationAbsUrl();
}

Solution 7 - Jasmine

Use this I think it's better

   *isAngularSite(false);*
    browser.get(crmUrl);


    login.username.sendKeys(username);
    login.password.sendKeys(password);
    login.submit.click();

    *isAngularSite(true);*

For you to use this setting of isAngularSite should put this in your protractor.conf.js here:

        global.isAngularSite = function(flag) {
        browser.ignoreSynchronization = !flag;
        };

Solution 8 - Jasmine

to wait until the click itself is complete (ie to resolve the Promise), use await keyword

it('test case 1', async () => {
  await login.submit.click();
})

This will stop the command queue until the click (sendKeys, sleep or any other command) is finished

If you're lucky and you're on angular page that is built well and doesn't have micro and macro tasks pending then Protractor should wait by itself until the page is ready. But sometimes you need to handle waiting yourself, for example when logging in through a page that is not Angular (read how to find out if page has pending tasks and how to work with non angular pages)

In the case you're handling the waiting manually, browser.wait is the way to go. Just pass a function to it that would have a condition which to wait for. For example wait until there is no loading animation on the page

let $animation = $$('.loading');

await browser.wait(
  async () => (await animation.count()) === 0, // function; if returns true it stops waiting; can wait for anything in the world if you get creative with it
  5000, // timeout
  `message on timeout`
);

Make sure to use await

Solution 9 - Jasmine

you can do something like this

emailEl.sendKeys('jack');
passwordEl.sendKeys('123pwd');

btnLoginEl.click().then(function(){
browser.wait(5000);
});

Solution 10 - Jasmine

browser.waitForAngular();

btnLoginEl.click().then(function() { Do Something });

to solve the promise.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZachView Question on Stackoverflow
Solution 1 - JasmineglepretreView Answer on Stackoverflow
Solution 2 - JasmineFilip SobczakView Answer on Stackoverflow
Solution 3 - JasmineAndres DView Answer on Stackoverflow
Solution 4 - Jasminemilan pandyaView Answer on Stackoverflow
Solution 5 - JasmineDao Minh DamView Answer on Stackoverflow
Solution 6 - JasmineJustin HelmerView Answer on Stackoverflow
Solution 7 - JasmineDantinhoView Answer on Stackoverflow
Solution 8 - JasmineSergey PleshakovView Answer on Stackoverflow
Solution 9 - Jasmineashish bansalView Answer on Stackoverflow
Solution 10 - JasmineShiwantha LakmalView Answer on Stackoverflow