Cached elements do not exist in DOM anymore - java

Like in similar issue, I use appium + java. Trying to select elements
In mobile application I am go to page, and after that, have many elements android.widget.ImageView(0), I need to select 6 (for example) such elements and go with other steps. Byt can select only one element and then get such exception:
org.openqa.selenium.StaleElementReferenceException: Cached elements 'By.id: com.company:id/selector_view' do not exist in DOM anymore
public GalleryPage choosePhotosFromAlbum(int count) {
List<MobileElement> photos = driver.findElementsById(elements.get("photo from gallery album selector"));
for (int i = 0; i < count; i++) {
photos.get(i).click();
}
return new GalleryPage(device);
}

I had the same issue. I think this happens because every time you click on a photo, the DOM changes. So, when you try to click on the second photo, the cached elements are not on the DOM anymore.
Try putting the photos inside the for cycle, like this:
public GalleryPage choosePhotosFromAlbum(int count) {
for (int i = 0; i < count; i++) {
List<MobileElement> photos = driver.findElementsById(elements.get("photo from gallery album selector"));
photos.get(i).click();
}
return new GalleryPage(device);
}
This way the list of photos is retrieved from the refreshed DOM on every cycle.
And by the way, you're not checking if the count is bigger than the photos list size, which can result in an OutOfBounds exception or similar.

You can use explicit wait to solve this problem.
public GalleryPage choosePhotosFromAlbum(int count)
{
List<MobileElement> photos = driver.findElementsById(elements.get("photo from gallery album selector"));
for (int i = 0; i < count; i++)
{
new WebDriverWait(driver,10).until(ExpectedConditions.presenceOfAllElementsLocatedBy("Your object property"));
photos.get(i).click();
}
return new GalleryPage(device);
}

