I am getting StaleElementReferenceException: element is not attached to the page document - java

HTMLCODE
I am getting StaleElementReferenceException: element is not attached to the page document. I went through some of the solutions that are already there in StackOverflow. It did not work and it continues to throw the same error. Here is the code I am using which is throwing the stale reference error
WebElement table2 = driver.findElement(By.cssSelector("body > div:nth-child(74) > div.sp-palette-container"));
List<WebElement> allrows2 = table2.findElements(By.tagName("div"));
for(WebElement row2: allrows2){
List<WebElement> cells = row2.findElements(By.tagName("span"));
for(WebElement cell:cells){
if (cell.getAttribute("title").equals("rgb(0, 158, 236)")) {
cell.click();
}
}
}

Because clicking the found cell lead some HTML changes on the current page , due to this changes selenium will treat the page(after click) is an "new" page (even though not redirect to another page actually).
In the next iteration of the loop, the loop still refer to element belongs to "previous" page, this is the root cause of "StateElementReference" exception.
So you need to find those elements again on the "new" page to change the reference of element comes from "new" page.
WebElement table2 = driver.findElement(By.cssSelector("body > div:nth-child(74) > div.sp-palette-container"));
List<WebElement> allrows2 = table2.findElements(By.tagName("div"));
int rowSize, cellSize = 0;
rowSize = allrows2.sie();
for(int rowIndex=0;rowIndex<rowSize;rowIndex++){
WebElement row2 = allrows2.get(rowIndex);
List<WebElement> cells = row2.findElements(By.tagName("span"));
cellSize = cells.size();
for(int cellIndex=0;cellIndex<cellSize;cellIndex++){
WebElement cell = cells.get(cellIndex);
if (cell.getAttribute("title").equals("rgb(0, 158, 236)")) {
cell.click();
// find cells again on "new" page
cells = row2.findElements(By.tagName("span"));
// find rows again on "new" page
allrows2 = table2.findElements(By.tagName("div"));
}
}
}

If your usecase is to click() on the elements with title as rgb(0, 158, 236) you can use the following code block :
String baseURL = driver.getCurrentUrl();
List<WebElement> total_cells = driver.findElements(By.xpath("//div[#class='sp-palette-container']//div//span"));
int size = total_cells.size();
for(int i=0;i<size;i++)
{
List<WebElement> cells = driver.findElements(By.xpath("//div[#class='sp-palette-container']//div//span"));
if (cells.get(i).getAttribute("title").contains("rgb(0, 158, 236)"))
{
cells.get(i).click();
//do your other tasks
driver.get(baseURL);
}
}

Use a "break" after clicking on the element found. The exception occurs because, after clicking on your element, the loop continues.
WebElement table2 = driver.findElement(By.cssSelector("body > div:nth-child(74) > div.sp-palette-container"));
List<WebElement> allrows2 = table2.findElements(By.tagName("div"));
for(WebElement row2: allrows2){
List<WebElement> cells = row2.findElements(By.tagName("span"));
for(WebElement cell:cells){
if (cell.getAttribute("title").equals("rgb(0, 158, 236)")) {
cell.click();
break;
}
}
}

Related

How To Drag And Drop the Items in Decending order using Selenium

