Stale element reference on button click

I am trying to iterate through a table and click on a certain button found on one of the rows of this table.
I do this by doing this:
String ExpectedValue = ‘CI: 47241111’
WebDriver driver = DriverFactory.getWebDriver()
WebElement Table = driver.findElement(By.id(‘GridContainerDiv’))
List Rows = Table.findElements(By.tagName(‘tr’))
println('No. of rows: ’ + Rows.size())
table: for (int i = 0; i < Rows.size(); i++) {
List Cols = Rows.get(i).findElements(By.tagName(‘td’))
for (int j = 0; j < Cols.size(); j++) {
println(Cols.get(i).getText())
if (Cols.get(j).getText().equalsIgnoreCase(ExpectedValue)) {
WebUI.delay(3)
Cols.get(1).findElement(By.tagName(‘img’)).click()
break;
}
}
}
The problem with this is that it throws the next error:
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document

I try to solve this problem by waiting for the element to be visible but this is not working either. It throws the next error:
No signature of method: static com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords.waitForElementVisible() is applicable for argument types: (org.openqa.selenium.remote.RemoteWebElement, java.lang.Integer, com.kms.katalon.core.model.FailureHandling) values: [[[[[[[[[CChromeDriver: chrome on XP (afbc4a2b4b73efefff11b16b9b731b20)] → id: GridContainerDiv]] → tag name: tr]] → tag name: td]] → tag name: img], …]

This is the html surrounding the button in the table:

The error message is clear: No signature = There is not such funcion wait for Element visible WITHOUT timeout. Just add the timeout in seconds as a second parameter and at least you won’t have this error message.
As a reminder when you mouse over a command, the prototype is showing up… image
Good luck

waitForElementVisible expects TestObject as parameter, and not RemoteWebElement

So I think you are right. I do it like this:
WebUI.waitForElementVisible(Cols.get(1).findElement(By.tagName(‘img’)), 30, FailureHandling.STOP_ON_FAILURE)
I think Cols.get(1).findElement(By.tagName(‘img’)) is a web element.
How can I solve this? how can i transform it into a test object?

You can create a TestObject, then use it call :
WebUI.waitForElementVisible(findTestObject('your/object/path'), 5)
https://docs.katalon.com/katalon-studio/docs/manage-test-object.html#create-a-test-object

Or script the object

TestObject to = new TestObject()
String objectXpath = "//tr//td//img"
to.addProperty("xpath", ConditionType.EQUALS, objectXpath)

then WebUI.waitForElementVisible(to, 5)

Edit : you can also see this post to convert into TestObject :

2 Likes

Yes I saw that post and I was trying to do something similar but I always get the same error:
groovy.lang.MissingPropertyException: No such property: ConditionType for class: Script1561476909579

Do I need to import something extra? Am I missing something?

Press Ctrl + Shift + O to add imports or add
import com.kms.katalon.core.testobject.ConditionType

1 Like

This is working in a very WEIRD way because my code finds the button clicks it and then waits for the button to appear so I enter the page I need to enter and then try to wait for the element I need to click.

This is the code:

if (Cols.get(j).getText().equalsIgnoreCase(ExpectedValue)) {
WebUI.delay(3)
TestObject to = new TestObject()
String objectXpath = “//div/table/tbody/tr/td[2]/img”
to.addProperty(“xpath”, ConditionType.EQUALS, objectXpath)
WebUI.waitForElementVisible(to, 30)
WebUI.delay(3)
Cols.get(1).findElement(By.tagName(‘img’)).click()
break;
}
,
This is the log with the error:

2019-07-01 11:56:56.849 DEBUG testcase.ModificarOrden(No terminado) - 2: if (getText().equalsIgnoreCase(ExpectedValue))
2019-07-01 11:56:56.870 DEBUG testcase.ModificarOrden(No terminado) - 1: delay(3)
2019-07-01 11:56:59.873 DEBUG testcase.ModificarOrden(No terminado) - 2: to = new com.kms.katalon.core.testobject.TestObject()
2019-07-01 11:56:59.874 DEBUG testcase.ModificarOrden(No terminado) - 3: objectXpath = “//div/table/tbody/tr/td[2]/img”
2019-07-01 11:56:59.875 DEBUG testcase.ModificarOrden(No terminado) - 4: to.addProperty(“xpath”, EQUALS, objectXpath)
2019-07-01 11:56:59.876 DEBUG testcase.ModificarOrden(No terminado) - 5: waitForElementVisible(to, 30)
2019-07-01 11:57:31.924 INFO c.k.k.c.webui.common.WebUiCommonHelper - Unable to find the element located by ‘By.xpath: //div/table/tbody/tr/td[2]/img’. Please recheck the objects properties to make sure the desired element is located.
2019-07-01 11:57:31.945 WARN k.k.c.w.k.b.WaitForElementVisibleKeyword - Web element with id: ‘’ located by ‘By.xpath: //div/table/tbody/tr/td[2]/img’ not found
2019-07-01 11:57:31.947 DEBUG testcase.ModificarOrden(No terminado) - 6: delay(3)
2019-07-01 11:57:34.951 DEBUG testcase.ModificarOrden(No terminado) - 7: tagName(“img”)).click()
2019-07-01 11:57:35.007 ERROR c.k.katalon.core.main.TestCaseExecutor -Test Cases/ModificarOrden(No terminado) FAILED.
Reason:
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document

