Error "no such element: Unable to locate element" - java

I am on this page
https://login.alibaba.com/?spm=a2700.8293689.0.0.NdeZUw&tracelog=hd_signin
And trying to access Email field by following web element code:
public static WebElement Email_Field(WebDriver driver) throws InterruptedException {
//element = (new WebDriverWait(driver, 10)).until(ExpectedConditions
//.visibilityOfElementLocated(By.xpath("//input[#id='fm-login-id']")));
element = driver.findElement(By
.xpath("//input[#id='fm-login-id']"));
while (!isDisplayed(element)) {
Thread.sleep(3000);
System.out.println("Element is not visible yet");
}
return element;
}
public static boolean isDisplayed(WebElement element) {
try {
if(element.isDisplayed())
return element.isDisplayed();
}catch (NoSuchElementException ex) {
return false;
}
return false;
}
But getting the following exception:
Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":".//*[#id='fm-login-id']"}
(Session info: chrome=59.0.3071.115)

The email field is inside the frame. Before access any element in the frame, you have to switch. please try following code.
public static WebElement Email_Field(WebDriver driver) throws InterruptedException {
WebElement element;
(new WebDriverWait(driver, 30)).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt("alibaba-login-box"));
element = driver.findElement(By.xpath("//input[#id='fm-login-id']"));
while (!isDisplayed(element)) {
Thread.sleep(3000);
System.out.println("Element is not visible yet");
}
return element;
}

Related

How to resolve wait method errors while migrating to selenium 4?