Try enableMultiWindows appium capability set to true https://github.com/appium/appium/blob/master/docs/en/advanced-concepts/settings.md
Or you can try finding elements via WebDriverWait. In Appium (C#), when the driver tries to find native elements, it can sometimes throw a StaleElementReferenceException. Thus you can ignore this exception and wait until elements exist in DOM:
public ReadOnlyCollection<IWebElement> WaitElements(By selector)
{
var wait = new WebDriverWait(this.Driver, new TimeSpan(0, 0, 10));
ReadOnlyCollection<IWebElement> results = null;
try
{
wait.Until(driver =>
{
try
{
var elements = driver.FindElements(selector);
if (elements.Any())
{
results = elements;
return true;
}
}
catch (StaleElementReferenceException)
{
// ignore
}
return false;
});
}
catch (WebDriverTimeoutException)
{
throw new NoSuchElementException("Elements not found");
}
return results;
}

Related

Below code is not woking with Chrome browser

I have created a reusable function which clicks the check box of a particular row and returns the text of that row.
CheckBoxXpath-> private static final String XPATH_JOBRATECATEGORIES_CHECKBOX_LIST = "//kendo-grid-list//table/tbody/tr/td[1]/label";
RowXpath -> private static final String XPATH_JOBRATECATEGORIES_LIST = "//kendo-grid-list//table/tbody/tr/td[2]//div//div";
count-> 0 (I want to click only first row check box)
public String Select_CheckBox_Return_SelectedText(String CheckBoxXpath,String RowXpath, int Count) {
List<WebElementFacade> listOfCheckBox = findAll(By.xpath(CheckBoxXpath));
List<WebElementFacade> listOfrow = findAll(By.xpath(RowXpath));
if(listOfCheckBox.size()>Count) {
for (int i = 0; i <= Count; i++) {
listOfCheckBox.get(i).click();
String Actual=listOfrow.get(i).getText();
}
}else {
Assert.fail("Need to have more rows to fullfill the requirement");
return null;
}
return Actual;
}
This is working fine with Firefox browser, but not working with Chrome browser.
On debugging code is throwing exception on -> "listOfCheckBox.get(i).click();"
I am not able to understand why it is behaving so weired.
Need help. Thanks in advance.
You need to target the checkboxes, not the labels in your xpath:
//kendo-grid-list//table/tbody/tr/td[1]/input[#type='checkbox']

StaleElementReference Exception with Webdriver using firefox v57

Using the following code I keep getting a StaleElementReference Exception when running my Webdriver scripts on firefox v57. I have tried all sorts of things but other than a thread.sleep or catching the exception and retrying I cannot get it to work.
public List<String> readCoIData (String column) throws StaleElementReferenceException
{
int colNumber 0;
WebTable searchResuIts = getTable();
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
wait.pollingEvery(250, TimeLinit.MILLISECONDS);
wait.with Timeout (30, TimeLlnit.SECONDS);
wait.ignoring (NoSuchElementException.class) ;
CustomLogger.addInfo(Logger, "Ensure that that the first column row contains text: " column ) ;
int colcount = searchResults.getColumnCount();
CustomLogger. addlnfoLog4jOnly (logger , "colcount= " colcount )
for (int col =1; col <= colcount; col++)
{
CustomLogger.addInfoLogJOnly(Logger, "Get the cell data for col. Use a string as this does not go stale unlike a reference.'
String locator = String.format("pf_table_t2 > tbody:nthchild(1) > tr:nth-child(1) > td:nth-child(%d)", col);
wait.until(ExpectedConditions.presenceOfElementLocated(By. cssSelector (locator))) ;
if (driver.FindElement(By.cssSelector(locator)).getText().contains (column))
{
colNumber = Col;
}
}
CustomLogger.addInfoLogJOnly(Logger, "Assert that there is not 0 columns");
assertThat (column + " not found' , colNumber !=0, is (true));
List<String> colvalues = new ArrayList<String>();
CustomLogger.addInfoLogJOnly(Logger, "Get the object .pf_paging a");
List<WebElement) paging = driver.findElements(By.cssSelector(.pf_paging a));
if (paging.size() !=0)
{
CustomLogger.addlnfoLogJOnly ( logger , "If more than one result page, wait..." );
wait.until(ExpectedConditions.visibilityOf((WebElement driver.findElement(By.cssSelector(".pf_paging_next_active"))));
CustomLogger.addInfoLogJOnly(Logger, "Span with '>>' is found so loop through all pages and get the data");
while (driver.findElements(By.cssSelector(".pf_paging_next_active")). size() == 1)
{
for (int i=2; i<=searchResults.getRowCount(); i++)
{
String locator = String.format("pf_table_t2 > tbody:nthchild(1) > tr:nth-child(%d) > td:nth-child(%d)", I, colNumber); col);
String cell Text = driver.findElement(By.cssSelector(locator)).getText();
colvalues.add(cellText);
}
CustomLogger.addInfoLogJOnLy(Logger, "Click the Next Page Button ' to move onto next page and wait for the page to be visible.'
driver.findElements(By.cssSelector(.pf_paging_next_active a").click();
CustomLogger.addInfoLogJ0nly(Logger, "Get & Wait for table after clicking next");
// Get the element table again as we have clicked 'filter' and the DOM would have changed.
searchResults.getTable();}
public WebTable getTable()
{
CustomLogger.addInfoLog450nLy(Iogger, "Wait and get the element table again as we have previously clicked 'filter' and the DOM would have changed");
new WebDriverWait(driver, 30).until((ExpectedConditions<Boolean> driver -> ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"));
FluentWait(WebDriver» wait new
wait.pollingEvery(250, TimeLinit.MILLISECONDSS);
wait.with Timeout(30, TimeLlnit.SECONDS);
wait.ignoring (NoSuchEIementException.class) ;
CustomLogger.addInfo(Logger, "Wait until the results table is present..
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("pf_table_t2"))));
CustomLogger.addInfo(Logger, "Get the results table");
SearchResuItsTable = driver.FindElement(By.cssSelector("pf_table_t2"));
WebTabIe searchResuIts = new WebTable(SearchResultsTabIe);
return searchResuIts;
}
Essentially the page has some filter criteria and a results table with results in blocks of 10 rows, to get each new set you have to click >. i.e. the page changes.
I get StaleElement exception in two places, the first happens getting the text at the locator (then setting colNumber = Col). The 2nd happens adding celltext to the colValues array.
In both places I have only just got the element again. Any help would be appreciated. Thanks in advance.
Note I don't get this with the Chrome browser.
Just to give you a brief (if you are not aware already)
StaleElementReferenceException happens because location of the webelement on the webpage (more preciously on the DOM) has changed due some ajax or similar reason. Coincidentally this happens exactly between you capturing the webelement and performing the action on the webelement.
For Example:
//Getting the webelement
WebElement element = driver.findElement(By.id("id_value"));
//Location of the webelement changes between these two steps.
//Click on the webelement
element.click();
One of the ways to handle the StaleElementReferenceException is to catch the exception at the place where it happens and handle it by re-initializing the webelement.
For example:
try {
WebElement element = driver.findElement(By.id("id_value"));
element.click();
} catch (StaleElementReferenceException e) {
Thread.sleep(3000);
WebElement element = driver.findElement(By.id("id_value"));
element.click();
}
There are also others ways to handle the StaleElementReferenceException. You can refer this link.
Better and cleaner way to handle StaleElementReferenceException is to make method for action that you are trying to perform.
For Example:
If you want click on a webelement.
public static void click(By by) throws Exception {
try {
driver.findElement(by).click();
} catch(StaleElementReferenceException staleElement) {
Thread.sleep(3000);
driver.findElement(by).click();
} catch (Exception e) {
e.printStacktrace();
}
}
Similarly you can create other methods.

Load multiple bitmaps in Android Studio one at time with threads

I'm currently working on a project which takes pictures from camera and saves the photoPath in a Database, this is working fine and actually I'm handling the memory correctly generating thumbnails when I load all images.
The thing I want is that I'm trying to dedicate threads to go loading images one per one in the layout, because for example, if I have 50, with normal load it shows the layout until all 50 are loaded, meanwhile it doesn't show anything.
I've already tried to implement this threads to load one, and then another one, but it's the same, until it loads all, it shows all, here my code:
String query = "Select id_reg_mem, information from Memory_REG where type = 'PHOTO' and id_memory =" + id_memory;
final Cursor resultado = memoryDB.rawQuery(query, null);
if(resultado.moveToFirst())
noPhotos = resultado.getCount();
for(int i=0; i<noPhotos; i++)
{
new Thread()
{
public void run()
{
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
updateNewPhoto(resultado.getString(1)); // I send the path from the DB to a method I made to add a tablerow with the image (inside an imageview)
}
});
}
}.start();
if(i + 1 == noPhotos)
break;
resultado.moveToNext();
}
Here this method, where I'm loading a single image to an ImageView inside a TableRow. This method is actually working to load all images from DB.
protected void updateNewPhoto(String path)
{
ImageView iv;
if(rows == null) {
rows = new ArrayList<TableRow>();
rows.add(new TableRow(TL.getContext()));
iv = new ImageView(TL.getContext());
iv.setLayoutParams(new TableRow.LayoutParams(250,250));
iv.setTag(DB_Utils.maxIDRegMem(memoryDB) - 1);
iv.setImageBitmap(getBitmapThumbnail(path));
rows.get(0).addView(iv);
TL.addView(rows.get(0));
count = 2;
}
else
{
iv = new ImageView(TL.getContext());
iv.setLayoutParams(new TableRow.LayoutParams(250,250));
iv.setTag(DB_Utils.maxIDRegMem(memoryDB) - 1);
iv.setImageBitmap(getBitmapThumbnail(path));
if(count == 2)
{
rows.get(rows.size() - 1).addView(iv);
count = 1;
}
else
{
rows.add(new TableRow(TL.getContext()));
rows.get(rows.size() - 1).addView(iv);
TL.addView(rows.get(rows.size() - 1));
count = 2;
}
}
Unfortunately for me, all images aren't shown until all of them are loaded (kind of 3 seconds it takes). I'm thinking in no limit of images, that's why I want a way where images be loaded one per one, not all together.
Any ideas you have? I appreciate your help.
Thanks.

(StaleElementException:Selenium) How do I handle this?

This is my first time first day working on selenium and I have no hands on experience on Web Technologies in depth either.
Working around, I have been facing StaleElementException while i try to access a particular object on the DOM.
Following Method handles all the task:
private void extract(WebDriver driver) {
try {
List<WebElement> rows = driver.findElements(By.xpath("//*[#id='gvSearchResults']/tbody/tr"));
for (WebElement row : rows) {
WebElement columns = row.findElement(By.xpath("./td[1]/a"));
if (assertAndVerifyElement(By.xpath("//*[#id='gvSearchResults']/tbody/tr/td[1]/a"))) {
columns.click();
}
List<WebElement> elements = driver
.findElements(By.xpath("//*[#id='ctl00_MainContent_pnlDetailsInd']/table/tbody/tr"));
for (WebElement element : elements) {
WebElement values = element.findElement(By.xpath("./td[1]"));
System.out.print(values.getText() + " ");
WebElement values2 = element.findElement(By.xpath("./td[2]"));
System.out.println(values2.getText());
}
if(assertAndVerifyElement(By.xpath("//*[#id='ctl00_MainContent_btnBack']")))
driver.findElement(By.xpath("//*[#id='ctl00_MainContent_btnBack']")).click();
}
} catch (Exception e) {
e.printStackTrace();
}
}
The Assertion logic goes here:
public boolean assertAndVerifyElement(By element) throws InterruptedException {
boolean isPresent = false;
for (int i = 0; i < 5; i++) {
try {
if (driver.findElement(element) != null) {
isPresent = true;
break;
}
} catch (Exception e) {
// System.out.println(e.getLocalizedMessage());
Thread.sleep(1000);
}
}
Assert.assertTrue("\"" + element + "\" is not present.", isPresent);
return isPresent;
}
I have tried few solutions asking me to use wait until expected conditions, but none of them worked.
Also, It would be appreciated if you point out any bad design practices I might be using in the above sample.
I can give you the idea to overcome staleness.
Generally we will be getting the Stale Exception if the element attributes or something is changed after initiating the webelement. For example, in some cases if user tries to click on the same element on the same page but after page refresh, gets staleelement exception.
To overcome this, we can create the fresh webelement in case if the page is changed or refreshed. Below code can give you some idea.
Example:
webElement element = driver.findElement(by.xpath("//*[#id='StackOverflow']"));
element.click();
//page is refreshed
element.click();//This will obviously throw stale exception
To overcome this, we can store the xpath in some string and use it create a fresh webelement as we go.
String xpath = "//*[#id='StackOverflow']";
driver.findElement(by.xpath(xpath)).click();
//page has been refreshed. Now create a new element and work on it
driver.findElement(by.xpath(xpath)).click(); //This works
Another example:
for(int i = 0; i<5; i++)
{
String value = driver.findElement(by.xpath("//.....["+i+"]")).getText);
System.out.println(value);
}
Hope this helps you. Thanks
The StaleElementException occurs when the webelement in question is changed on the dom and the initial reference to that webelement is lost.
You can search for the webelement again
try this
try:
element = self.find_element_by_class('')
element.click()
except StaleElementReferenceException:
element = self.find_element_by_class('')
element.click()

Getting "Element is no longer valid" error while executing the below the code

I am new to Selenium. Getting
org.openqa.selenium.StaleElementReferenceException: Element is no longer valid (WARNING: The server did not provide any stacktrace information)
error while running the below the code.
Expectation: while loop should resume once the method "changdrawer" returned true. Please help me if any correction is needed in my code.
public class ManageTaskList {
public void CheckRequestType() throws InterruptedException
{
//Switching the driver to TaskList frame
LaunchBrowser.driver.switchTo().frame("taskList");
boolean dateFlag=false;
String date = "06/12";
WebElement table = LaunchBrowser.driver.findElement(By.id("dataTable"));
List<WebElement> rows = table.findElements(By.tagName("tr"));
Iterator<WebElement> i = rows.iterator();
System.out.println("Table has following content");
while(i.hasNext())
{
WebElement row=i.next();
List<WebElement> columns= row.findElements(By.tagName("td"));
Iterator<WebElement> j = columns.iterator();
while(j.hasNext())
{
WebElement column = j.next();
String ColumnValues=column.getText();
//System.out.println("ColumnValues" + ColumnValues);
if (ColumnValues.contains(date))
{
System.out.println("Date confirmed" +ColumnValues );
dateFlag = true;
}
if (ColumnValues.contentEquals("Issue Change Drawer") && dateFlag==true)
{
System.out.println("Found Change Drawer");
dateFlag=false;
column.click();
ChangeDrawer();
Thread.sleep(100);
}
}
}
public boolean ChangeDrawer()
{
// Issue Change Drawer
LaunchBrowser.driver.findElement(By.xpath(".//*[#id='content']/div[3]/form/table/tbody/tr[2]/td/table/tbody/tr/td[1]/input")).click();
LaunchBrowser.driver.switchTo().defaultContent();
return true;
}
}
If the changeDrawer method (that is, a click on the element) causes the page to refresh, or even the table elements to change, even if you end up having a WebElement that still matches your selector (in this case, rows), you are still holding a reference to the "old" object, which doesn't exist anymore in the page.
You would need to call the findElement/s method again to refresh the WebElement if that is the case.

Categories