Hi Iam new to selenium,
In URL: https://jqueryui.com/sortable/ with help of Mouse We need to sort the list. I tried this code but nothing happens any workaround in selenium how we can do this?
there are 7 items we need to sort data in descending order by mouse
I tried the below code but it's not working how can I achieve it
WebDriver driver =new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://jqueryui.com/sortable/");
driver.switchTo().frame(0);
List<WebElement> lists = driver.findElements(By.xpath("//ul[#id='sortable']/li"));
Actions a = new Actions(driver);
for(int i=0;i<lists.size();++i){
WebElement element = lists.get(i);
String text = lists.get(i).getText();
String[] values = text.split(" ");
int number = Integer.valueOf(values[1]);
}
a.clickAndHold(lists.get(0)).dragAndDrop(lists.get(0), lists.get(6)).build().perform();
a.clickAndHold(lists.get(0)).moveToElement(lists.get(3)).release().build().perform();
///////////////////////////////////////////////////////////////
for(int i =dragAndDropElement.size();i>1;i--) {
WebElement element = driver.findElement(By.xpath("((//ul[#id='sortable']/li)["+i+"])"));
//Just collected all the destination location,
WebElement destination1 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[1])"));
WebElement destination2 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[2])"));
WebElement destination3 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[3])"));
WebElement destination4 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[4])"));
WebElement destination5 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[5])"));
WebElement destination6 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[6])"));
WebElement destination7 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[7])"));
Actions action = new Actions(driver);
if(element!=null) {
action.dragAndDrop(destination1,element).perform();
action.dragAndDrop(destination2,element).perform();
action.dragAndDrop(destination3,element).perform();
action.dragAndDrop(destination4,element).perform();
action.dragAndDrop(destination5,element).perform();
action.dragAndDrop(destination6,element).perform();
action.dragAndDrop(destination7,element).perform();
break;
}
You can check with this solution, Further, you could enhance this as per your requirement and simplification. Anyway, I hope it will help you.
WebDriver driver = new ChromeDriver();
driver.get("https://jqueryui.com/sortable/");
new WebDriverWait(driver,10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//iframe[#class='demo-frame']")));
List<WebElement> dragAndDropElement = driver.findElements(By.xpath("//ul[#id='sortable']/li"));
System.out.println(dragAndDropElement.size());
for(int i =1;i<dragAndDropElement.size();i++) {
WebElement element = driver.findElement(By.xpath("((//ul[#id='sortable']/li)["+i+"])"));
//Just collected all the destination location,
WebElement destination1 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[1])"));
WebElement destination2 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[2])"));
WebElement destination3 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[3])"));
WebElement destination4 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[4])"));
WebElement destination5 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[5])"));
WebElement destination6 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[6])"));
WebElement destination7 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[7])"));
Actions action = new Actions(driver);
if(element!=null) {
action.dragAndDrop(destination7,element).perform();
action.dragAndDrop(destination6,element).perform();
action.dragAndDrop(destination5,element).perform();
action.dragAndDrop(destination4,element).perform();
action.dragAndDrop(destination3,element).perform();
action.dragAndDrop(destination2,element).perform();
action.dragAndDrop(destination1,element).perform();
break;
}
}
You can try this code:
List<WebElement> lists = driver.findElements(By.xpath("//ul[#id='sortable']/li"));
// above list holds size of 7
Actions a = new Actions(driver);
WebElement lastEle = driver.findElement(By.xpath("//li[text()='Item " + lists.size() + "']"));
// I am picking last element as we have to sort in descending order. That means 1-7, 2-7, 3-7 etc..
// At last the order should be Item 7, 6, 5, 4, 3, 2, 1.
for(int i=1;i<=lists.size() - 1;++i) {
// Here, I don't want to drag last element i.e Item 7 as it will be on top at last. That is why I am not considering 7th element to drag
WebElement elementToDrag = driver.findElement(By.xpath("//li[text()='Item " + i + "']"));
a.clickAndHold(elementToDrag).dragAndDrop(elementToDrag, lastEle).build().perform();
Thread.sleep(1000);
}

Click on table row if text is found

I use this Java code with Selenium to select table row based on found text:
WebElement tableContainer = driver.findElement(By.xpath("//div[#class='ag-center-cols-container']"));
List<WebElement> list = tableContainer.findElements(By.xpath("./child::*"));
// check for list elements and print all found elements
if(!list.isEmpty())
{
for (WebElement element : list)
{
System.out.println("Found inner WebElement " + element.getText());
}
}
// iterate sub-elements
for ( WebElement element : list )
{
System.out.println("Searching for " + element.getText());
if(element.getText().equals(valueToSelect))
{
element.click();
break; // We need to put break because the loop will continue and we will get exception
}
}
Full code: https://pastebin.com/ANMqY01y
For some reason table text is not clicked. I don't have exception. Any idea why it's not working properly?
See there are 2 divs with //div[#class='ag-center-cols-container'] with this xpath.
first div does not have anything, while second div has child divs.
I would suggest you to use :
List<WebElement> list = driver.findElements(By.xpath("//div[#class='ag-center-cols-container']//div"));
Remove this line from your code :
WebElement tableContainer = driver.findElement(By.xpath("//div[#class='ag-center-cols-container']"));

Shadow Root - click in a href under several shadow roots