Try change your xpath, you can also use WebUI.click(to) at the end

Hello again
As I keep having a stale element reference exception I tried a different approach
I saw on other forums that I can do something like this:
public boolean retryingFindClick(By by) {
boolean result = false;
int attempts = 0;
while(attempts < 2) {
try {
driver.findElement(by).click();
result = true;
break;
} catch(StaleElementException e) {
}
attempts++;
}
return result;
}
So I adapted that to my very own test case and did something liike this:
println('No. of rows: ’ + Rows.size())
table: for (int i = 0; i < Rows.size(); i++) {
List Cols = Rows.get(i).findElements(By.tagName(‘td’))
for (int j = 0; j < Cols.size(); j++) {
println(Cols.get(i).getText())
if (Cols.get(j).getText().equalsIgnoreCase(ExpectedValue)) {
int count = 0;
boolean clicked = false;
while (count < 3 || !clicked){
try {
Cols.get(1).findElement(By.tagName(‘img’)).click()
clicked = true;
} catch (StaleElementReferenceException e){
e.toString();
System.out.println(“Trying to recover from a stale element :” + e.getMessage());
count = count+1;
}
}
}
}
}
The thing is that I get this error:
org.openqa.selenium.ElementClickInterceptedException: element click intercepted
Do you have any suggestions on how to resolve this? I dont seem to find any solution in the web

See this doc, #4 : you can try use javascript


If it doesn’t work, it’s because the object detected is not the good one

Just as an FYI, the most common reason for a StaleElementReferenceException is that you’ve:

1.) Located an element and have a reference to it, like so:

WebElement element = driver.findElement(…);

2.) Before you do anything with this element reference (clicking on it, finding another element relative to this one, etc.), the element gets updated in the DOM. Maybe an attribute is changed, or the node is removed altogether.

3.) When you then go and try and do something with the element, WebDriver notices that it has changed in some way, making your reference to it “stale”.

I noticed that in your code, you are trying to find an element relative to another, already located element:

Cols.get(1).findElement(By.tagName(‘img’)).click()

And this is the part that is giving you trouble, according to your error log:

2019-07-01 11:57:34.951 DEBUG testcase.ModificarOrden(No terminado) - 7: tagName(“img”)).click()
2019-07-01 11:57:35.007 ERROR c.k.katalon.core.main.TestCaseExecutor -Test Cases/ModificarOrden(No terminado) FAILED.
Reason:
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document

In my experience, you should try to avoid finding one element relative to another one that has been located already, exactly for the reason that it often leads to a StaleElementReferenceException. It’s much better if you can find the element once, using a better locator in the first place.

Also, your waitForElementVisible() call didn’t work either:

2019-07-01 11:57:31.945 WARN k.k.c.w.k.b.WaitForElementVisibleKeyword - Web element with id: ‘’ located by ‘By.xpath: //div/table/tbody/tr/td[2]/img’ not found

Can you share the HTML of the table, and highlight which button you are trying to click? From what I can gather, you are trying to check a column name, then click a button in that column. Is that correct?

“From what I can gather, you are trying to check a column name, then click a button in that column. Is that correct?” This is exactly what I am trying to do.
To get to this solution I followed this tutorial:
Example 2: https://docs.katalon.com/katalon-studio/docs/handle_web_tables.html#example-2you-want-to-perform-actions-on-the-web-table-below

Html of table:

@Brandon_Hein

It would be a crying shame (if not a crime) if that post isn’t the beginnings of a new Tips&Tricks post…

How To Avoid StaleElementReferenceException

1 Like

I think you may be right :wink: I’ll see if I can carve out some time today.

Ok we do this kind of thing all the time. The below code is assuming that:

1.) The number of columns in the “header” row of the table is always equal to the number of columns in the body of the table.

2.) The button you want to click exists in the first row. If you want to change this, you will need to change the index in the tr[] part of the xpath used below.

WebDriver driver = DriverFactory.getWebDriver();
List<WebElement> elements = driver.findElements(By.xpath("//table[@id='GridContainerTbl']//thead//th"));
for(WebElement element : elements) {
   if(element.getAttribute("textContent").trim().equals(ExpectedValue) {
      int columnIndex = elements.indexOf(element);
      WebElement buttonToClick = driver.findElement(By.xpath("//table[@id='GridContainerTbl']//tbody//tr[1]//td[" + columnIndex + "]//img")); 
      buttonToClick.click();
      break;
   }
}

The idea behind this is to first find the column header element that contains your expected text, get its index from within the set of all headers, then use that index in your search for the row/column that contains your button.

First of all, thanks to all of you for the help !
Second of all, I tried all of your solutions and the best thing for me was doing this:
TestObject to = new TestObject()
String objectXpath = “//div/table/tbody/tr/td[2]/img”
to.addProperty(“xpath”, ConditionType.EQUALS, objectXpath)
WebUI.waitForElementVisible(to, 30)
WebUI.click(to)
I tried various approaches but this was what worked for me.

2 Likes