I am new to the selenium framework and writing a method for the presence of element. Below is the method which I wrote:
public class WebUtlities {
WebDriver driver;
public void waitforanelement(WebElement element)
{
WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.presenceOfElementLocated((By) element));
}
When I call this method for an element, I see the below error:
java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to org.openqa.selenium.By
at Uilities.WebUtlities.waitforanelement(WebUtlities.java:16)
at TestScripts.Testcases.Selfpay(Testcases.java:29)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Please correct me how to make it work for the element to wait
Try with this
public class WebUtlities {
WebDriver driver;
public void waitforanelement(WebElement element)
{
driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("xpath of that element"))); //you can use any other By like id, cssselector, name, linktext etc
}
Hope this helps
use the below code:
public void waitforanelement(By element)
{
WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.presenceOfElementLocated(element));
}
when u call the method, do like below:
By css = By.cssSelector("ur selector");
waitforanelement(css);
hope this will help u.
The problem lies with this line:
wait.until(ExpectedConditions.presenceOfElementLocated((By) element));
Firstly, the presenceOfElementLocated method is used to locate an element on the page, rather than to check that a previously found element is present on the page - as such you should change the argument for your waitforanelement method to accept a By locator instead of a WebElement like so:
public void waitforanelement(By by)
You should then subsequently change the arguments passed to the presenceOfElementLocated method like so:
wait.until(ExpectedConditions.presenceOfElementLocated(by));
The Javadoc for the By class lists the locators you can use.
The problem as you can see from the error is that
new WebDriverWait(driver,20);
wait.until(ExpectedConditions.presenceOfElementLocated((By) element));
returns an WebElement instance which should be assigned to an WebElement. So It can not cast a WebElement to nothing.
Follow the following list for complete list of methods of ExpectedConditions Class.
https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html
Try the following,
public WebElement waitforanelement(WebElement element)
{
WebDriverWait wait= new WebDriverWait(driver,20);
WebElement Element=wait.until(ExpectedConditions.presenceOfElementLocated((By) element));
return Element1;
}
Related
I am trying to use the following selenium to look for a child in a parent element and this works great
ExpectedConditions.presenceOfNestedElementLocatedBy(parent, By.xpath(xpath))
Now I want a method that returns ALL the elements that match the xPath, however, to my surprise the signature requires a By instead of the WebElement I would expect.
How can I convert my WebElement to a by to get the other elements?
Here's an example for you to get all the child Elements by Passing BY:
public class Demo {
static WebDriver driver;
public static void main(String[] args)
{
System.setProperty("webdriver.chrome.driver", "c:\\eclipse\\selenium\\chromedriver.exe");
driver = new ChromeDriver();
driver.get("http://google.com");
By x = By.xpath("//div"); //or your By.xpath(xpath)
List<WebElement> allItem = getChildElements(x);
System.out.println(allItem.size());
for(WebElement item : allItem){
System.out.println(item.getText());
}
}
public static List<WebElement> getChildElements(By x){
List<WebElement> allElems = driver.findElements(x);
return allElems;
}
}
Try doing class casting and proceed with. The code will look something similar to this.
WebElement parent = driver.findElement(By.xpath(""));
WebElement child = driver.findElement(By.xpath(""));
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfNestedElementLocatedBy(parent, (By)child));
Hope this helps you. Thanks.
For the Page Object example class below, I have an accountsLink private member which maps to a non-dynamic element on the Login page when it loads. It is initialized using the FindBy annotation when the initElements method is called from the constructor.
public class Login {
private WebDriver driver;
#FindBy(id = "account")
private WebElement accountsLink;
//constructor, elements are initialized by the PageFactory
public MainPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
//clicking accounts opens a dynamic ajax menu which has a Sign In Button
public SignInPage clickAccountsLink() {
accountsLink.click();
WebElement signInButton = driver.findElement(By.id("signin"));
signInButton.click();
return new SignInPage(driver);
}
}
Now for the problem. I have another element (signInButton) which is dynamically loaded only when you click the accountsLink element. This action doesn't take you to another page but only brings up an ajax menu where the sign in button will appear.
My question is, since the signInButton element only appears when the accountsLink element is clicked, can it be declared as a member of the Login class with a FindBy annotation or do I have to stick with my current solution of using a driver.findElement(By.id("signin")) inside the clickAccountsLink method?
I hope my question makes sense.
When PageFactory.initElements is called it parses the current DOM. If the WebElement doesn't exist in that time it can't be given as a value to a variable, exactly as you can't locate non-existing WebElement using driver.findElement.
Your solution is the way to go, although I would use explicit wait and Expected Conditions when loading the signInButton.
You can declare, I don't think it's gonna give you any error. Page Factory creates a dummy element when it initialized the class. It creates the actual element only when you intersect with the element for the first time.
For example in following class NoExistingElement element doesn't exist and it won't give me any error, If I will call the enterText method of class. The test case will pass without any error.
However, If i will try to call any function on NoExistingElement element then only it will fail with Webdriver exception, ElementNotFoundException
public class GoogleSearch {
#FindBy(name="q")
static WebElement searchBox;
#FindBy(name = "qqqqq")
WebElement NoExistingElement;
public GoogleSearch(WebDriver driver){
PageFactory.initElements(driver, this);
driver.get("https://www.google.com");
}
public void searchOnGoogle(String text){
searchBox.sendKeys(text);
}
}
I am Having a Lot of WebElements
For Example I Declared a WebElement a
#FindBy(id="BtnLogin")
private WebElement btnLogin;
In the Same Manner I created "N" number of WebElements
Every time I Cant use "driver.findElement()" function So I wrote a function
public static void WebElementClick(WebElement we)
{
we.click();
}
When Ever the Control is Going to The Line we.click() in the WebElementclick Function it is Showing NullPointerException as a Result My Purpose is Failing
I am Not Getting What to Do,Some One Please Help Me on this :)
Your WebElementClick should receive the selector and it should: find element -> click, you can get an example from the above link.
In your case you it seems that you are not using wait and the WebElementClick it tries to click on the string.
Using find will return an object that will make click available.
The method should contain something like: driver.findElement(By.xpath("your_selector"));
Ant then use click on what this method returns.You can use also css if you want to.
public class testJava{
#Test
public void testMethod() throws InterruptedException {
WebDriver driver = new FirefoxDriver();
pageClass pageClass = PageFactory.initElements(driver, pageClass.class);
driver.get("http://www.facebook.com");
Thread.sleep(5000);
pageClass.clickLoginBtn();
}}
public class pageClass {
#FindBy(id = "loginbutton")
private WebElement loginBtn;
WebDriver driver;
public pageClass(WebDriver driver) {
this.driver = driver;
}
public void clickLoginBtn()
{
click(loginBtn);
}
public void click(WebElement we)
{
we.click();
}}
Its best practice to use the page class & test class..Try this it will help you i guess.
You are suppose to use driver to find & click the element.
I think that driver may try to click element before it's presented. Good practice before clicking WebElement is to wait for WebElement being clickable. I would try:
public static void WebElementClick(WebElement we)
{
wait.forElementClickable(we);
we.click();
}
I have been reading about stale elements and am still a bit confused. For instance, the following won't work, correct?
public void clickFoo(WebElement ele) {
try {
ele.click();
} catch (StaleElementReferenceException ex) {
ele.click();
}
}
because if ele is stale, it will remain stale. The best thing is to redo the driver.findElement(By), but as you can see in this example, there is no xpath. You can attempt to ele.getAttribute("id") and use that, but if the element has no id, this also will not work. All methods calling this would have to put the try/catch around it, which may not be feasible.
Is there some other way the element could be refound? Also, assuming there is an id, would the id remain the same after the element goes stale? What in the WebElement object ele is different once it goes stale?
(Java Eclipse)
I would recommend you NOT create a method like the above. There's no need to add another function layer on top of .click(). Just call .click() on the element itself.
driver.findElement(By.id("test-id")).click();
or
WebElement e = driver.findElement(By.id("test-id"));
e.click();
One way that I use regularly to avoid stale elements is find the element only when you need it and generally I do this by in a page object method. Here's a quick example.
The page object for a home page.
public class HomePage
{
private WebDriver driver;
public WebElement staleElement;
private By waitForLocator = By.id("sampleId");
// please put the variable declarations in alphabetical order
private By sampleElementLocator = By.id("sampleId");
public HomePage(WebDriver driver)
{
this.driver = driver;
// wait for page to finish loading
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(waitForLocator));
// see if we're on the right page
if (!driver.getCurrentUrl().contains("samplePage.jsp"))
{
throw new IllegalStateException("This is not the XXXX Sample page. Current URL: " + driver.getCurrentUrl());
}
}
public void clickSampleElement()
{
// sample method code goes here
driver.findElement(sampleElementLocator).click();
}
}
To use it
WebDriver driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.get("http://www.example.com");
HomePage homePage = new HomePage(driver);
homePage.clickSampleElement();
// do stuff that changes the page and makes the element stale
homePage.clickSampleElement();
Now I no longer have to rely on an old reference. I just call the method again and it does all the work for me.
There are many references on the page object model. Here's one from the Selenium wiki. http://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern
If you want to read more info on what a stale element is, the docs have a good explanation. http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp
It's convenient to wait for an WebElement to be present with WebDriverWait and ExpectedConditions.
The problem is, what if WebElement.findElment was the only possible way to locate the element , 'cause it has no id, no name, no unique class?
WebDriverWait's constructor accepts only WebDriver as arguments, not WebElement.
I've set the implicitlyWait time, so it seems not a good idea to use try{} catch(NoSuchElementException e){}, 'cause I don't want to wait that long time for this element.
Here's the scenario:
There's one web page with a form containing many input tags. Each input tag has a format requirement.
A dynamic div tag would be present after this input tag when the format requirement is not satisfied.
As there're so many input tags, I create a general method like:
public WebElement txtBox(String name) {
return driver.findElement(By.name(name));
}
instead of creating a data member for each input tag.
Then I create a method isValid to check whether user inputs in some input are valid. All I should do in isValid is to check whether a div tag is present after inputboxToCheck, with code like this:
public boolean isValid(WebElement inputboxToCheck) {
WebElementWait wait = new WebElementWait(inputboxToCheck, 1);
try {
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("./following-sibling::div")));
return false;
} catch (TimeOutException e) {
return true;
}
}
WebElementWait is an imaginary (not exist) class which works the same way as WebDriverWait.
The WebElementWait class as metioned above:
package org.openqa.selenium.support.ui;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebElement;
public class WebElementWait extends FluentWait<WebElement> {
public final static long DEFAULT_SLEEP_TIMEOUT = 500;
public WebElementWait(WebElement element, long timeOutInSeconds) {
this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, DEFAULT_SLEEP_TIMEOUT);
}
public WebElementWait(WebElement element, long timeOutInSeconds, long sleepInMillis) {
this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, sleepInMillis);
}
protected WebElementWait(WebElement element, Clock clock, Sleeper sleeper, long timeOutInSeconds,
long sleepTimeOut) {
super(element, clock, sleeper);
withTimeout(timeOutInSeconds, TimeUnit.SECONDS);
pollingEvery(sleepTimeOut, TimeUnit.MILLISECONDS);
ignoring(NotFoundException.class);
}
}
It's the same as WebDriverWait, except that the WebDriver argument is replaced with WebElement.
Then, the isValid method:
//import com.google.common.base.Function;
//import org.openqa.selenium.TimeoutException;
public boolean isValid(WebElement e) {
try {
WebElementWait wait = new WebElementWait(e, 1);
//#SuppressWarnings("unused")
//WebElement icon =
wait.until(new Function<WebElement, WebElement>() {
public WebElement apply(WebElement d) {
return d.findElement(By
.xpath("./following-sibling::div[class='invalid-icon']"));
}
});
return false;
} catch (TimeoutException exception) {
return true;
}
}
I don't know if this help you, but it permits to wait element how much time do you want.
public WebElement findDynamicElement(By by, int timeOut) {
WebDriverWait wait = new WebDriverWait(driver, timeOut);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
return element;
}
findDynamicElement(By.xpath("//body") , 30);
A more universal variant of user2432405's solution would be using SearchContext type rather then WebElement:
public class SearchContextWait extends FluentWait<SearchContext> {
...
This allows to do waits on both WebDriver and WebElement similarly as the SearchContext interface is the ancestor of both WebDriver and WebElement. The isValid method needs adjustment too:
...
WebElement icon = wait
.until(new Function<SearchContext, WebElement>() {
public WebElement apply(SearchContext d) {
...
Unfortunately, you lose all conveniences of ExpectedConditions.xxxx() methods as they use the WebDriver interface internally.
I found this blog: Checking for an element – exists?, visible?, present? - https://jkotests.wordpress.com/2012/11/02/checking-for-an-element-exists-visible-present/
And it brought up the differences between exists, visible, and present.
exists? – Returns whether this element actually exists.
present? – Returns true if the element exists and is visible on the page
visible? – If any parent element isn’t visible then we cannot write to the element. The only reliable way to determine this is to iterate
up the DOM element tree checking every element to make sure it’s
visible.
Exists will tell you if what you are searching for is anywhere in the DOM; however, WebDriver does not seem to have a built in way to check if an element exists similar to plain driver.findElement(By.name(name)).
And, as explained in the blog, Exists is not the same as Present. So I can't use ExpectedConditions.presenceOfAllElementLocatedBy(By.cssSelector(cssSelector)
My solution: (looking for feedback here :)
public WebElement waitForElementExists(String selector, String timeout) {
Wait<WebDriver> wait = new WebDriverWait(driver, timeout);
WebElement element = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.cssSelector(selector));
}
});
return element;
}