I am sending text to an input field then within the array of elements searching for specific by checking if element text equal street address
As you can see i have Thread sleep which is not the right approach, the reason i am using this is because i am not to sure how to proceed with the current state of the default values.
When i click on input field there are some values by default within the web elements i am locating which means if i remove Thread sleep it will fail due to the fact that the default values will be assigned to the web elements so i am wondering what can i do in such case
Since i know the default values i could potential just find one and wait until it disappears but thinking if there is a better approach to deal with it
default values on input click
the text i am then entering
public LocatedCarParksMap searchForCarPark(String carPark,String location) {
clickOnSearchInput();
searchCarPark.sendKeys(carPark);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (WebElement i : locatedCarParkAddresses) {
if(i.getText().equals(location)){
click(i);
}
}
return new LocatedCarParksMap(driver);
}
You can look for some loaders that are appearing in between you enter the search text and the search result appearance. You can wait for that loader to vanish. After that, you can look for your search results.
Even if you have/don't have loader, this similar FluentWait approach should work:
public LocatedCarParksMap searchForCarPark(String carPark,String location) {
clickOnSearchInput();
searchCarPark.sendKeys(carPark);
//If loader available, write code here to wait for your loader to vanish. Just a simple invisibilityOf should work.
boolean clickStatus = waitAndClickSearchElement(location);
if(! clickStatus) {
throw new Exception(carPark + " is not available in Search Results");
}
return new LocatedCarParksMap(driver);
}
public boolean waitAndClickSearchElement() {
try {
//Change this timeout of 10 sec according to your need.
WebDriverWait webDriverWait = new WebDriverWait(driver,10);
//Increased the polling time to 2 secs to avoid checking the results frequently.
webDriverWait.pollingEvery(Duration.ofSeconds(2))
//Ignoring these 2 exceptions as they are more likely to occur.
webDriverWait.ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
//This until method keeps checking the text for 10 secs. Once it finds the element, will click on it.
return webDriverWait.until(driver -> {
for (WebElement weAddress : locatedCarParkAddresses) {
if(weAddress.getText().equals(location)){
weAddress.click();
return true;
}
}
return false;
});
} catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
There is one edge case here. Lets say your expected search result is already part of default search results, the above code may throw StaleElementReferenceException. But we have handled it so I hope it would work fine. Please let me know if you have any issues.
I am new to selenium.
I am trying to automate amazon login and log out.
I am facing couple of problems.
1.In login page the button "continue" appears after username when I try to login for first time.
But later when I try to login for second time , its does not appear.
How to handle this.
Here is the code I have written so far:
public void logindetails()
{
Datafile d=new Datafile("C:\\Users\\kirruPC\\selenium divers\\Data.xlsx",0);
String uname= d.username(0, 0);
WebElement u=driver.findElement(useid);
u.sendKeys(uname);
u.click();
if(driver.findElement(By.xpath(".//*[#id='continue']")).isDisplayed()==true)
{
driver.findElement(By.id("continue")).click();
String psw=d.pass(0,1);
driver.findElement(password).sendKeys(psw);
}
else
{
String psw=d.pass(0,1);
driver.findElement(password).sendKeys(psw);
}
}
Unable to locate sign Out element.
Below is the code I have written to move to sign out link and click:
public void logout() throws Exception
{
Actions a= new Actions(driver);
WebElement ele=driver.findElement(By.xpath(".//*[#id='nav-link-accountList']"));
a.moveToElement(ele).build().perform();
driver.findElement(By.xpath(".//*[#id='nav-al-your-account']"));
Thread.sleep(3000);
driver.findElement(By.xpath(".//*[#id='nav-al-your-account']/a[22]")).click();
}
Please help me
Thanks in advance
First of all, there is a high change that the element you are searching for might not exist at all in the page, so first let's check if the element exist (if the element does not exist, an exception is thrown, so let's add a handle for that as well). For all that, create a function like so:
public bool ElementExists(By locator)
{
try
{
driver.findElement(locator);
//If no exception is thrown here, element exists, so return true
return true;
}
catch (NoSuchElementException ex)
{
return false;
{
}
Now that we have a function that can safely check if an element exists without getting an exception, you can use it to determine if you will run the code handling the element.
Function isDisplayed() already returns a bool, so checking equality with true is not necessary.
if(ElementExists(By.xpath(...)).isDisplayed())
{
if(driver.findElement(By.xpath(".//*[#id='continue']")).isDisplayed())
{
driver.findElement(By.id("continue")).click();
}
}
//The code below will run either way, so move it out of the if statement
String psw=d.pass(0,1);
driver.findElement(password).sendKeys(psw);
As for the second part of your question, your code can be simplified by just, searching for the element and then clicking it like so:
driver.findElement(By.xpath(".//*[#id='nav-al-your-account']/a[22]")).click();
If you will, double-check the xpath or "catch" the element by an ID.
I wonder if someone could help me with an issue I'm having trying to work out and If statement in Java for Webdriver.
When logging into the app I am testing it is possible to be taken to a security questions page before the main page (if a new user etc). What I would like the code in my test to do is if presented with the security questions page fill it in and move on, if not check you are on the main page.
I was able to do this in Selenium RC using
if (selenium.isTextPresent("User Account Credentials Update")) {
selenium.type("//input[#id='securityQuestion']", "A");
selenium.type("//input[#id='securityAnswer']", "A");
selenium.type("//input[#id='emailAddress']", "test#test.com");
selenium.click("update");
selenium.waitForPageToLoad("30000");
}
assertTrue(selenium.isTextPresent("MainPage"));
Playing around with Webdriver I am using:
if(driver.findElement(By.id("securityQuestion")) != 0) {
driver.findElement(By.id("securityQuestion")).sendKeys("A");
driver.findElement(By.id("securityAnswer")).sendKeys("A");
driver.findElement(By.id("emailAddress")).sendKeys("test#test.com");
driver.findElement(By.id("update")).click();
Assert.assertTrue("Main Page is not Showing",
driver.getPageSource().contains("MainPage"));
The Problem with this is is that it always chucks an exception if the Security screen is not displayed. How do I need to set the code so that it ignores the security page stuff if that page is not presented?
Thank you for any help :-)
You can use driver.findElements as a way to check that a specific element is present without having exceptions thrown. This works because it will return a list of size 0 of WebElements if no element is found. At the moment, if Selenium tries to find an element using findElement and the element doesn't exist, it will throw a NoSuchElementException This means you can replace:
if (driver.findElement(By.id("securityQuestion")) != 0)
with this:
if (driver.findElements(By.id("securityQuestion")).size() != 0)
There is actually nothing wrong in an exception being thrown as long as you catch/handle it.
In other words, I'd follow the EAFP approach here:
try {
driver.findElement(By.id("securityQuestion"));
// ...
} catch (NoSuchElementException e) {
// handle exception, may be at least log in your case
}
I usually just wrap it into a method:
public boolean elementExists(By selector)
{
try
{
driver.findElement(selector)
return true;
}
catch(NoSuchElementException e)
{
return false;
}
}
Can anyone please help me with the following scenarios I want to use with if/else conditions. I'm using java with Testng Eclipse.
1) If login is successful and navigates you to Home page, avoid try/catch
2) If login fails, go to try block.
driver.findElement(By.name("username")).sendKeys(username);
driver.findElement(By.name("password")).sendKeys(password);
driver.findElement(By.name("login")).submit();
try{
Assert.assertFalse(driver.findElement(By.xpath("//div[#class='errorMsg']")).getText().matches("Username or password incorrect. Try again."));
}
catch(Throwable t){
Assert.fail("Username Or Password is Incorrect.");
}
Assert.assertEquals(actualTitle, title,"Home is not accessible!");
It'd be as simple as replacing the try-catch with an if, but since findBy will throw exception if no element is found, you have at least the following 2 approaches
1) create a reusable findElementIfPresent method which returns null if no element is found:
private WebElement findElementIfPresent(WebDriver driver, By by){
try {
return driver.findElement(by);
} catch (NoSuchElementException e) {
return null;
}
}
...
driver.findElement(By.name("username")).sendKeys(username);
driver.findElement(By.name("password")).sendKeys(password);
driver.findElement(By.name("login")).submit();
// obtain the div which holds the information
WebElement errorDiv = findElementIfPresent(driver, By.xpath("//div[#class='errorMsg']"));
// if the div exists and it has an authentication-problem messages, fail
if(errorDiv != null && errorDiv.getText().matches("Username or password incorrect. Try again."))
fail("Username Or Password is Incorrect.");
}
// otherwise proceed with additional verifications
assertEquals(actualTitle, title,"Home is not accessible!");
2) go with the javadoc's suggestion and use findElements(By) which returns a list of elements. In your particular case, if the list is empty then the authentication was successful, otherwise fail the test
// obtain the list of error divs
List<WebElement> errorDivs = driver.findElements(By.xpath("//div[#class='errorMsg']"));
// if there is at east one element present
if(!errorDivs.isEmpty()){
// pick first one and use as main failure reason
fail(errorDivs.get(0).getText());
}
// otherwise proceed with additional verifications
assertEquals(actualTitle, title,"Home is not accessible!");
I have a question regarding "Element is no longer attached to the DOM".
I tried different solutions but they are working intermittent. Please suggest a solution that could be permanent.
WebElement getStaleElemById(String id, WebDriver driver) {
try {
return driver.findElement(By.id(id));
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElemById(id, driver);
}
}
WebElement getStaleElemByCss(String css, WebDriver driver) {
try {
return driver.findElement(By.cssSelector(css));
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElemByCss(css, driver);
} catch (NoSuchElementException ele) {
System.out.println("Attempting to recover from NoSuchElementException ...");
return getStaleElemByCss(css, driver);
}
}
Thanks,
Anu
The problem
The problem you are probably facing is that the method returns the right (and valid!) element, but when you're trying to access it a second later, it is stale and throws.
This usually arises when:
You click something that loads a new page asynchronously or at least changes it.
You immediatelly (before the page load could finish) search for an element ... and you find it!
The page finally unloads and the new one loads up.
You try to access your previously found element, but now it's stale, even though the new page contains it, too.
The solutions
There are four ways to solve it I know about:
Use proper waits
Use proper waits after every anticipated page-load when facing asynchronous pages. Insert an explicit wait after the initial click and wait for the new page / new content to load. Only after that you can try to search for the element you want. This should be the first thing you'll do. It will increase the robustness of your tests greatly.
The way you did it
I have been using a variant of your method for two years now (together with the technique above in solution 1) and it absolutely works most of the time and fails only on strange WebDriver bugs. Try to access the found element right after it is found (before returning from the method) via a .isDisplayed() method or something. If it throws, you already know how to search again. If it passes, you have one more (false) assurance.
Use a WebElement that re-finds itself when stale
Write a WebElement decorator that remembers how it was found and re-find it when it's accessed and throws. This obviously forces you to use custom findElement() methods that would return instances of your decorator (or, better yet, a decorated WebDriver that would return your instances from usual findElement() and findElemens() methods). Do it like this:
public class NeverStaleWebElement implements WebElement {
private WebElement element;
private final WebDriver driver;
private final By foundBy;
public NeverStaleWebElement(WebElement element, WebDriver driver, By foundBy) {
this.element = element;
this.driver = driver;
this.foundBy = foundBy;
}
#Override
public void click() {
try {
element.click();
} catch (StaleElementReferenceException e) {
// log exception
// assumes implicit wait, use custom findElement() methods for custom behaviour
element = driver.findElement(foundBy);
// recursion, consider a conditioned loop instead
click();
}
}
// ... similar for other methods, too
}
Note that while I think that the foundBy info should be accessible from the generic WebElements to make this easier, Selenium developers consider it a mistake to try something like this and have chosen not to make this information public. It's arguably a bad practice to re-find on stale elements, because you're re-finding elements implicitly without any mechanism for checking whether it's justified. The re-finding mechanism could potentially find a completely different element and not the same one again. Also, it fails horribly with findElements() when there are many found elements (you either need to disallow re-finding on elements found by findElements(), or remember the how-manyeth your element was from the returned List).
I think it would be useful sometimes, but it's true that nobody would ever use options 1 and 2 which are obviously much better solutions for the robustness of your tests. Use them and only after you're sure you need this, go for it.
Use a task queue (that can rerun past tasks)
Implement your whole workflow in a new way!
Make a central queue of jobs to run. Make this queue remember past jobs.
Implement every needed task ("find an element and click it", "find an element and send keys to it" etc.) via the Command pattern way. When called, add the task to the central queue which will then (either synchronously or asynchronously, doesn't matter) run it.
Annotate every task with #LoadsNewPage, #Reversible etc. as needed.
Most of your tasks will handle their exceptions by themselves, they should be stand-alone.
When the queue would encounter a stale element exception, it would take the last task from the task history and re-run it to try again.
This would obviously take a lot of effort and if not thought through very well, could backfire soon. I used a (lot more complex and powerful) variant of this for resuming failed tests after I manually fixed the page they were on. Under some conditions (for example, on a StaleElementException), a fail would not end the test right away, but would wait (before finally time-outing after 15 seconds), popping up an informative window and giving the user an option to manually refresh the page / click the right button / fix the form / whatever. It would then re-run the failed task or even give a possibility to go some steps back in history (e.g. to the last #LoadsNewPage job).
Final nitpicks
All that said, your original solution could use some polishing. You could combine the two methods into one, more general (or at least make them delegate to this one to reduce code repetition):
WebElement getStaleElem(By by, WebDriver driver) {
try {
return driver.findElement(by);
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElem(by, driver);
} catch (NoSuchElementException ele) {
System.out.println("Attempting to recover from NoSuchElementException ...");
return getStaleElem(by, driver);
}
}
With Java 7, even a single multicatch block would be sufficient:
WebElement getStaleElem(By by, WebDriver driver) {
try {
return driver.findElement(by);
} catch (StaleElementReferenceException | NoSuchElementException e) {
System.out.println("Attempting to recover from " + e.getClass().getSimpleName() + "...");
return getStaleElem(by, driver);
}
}
This way, you can greatly reduce the amount of code you need to maintain.
I solve this by 1. keeping the stale element and poll it until it throws an exception, and then 2. wait until the element is visible again.
boolean isStillOnOldPage = true;
while (isStillOnOldPage) {
try {
theElement.getAttribute("whatever");
} catch (StaleElementReferenceException e) {
isStillOnOldPage = false;
}
}
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("theElementId")));
If you are trying to Click on link, that taking you to new page. After that navigating back and clicking on other links. They below code may help you.
public int getNumberOfElementsFound(By by) {
return driver.findElements(by).size();
}
public WebElement getElementWithIndex(By by, int pos) {
return driver.findElements(by).get(pos);
}
/**click on each link */
public void getLinks()throws Exception{
try {
List<WebElement> componentList = driver.findElements(By.tagName("a"));
System.out.println(componentList.size());
for (WebElement component : componentList)
{
//click1();
System.out.println(component.getAttribute("href"));
}
int numberOfElementsFound = getNumberOfElementsFound(By.tagName("a"));
for (int pos = 0; pos < numberOfElementsFound; pos++) {
if (getElementWithIndex(By.tagName("a"), pos).isDisplayed()){
getElementWithIndex(By.tagName("a"), pos).click();
Thread.sleep(200);
driver.navigate().back();
Thread.sleep(200);
}
}
}catch (Exception e){
System.out.println("error in getLinks "+e);
}
}
Solutions to resolve them:
Storing locators to your elements instead of references
driver = webdriver.Firefox();
driver.get("http://www.github.com");
search_input = lambda: driver.find_element_by_name('q');
search_input().send_keys('hello world\n');
time.sleep(5);
search_input().send_keys('hello frank\n') // no stale element exception
Leverage hooks in the JS libraries used
# Using Jquery queue to get animation queue length.
animationQueueIs = """
return $.queue( $("#%s")[0], "fx").length;
""" % element_id
wait_until(lambda: self.driver.execute_script(animationQueueIs)==0)
Moving your actions into JavaScript injection
self.driver.execute_script("$(\"li:contains('Narendra')\").click()");
Proactively wait for the element to go stale
# Wait till the element goes stale, this means the list has updated
wait_until(lambda: is_element_stale(old_link_reference))
This solution, which worked for me
When a Stale Element Exception occurs!!
Stale element exception can happen when the libraries supporting those textboxes/ buttons/ links has changed which means the elements are same but the reference has now changed in the website without affecting the locators. Thus the reference which we stored in our cache including the library reference has now become old or stale because the page has been refreshed with updated libraries.
for(int j=0; j<5;j++)
try {
WebElement elementName=driver.findElement(By.xpath(“somexpath”));
break;
} catch(StaleElementReferenceException e){
e.toString();
System.out.println(“Stale element error, trying :: ” + e.getMessage());
}
elementName.sendKeys(“xyz”);
For Fitnesse you can use:
|start |Smart Web Driver| selenium.properties|
#Fixture(name = "Smart Web Driver")
public class SmartWebDriver extends SlimWebDriver {
private final static Logger LOG = LoggerFactory.getLogger(SmartWebDriver.class);
/**
* Constructs a new SmartWebDriver.
*/
#Start(name = "Start Smart Web Driver", arguments = {"configuration"}, example = "|start |Smart Web Driver| selenium.properties|")
public SmartWebDriver(String configuration) {
super(configuration);
}
/**
* Waits for an element to become invisible (meaning visible and width and height != 0).
*
* #param locator the locator to use to find the element.
*/
#Command(name = "smartWaitForNotVisible", arguments = {"locator"}, example = "|smartWaitForNotVisible; |//path/to/input (of css=, id=, name=, classname=, link=, partiallink=)|")
public boolean smartWaitForNotVisible(String locator) {
try {
waitForNotVisible(locator);
} catch (StaleElementReferenceException sere) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a StaleElementReferenceException occurred, trying to continue...", locator);
} catch (NoSuchElementException ele) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a NoSuchElementException occurred, trying to continue...", locator);
} catch (AssertionError ae) {
if (ae.getMessage().contains("No element found")) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a AssertionError occurred, trying to continue...", locator);
} else {
throw ae;
}
}
return true;
}
}
https://www.swtestacademy.com/selenium-wait-javascript-angular-ajax/ here is a good article about dynamic waiter strategies.
Your problem is not waiting properly all the ajax, jquery or angular calls.
Then you end up with StaleElementException.
If your approach is to use Try-Catch mechanism, I guess it has a flaw. You shouldn't rely on that structure as you'll never know it's gonna work in the catch clause.
Selenium gives you the opportunity to make javascript calls.
You can execute
"return jQuery.active==0"
return
angular.element(document).injector().get('$http').pendingRequests.length
=== 0"
"return document.readyState"
"return angular.element(document).injector() === undefined"
commands just to check the existence and states of those calls.
You can do that before any findBy operation so you always work with the latest page