7

Code 1:

element(by.id('myButtonId')).click();
return element(by.id('myValidationSummaryId')).getText().then(function (val) {
    return val;
});

Above code worked fine many times and then it started giving below error

"Failed: stale element reference: element is not attached to the page document"

this id 'myValidationSummaryId' is no where used before, clicking button posts form and success/failure message available from service side in 'myValidationSummaryId'.

Code 2:

return element(by.id('myButtonId')).click().then(function () {
    return element(by.id('myValidationSummaryId')).getText().then(function (val) {
      return val;
    });
});

Fixing code as above fixed original issue and it worked consistently fine many times but later it started failing randomly with original stale element reference error.

Code 3:

return element(by.id('myButtonId')).click().then(function () {
    return element(by.id('myValidationSummaryId')).waitReady().then(function (isReady) {
        if (isReady) {
            return element(by.id('myValidationSummaryId')).getText().then(function (val) {
                return val;
            });
        } else {
            return 'Failed to check success/failure message';
        }
    });
});

Then I fixed code as above and now it works fine consistently, waitReady function actively wait for an element present and displayed up to specified time.

Shouldn't protractor/WebdriverJS supposed to handle this issues fine natively.

1> could you please explain why Code 1 and Code 2 sometime worked and sometime failed?

2> do you think Code 3 is now fine and expected to work every time?

Element 'myValidationSummaryId' used only once and after click so if pages is not loaded fully and if element is yet not available it should say No Element Found but why stale element reference? I have used pageLoadTimeout as 5 minutes and page is loaded in few second. This is non AngularJS application and browser.ignoreSynchronization = true.

everywhere it talked about what code can fix it but not found much on why this behavior and why WebdriverJS itself not able to handle it.

Morbia
  • 4,144
  • 3
  • 21
  • 13
  • Yeah, explicit wait is the usual way to solve problems like these. But, I had the same exact question, why sometimes waits are actually necessary and should not protractor handle it naturally. One thing protractor didn't recognize in my case was an animation - if there were an animation showing an element I had to use waits. Great question! – alecxe Aug 03 '15 at 16:25
  • I can confirm I had the exact same error today. Without any reason, any code changed and tests start failing. As for the weird Protractor's behavior - I can recommend **async** as a way to tame it. If **async** doesn't help, then I throw the towel. – Dejan Toteff Aug 03 '15 at 18:59

2 Answers2

11

I don't think we can be certainly sure why that happens, but you're definitely not alone (1) (2). This may be due to the way your page is rendered specifically (e.g. how your app/framework is handling rendering DOM elements), or just a Selenium/driver thing. If you're interested into an exact explanation, you might have better luck if using Protractor bug report system.

A good guess, however, may be that it is related to the way Selenium defines stale element:

A less common, but still common cause is where a JS library has deleted an element and replaced it with one with the same ID or attributes

Some libraries can fool Selenium into believing an element is gone from the DOM, but it has been really just replaced in an instant. Adding there a tight, frail timing between clicking and element being placed in the DOM (race condition basically) - that might be the cause. You might be interested in reading a little more about it here.

Anyway, if you're having such issues, I'd recommend you using browser.wait and Expected Conditions.

Expected conditions are basically functions that return true or false, and you can specify a timeout that will cause test to fail if true is not returned in that time - you can see how it's used in a similar question.

Basically, you might want to do it like this:

var EC = protractor.ExpectedConditions;
var summaryId = element(by.id('myValidationSummaryId'));

browser.wait(EC.presenceOf(summaryId), 5000);
//rest of your code
wap300
  • 2,660
  • 1
  • 16
  • 25
  • Thank you for your suggestions, waitReady function uses browser.wait, and it works fine, I had gone through http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp but in my case element is not removed, replaced or its type does not change. – Morbia Aug 03 '15 at 20:47
  • Then you'd probably need to share your exact code, or do some advanced debugging on your own. The cause will be probably very hard to determine, but if you find out what that is, I'd be great if you shared the cause here. – wap300 Aug 03 '15 at 21:07
  • Agreed, I'm working on a project now whereby if I open up developer tools in Chrome F12 and watch the DOM, I can actually see Angular's Asynchronous puts and gets change certain (and unknown to the test) DOM elements. This makes testing these pages impossible because of obvious timing issues and the "Stale Element Reference". – JWP Aug 05 '15 at 13:53
  • 1
    The definition of "stale element" you mentioned showed me the solution in my case: A master detail relationship where a change in the master record replaces the detail table, but with the same cell ids. Sometimes my test code got the reference to the old element, because it has not yet been removed from the DOM. – FrankL Apr 26 '20 at 11:05
0

I was able to resolve this issue by adding a sleep. Given User is on the "xxx" page, when User clicks on "431511" site and User clicks on "DisplayMenu" and User clicks on "Create Device", then CREATE DEVICE form is displayed.

  When('User clicks on {string}',async (string)=>{
      if(string==="DisplayMenu"){
        **await browser.sleep(3000);**
      await TMS.displayMenu.click();}
      else if (string==="CreateDevice"){
        await TMS.createDevice.click();
      }
TT.
  • 15,774
  • 6
  • 47
  • 88
Divya
  • 59
  • 10