i'm need to click a button which may appear with a 50 percent chance, decided to use try/catch with findElementBy. Nevertheless try/catch doesn't work and I'm getting an exception. Maybe there is a more efficient way to handle that button?
driver.manage().timeouts().implicitlyWait(5000, TimeUnit.MILLISECONDS);
WebDriverWait wait = new WebDriverWait(driver,5);
try {
WebElement element = driver.findElement(By.xpath("buttonXpath"));
element.click();
}
catch (NoSuchElementException e){ }
Possibly you are seeing NoSuchElementException which can happen due to a lot of reasons. You can find a detailed discussion in NoSuchElementException, Selenium unable to locate element
Solution
The best approach would be to construct a Locator Strategy which uniquely identifies the desired element with in the HTML DOM following the discussions in:
How to inspect element for Selenium v3.6 as FireBug is not an option any more for FF 56?
FirePath not displaying HTML code after typing x-path
Now as per best practices while invoking click() always induce induce WebDriverWait with in a try-catch{} block for the elementToBeClickable() as follows:
try{
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("buttonXpath"))).click();
System.out.println("Element was clicked")
}
catch (TimeoutException e){
System.out.println("Element wasn't clicked")
}
This will work for you:
List<Webelement> element = driver.findElements(By.xpath("buttonXpath"));
if(element.size() > 0) {
element.get(0).click();
}
Use method to check if this element is on your screen:
if (!driver.findElementsByXPath("buttonXpath`enter code here`").isEmpty()) {
driver.findElementByXPath("buttonXpath`enter code here`").click();
}
Related
I am trying to add multiple products in to the cart
WebElement ele = driver.findElement(By.xpath("//li[text()='Grocery ']"));
//Creating object of an Actions class
Actions action = new Actions(driver);
//Performing the mouse hover action on the target element.
action.moveToElement(ele).perform();
Thread.sleep(3000);
driver.findElement(By.xpath("//li[#title='staples']")).click();
Thread.sleep(5000);
List<WebElement> products = driver.findElements(By.xpath("//div[#class='product-grid-img']"));
for(int i=0;i<products.size();i++)
{
products.get(i).click();
Thread.sleep(3000);
driver.findElement(By.xpath("(//span[text()='ADD TO CART'])[1]")).click();
driver.navigate().back();
driver.navigate().refresh();
}
As we can see, by clicking on a product a new page is opened so to get back you are navigating to the previous page explicitly and refreshing the page.
When you leaving the original page or refreshing it the elements collected by Selenium on that page becoming no more relevant AKA Stale.
You can read here or at any other online resource about this issue.
To make your code work you will have to get the product again.
Something like this should work:
List<WebElement> products = driver.findElements(By.xpath("//div[#class='product-grid-img']"));
for(int i=0;i<products.size();i++)
{
List<WebElement> products = driver.findElements(By.xpath("//div[#class='product-grid-img']"));
products.get(i).click();
Thread.sleep(3000);
driver.findElement(By.xpath("(//span[text()='ADD TO CART'])[1]")).click();
driver.navigate().back();
driver.navigate().refresh();
Thread.sleep(3000);
}
Every time you navigate to anywhere, your browser constructs a map of a sorts of the page, in memory. This is called the DOM. When you navigate somewhere else, the DOM is replaced with a new DOM of the new page. The browser does not keep a history of the DOMs you visited, so when you navigate back to somewhere you have already been, the browser has to construct the DOM again.
Let's look at the relevant parts of your code:
List<WebElement> products = driver.findElements(By.xpath("//div[#class='product-grid-img']"));
Find a bunch of elements in the current DOM.
for(int i=0;i<products.size();i++)
{
products.get(i).click();
First time navigate to another page. So discard all the elements you just found above and rebuild the DOM.
Second time through the loop, you are trying to use an element that is no longer found in the current DOM. Which throws the StaleElementException.
Thread.sleep(3000);
driver.findElement(By.xpath("(//span[text()='ADD TO CART'])[1]")).click();
driver.navigate().back();
Navigate again somewhere. Another rebuild of the DOM.
driver.navigate().refresh();
Will not help.
}
You will need to restructure your loop to find the element each time. Perhaps something like:
for(int i=0;i<products.size();i++)
{
// You will have to find the correct XPath here!
WebElement product = driver.findElement(By.xpath("//div[#class='product-grid-img'][" + i + "]"));
product.click();
Thread.sleep(3000); // You might want to use a proper wait here.
driver.findElement(By.xpath("(//span[text()='ADD TO CART'])[1]")).click();
driver.navigate().back();
}
StaleElementExceptions are caused by going to a new page and accessing old elements that are no longer valid.
You could do what others did and regrab the values or if it's in an a tag you could just collect all the hrefs and then just driver.get() to them removing the need to driver.navigate().back();
.getAttribute("href")
I just searched for your query in Google to check , with the intention to learn more about what exactly is the question and topic ,
I got this :
"People also ask"
(Q)How do you fix stale element reference element is not attached to the page document in selenium?
Solution : The element in the DOM is not found because your page is not entirely loaded when Selenium is searching for the element. To solve that, you can put an explicit wait condition that tells Selenium to wait until the element is available to be clicked on.
https://www.google.com/search?q=his+error+%22stale+element+reference%3A+element+is+not+attached+to+the+page+document%22%2C&sourceid=chrome&ie=UTF-8
I am trying to do web automation.
I am defining a pop-up menu containing a button defined with either xpath or css respectively as
XPath:-->: //button[contains(text(), 'Open Door')
CSS:-->: div.device-item.content.view-content > div.detail > div > button.btn.btn-primary.ng-star-inserted
While all is well, it throws
org.openqa.selenium.ElementClickInterceptedException: element click intercepted:
when I am debugging the test one step at a time, it
runs successfully by clicking the button, with out any
problem. But when I am running the test, it fails. I hope it is not a wait issue, as we apply check waiting for
the presence of the button and verify it exists and clickable.
I believe many would advice to use JavaScriptExecutor approach, but our framework has a problem of returning any web element as a custom object called "Element" which is neither Web Element nor sub class of it, but extends Object and implements an interface called IElement, so we can't use JavaScriptExecutor method since it needs Web Element form of the button which we want to click on.
If it works in debug it means the overlay disappear automatically. You can wait for it to vanish
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("[id^='device-card']")));
And in any case you can wait for the button to be clickable
button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[contains(text(), 'Open Door')")));
button.click();
It will look something like:
driver.executeScript("document.querySelector('button.btn').click()")
Just adjust the css
There are a couple of things you need to take care:
XPath //button[contains(text(), 'Open Door'): This xpath can be optimized further in either of the formats:
//button[text()='Open Door']
//button[contains(., 'Open Door')]
CSS: div.device-item.content.view-content > div.detail > div > button.btn.btn-primary.ng-star-inserted looks good however I strongly believe button.btn.btn-primary.ng-star-inserted would also work.
"...Executes successfully in debug mode...": As the browser client gets ample time to settle the webpage dynamics and the desired WebElement gets enough time to get interactive.
"...we amply check waiting for the presence of the button and verify it exists and clickable...": Is a myth as:
presenceOfElementLocated(): Is the expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible.
where as:
elementToBeClickable(): Is the expectation for checking an element is visible and enabled such that you can click it.
As your usecase is to invoke click() on the element you need to use the ExpectedConditions as elementToBeClickable().
Example:
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("css_element"))).click();
You can find a detailed discussion in What is the most efficient way to wait for a page element (xpath) to show up in Selenium Webdriver?
Finally, when using the Selenium java clients, of coarse there are methods from JavascriptExecutor but that should be the last resort.
Update
As you are still seeing the error ...ElementClickInterceptedException: element click intercepted..., you can add an additional step to induce WebDriverWait for the invisibility and you can use either of the following options:
invisibilityOf(WebElement element):
new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOf(overlapping_webelement));
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("css_clickable_element"))).click();
invisibilityOfElementLocated(By locator):
new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("css_overlapping_element")));
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("css_clickable_element"))).click();
You can find a relevant detailed discussion in Selenium invisibilityOf(element) method throwing NoSuchElementException + WebDriverWait.ignoring(NoSuchElementException.class) is not working
you can move the mouse to that element and then click on it, even I was facing this issue and this solution solved it
Actions clickOnBtn = new Actions(driver);
clickOnBtn .moveToElement("//button[contains(text(), 'Open Door')").click().build().perform;
this happens even when the element is not visible completely onscreen, in this case you can scroll to that element and then use the above code as shown below
JavascriptExecutor jse2 = (JavascriptExecutor)driver;
jse2.executeScript("arguments[0].scrollIntoView()", ele);
Actions clickOnBtn = new Actions(driver);
clickOnBtn .moveToElement("//button[contains(text(), 'Open Door')").click().build().perform;
click element using javascriptExecutor
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", ele);
This even happens sometimes with the way we selected the element, the xpath can be changed, we can try to use a parent tag rather than the button and try
you can define your own ExpectedCondition with click action:
public class SuccessfulClick implements ExpectedCondition<Boolean> {
private WebElement element;
public SuccessfulClick(WebElement element) { //WebElement element
this.element = element;
}
#Override
public Boolean apply(WebDriver driver) {
try {
element.click();
return true;
} catch (ElementClickInterceptedException | StaleElementReferenceException | NoSuchElementException e) {
return false;
}
}
}
and then use it:
wait10.until(elementToBeClickable(btn));
wait10.until(new SuccessfulClick(btn));
I want to search Prime Video on Google Home Page and then I want to click on News Link on Google Search Page. I have used xpath to find this Link but while executing the code, I am getting NoSuchElementException. I have used below code, Please help me to know that why below code is not working ::
System.setProperty("webdriver.gecko.driver", "C:/Users/gecko/geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.get("https://www.google.com/");
WebElement ele = driver.findElement(By.name("q"));
ele.sendKeys("prime video");
ele.submit();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement news = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id='hdtb-msb-vis']//div[text()='News']")));
news.click();
driver.close();
Can you try with this one. I see you forgot to Click(); as well.
Unlocate element has a several causes. One of this cause is xpath is invalid or not found on that page. One way to check is using find.element then use your xpath if it does not found it will throw an exception. Here is an example.
WebDriver driver = new FirefoxDriver();
driver.get("https://www.google.com/");
/*wait page for 2 seconds -- simple way wait, but don't recommended for using real testing*/
Thread.sleep(2000);
driver.findElement(By.name("q")).Click;
driver.sendKeys("prime video");
driver.sendKeys(Keys.ENTER);
then try to verify if xpath is valid or invalid by using
try
{
driver.findElement(By.xpath("//*[#id='hdtb-msb-vis']//div[text()='News']")).Click;
}
catch(NoSuchElementException ex)
{
System.out.println("There is no element in this page or xpath is invalid : "+ex.Message);
}
catch(Exception ex)
{
System.out.println("Exception : "+ex.Message);
}
If xpath is invalid or not found, you may try Katalon Recorder or Chropath extension for chrome to let help to find xpath.
Katalon Record
https://chrome.google.com/webstore/detail/katalon-recorder/ljdobmomdgdljniojadhoplhkpialdid
Chropath
https://chrome.google.com/webstore/detail/chropath/ljngjbnaijcbncmcnjfhigebomdlkcjo?hl=en
It works for me with a slightly different xpath:
WebElement news = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id=\"hdtb-msb-vis\"]/div[2]/a")));
I am new to the automation and I would like to know how to scroll to a web element on the current page using selenium and java.
I have tries many methods which is described in stackoverflow. But couldn't able to solve my problem.
Solutions I tried:
WebElement element = driver.findElement(By.id("id_of_element"));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
Thread.sleep(500);
You can use Actions class provided by Selenium.
public void scrollToElement(WebElement element){
Actions actions = new Actions(driver);
actions.moveToElement(element);
actions.perform();
WebDriverWait wait = new WebDriverWait(driver, 60);
wait.until(ExpectedConditions.visibilityOf(element));
}
Here I have added an explicit wait and it will wait until the web element is visible. Maximum waiting time will be 60 seconds. If the web element is not visible within 60 seconds, this will throw an exception. You can increase the waiting time by changing this line.
WebDriverWait wait = new WebDriverWait(driver, 60);
Hope this helps.
To scroll a WebElement on the current page within the Viewport using Selenium and Java you need to induce WebDriverWait for the visibility of element located and you can use the following solution:
WebElement element = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.id("id_of_element")));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView();", element)
You're passing that element from javascript to java and back to javascript.
That's a bad idea, by the time it makes that round trip it might not be there anymore.
((JavascriptExecutor) driver).executeScript("document.querySelector('#id_of_element').scrollIntoView(true);");
Also, a lot of things that you needed to scroll into view for (with older seleniums), you no longer do.
I am trying to locate an element and click on that element to go to the other page but the element is not getting clicked but it is not showing any errors or warning. Its just highlighting the element but it is not getting clicked
i am using the following
WebDriverWait wait2 = new WebDriverWait(driver,10);
Thread.sleep(10000);
WebElement elements = driver.findElement(By.id("menuItem_Permissions"));
Actions action = new Actions(driver);
action.moveToElement(elements).click().perform();
Try Using Implicit Wait and a bit of this trick
WebElement element = new WebDriverWait( driver, 10 )
.until( ExpectedConditions.elementToBeClickable
(By.id("menuItem_Permissions")));
WebElement wait = new WebDriverWait(driver,
10).until(ExpectedConditions.visibilityOf(element));
Actions scrollToElement = new Actions(driver);
scrollToElement.moveToElement(wait).perform();
element.click();
In your action string you want to use .build() - so adding it like this.
action.moveToElement(elements).click().build().perform();
And as #Faiz has mentioned, you have declared a WebDriverWait command but its not being called anywhere, not from what you have posted. Avoid the Thread.sleep is where possible. Thats not causing the issue however.
You shouldn't need to use an actions builder for one element, just try using elements.click();