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!");
Related
In a setup with Java, Cucumber and Selenium:
I've got the following code which attempts to navigate to a page, and then look for the presence of one or two elements to verify that I am on the page itself.
The problem: About 1 out of 5 times, the test hangs on the page before the target page, apparently looking for (and not finding) the elements before the page navigation is completed.
The error message:
org.openqa.selenium.TimeoutException: Expected condition failed: waiting
for e2e.navigation.NavigationSteps$$Lambda$260/975372289#202898d7 (tried
for 40 second(s) with 500 milliseconds interval)
The Cucumber step:
And I navigate to the decision list for the "case"
The step definition:
#When("^I navigate to the decision list for the \"([^\"]*)\"$")
public void INavigateToDecisionListFor(String case) throws Throwable {
long caseId = ScenarioState.getCaseId(case);
desicionlistPage.navigateTo(caseId);
// It looks like this code is executed before the page navigation
// (above) is executed, hence making the test hang here looking for
// the elements on the
// target page:
Browser.Wait().ignoring(WebDriverException.class).until(webDriver ->
{
WebElement enabledButton = null;
WebElement disabledButton = null;
try {
enabledButton = webDriver.findElement(By.id("opprett-
innstilling-btn"));
} catch (NoSuchElementException ignore) { }
try {
disabledButton = webDriver.findElement(By.id("opprett-
innstilling-btn-disabled"));
} catch (NoSuchElementException ignore) { }
return enabledButton != null || disabledButton != null;
});
}
DecisionListPage.java:
public void navigateTto(long vased) {
driver.navigate().to(Config.getSimulatedUrl() + "/#/case/" + cased +
"/decision/");
}
The URL is correct. I can enter it manually when the test hangs, and then the test continues (to the element verification). So the problem definetely seem to be that the verification is attempted before the navigation is performed.
When troubleshooting, I've tried adding extra waits and replacing driver.navigate.To() with driver.get(), with no luck. It still fails frequently.
However, if I repeat the navigate().to() step, then it seems to work. That is, just do it twice, like this:
driver.navigate().to(Config.getSimulatedUrl() + "/#/case/" + cased +
"/decision/");
driver.navigate().to(Config.getSimulatedUrl() + "/#/case/" + cased +
"/decision/");
I've run the tests manually 30-40 times, and it hasn't failed with the above solution. But that's just a silly way to do it.
So what I'm wondering about is: The best wait to ensure that the driver.navigate.To() is actually performed before the execution continues? I thought driver.get() was the way to acchieve that, but that fails just as surely.
NB: This code is not written by me, but I'm using it. I'm not sure that I'd do the element verification quite like this myself, but the problem seems to be with the navigation not completing/waiting, and not the checks themselves.
I apologize if the question is unclear, or if I should've checked this or that obvious thing before asking. If so, please tell me and I'll update the question.
UPDATE
There is also a link button for navigating to the page. When I use THAT, it seems to work all the time. But this is kind of worse; Why on earth doesn't it work with navigate().to() (unless I do it twice), when it works with the link?
After reviewing your code, I hope you are using Scenario Outline concept of cucumber to run the same test case with multiple cases like below:
Scenario Outline:
When I navigate to the decision list for the "<code>"
Examples:
|code|
|100|
|200|
|300|
|400|
|500|
In your code, you are performing navigation and validation whether the expected elements are displaying on the loaded page or not in single step. Instead you can try in this in two steps to overcome navigational issues to the right coded url:
-- feature file
Scenario Outline:
When I navigate to the decision list for the "<code>"
Then I perform validation on loaded page
Examples:
|code|
|100|
|200|
|300|
|400|
|500|
--spec file
#When("^I navigate to the decision list for the \"([^\"]*)\"$")
public void INavigateToDecisionListFor(String case) {
long caseId = ScenarioState.getCaseId(case);
DecisionListPage.navigerTil(caseId );
}
// Above step will navigates you to the specific case page
#Then("^I perform validation on loaded page"$)
public boolean performValidation() throws Throwable {
WebElement enabledButton = null;
WebElement disabledButton = null;
try {
enabledButton = webDriver.findElement(By.id("opprett-
innstilling-btn"));
} catch (Exception ignore) { }
try {
disabledButton = webDriver.findElement(By.id("opprett-
innstilling-btn-disabled"));
} catch (Exception ignore) { }
return enabledButton != null || disabledButton != null;
}
// above step will perform validations for you
--DecisionListPage.java:
public static void navigerTil(long caseId ) {
driver.navigate().to(Config.getSimulatedUrl() + "/#/case/" + caseId +
"/decision/");
}
Do these changes in your code and run it once. I hope, this process will resolve this issue.
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 would like to use conditional function using .isDisplayed() method. Everything is working correct as long as this method returns true.
HTML is not required I think here, because I have only one button to be visible on the page, which is correclty found (I successfully clicked the button with the following xpath.
Now I try with:
if (driver.findElement(By.xpath("//a[#id='button1']")).isDisplayed()) {
//do stuff
}
else {
//do other stuff
}
Or even
WebElement withdrawnBtn = driver.findElement(By.xpath("//a[#id='button1']"));
boolean isVisible = withdrawnBtn.isDisplayed();
if (isVisible) {
//do stuff
}
else {
//do other stuff
}
but both conditionals fails, if in the first run there should be executed code from else, because everytime when the button is not available, there is fail pointing on the line with driver.findElement(By.xpath("//a[#id='button1']")).isDisplayed()); - fails, because the button is not displayed. I need t o do something, when the button is not displayed instead failing code...
Before checking isDisplayed conditions we need to check whether element exist on the page or not Otherwise it will throw Nosuchelementfound exception
driver.findElements("Locator").size()-- will return integer value if the element exist on the page.
Below is the fix code.
int size = driver.findElements("Locator").size();
if(size!=0){
if(driver.findElement("Locator").isDisplayed()){
// do operations
}
}
After reading comments, I got to know isEmpty is better way to use instead of size I made changes to the above code.
WebDriver driver;
List<WebElement> webElements = driver.findElements(By.xpath("test"));
if(!webElements.isEmpty()){
if(driver.findElement(By.xpath("test")).isDisplayed()){
// do operations
}
}
Try it and let me know if it works for you
you can also use following to identify if an element exists or not:
private boolean isPresent(WebElement element) {
try {
element;
} catch (NoSuchElementException e) {
return false;
}
return true;
}
OK, I was thinking about catching NoElementFound exception, but I found this issue:
Selenium Webdriver: best practice to handle a NoSuchElementException
using link above I used:
List<WebElement> withdrawnBtn = driver.findElements(By.xpath("//a[#id='button1']"));
if (withdrawnBtn.size() != 0) {
//do stuff
}
else {
//do other stuff
}
Instead of size() method you could use isEmpty() method.
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;
}
}
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