Skip to content

Instantly share code, notes, and snippets.

@elgalu
Last active February 2, 2021 07:14
Show Gist options
  • Save elgalu/2939aad2b2e31418c1bb to your computer and use it in GitHub Desktop.
Save elgalu/2939aad2b2e31418c1bb to your computer and use it in GitHub Desktop.
Actively wait for an element present and displayed up to specTimeoutMs ignoring useless webdriver errors like StaleElementError.
/**
* Actively wait for an element present and displayed up to specTimeoutMs
* ignoring useless webdriver errors like StaleElementError.
*
* Usage:
* Add `require('./waitReady.js');` in your onPrepare block or file.
*
* @example
* expect($('.some-html-class').waitReady()).toBeTruthy();
*/
"use strict";
// Config
var specTimeoutMs = 10000; // 10 seconds
/**
* Current workaround until https://github.com/angular/protractor/issues/1102
* @type {Function}
*/
var ElementFinder = $('').constructor;
ElementFinder.prototype.waitReady = function(opt_optStr) {
var self = this;
var driverWaitIterations = 0;
var lastWebdriverError;
function _throwError() {
throw new Error("Expected '" + self.locator().toString() +
"' to be present and visible. " +
"After " + driverWaitIterations + " driverWaitIterations. " +
"Last webdriver error: " + lastWebdriverError);
};
function _isPresentError(err) {
lastWebdriverError = (err != null) ? err.toString() : err;
return false;
};
return browser.driver.wait(function() {
driverWaitIterations++;
if (opt_optStr === 'withRefresh') {
// Refresh page after more than some retries
if (driverWaitIterations > 7) {
_refreshPage();
}
}
return self.isPresent().then(function(present) {
if (present) {
return self.isDisplayed().then(function(visible) {
lastWebdriverError = 'visible:' + visible;
return visible;
}, _isPresentError);
} else {
lastWebdriverError = 'present:' + present;
return false;
}
}, _isPresentError);
}, specTimeoutMs).then(function(waitResult) {
if (!waitResult) { _throwError() };
return waitResult;
}, function(err) {
_isPresentError(err);
_throwError();
return false;
});
};
// Helpers
function _refreshPage() {
// Swallow useless refresh page webdriver errors
browser.navigate().refresh().then(function(){}, function(e){});
};
Copy link

ghost commented May 21, 2015

Very nice solution!

If needed, you can remove a lot of lines of code from spec files using waitReady.js by rewriting...

return waitResult;

with...

return self;

This way, you can do...

element.waitReady().then(function (elm) { ... })

@prabinmetals
Copy link

Great. Solved my issue where an input filed did not load and caused NoSuchElement error (http://stackoverflow.com/questions/31108455/protractor-sendkeys-returns-nosuchelementerror).

@michalpelc
Copy link

Is that solution really work for you ?
Have tried to use it to click on stale elements but sometimes exceptions occurs anyway.

have written is function like that:

function clickWait(element) {
    (element).waitReady().then(function () {
        return element.click();
    });
};

and invoking it like this :

    clickWait(usersPage.element);

where usersPage is my page object.

@matbruc
Copy link

matbruc commented Jan 7, 2016

Hi, thanks for share this solution. I have a problem while trying to use it.

The error says:
ReferenceError: $ is not defined
for the line 20.

Can you help me with this?
Thanks in advance

@jaguwalapratik
Copy link

Really nice solution.

Solved my problem which i m facing in protractor test with AngularJS + RequireJS setup.

Thank you so much...

@dgasi
Copy link

dgasi commented May 12, 2016

Nice man. Helped me a lot.

@ToreyStapleton
Copy link

ToreyStapleton commented Jun 6, 2016

This is awesome -- been using Protractor for awhile and have always relied on Expected Conditions to wait for things. For some reason today I was having an unusually hard time with one of my EC's throwing a stale element error, and I found this code after some googling. Works flawlessly for that same element I was having trouble with earlier. Thanks again!

@jrharshath
Copy link

jrharshath commented Jul 25, 2016

This is great!

Also, looks like angular/protractor#1102 is resolved after this PR angular/protractor#1633.

@miriamstub
Copy link

This looks awesome, exactly what i looked for, but i have a problem - element(by.id('login_field')) is a protractor function which can not be used on non angular pages. $('#login_field') is giving undefined. How to waitReady for a element on non angular Page ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment