I am trying to write a Selenium object Builder for a Swagger page, in groovy. For the purposes of this discussion, my problem code can be reduced down to the following:
After the most excellent research / suggestion by @Louis, I ended up using:
def wait = new FluentWait<By>(By.className("resource")).
withTimeout(10, TimeUnit.SECONDS).
ignoring(NoSuchElementException)
wait.until(new Function<By, Boolean>() {
WebElement res
Boolean apply(By by) {
def oldRes = res
res = driver.findElement(by)
return res == oldRes
}
})
If anyone is interested, the entire Builder can be found on SourceForge (still under construction at the time of this writing).
When I load your page, I see in the console "Loaded SwaggerUI"
three times over. That's your problem: SwaggerUI is loaded 3 times over.
So I did this:
I put a breakpoint over the line that prints out "Loaded SwaggerUI"
.
I reloaded.
When I hit the breakpoint, I took a snapshot of the elements that have the class resource
:
var snap1 = Array.prototype.slice.call(
document.getElementsByClassName("resource"))
(You have to copy the returned value to an Array
(with slice
here) because getElementsByClassName
returns a live collection.)
I hit the debugger's continue button.
When I hit the breakpoint again, I took a second snapshot (named snap2
).
Ok now for some tests. If the DOM has not changed, the elements should be identical:
> snap1[0] === snap2[0]
false
That does not look good. Let's see what's still in the DOM tree:
> document.contains(snap1[0])
false
> document.contains(snap2[0])
true
The element in the first snapshot is no longer in the tree but the one in the 2nd is.
The 2 second wait is enough to let Selenium start finding elements after the DOM has stabilized. However, when you tell Selenium to wait until there are visible elements of class resource
in the page, it waits until SwaggerUI is loaded for the first time. At some point when it is processing the elements it first finds, SwaggerUI loads another time and then the old elements that it found are no longer in the DOM tree. So it raises a StaleElementReferenceException
because the element it once found in the DOM tree is no longer there. It's been replaced by an element which is in the same location and structurally identical but Selenium wants the exact same element not an identical copy.