Reputation: 3092
Using the page-object gem and Watir webdriver, we occasionally come across a Selenium::WebDriver::Error::StaleElementReferenceError on a page that loads some basic stuff, makes an ajax request, and repopulates with more info (for the illusion of speed on the page).
This happens because there will be an HTML element there, it disappears quickly and reappears again before the user is really aware of it.
We use page-object's ".when_present" method to wait until the object's on the page the first time before accessing it. However, even after the code finds the element, usually it will get the stale element error because the original HTML element gone and the other one has reappeared by the time it tries to access it.
We found a way using just straight Watir (not page-object) around this. We basically catch the StaleElementReferenceError inside of a Watir::Wait.until block. If it gets an exception, the block returns false, and the Wait.until tries again until it either becomes true, or times out eventually. What we've found is that this usually gets the Stale Element the first time (on line 3 below), returns false from the rescue, Wait.until executes the block again, and the 2nd time it's true and the test moves on and passes.
1 Watir::Wait.until {
2 begin
3 tds = page.my_element.when_present.element.tds
4 table_data_classes = tds.map{|cell| cell.attribute_value("class") }
5
6 # Should have at least one with a class of "xyz"
7 xyz = table_data_classes.select{|data| data.include?("xyz")}
8 xyz.size > 0
9 rescue Selenium::WebDriver::Error::StaleElementReferenceError
10 false
11 end
12 }
I'm really just wondering if there's any kind of page-object wrapper for this kind of thing. I couldn't find anything. If not, that's ok because the above works. Just curious.
Thanks
Upvotes: 4
Views: 2043
Reputation: 789
Gayle, great question. At this time there is no specific handling of a retry if the StaleElementReferenceError occurs in the page-object gem. I have heard from another person that they periodically get this error and it is something I could look into. What version of watir-webdriver are you using?
There is a way to duplicate the code you have above using page-object. I am not sure if the above code you provided is inside of your page or if it is somewhere else (like step definitions or some other place). Here's what I would do using the page-object gem:
Inside of your PageObject class
def has_element_with_class(clz)
wait_until
begin
cells = my_element.when_present.cell_elements
cells.any? { |cell| cell.attribute('class').include? clz }
rescue Selenium::WebDriver::Error::StaleElementReferenceError
false
end
end
I am simply getting all of the cells (tds) nested within my_element
into an array. I am calling the any?
method on that array which will return true if any of the blocks returns true and otherwise false. This has the same effect as all of the code you have above. If the error happens then you will continue another time.
Upvotes: 3