I have a list of links inside of several shadowRoots. Already solved this problem.
public WebElement expandRootElement(WebElement element) {
WebElement ele = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot",element);
return ele;
}
WebElement root5_adminPanel = shadowRoot4_MduiContainerChild2.findElement(By.cssSelector("#layout > border-layout > ng-view > admin-panel"));
WebElement shadowRoot5_AdminPanel= expandRootElement(root5_adminPanel);
WebElement root6_breadCrumb = shadowRoot5_AdminPanel.findElement(By.cssSelector("#layout > border-layout > breadcrumb"));
WebElement shadowRoot6_breadCrumb = expandRootElement(root6_breadCrumb);
WebElement root6_domainPanel = shadowRoot5_AdminPanel.findElement(By.cssSelector("#layout > border-layout > ng-view > gdsr-domain-panel"));
WebElement shadowRoot6_domainPanel = expandRootElement(root6_domainPanel);
WebElement root7_selectDomain = shadowRoot6_domainPanel.findElement(By.cssSelector("#domainContainer > domain-panel-item.ng-binding.last"));
WebElement shadowRoot7_selectDomain = expandRootElement(root7_selectDomain);
When I reach this shadowRoot7, I have a list of items with the same name, which I already created a List to fix it.
List<WebElement> rows_table = shadowRoot6_domainPanel.findElements(By.cssSelector("#domainContainer > domain-panel-item:nth-child(n)"));
(They are around 45 items)
This will select all of them, in this case all the domain-panel-item rows.
My problem is that each domain-panel-item still contain another shadowRoot (the same path for all of them) an i would like to select a random item, not the first or last one, for example, the item number 43.
enter image description here
My solution was this one but it doesn't work because it doesnt access to the link that i want:
public void clickSelectedDomain(String domain) {
List<WebElement> rows_table = shadowRoot6_domainPanel.findElements(By.cssSelector("#domainContainer > gdsr-domain-panel-item:nth-child(n)"));
int rows_count = rows_table.size();
for (int row=0; row<rows_count; row++) {
if(rows_table.get(row).getAttribute("href").contains(domain)) {
rows_table.get(row).click();
}
}
}
Some have an idea how to fix this?
You solved the problem by calling recursively executeScript() in order to get the imbricated Shadow DOMs but actually you could have just called executeScript() once, and inside got the Shadow DOMs successively.
driver.executeScript( function ()
{
var root1 = document.querySelector( 'selector string 1' ).shadowRoot
var root2 = root1.querySelector( 'selector string 2' ).shadowRoot
var root3 = root2.querySelector( 'selector string 3' ).shadowRoot
...
return foundElement
}
Anyways, in the for() {} loop, you should extract the ultimate Shadow DOM one last time, and then select the <a> element to check its content.

Why is this WebElement not returning the full xpath?

I have several WebElements such that executing the following
List<WebElement> customers = driver.findElements(By.xpath("//div[#id='Customers']/table/tbody/tr"));
System.out.println(customers.size());
would print 5.
So then why does the following code
List<WebElement> customers = driver.findElements(By.xpath("//div[#id='Customers']/table/tbody/tr"));
for (WebElement customer : customers) {
if (customer.getText().equals("SQA")) {
WebElement test = customer;
System.out.println(test);
break;
}
}
print xpath: //div[#id='Customers']/table/tbody/tr and fail to actually include the specific index of the path? The above xpath is absolutely useless; I'm expecting the location of where SQA was found.
xpath: //div[#id='Customers']/table/tbody/tr[4]
I think it just prints the locator used to find the element. If you want the index, just change your code to
List<WebElement> customers = driver.findElements(By.xpath("//div[#id='Customers']/table/tbody/tr"));
for (int i = 0; i < customers.size(); i++)
{
if (customers.get(i).getText().equals("SQA"))
{
System.out.println(i);
break;
}
}

How to use select list in selenium?

I'm trying to select an element from a select list in selenium using java with WebDriver - based syntax.
I've got the select list by
elements = driver.findElements(By.xpath("//form[#action='inquiry/']/p/select[#name='myselect']"));
if (elements.size() == 0) {
return false;
}
if (guests != null) {
//what do I do here?
}
How do I do that?
WebElement select = driver.findElement(By.name("myselect"));
Select dropDown = new Select(select);
String selected = dropDown.getFirstSelectedOption().getText();
if(selected.equals(valueToSelect)){
//already selected;
//do stuff
}
List<WebElement> Options = dropDown.getOptions();
for(WebElement option:Options){
if(option.getText().equals(valueToSelect)) {
option.click(); //select option here;
}
}
If this is slower, then consider something like
dropDown.selectByValue(value);
or
dropDown.selectByVisibleText(text);
A little side note which applies to Java:
In my case, when I was writing the test according the example of #nilesh, I got a strange error, that the constructor is invalid. My import was:
import org.openqa.jetty.html.Select;
If you happen to have similar errors, you have to correct that import to this:
import org.openqa.selenium.support.ui.Select;
If you use this second import, everything will work.
element = driver.findElements(By.xpath("//form[#action='inquiry/']/p/select[#name='myselect']/option[*** your criteria ***]"));
if (element != null) {
element.click();
}
find the option, and then click it
Try to do it like this :
//method to select an element from the dropdown
public void selectDropDown(String Value) {
webElement findDropDown=driver.findElements(By.id="SelectDropDowm");
wait.until(ExpectedConditions.visibilityOf(findDropDown));
super.highlightElement(findDropDown);
new Select(findDropDown).selectByVisibleText(Value);
}
//method to highlight the element
public void highlightElement(WebElement element) {
for (int i = 0; i < 2; i++) {
JavascriptExecutor js = (JavascriptExecutor) this.getDriver();
js.executeScript(
"arguments[0].setAttribute('style', arguments[1]);",
element, "color: yellow; border: 3px solid yellow;");
js.executeScript(
"arguments[0].setAttribute('style', arguments[1]);",
element, "");
}
}

Categories

Resources