Problem: Using Selenium Java I want to automate a table that contains a price list and a price calculator
Another little problem: I can't click on the "Analysis" (Filter) button, because I have to double-click, which I could do in this case
What I want: I'm trying to find a method so that when I run the program, the program will click on another analysis (on another + button) Now with the help of a selector, I can only click on the first (+). But I want each time, the program to test, randomly other analyzes (other buttons +).
What I do
#FindBy(xpath = "//*[#id='footable_501']/thead/tr[2]/th[1]")
WebElement analizaSort;
#FindBy(xpath = "//*[#id='footable_501']/thead/tr[2]/th[2]")
WebElement pretSort;
#FindBy(xpath = "//*[#id='calculator']/div[1]/div[2]/div[2]")
WebElement total;
public void checkCalculator()
{
add.click();
add2.click();
}
public void checkFilter()
{
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollBy(0,500)"); //Scroll vertically down by 1000 pixels
analizaSort.click();
analizaSort.click();
pretSort.click();
}
Link: https://www.poliana.ro/analize-preturi/
I've added below the code to click on a random analyze and to calculate the total:
#FindBy(css = "th.footable-sortable[class*='pret']") // css locator is faster than xpath
WebElement pretSort;
#FindBy(css = "th.footable-sortable[class*='analiza']")
WebElement analizaSort;
#FindBy(css = "tr[class*='row'] td[class*='pret']")
List<WebElement> analyzePriceList;
#FindBy(css = "#calculator .total .right")
WebElement total;
public void checkCalculator() {
int elementListSize = analyzePriceList.size();
assertTrue("No analyze was found in the table", elementListSize != 0); // replace here with the specific of your testing framework
int elementIndex = getRandomNumber(elementListSize - 1);
scrollElementToTheMiddle(analyzePriceList.get(elementIndex));
int expectedTotal = getTextAsInt(analyzePriceList.get(elementIndex));
analyzePriceList.get(elementIndex).click();
String totalAsString = total.getText().replace("lei", "");
int actualTotal = getInt(totalAsString);
assertEquals(expectedTotal, actualTotal);
}
public void checkFilter() {
scrollElementToTheMiddle(analizaSort);
analizaSort.click();
analizaSort.click(); // if you need double click, please see the below method
pretSort.click();
}
private void doubleClick(WebElement element) {
Actions act = new Actions(driver);
act.doubleClick(element).build().perform();
}
private int getTextAsInt(WebElement element) {
String text = element.getText();
return getInt(text);
}
private int getInt(String text) {
assertTrue("The " + text + " text was expected to be numeric", isNumeric(text)); // replace here with the specific of your testing framework
return Integer.parseInt(text);
}
private boolean isNumeric(String possibleNumberAsString) {
Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?\n");
if (possibleNumberAsString == null) {
return false;
}
return pattern.matcher(possibleNumberAsString.trim()).matches();
}
private int getRandomNumber(int maximum) {
return ThreadLocalRandom.current().nextInt(0, maximum);
}
private void scrollElementToTheMiddle(WebElement element) {
String scrollElementIntoMiddle = "var viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);"
+ "var elementTop = arguments[0].getBoundingClientRect().top;"
+ "window.scrollBy(0, elementTop-(viewPortHeight/2));";
((JavascriptExecutor) driver).executeScript(scrollElementIntoMiddle, element);
}
Currently I am going through a situation. There are three rows in a the body of the table. I have to perform some action on each row if row matches with a text. For this I am getting the size for the the rows and using for loop and checking the condition. When condition are met, I have to perform some action by which the row is getting removed from the webtable which is as per my expectations. Further, I am getting org.openqa.selenium.StaleElementReferenceException: here "totalOrders.get(i).click();" when the loop try to perform action in next row here
here is some part of my code:
By loading = By.xpath("//div[#class='loading-wrap']");
By orders = By.xpath("//tbody/tr"); //this retruns 3 row
public void invoiceAllStockOrder() {
eu.waitForInvisibilityOfElementLocated(loading, 10);
List<WebElement> totalOrders = eu.getElements(orders);
int rowSize =totalOrders.size();
if(rowSize == 0) {
System.out.println("No order");
}
else {
for (int i = 0; i < totalOrders.size(); i++) {
eu.waitForInvisibilityOfElementLocated(loading, 10);
totalOrders.get(i).click();//getting stale element exception here when i = 1 but there are still 2 rows left
selectInstockOrders();
invoiceOrder();
}
}
}
If the page has Javascript which automatically updates the DOM,
you should assume a StaleElementException will occur.
Can you try with the below code, I hope this will work for you
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;
}
This will attempt to find and click the element. If the DOM changes
between the find and click, it will try again.
can someone please help me with this.
Task: Open ListView element in Android App, scroll to specific position and click on it. If element wasn't found, than scroll to the bottom of the list and stop to search and drop the test with exception.
//Yes, I have been looking for a solution on other questions, but I can't combine then to use in my case.
What did i get:
1) Test swipes inside ListView to specific position and clicks on it;
2) Test stacks in loop in the bottom of ListView.
Questions:
1) How to stop test with exception if specific position wasn't found when the bottom of ListView was reached?
2) Swipe looks like incorrect solution and seems there must be used another solution, or no?
code:
public void scrollToElementFromList (String keyword_locator){
// keyword_locator = (By.xpath("//*[#resource-id = 'android:id/text1'][#text = 'Spain']"))
boolean token = false;
while(!token) {
if (this.isElementPresent(keyword_locator)){
waitForElementAndClick(keyword_locator,"Cannot click selected element",3);
token = true;
} else {
TouchAction action = new TouchAction(driver);
WebElement element = driver.findElement(By.xpath("//android.widget.ListView"));
int middleX = element.getLocation().getX() + element.getSize().getWidth() / 2;
int upperY = element.getLocation().getY();
int lowerY = upperY + element.getSize().getHeight() - 50;
action.press(middleX, lowerY).waitAction(1200).moveTo(middleX, upperY).release().perform();
continue;
}
}
}
answer:
public void scrollToElementFromList (String locator, String keyword_locator, int max_swipes){
By by = this.getLocatorByString(locator);
boolean element_found = false;
int already_swiped = 0;
while(!element_found) {
if (this.isElementPresent(keyword_locator)){
waitForElementAndClick(keyword_locator,"Cannot click selected element",3);
element_found = true;
} else if (already_swiped > max_swipes){
throw new AssertionError("Cannot find element by swiping up.");
}
else {
TouchAction action = new TouchAction(driver);
WebElement element = driver.findElement(by);
int middleX = element.getLocation().getX() + element.getSize().getWidth() / 2;
int upperY = element.getLocation().getY();
int lowerY = upperY + element.getSize().getHeight() - 50;
action.press(middleX, lowerY).waitAction(1200).moveTo(middleX, upperY).release().perform();
++already_swiped;
continue;
}
}
}
This is my code when I run it goes to the 2nd page and stop it not looping all pages and search the required element. It should look for particular text in a page and click on the link of it.
if (driver.getTitle().contains("Article properties")) {
WebElement assigninitial = driver.findElement(By.partialLinkText("Assign reviewer for initial review"));
assigninitial.click();
} else {
//pagination code
//driver.findElement(By.xpath("/html/body/app/main/app-mytasks/div[1]/section/div/pagination/ul/li[3]/a")).click();
#SuppressWarnings("unchecked")
ArrayList<WebElement> pagination = (ArrayList<WebElement>) driver.findElements(By.xpath("/html/body/app/main/app-mytasks/div[1]/section/div/pagination/ul/li[5]/a"));
// checkif pagination link exists
if ((pagination).size() > 0) {
//System.out.print("pagination exists");
// click on pagination link
for (int i = 0; i < pagination.size(); i++) {
pagination.get(i).click();
if (driver.getPageSource().contains("Article properties")) {
WebElement assigninitial = driver.findElement(By.partialLinkText("Assign reviewer for initial review"));
assigninitial.click();
}
}
} else {
System.out.print("pagination not exists");
}
}
public void pagination_check() throws InterruptedException {
loader_wait(5); //wait until 'loader' loading
List<WebElement> pagination = driver.findElements(By.xpath("//page-navigation/div/div/span/a"));
Thread.sleep(5000);
if (pagination.size() > 0) {
System.out.println("pagination exists and size=>"+pagination.size());
int page_no=pagination.size();
for (int i = 2; i <= pagination.size(); i++) {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].scrollIntoView();", driver.findElement(By.xpath("//page-navigation/div/div/span"))); //for
scroller move
js.executeScript("arguments[0].click();", driver.findElement(By.xpath("//page-navigation/div/div/span/a["+i+"]")));
loader_wait(5); //wait
}
} else {
System.out.println("no pagination");
}
}
I get this error when running my tests:
org.openqa.selenium.StaleElementReferenceException: Element is no longer attached to the DOM
any idea on how to solve the above exception?
this happen in my grid
which has a ref Xpath expression which is dynamic
I ran across this same problem and could not find any solutions. Came up with a solution and posting it here, hope this helps someone with the same problem. I created a class to handle stale elements depending on their type, cssselector, id, etc and simply call it like I would any other page object.
public void StaleElementHandleByID (String elementID)
{
int count = 0;
boolean clicked = false;
while (count < 4 && !clicked)
{
try
{
WebElement yourSlipperyElement= driver.findElement(By.id(elementID));
yourSlipperyElement.click();
clicked = true;
}
catch (StaleElementReferenceException e)
{
e.toString();
System.out.println("Trying to recover from a stale element :" + e.getMessage());
count = count+1;
}
}
}
I'd recommend only using this on elements you know cause problems for WebDriver.
We get around this issue by doing something called WebdriverWrapper and WebElementWrapper.
What these wrappers do is handle the StaleElementException within and then use the locator to re-evaluate and get the new WebElement object. This way, you need to spread the code handling the exception all over your codebase and localize it to one class.
I will look into open sourcing just these couple of classes soon and add a link here if you folk are interested.
That exception is thrown when you try to use a method of a WebElement that is not longer on the page. If your grid is dynamically loading data and you refresh the grid, any references to elements on that grid would be 'stale'. Double check that the element you're trying to reference is on the page in your tests, and you may need to re-instantiate the object.
It also encountered this issue, It looks very obvious the modal panel loading falls into a race condition and keeps waiting till time out.
I have tried many times, and found the solution is to hold the modal panel loading till it can be exactly found by webDriver and at the same time keep refresh the webDriver instance , then try to find WebElements within the modal panel.
So the solution is like follows:
e.g. MyModalPanel is your ModalPanel Id, then do the following
page.openModalPanel();
Assert.assertTrue(page.waitTillDisplay( "MyModalPanelContentDiv"), Wait.MODAL_PANEL));
page.fillInFormInModalpanel(formObj);
and the waitTillDisplay code can be found on WebDriver website, I will just paste my code here for your reference:
public Boolean waitTillDisplay(final String id, int waitSeconds){
WebDriverWait wait = new WebDriverWait(driver, waitSeconds);
Boolean displayed = wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return driver.findElement(By.id(id)).isDisplayed();
}
});
return displayed;
}
You might be trying to get any of element properties after clicking an element.
I had the same issue, I was trying to getText() of button after it was clicked. In my case, once button is clicked, new window comes.
I used a FluentWait and also the ExpectedCondition apply override: https://gist.github.com/djangofan/5112655 . This one handles the exception inside the finalized block, unlike how other people answer this, and allows the successive tries to be wrapped in that block. I think this is more elegant.
public static void clickByLocator( final By locator ) {
final long startTime = System.currentTimeMillis();
driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(90000, TimeUnit.MILLISECONDS)
.pollingEvery(5500, TimeUnit.MILLISECONDS);
//.ignoring( StaleElementReferenceException.class );
wait.until( new ExpectedCondition<Boolean>() {
#Override
public Boolean apply( WebDriver webDriver ) {
try {
webDriver.findElement( locator ).click();
return true;
} catch ( StaleElementReferenceException e ) { // try again
return false;
}
}
} );
driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
log("Finished click after waiting for " + totalTime + " milliseconds.");
}
public static Boolean executeElementSendKeys
(WebDriver driver, WebElement element, String sInputParameters) throws Exception {
return (Boolean) executeElementMaster
(driver, element, "sendKeys", sInputParameters, 30, true);
}
public static Boolean executeElementClear
(WebDriver driver, WebElement element) throws Exception {
return (Boolean) executeElementMaster (driver, element, "clear", "", 30, true);
}
public static String executeElementGetText
(WebDriver driver, WebElement element) throws Exception {
return (String) executeElementMaster (driver, element, "getText", "", 30, true);
}
public static Boolean executeElementClick
(WebDriver driver, WebElement element) throws Exception {
return (Boolean) executeElementMaster (driver, element, "click", "", 30, true);
}
public static boolean executeElementIsDisplayed
(WebDriver driver, WebElement element) throws Exception {
return (Boolean) executeElementMaster (driver, element, "isDisplayed", "", 30, true);
}
public static String executeElementGetAttribute
(WebDriver driver, WebElement element, String sInputParameters) throws Exception {
return (String) executeElementMaster
(driver, element, "getAttribute", sInputParameters, 30, true);
}
// And below is the master method that handles the StaleElementReferenceException and other exceptions.
// In the catch section, replace (Exception e) with (StaleElementReferenceException e) if you want this method to retry actions (like click, sendkeys etc.) for only StaleElementReferenceException and not other exceptions.
private static Object executeElementMaster(WebDriver driver, WebElement element, String sExecuteAction, String sInputParametersOptional, int MaxTimeToWait,
boolean bExpectedElementState) throws Exception {
try {
// Local variable declaration
String sElementString = "";
String sElementXpath = "";
Object ReturnValue = "";
int Index = 0;
boolean bCurrentElementState = true;
boolean bWebDriverWaitUntilElementClickableFlag = false;
System.out.println("**** Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Expected : '" + bExpectedElementState + "'");
System.out.println("**** MaxTimeToWait ='" + MaxTimeToWait + "' seconds");
// Set browser timeout to 1 second. Will be reset to default later
driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
// Keep trying until 'MaxTimeToWait' is reached
for (int i = 0; i < MaxTimeToWait; i++) {
try {
// Get element xPath - and find element again
if (element != null && i < 2 && sElementString == "") {
sElementString = (element).toString();
if (sElementString.contains("xpath: ")) {
// Retrieve xPath from element, if available
Index = sElementString.indexOf("xpath: ");
sElementXpath = sElementString.substring(Index + 7, sElementString.length());
}
}
// Find Element again
if (sElementXpath != "" && i > 0) {
element = driver.findElement(By.xpath(sElementXpath));
}
// Execute the action requested
switch (sExecuteAction) {
case ("isDisplayed"):
// Check if element is displayed and save in bCurrentElementState variable
ReturnValue = element.isDisplayed();
bCurrentElementState = (Boolean) ReturnValue;
bWebDriverWaitUntilElementClickableFlag = true;
break;
case ("getText"):
ReturnValue = element.getText();
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
case ("sendKeys"):
// Scroll element into view before performing any action
element.sendKeys(sInputParametersOptional);
ReturnValue = true;
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
case ("clear"):
// Scroll element into view before performing any action
element.clear();
ReturnValue = true;
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
case ("click"):
// Scroll element into view before performing any action
element.click();
ReturnValue = true;
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
default:
ReturnValue = element.getAttribute(sInputParametersOptional);
bCurrentElementState = true;
break;
}
} catch (Exception e) {
Thread.sleep(500);
bCurrentElementState = false;
ReturnValue = false;
}
if (bCurrentElementState == bExpectedElementState) {
// If element's actual and expected states match, log result and return value
System.out.println("**** PASSED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' **** \n"
+ "Actual element status: '" + bCurrentElementState + "' Expected element status: '" + bExpectedElementState + "'");
break;
} else {
// If element's actual and expected states do NOT match, loop until they match or timeout is reached
Thread.sleep(500);
}
}
// Reset browser timeout to default
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// Return value before exiting
if (bCurrentElementState != bExpectedElementState) {
// If element's actual and expected states do NOT match, log result and return value
System.out.println("**** FAILED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' **** \n"
+ "Actual element status: '" + bCurrentElementState + "' Expected element status: '" + bExpectedElementState + "'");
if (sExecuteAction.equalsIgnoreCase("findElement")) {
ReturnValue = null;
}
}
return ReturnValue;
} catch (Exception e) {
System.out.println("Exception in executeElementMaster - " + e.getMessage());
throw (e);
}
}
I made some changes to be more flexible:
delegate void StaleFunction(IWebElement elt);
private static void StaleElementHandleByID(By by, StaleFunction func )
{
int count = 0;
while (count < 4)
{
try
{
IWebElement yourSlipperyElement = Driver.FindElement(by);
func(yourSlipperyElement);
count = count + 4;
}
catch (StaleElementReferenceException e)
{
count = count + 1;
}
}
}
StaleElementHandleByID(By.Id("identDdl"),
delegate(IWebElement elt)
{
SelectElement select = new SelectElement(elt);
select.SelectByText(tosave.ItemEquipamentoCem.CodigoCne.ToString());
});
a quick & dirty solution:
el.click()
time.sleep(1)
then continue to parse in iteration way
In this case, the tests are looking for an element that is not yet loaded, or has been refreshed. As a result, the StaleElementException. A simple solution would be to add a fluentWait.
#netz75 : Thank you. Had this problem when a click redirects to second page.
This worked for me:
//.. (first page asserts)
//...
element.Click();
Thread.Sleep(200);
//.. (second page asserts)
//...