I am finding trouble in ExpectedConditions.Provided type is "ExpectedCondition<List>
" and it is showing that expected should be "function". Not getting how to resolve it. Below is a code snippet.
public boolean verifyElementExists(final By locator) {
try {
List<WebElement> elementList = (new WebDriverWait(driver, Duration.ofSeconds(60), Duration.ofMillis(5000))
.until(new ExpectedCondition<List<WebElement>>() {
public List<WebElement> apply(WebDriver d) {
LOGGER.info("method[verifyElementExists] try to find element in HTML "
+ locator);
return d.findElements(locator);
}
});
if (elementList.size() > 0) {
return true;
}
} catch (Exception e) {
LOGGER.info("Error: element not found for " + locator);
ERRORLOGGER.error(this.getClass().getName() + e.getMessage());
}
return false;
}
Please help to get it resolve. Thanks!

Selenium: How to avoid StaleElementReferenceException when looping through a set of elements?

I have a page that contains a bunch of tables. I loop through the tables in the outer loop and then loop through each row in the table in the inner loop. It all works fine. But some of the pages have a Next button. When I add code to click that after completing the page, then I start getting StaleElementReferenceException while looping through the rows of a table.
Here is the code:
WebDriverWait wait1 = new WebDriverWait(driver, 10000);
WebElement maxPage = null;
WebElement auctionsWaitingDiv = driver.findElement(By.cssSelector("div[class='Head_W']"));
if (auctionsWaitingDiv.isDisplayed() == false) return properties;
try {
maxPage = wait1.until(ExpectedConditions.visibilityOfElementLocated(By.id("maxWA")));
} catch (TimeoutException ex) {
return properties;
}
Integer maxPageNo = 1;
if (!maxPage.getText().isEmpty())
maxPageNo = Integer.parseInt(maxPage.getText());
for (int i = 1; i <= maxPageNo; i++) {
driver.findElement(By.cssSelector("div[id='Area_W']")); //only look at Auctions Waiting section
WebDriverWait wait2 = new WebDriverWait(driver, 10000);
List<WebElement> tables = null;
try {
tables = wait2.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("table[class='ad_tab']")));
} catch (TimeoutException ex) {
System.out.println("table not found in allotted time");
return properties;
} catch (StaleElementReferenceException ex) {
System.out.println("returning due to StaleElementReferenceException");
return properties;
}
for (WebElement table: tables) {
List<String> propAttributes = new ArrayList<>();
// StaleElementReferenceException: The element reference of
// <table class="ad_tab"> is stale; either the element is no
// longer attached to the DOM, it is not in the current
// frame context, or the document has been refreshed
List<WebElement> rows = table.findElements(By.cssSelector("tr"));
String parcelLink = "";
for (WebElement row : rows) {
WebElement key = row.findElement(By.cssSelector("th"));
WebElement val = row.findElement(By.cssSelector("td"));
String keyVal = key.getText() + val.getText();
propAttributes.add(keyVal);
if (key.getText().equals("Parcel ID:")) {
WebElement a = val.findElement(By.cssSelector("a"));
parcelLink = a.getAttribute("href");
}
}
}
driver.findElement(By.xpath(".//*[#class='PageRight']")).click(); //click the "Next" button
}
What I don't understand is why the stale element is happening at all? The page is not changing during the loop and I've waited until all elements have been fetched. How to avoid the StaleElementReferenceException?
Edit: The last stack trace shows it is happening in this line:
List<WebElement> rows = table.findElements(By.cssSelector("tr"));
and the error message above it shows:
SEVERE: null
org.openqa.selenium.StaleElementReferenceException: The element reference of <table class="ad_tab"> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed
The StaleElementReferenceException is thrown whenever you want to access an element reference which is not available anymore. This happens when the element is no longer attached to the DOM or if the page was updated.
The solution for this is just searching for the element again whenever this happens.
You could adapt all your tests or page objects. Or you write your own RobustWebDriver and RobustWebElement which refreshes the element if a SERE is thrown.
RobustWebDriver:
public class RobustWebDriver implements WebDriver {
private WebDriver originalWebDriver;
public RobustWebDriver(WebDriver webDriver) {
this.originalWebDriver = webDriver;
}
#Override
public void get(String url) {
this.originalWebDriver.get(url);
}
#Override
public String getCurrentUrl() {
return this.originalWebDriver.getCurrentUrl();
}
#Override
public String getTitle() {
return this.originalWebDriver.getTitle();
}
#Override
public List<WebElement> findElements(By by) {
List<WebElement> elements = new ArrayList<>();
for (WebElement element : this.originalWebDriver.findElements(by)) {
elements.add(new RobustWebElement(element, by, this));
}
return elements;
}
#Override
public WebElement findElement(By by) {
return new RobustWebElement(this.originalWebDriver.findElement(by), by, this);
}
#Override
public String getPageSource() {
return this.originalWebDriver.getPageSource();
}
#Override
public void close() {
this.originalWebDriver.close();
}
#Override
public void quit() {
this.originalWebDriver.quit();
}
#Override
public Set<String> getWindowHandles() {
return this.originalWebDriver.getWindowHandles();
}
#Override
public String getWindowHandle() {
return this.originalWebDriver.getWindowHandle();
}
#Override
public TargetLocator switchTo() {
return this.originalWebDriver.switchTo();
}
#Override
public Navigation navigate() {
return this.originalWebDriver.navigate();
}
#Override
public Options manage() {
return this.originalWebDriver.manage();
}
}
RobustWebElement:
public class RobustWebElement implements WebElement {
private WebElement originalElement;
private RobustWebDriver driver;
private By by;
private static final int MAX_RETRIES = 10;
public RobustWebElement(WebElement element, By by, RobustWebDriver driver) {
this.originalElement = element;
this.by = by;
this.driver = driver;
}
#Override
public void click() {
int retries = 0;
while (retries < MAX_RETRIES) {
try {
this.originalElement.click();
return;
} catch (StaleElementReferenceException ex) {
refreshElement();
}
retries++;
}
throw new StaleElementReferenceException(
String.format("Element is still stale after %s retries.", MAX_RETRIES));
}
#Override
public void sendKeys(CharSequence... keysToSend) {
int retries = 0;
while (retries < MAX_RETRIES) {
try {
this.originalElement.sendKeys(keysToSend);
return;
} catch (StaleElementReferenceException ex) {
refreshElement();
}
retries++;
}
throw new StaleElementReferenceException(
String.format("Element is still stale after %s retries.", MAX_RETRIES));
}
// TODO add other unimplemented methods with similar logic.
private void refreshElement() {
this.originalElement = driver.findElement(by);
}
And then you just need to wrap your WebDriver into the RobustWebDriver and you are ready to go:
WebDriver driver = new RobustWebDriver(new ChromeDriver());
EDIT:
Of course you need to take care of scrolling up and down by yourself.
Well after tearing my hair out for a day, I finally realized what was happening. It should have been obvious to me. When the "Next" button is clicked, it takes some time for the new page to load. By simply adding a delay, the new DOM is loaded and processing begins on it, not again on the previous one!
driver.findElement(By.xpath(".//*[#class='PageRight']")).click();
try {
Thread.sleep(4000); //provide some time for the page to load before processing it
} catch (InterruptedException ex) {
Logger.getLogger(RealAuction.class.getName()).log(Level.SEVERE, null, ex);
}
Now it runs to completion with no StaleElementReferenceException.

Unable to access method from outside of class

I have two .java files, one file (StockWatchlistElements.java) I have declare all the elements of the page and on second file (Example.java) I used that element.
StockWatchlistElements.java
public static WebElement lnkaStockWatchlist(WebDriver driver) {
try {
element = driver.findElements(By.xpath("//*[#id=\"dnn_ctr769_StockWatchList_pnlContent\"]/table/tbody/tr"));
} catch (Exception e) {
throw (e);
}
return element;
}
Example.java
List<WebElement> rows = StockWatchlistElements.lnkaStockWatchlist(driver);
int count = rows.size();
System.out.println("ROW COUNT : " + count);
change your method definition from WebElement to List<WebElement> like:
public static List<WebElement> lnkStockWatchlist(WebDriver driver) {
List<WebElement> element = new ArrayList<>();
try {
element = driver.findElements(By.xpath("//*[#id=\"dnn_ctr769_StockWatchList_pnlContent\"]/table/tbody/tr"));
} catch (Exception e) {
throw (e);
}
return element;
}

Proper way to pass a webdriver to another class

I want to pass my WebDriver to another class instead of passing it to the individual methods within that class. That would mean passing it to the constructor of the class when I create an instance of it. Here is my code, and my issue further below -
public class StepDefinitions{
public static WebDriver driver = null;
CustomWaits waits;
#Before("#setup")
public void setUp() {
driver = utilities.DriverFactory.createDriver(browserType);
System.out.println("# StepDefinitions.setUp(), driver = " + driver);
waits = new CustomWaits(driver);
}
}
public class CustomWaits {
WebDriver driver;
public CustomWaits(WebDriver driver){
this.driver = driver;
}
public boolean explicitWaitMethod(String id) {
boolean status = false;
try {
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(id)));
status = element.isDisplayed();
} catch (NullPointerException e){
e.printStackTrace();
}
return status;
}
}
The error I am getting in is NullPointerException when a method of that class is called within an #Given, #When, etc. This is a scope issue I cannot resolve.
Feature File:
#test
Feature: Test
#setup
Scenario: Navigate to Webpage and Assert Page Title
Given I am on the "google" Website
Then page title is "google"
Here is the step definition:
#Given("^element with id \"([^\"]*)\" is displayed$")
public void element_is_displayed(String link) throws Throwable {
if (waits.explicitWaitMethod(link)) {
// This is where waits becomes null when I put a breakpoint
driver.findElement(By.id(link)).isDisplayed();
} else {
System.out.println("Timed out waiting for element to display");
}
}
I would do something like this.
public class StepDefinitions{
public StepDefinitions() {
driver = utilities.DriverFactory.createDriver(browserType);
System.out.println("# StepDefinitions.setUp(), driver = " + driver);
waits = new CustomWaits(driver);
}
public static WebDriver driver = null;
public static CustomWaits waits;
#Given("^element with id \"([^\"]*)\" is displayed$")
public void element_is_displayed(String link) throws Throwable {
if (waits.explicitWaitMethod(link)) {
// This is where waits becomes null when I put a breakpoint
driver.findElement(By.id(link)).isDisplayed();
} else {
System.out.println("Timed out waiting for element to display");
}
}
}
public class CustomWaits {
private static WebDriver driver;
public CustomWaits(WebDriver driver){
this.driver = driver;
}
public boolean explicitWaitMethod(String id) {
boolean status = false;
try {
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(id)));
status = element.isDisplayed();
} catch (NullPointerException e){
e.printStackTrace();
}
return status;
}
}

