How to overcome state Element Reference exception - java

I am trying to automate the following actions:
Launching https://www.flipkart.com > Click on Mobiles > Mouse hover on Electronics and then click on Mi.
I am getting Expection in thread "main" state Element Reference: element is not attached to the page document in the miButton() method.
Please refer the error details section.
HTML Code
Mi Button Click - HTML
Base class:
public class Base {
static WebDriver driver;
public void setupBrowser(String browser, String url) {
String currDir = System.getProperty("user.dir");
if(browser.equalsIgnoreCase("chrome")) {
System.setProperty("webdriver.chrome.driver", currDir + "\\drivers\\chromedriver.exe");
driver = new ChromeDriver();
}
else if(browser.equalsIgnoreCase("firefox")) {
System.setProperty("webdriver.gecko.driver", currDir + "\\drivers\\geckodriver.exe");
driver = new FirefoxDriver();
}
else if(browser.equalsIgnoreCase("edge")) {
System.setProperty("webdriver.edge.driver", currDir + "\\drivers\\msedgedriver.exe");
driver = new EdgeDriver();
}
else {
System.out.println("Valid browser not found therefore quitiing");
System.exit(0);
}
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
if(url != "")
driver.get(url);
else
driver.get("about:blank");
}
public void closeBrowser() {
driver.close();
}
Page Class
public class pagetest extends Base{
Actions action;
public void closebtn() {
driver.findElement(By.cssSelector("button._2doB4z")).click();
}
public void mibutton() {
WebElement mobiles = driver.findElement(By.xpath("//div[text()='Mobiles']"));
action = new Actions(driver);
action.moveToElement(mobiles).click().perform();
WebElement electronicsmenu = driver.findElement(By.xpath("//span[text()='Electronics']"));
action.moveToElement(electronicsmenu).click().perform();
List <WebElement> value = driver.findElements(By.xpath("//div[#class='_1kidPb']/div[#class='_1QrT3s']//a");
for(WebElement elem:value) {
if(elem.getText().equals("Mi")) {
elem.click();
}
}
WebElement label = driver.findElement(By.xpath("//p[text()='Latest from MI : ']"));
System.out.println("The Label 'Latest from MI' is present : " +label.isEnabled());
}
public static void main(String[] args) {
pagetest obj = new pagetest();
obj.setupBrowser("chrome", "https://www.flipkart.com/");
obj.closebtn();
obj.mibutton();
}
}
Error Details
Exception in thread "main" org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document
(Session info: chrome=89.0.4389.90)
For documentation on this error, please visit: https://www.seleniumhq.org/exceptions/stale_element_reference.html

You never find elements and then right away try to click on them. When the page is loading the elements are created, but after a few milliseconds they change their attributes, size and or location. This exception means that you found the element but as of now you "lost" it.
In order to avoid StateElementReferecneException use WebDriverWait object. You can wait for element to be visible / clickable as well as other options. Best option is to wait for the element to be clickable:
WebDriverWait wait = new WebDriverWait(driver, 20, 10);
wait.until(ExpectedConditions.elementToBeClickable
(By.id("elementID")));

Related

org.openqa.selenium.StaleElementReferenceException: element is not attached to the page document

I am trying to test the GeeksForGeeks UI. When I click the tutorials dropdown, then select languages and select Java, it links to a new page and the following error occurs org.openqa.selenium.StaleElementReferenceException. How can I solve this issue? I have tried all the possible solutions from stackoverflow.
public class SeleniumTest {
public static WebDriver driver;
#BeforeClass
public static void setupClass() {
System.setProperty("webdriver.chrome.driver", "driver/chromedriver.exe");
}
#Before
public void setup() {
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
}
#After
public void after() {
driver.close();
}
#Test
public void testGeeksForGeeksR() throws InterruptedException {
driver.get("https://www.geeksforgeeks.org/");
WebElement tutorialsMenu = driver.findElement(By.className("header-main__list-item"));
tutorialsMenu.click();
List<WebElement> tutorialsList = tutorialsMenu.findElements(By.tagName("li"));
for (WebElement li : tutorialsList) {
if (li.getText().equals("Languages")) {
li.click();
List<WebElement> languages = driver.findElements(By.tagName("a"));
for (WebElement a : languages) {
if (a.getText().equals("Java")) {
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(a));
a.click();
WebElement title = driver.findElement(By.className("entry-title"));
assertEquals("Java Programming Language", title.getText());
}
}
}
}
Thread.sleep(6000);
}
}
Solution:
#Test
public void testGeeksForGeeksR() throws InterruptedException {
driver.get("https://www.geeksforgeeks.org/");
WebElement tutorialsMenu = driver.findElement(By.className("header-main__list-item"));
tutorialsMenu.click();
List<WebElement> tutorialsList = tutorialsMenu.findElements(By.tagName("li"));
WebElement javaLanguage = null;
for (WebElement li : tutorialsList) {
if (li.getText().equals("Languages")) {
li.click();
List<WebElement> languages = driver.findElements(By.tagName("a"));
for (WebElement a : languages) {
if (a.getText().equals("Java")) {
javaLanguage = a;
break;
}
}
}
}
javaLanguage.click();
driver.switchTo().activeElement();
WebElement title = driver.findElement(By.className("entry-title"));
assertEquals("Java Programming Language", title.getText());
Thread.sleep(3000);
}
After clicking on the a element with Java text the Java Programming Language page is opened.
At this point all the element references collected on the previous page are becoming Stale.
Generally, each Selenium WebElement object is actually a reference (pointer) to physical web element object.
So, when you are opening another web page or refreshing the existing page (reloading the web elements there) all the references to the web elements on the previous web page are no more valid.
In the Selenium terminology this situation is called Stale Element.
Getting back to your specific code flow.
Looks like your target here is to open the Java Programming Language page. If so, all what you are missing here is to exit your loop once that page is opened and finish the test.
In case you wish to continue opening another tutorials from the menu on the main page you will have to go back from the internal page you opened and then get all the elements you wish to use there again.

How do I create Page Object Model that works for Android AND iOS in Appium Java

I have created a Page Object in Java with Appium and Selenium that is currently working for an Android app as shown below:
public class MattVerifyPage extends PageObject{
private AppiumDriver driver = FrameworkInitialize.driver;
By verifyTitle = By.xpath("/hierarchy/android.widget.TextView");
public void verifyTitle(String expectedTitle){
String actualTitle = driver.findElement(verifyTitle).getText();
However, I need it to work an the Android app and the iOS app, the xpath selector is different for both apps. I think I need to do something like this:
#AndroidFindBy(xpath = “androidxpath”)
#iOSFindBy(xpath = “iOSxpath”)
public MobileElement verifyTitle ;
This would mean regardless of whether I am using Android or iOS I would still just use the one variable called 'verifyTitle'.
However, when I do this, the driver.findElement line (String actualTitle = driver.findElement(verifyTitle).getText() shows the following error:
findElement
(org.openqa.selenium.By)
in DefaultGenericMobileDriver cannot be applied
to
(io.appium.java_client.MobileElement)
I think I am comparing AppiumElements with SeleniumElements but I’m not sure how to resolve it.
Any help would be greatly appreciated.
Thanks
Matt
Yes, lots of mixing of object types in your original example. You're on the right track with the #OSFindBy annotations. Once you have those defined you already have the element so no need to find it again. The following would be all you'd need:
verifyTitle.getText()
See this blog post for more information on the Page Object Model (POM).
Summary:
import all the good stuff including PageFactory;
public class YourPage {
private WebDriver driver;
public YourPage(AppiumDriver<MobileElement> driver) {
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
#AndroidFindBy(id = "android_button")
#iOSFindBy(id = "ios_button")
private MobileElement that_button;
public void pushTheButton() {
that_button.click()
}
}
Note: above code is untested / written off the top of my head / I don't write Java for a living. Prone to error, but should give you the idea.
This Working with Me, My Project Selenium, TestNG and Appium use PageFactory.initElements
public class Login extends Setup {
#Test
public void loginAlert() throws InterruptedException {
Button button = new Button(driver);
PageFactory.initElements(driver, button);
Input input = new Input(driver);
PageFactory.initElements(driver, input);
Input input1 = new Input(driver);
System.out.println("Test Alert Login");
button.ById("navigation_more");
button.ById("btnLogin");
input.ById("et_email_or_phone_number", "dikakoko.com");
input1.ById("tet_password", "dikakoko");
}
}
Below this is the function I called above.
public class Input {
AppiumDriver<MobileElement> driver;
Root root = new Root();
public Input(AppiumDriver<MobileElement> driver) {
this.driver = driver;
}
public void ById(String selector, String textValue) {
MobileElement element = driver.findElement(By.id(root.element() + ":id/" + selector));
waitForVisible(driver, element);
Actions actions = new Actions(driver);
actions.moveToElement(element);
actions.click();
actions.sendKeys(textValue);
actions.build().perform();
System.out.println("Input: " + textValue);
}
private void waitForVisible(AppiumDriver<MobileElement> driver, MobileElement element) {
try {
Thread.sleep(5000);
System.out.println("Waiting for element visibility");
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.visibilityOf(element));
} catch (Exception e) {
e.printStackTrace();
}
}
}
and This
public class Button {
AppiumDriver<MobileElement> driver;
Root root = new Root();
public Button(AppiumDriver<MobileElement> driver) {
this.driver = driver;
}
public void ById(String selector) {
MobileElement element = driver.findElement(By.id(root.element() + ":id/" + selector));
Actions actions = new Actions(driver);
actions.moveToElement(element);
actions.click();
actions.build().perform();
System.out.println("Button is Clicked!");
}
}
I Use This
Button button = new Button(driver);
PageFactory.initElements(driver, button);
Input input = new Input(driver);
PageFactory.initElements(driver, input);
My References : From www.seleniumeasy.com

Could not getting correct text in output after refresh of search results

This is a site related to find shoe costs. Initially I have entered the text and performed the search and output the number of results obtained.
After selecting a criteria, the search result refresh according to new criteria.
but the output still shows the previous result. I tried with implicit wait but it still shows old result.
This is the code:
public void openBrowser()
{
StaticData.driver.get("http://laceup.io/phase2");
}
public void homeSearchAndClick()
{
System.out.println("In home search");
StaticData.driver.findElement(By.xpath(".//*[#id='search_field']")).sendKeys("Nike");
StaticData.driver.findElement(By.xpath("html/body/div[1]/div/div[1]/div[1]/div[1]/div/button")).click();
}
// Function to search by FEMALE gender
public void searchForFemale()
{
System.out.println("Gender: Female clicked");
StaticData.driver.findElement(By.xpath("html/body/div[1]/div/section/div[1]/div[1]/div/div[1]/div/div[2]/label/span")).click();
}
public void filterSearchCount()
{
StaticData.driver.manage().timeouts().implicitlyWait(500, TimeUnit.SECONDS);
String searchCount = StaticData.driver.findElement(By.xpath(".//*[#id='show_query']/h2")).getText();
System.out.println("Filter search count: " + searchCount);
}
I discovered that a driver.navigate().refresh(); used in the method filterSearchCount() do the trick. Even so, I've noticed that the Nike checkbox for filter isn't checked. In this way, the program will display Filter search count: 1919 RESULTS (1918 from Nike + 1 from Warrior)
If you want the exact result for Nike- woman you should check also Nike in the filer area, as I've told you before that the site doesn't check it automatically even if you have been written Nike in the Search Textbox.
If your objective is to fetch the number of results for "Nike" for Women gender there is another way to do it. You can toggle the Ladies beforehand on the homepage itself.
FYI, I'm using PageObjectFactory to simplify your code
Phase2Page.java - Page Object Factory for your Home Page
public class Phase2Page {
WebDriver driver;
public Phase2Page(WebDriver driver){
this.driver = driver;
PageFactory.initElements(driver, this);
}
#FindBy(xpath = "//*[#id='search_field']")
WebElement searchField;
#FindBy (xpath = "html/body/div[1]/div/div[1]/div[1]/div[1]/div/button")
WebElement searchBtn;
#FindBy(xpath = ".//*[#id='filter_gender_ul']/li[2]")
WebElement LadiesToggle;
public void homeSearchAndClick() {
System.out.println("In home search");
LadiesToggle.click();
searchField.sendKeys("Nike");
searchBtn.click();
}
}
SearchPage.java - Page Object Factory for Search Page
public class SearchPage {
WebDriver driver;
#FindBy(xpath = ".//*[#id='show_query']/h2")
WebElement searchCount;
public SearchPage(WebDriver driver){
this.driver = driver;
PageFactory.initElements(new AjaxElementLocatorFactory(driver, 50),this);
}
#FindBy(xpath = "html/body/div[1]/div/section/div[1]/div[1]/div/div[1]/div/div[2]/label/span")
WebElement femaleCheckbox;
// Function to search by FEMALE gender
public void searchForFemale() {
System.out.println("Gender: Female clicked");
femaleCheckbox.click();
}
public void filterSearchCount() {
String count = searchCount.getText();
System.out.println("Filter search count: " + count);
}
}
Test1.java - Your Actual Test for execution
public class Test1 {
WebDriver driver;
public void openBrowser() {
driver.get("http://laceup.io/phase2");
}
#Test
public void testSearch(){
System.setProperty("webdriver.chrome.driver", "D:\\Selenium Webdriver/chromedriver.exe");
driver = new ChromeDriver();
openBrowser();
Phase2Page objHome = new Phase2Page(driver);
SearchPage objSearch = new SearchPage(driver);
objHome.homeSearchAndClick();
objSearch.filterSearchCount();
driver.quit();
}
}
My code worked when i used thread.sleep in filterSearchCount().

Selenium : Automating LinkedIn - Profile Icon

I am new to Selenium and trying to use Actions class to mouseover on the Profile icon available on linked in site to open the menu that appears on Mouseover of profile image.
Below is my code and when it reaches on to those lines the error comes : Unable to locate element..
This is happening with all the icons available on Linked on top bar ( messages / Flag icon etc.
Code :
public class LinkedIn {
WebDriver driver = new FirefoxDriver();
#BeforeTest
public void setUp() throws Exception {
String baseUrl = "http://www.linkedin.com/";
driver.get(baseUrl);
}
#Test
public void login() throws InterruptedException
{
WebElement login = driver.findElement(By.id("login-email"));
login.sendKeys("*****#gmail.com");
WebElement pwd = driver.findElement(By.id("login-password"));
pwd.sendKeys("*****");
WebElement in = driver.findElement(By.name("submit"));
in.click();
Thread.sleep(10000);
}
#Test
public void profile() {
// here it gives error to me : Unable to locate element
Actions action = new Actions(driver);
WebElement profile = driver.findElement(By.xpath("//*[#id='img-defer-id-1-25469']"));
action.moveToElement(profile).build().perform();
driver.quit();
}
}
It seems you have used incorrect xpath , Kindly check below example to mouse hover on Message button :
Thread.sleep(5000);
Actions action = new Actions(driver);
WebElement profile = driver.findElement(By.xpath("//*[#id='account-nav']/ul/li[1]"));
action.moveToElement(profile).build().perform();
Correct Xpaths are :
For Message Icon : "//*[#id='account-nav']/ul/li[1]"
For Connection Icon : //*[#id='dropdowntest']
Above code I just tested and working fine so will work for you.

How to fetch all links and click those links one by one with Selenium WebDriver

I want to do the following:
I want to fetch and display all links on webpage.
After displaying, I want to click each link one by one.
I'm able to do point 1 using foreach loop but I'm not able to 2nd point.
Here is the code:
public class OpenAllLinks {
public static void main(String[] args) {
WebDriver driver=new FirefoxDriver();
driver.get("http://bing.com");
List<WebElement> demovar = driver.findElements(By.tagName("a"));
System.out.println(demovar.size());
for (WebElement var : demovar) {
System.out.println(var.getText()); // used to get text present between the anchor tags
System.out.println(var.getAttribute("href"));
}
for (WebElement var : demovar) {
var.click();
}
}
}
when the first link is clicked, the browser will load the respective page. hence the other links those you had captured in the first page wouldn't be available.
If the intent is to navigate to the every link's target, then store the target location and navigate to it, like this
driver.get("<some site>");
List<WebElement> links=driver.findElements(By.tagName("a"))
ArrayList<String> targets = new ArrayList<String>();
//collect targets locations
for (WebElement link : links) {
targets.add(link.getAttribute("href"));
}
for (WebElement target : targets) {
driver.get(target);
//do what is needed in the target
}
static WebDriver driver=null;
public static void main(String[] args) throws IOException
{ System.setProperty("webdriver.chrome.driver","D:\\softwaretesting\\broswer driver\\chromedriver.exe");
WebDriver driver = new ChromeDriver();``
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
//driver.manage().window().maximize();
driver.get("http://google.com/");
List<WebElement> links=driver.findElements(By.tagName("a"));
System.out.println("Total links are "+links.size());
for(int i=0;i<links.size();i++)
{
WebElement ele= links.get(i);
String url=ele.getAttribute("href");
verifyLinkActive(url);
}
}
public static void verifyLinkActive(String linkUrl)
{ try
{
URL url = new URL(linkUrl);
HttpURLConnection httpURLConnect=(HttpURLConnection)url.openConnection();
httpURLConnect.setConnectTimeout(3000);
httpURLConnect.connect();
if(httpURLConnect.getResponseCode()==200) {
System.out.println(linkUrl+" - "+httpURLConnect.getResponseMessage());
File src= (TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(src, new File("D://screenshort//Spiritualbridge//"+System.currentTimeMillis()+".png"));
} if(httpURLConnect.getResponseCode()==HttpURLConnection.HTTP_NOT_FOUND)
{
System.out.println(linkUrl+" - "+httpURLConnect.getResponseMessage() + " - "+ HttpURLConnection.HTTP_NOT_FOUND);
}
} catch (Exception e)
{
}
}
That happens because the link when clicked, navigates to a new page where it doesn't find the next element in your list to click. Please try the below code that will navigate to each link (I have used the code by #deepak above and have modified it accordingly as per your need):
WebDriver driver=new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://bing.com");
List<WebElement> demovar=driver.findElements(By.tagName("a"));
System.out.println(demovar.size());
ArrayList<String> hrefs = new ArrayList<String>(); //List for storing all href values for 'a' tag
for (WebElement var : demovar) {
System.out.println(var.getText()); // used to get text present between the anchor tags
System.out.println(var.getAttribute("href"));
hrefs.add(var.getAttribute("href"));
System.out.println("*************************************");
}
//Navigating to each link
int i=0;
for (String href : hrefs) {
driver.navigate().to(href);
System.out.println((++i)+": navigated to URL with href: "+href);
Thread.sleep(3000); // To check if the navigation is happening properly.
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
}

Categories

Resources