Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for page redirection in Protractor / Webdriver

I have a test that clicks a button and redirects to a user dashboard. When this happens Webdriver returns: javascript error: document unloaded while waiting for result.

To fix this I insert browser.sleep(2000) at the point where redirection occurs and assuming my CPU usage is low, this solves the issue. However, 2000 ms is arbitrary and slow. Is there something like browser.waitForAngular() that will wait for the angular to load on the redirected page before the expect(..)?

it('should create a new user', () => {
  $signUp.click();
  $email.sendKeys((new Date().getTime()) + '@.com');
  $password.sendKeys('12345');
  $submit.click();

  browser.sleep(2000); // Need alternative to sleep...

  // This doesn't do it...
  // browser.sleep(1);
  // browser.waitForAngular();

  $body.evaluate('user')
  .then((user) => {
    expect(user).toBe(true);
  });
});
like image 642
northamerican Avatar asked Sep 29 '15 21:09

northamerican


2 Answers

do you think something like this could work for you? This will wait up to 10 seconds for the url to include the text 'pageTwo', or whatever you put in.

var nextPageButton = $('#nextPage');
nextPageButton.click().then(function(){
    return browser.driver.wait(function() {
      return browser.driver.getCurrentUrl().then(function(url) {
        return /pageTwo/.test(url);
      });
    }, 10000);
};

Just stick in the regex of the url you are expecting.

Alternatively, you could wait for an element from the next page to appear as well:

var nextPageButton = $('#nextPage');
nextPageButton.click();

var elementFromSecondPage = $('#coolElement');
browser.wait(protractor.until.elementIsVisible(elementFromSecondPage), 5000, 'Error: Element did not display within 5 seconds');

When using .click, protractor will naturally wait for angular to finish the action attached to the click, such as changing the page. But, while the page change, you may still be needing something specific to be loaded, so the test fails before that part is available. Using this, it should wait for the click part to finish, then wait for the element to appear.

like image 134
user2020347 Avatar answered Nov 16 '22 00:11

user2020347


To expand on user2020347's answer: Thanks that solved my issue. I wonder why this isn't a built in function. I'll be using this in many places to wait for browser navigation.

To make it more concise, I made a little helper:

Object.assign(global, {
  waitUntilURLContains: string => {
    let fn = () => {
      return browser.driver.wait(() => {
        return browser.driver.getCurrentUrl().then((url) => {
          return url.includes(string);
        });
      }, waitDelay);
    }

    return fn.bind(null, string);
  }
});

In my test:

$button.click().then(waitUntilURLContains('dashboard'));
like image 36
northamerican Avatar answered Nov 16 '22 02:11

northamerican