ElementNotVisibleException error

I'm trying to expand all comments, replies, see more in comment, and see more in post in Facebook.
1) The codes I have written below allows me to expand all contents that I want except for maybe a few replies in a post even though I have put the repliesbutton in a loop.
2) There will a Exception in thread "main" org.openqa.selenium.ElementNotVisibleException: Element is not currently visible and so may not be interacted with error at the .click() if there is no try-catch in all the smaller for loops.
//declare WebDriverWait variable, times out after 20 seconds
WebDriverWait wait = new WebDriverWait(dr, 20);
//check element is present on the DOM of a page and visible
wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("commentable_item")));
List<WebElement> comments = dr.findElements(By.className("commentable_item")); //get the comments
//iterate through the comments
for (WebElement comment : comments) {
boolean clickMore = true;
try {
while(clickMore == true) {
//find web elements by their respective class name
List<WebElement> commentsbutton = comment.findElements(By.className("UFIPagerLink")); //view more/previous comments
List<WebElement> repliesbutton = comment.findElements(By.className("UFIPagerIcon")); //replies
List<WebElement> seemorebutton = comment.findElements(By.className("_5v47")); //see more in comment
List<WebElement> seemorelinkbutton = dr.findElements(By.className("see_more_link")); //see more in link
//click more comments
if(commentsbutton.size() > 0) {
for (WebElement comments_element : commentsbutton) {
//comments_element.click(); //click on button if found
//Thread.sleep(5000); //pause for 5 seconds
try{
comments_element.click(); //click on button if found
Thread.sleep(5000); //pause for 5 seconds
} catch(Exception e){
}
}
for (WebElement replies_element : repliesbutton) {
//replies_element.click(); //click on button if found
//Thread.sleep(3000); //pause for 3 seconds
try{
replies_element.click(); //click on button if found
Thread.sleep(3000); //pause for 5 seconds
} catch(Exception e){
}
}
}
else clickMore = false;
for (WebElement seemorelinks_element : seemorelinkbutton) {
try{
seemorelinks_element.click(); //click on button if found
Thread.sleep(5000); //pause for 5 seconds
} catch(Exception e){
}
}
for (WebElement seemore_element : seemorebutton) {
try{
seemore_element.click(); //click on button if found
Thread.sleep(5000); //pause for 5 seconds
} catch(Exception e){
}
}
}
} catch (NoSuchElementException e) { //when no elements are found
System.out.println("Comments in this post not found");
}
}
}
//return the given element if it is visible and has non-zero size, otherwise null.
private static WebElement elementIfVisible(WebElement element) {
return element.isDisplayed() ? element : null;
}
public static ExpectedCondition<WebElement> visibilityOfElementLocated(final By locator) {
return new ExpectedCondition<WebElement>() {
#Override
public WebElement apply(WebDriver driver) {
try {
return elementIfVisible(dr.findElement(locator));
} catch (StaleElementReferenceException e) {
return null;
}
}
};
}
}
You can create a utility method and put it in some 'Utility.java' class something like below:
public void click(WebElement element)
{
((JavascriptExecutor)driver).executeScript("arguments[0].scrollIntoView(true);", element);
Thread.sleep(500);
if(element.isDisplayed())
element.click();
}
Usage:
WebElement element=driver.findElement(//Locator);
Utility.click(element);
This will ensure every time before you click the element is scrolledIntoView.
Let me know if you need further help on this.

Categories

Resources