2

I am using WebDriver in Java.

I want to get all the amount values from the amount field below, so what I am planning to do it to loop throug each table row, and find if the check box is selected, set the amount to a number defined.

enter image description here

Example source code can be found here at: http://eric-lin.net/upload/index.php

I use the following Java method to find the amount field value:

public void fillInAllAmountForSelectedItems() {

    List<WebElement> allItems = driver
            .findElements(By
                    .xpath("//table[@id = 'bulkPaymentForm:itemTable']//tbody[@id = 'bulkPaymentForm:itemTable:tbody_element']//tr[contains(@class, 'handCursor row-border tranItemRow')]"));
    System.out.println(allItems.size());
    //return 3, expected

    waitTimer(2, 1000);

    for (WebElement item : allItems) {
        System.out.println(item.findElement(By.xpath("//td[4]"))
                .getAttribute("Value"));
    }       
}

Most of the time, the foreach loop will fail because of stale element exception. Which I don't understand because the DOM didn't change.

When it works, the foreach loop does not print anything so it looks like it doesn't locate the element correct.

How can I do to fix it, and what do I need to do to fulfill the purpose of this function to fill in amount value for all the checked items?

Thanks very much in advance.

2
  • Did you tried adding wait() function? try to execute in step by step (debug mode) if you are using eclipse Commented Nov 18, 2013 at 5:15
  • Note that the input field within the td will contain the amount, not the td itself. Commented Nov 18, 2013 at 5:54

2 Answers 2

3

Handling StaleElementException is usually a try retry till you succeed story. The DOM might refresh for several reasons causing the element to go stale.

A strategy sometimes used and often effective when working with list of elements is to obtain each item one by one. An excellent solution is posted here, sample code is as below.

You will need to construct the xpath /css selector to refer to the required table cell accordingly. Note that the value is to be retrieved from the amount input field from within the td - If you try to get the text from td it will be blank, like you see now.

//get the number of items that are required
int size = driver.findElements(By.cssSelector("table#mytable>tbody>tr>td[4]/input")).size();

//now work with each one individually, rather than with a list
for(int i = 1; i <= size; i++) {
    String locator = String.format("table#mytable>tbody>tr[%d]>td[4]/input", i);
    WebElement inputField = driver.findElement(By.cssSelector(locator));
    //get or set the value of the input element
    System.out.println(inputField.getAttribute("value"));
}
Sign up to request clarification or add additional context in comments.

5 Comments

Hi Faiz, your solution looks great but I can't seem to locate the amount field elements by the cssSelector. I replaced the id #mytable with the id of the payment table #bulkPaymentForm:itemTable and it is complaining about org.openqa.selenium.WebDriverException: An invalid or illegal string was specified.
I use xpath //table[@id = 'bulkPaymentForm:itemTable']//tbody//tr[%d]/td[4]/input" and it works, but I still want to know why the cssSelector doesn't work. Thanks
The : in your table id might be the culprit for the cssSelector to not work. The : has a specific meaning for css and is used to specify pseudo classes. See section 6.6 pseudo classes here.
Using the xpath, were you able to access the fields and get rid of the StaleElementException ?
I was able to retrieve the fields and get rid of the StaleElementException using xpath. Your solution overall is very good for me, thank you so much.
0

STALE happens because

your initial target (variable) made a local copy of how the HTML looks like. When the DOM changes(as an example you went to next page), it still carries the same initial state which is considered stale.

The Fix

The fix is really simple, all you have to do is retarget/ reassign that target again. This is considering that you have multiple pages and the same target HTML tag but you don't want to refresh the page everytime which is a waste of time. Sample of retargetting HTML Tag in a for loop

Example

I bet you guys must be using python, my apologies for dropping javascript code.

for (let x = 0; x <= totalPages; x++) {
  // Skip clicking the next page if x is 0 [first page]
  if (x > 0) {
    await driver
      .wait(
        until.elementLocated(By.xpath("input your next button xpath")),
        patience, // input your time in milliseconds
      )
      .click();

    // time taken to get to next page
    await driver.sleep(5000);
  }

  // this is your target, this will retarget everytime the loop runs
  const tableBody = await driver.wait(
    until.elementsLocated(By.tagName("tbody")),
    patience,
  );

  // write your other business logic as you like
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.