I have one end user page which have number of controls (textboxes, checkbox, dropdown) let's say 30 . All these enabled from admin panel .
I have enclosed all these in try catch block individually e.g.
try
{
driver.findElement(By.locator); // For Control 1
}
catch(Exception e)
{
}
try
{
driver.findElement(By.locator); // For Control 2
}
catch(Exception e)
{
}
and So On...
The problem is, suppose admin enabled only 1 field which is last in my code. So while executing the script My script is too slow because it check each element one by one and if not found then handle that in catch block until the last element found.
Is there any way to mitigate this time wastage ?
You can use findElements and check if there are any elements found. If there aren't any you will get an empty list without an exception. You can build a method that returns the element if it exists or null if it doesn't
private WebElement findElement(WebDriver driver, By locator) {
List<WebElement> elements = driver.findElements(By.locator);
return elements.size() > 0 ? elements.get(0) : null;
}
findElements(driver, By.locator); // For Control 1
findElements(driver, By.locator); // For Control 2
// ...
You can manage your timeouts by doing:
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
You can do this if you want at the beginning of your method and then set it again to what you had and fits best the needs of your site.
More on that: http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp
In such scenarios, using FluentWait is the most reliable approach. You should chuck using driver.findElement(By) and instead create a method getElement(By) in a commonly accessible class such as BasePage.class
public class BasePage {
WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public WebElement getElement(By locator) {
// Waiting 30 seconds for an element to be present on the page, checking
// for its presence once every 5 seconds.
Wait wait = new FluentWait(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
// Get the web element
WebElement element = wait.until(new Function() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});
return element;
}
}
Related
I need to find if an element is displayed or not. How to check that in selenium web driver?
if(driver.findElement(By.id("p_first_name")).isDisplayed())
{
WebElement fname =driver.findElement(By.id("p_first_name"));
fname.sendKeys("pradnya");
WebElement lname = driver.findElement(By.xpath("//*[#id=\"p_last_name\"]"));
lname.sendKeys("Bolli");
WebElement Address1 = driver.findElement(By.xpath("//*[#id=\"address_11\"]"));
Address1.sendKeys("New address1");
WebElement Address2 = driver.findElement(By.xpath("//*[#id=\"address_21\"]"));
Address2.sendKeys("New address2");
WebElement City = driver.findElement(By.xpath("//*[#id=\"city1\"]"));
City.sendKeys("Pune");
WebElement Country = driver.findElement(By.xpath("//*[#id=\"country1\"]"));
Country.sendKeys("India");
WebElement ZipCode = driver.findElement(By.xpath("//*[#id=\"pincode1\"]"));
ZipCode.sendKeys("India");
WebElement State = driver.findElement(By.xpath("//*[#id=\"bds\"]"));
State.sendKeys("Maharashtra");
}
else
{
WebElement address = driver.findElement(By.xpath("//*[#id=\"update_add77\"]"));
address.click();
}
On the checkout page first it shows address form and when user fils that then listing is shown. Address form is not showing when the listing is showing. In this case, how to check if an address form field is displayed or not?
I use above code but it gives me exception message
'Unable to locate element: #p_first_name'
The element is giving NoSuchElementException as the element is not present on the UI on which you are trying to find it using the isDisplayed() method.
So, to solve your problem you should fetch the list of the element and then can get the size of that list, if the size is greater than 0, it means the element is present on the page else the element is not present.
You need to make the following changes in the code:
if(driver.findElements(By.id("p_first_name")).size()>0){
// Add the if code here
}
else{
// Add the else code here
}
You can create method for such check. We are using NoSuchElementException to verify element is not existing.
public boolean isElementExist(By locator)
{
try {
driver.findElement(locator);
} catch (NoSuchElementException e) {
return false;
}
return true;
}
Or due slow loading and timeouts, i advice to use *WebDriverWait*
public boolean isElementPresent(By element,int timeOutInSeconds,int pollingEveryInMiliSec) {
try {
WebDriverWait wait = new WebDriverWait(d, timeOutInSeconds);
wait.pollingEvery(pollingEveryInMiliSec, TimeUnit.MILLISECONDS);
wait.ignoring(NoSuchElementException.class);
wait.ignoring(ElementNotVisibleException.class);
wait.ignoring(StaleElementReferenceException.class);
wait.ignoring(NoSuchFrameException.class);
wait.until(ExpectedConditions.visibilityOfElementLocated(element) ));
return true;
}
catch(Exception e) {
return false;
}
}
If you consider timeOutInSeconds=20 and pollingEveryInMiliSec=5 in every 5 ms this method will search for the giving element until it find's it with in 20ms
Is there any FluentWait implementation available for WebdriverIO?
Looking for something similar to the Selenium Java FluentWait implementation, for example one below:
Wait wait = new FluentWait(WebDriver reference)
.withTimeout(timeout, SECONDS)
.pollingEvery(timeout, SECONDS)
.ignoring(Exception.class);
WebElement foo=wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});
I tried searching on various docs, but couldn't find an equivalent. Thanks!
You can use waitUntil api for that
it('should wait until element is existing for 5000ms with 250ms polling', () => {
browser.waitUntil(() => {
return $('#someText').isExisting(); // condition
}, 5000, 'expected element to be exist after 5s', 250);
});
it doesn't have ignore exception but maybe you can add try catch in condition function. But it will provide all the other functionalities.
I have created one override method(click() method) in BaseElement class which implements from WebElement interface.
I would like to call this overridden method on all web elements wherever applicable.
WebElement ele = driver.findElement(By.id("button")); // it returns webelement type by default
How Can I call my override click() method on above web element?
I have tried with down casting ele to BaseElement like below:
BaseElement m_ele = (BaseElement) ele; // No compilation error but throws runtime class casting exception
Any idea could help me here in order to call overridden click() method on WebElement? I dont want to user in-built click() method of WebElement.
Let me know if I have to provide any additional information?
Here is my code snippet:
public class BaseElement implements WebElement {
public BaseElement(WebElement element) {
m_element = element;
}
#Override
public void click() {
try {
m_element.click();
} catch (WebDriverException e) {
try {
logger.debug("Click Failed, Attempting to click by scrolling into view with bottom align option");
scrollIntoView();
m_element.click();
} catch (WebDriverException ef) {
try {
logger.debug("Click Failed, Attempting to click by scrolling into view with top align option");
scrollIntoView(true);
m_element.click();
} catch (WebDriverException e2) {
try {
logger.debug("Click Failed, Attempting to click by scrolling down by 200 pixels");
m_jsDriver.executeScript("window.scrollBy(0,200)");
m_element.click();
} catch (WebDriverException e3) {
logger.debug("Click Failed, Attempting to click by scrolling up by 200 pixels");
m_jsDriver.executeScript("window.scrollBy(0,-200)");
m_element.click();
}
}
}
}
}
}
You can try the following code to use over ridden click method.
WebElement ele = driver.findElement(By.id("button"));
BaseElement m_ele = new BaseElement(ele);
m_ele.click();
I have used below code, but it throws an error saying "Cannot focus on element". Please help.
String selectAll = Keys.chord(Keys.ALT,"T");
driver.findElement(By.tagName("html")).sendKeys(selectAll);
The best way to switch tabs would be to use switchTo(), if you know the new window name:
driver.switchTo().window(WINDOW_NAME);
Otherwise get a list of the open windows and switch using that:
List<String> openTabs = driver.getWindowHandles();
for(String tab in openTabs) {
driver.switchTo().window(openTabs.get(tab);
}
So you can iterate over the open windows until you find the one you need.
You can send ShortcutKeys like Alt + Tab to driver without using element by using Actions.
public static void sendShortCut(WebDriver driver) {
Actions action = new Actions(driver);
action.sendKeys(Keys.chord(Keys.CONTROL, "T")).build().perform();
}
However your goal was to switch to the window/tab.In Selenium both window and tab are same.
I've provided you two solutions which is self explanatory from the name of the functions
public static void switchToWindowByTitle(WebDriver driver, String title) {
Set<String> Handles = driver.getWindowHandles();
for (String handle : Handles) {
driver.switchTo().window(handle);
String drivertitle = driver.getTitle().trim();
if (drivertitle.equals(title)) {
break;
}
}
}
//Index is 0 based
public static void switchToWindowByIndex(WebDriver driver, int index) {
Set<String> handles = driver.getWindowHandles();
if (handles.size() > index) {
String handle = handles.toArray()[index].toString();
driver.switchTo().window(handle);
}
}
You can open another tab using:
driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL + "t");
and switch to tabs by using:
driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL, Keys.PAGE_DOWN);
In Selenium 2 I want to ensure that an element on the page that the driver has loaded does not exist. I'm including my naive implementation here.
WebElement deleteLink = null;
try {
deleteLink = driver.findElement(By.className("commentEdit"));
} catch (NoSuchElementException e) {
}
assertTrue(deleteLink != null);
Is there a more elegant way that basically verifies to assert that NoSuchElementException was thrown?
If you are testing using junit and that is the only thing you are testing you could make the test expect an exception using
#Test (expected=NoSuchElementException.class)
public void someTest() {
driver.findElement(By.className("commentEdit"));
}
Or you could use the findElements method that returns an list of elements or an empty list if none are found (does not throw NoSuchElementException):
...
List<WebElement> deleteLinks = driver.findElements(By.className("commentEdit"));
assertTrue(deleteLinks.isEmpty());
...
or
....
assertTrue(driver.findElements(By.className("commentEdit")).isEmpty());
....
You can use this:
Boolean exist = driver.findElements(By.whatever(whatever)).size() == 0;
If it doesn't exist will return true.
I split out page classes so I don't have to define elements more than once. My nunit and mbunit test classes call those page classes. I haven't tried this out yet but this is how I'm thinking about doing it so I can use .exists() like I did with WatiN.
Extension Class:
public static class ExtensionMethods
{
public static IWebElement ElementById(this IWebDriver driver, string id)
{
IWebElement e = null;
try
{
e = driver.FindElement(By.Id(id));
}
catch (NoSuchElement){}
return e;
}
public static bool Exists(this IWebElement e)
{
if (e == null)
return false;
return true;
}
}
Page Class:
public IWebElement SaveButton { get { try { return driver.ElementById("ctl00_m_m_body_body_cp2_btnSave")); } }
Test Class:
MyPageClass myPageClass = new MyPageClass(driver);
if (myPageClass.SaveButton.Exists())
{
Console.WriteLine("element doesn't exist");
}
You can retrieve a list of elements by using driver.findElements("Your elements") and then search for the element. if the list doesn't contains the element you got yourself your desired behavior :)
If you're using the Javascript API, you can use WebElement.findElements(). This method will return a Promise with an array of found elements. You can check the length of the array to ensure no items were found.
driver.findElements(By.css('.selector')).then(function(elements) {
expect(elements.length).to.equal(0)
})
I'm using Chai assertion library inside the Promise's callback to expect a certain value.
Reference: https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebElement.html
Best solution
protected boolean isElementPresent(WebElement el){
try{
el.isDisplayed();
return true;
}
catch(NoSuchElementException e){
return false;
}
}
public boolean exist(WebElement el){
try {
el.isDisplayed();
return true;
}catch (NoSuchElementException e){
return false;
}
}
if(exist(By.id("Locator details"))==false)
or
WebElement el= driver.findElementby(By.locator("locator details")
public boolean exists(WebElement el)
try{
if (el!=null){
if (el.isDisplayed()){
return true;
}
}
}catch (NoSuchElementException e){
return false;
}
}
Using webdriver find_element_xxx() will raise exception in my code and take us the waiting time of implicit/explicit webdriver wait.
I will go for DOM element check
webdriver.execute_script("return document.querySelector('your css class')")
p.s.
Also found similar discussion on our QA-main sister site here
For full check for visibility+existence
# check NOT visible the :aftermeet and :viewintro
# ! . . ! !offsetWidth to check visible in pure js ref. https://stackoverflow.com/a/20281623/248616
css='yourcss'; e=wd.execute_script(f"return document.querySelector('{css}').offsetWidth > 0") ; assert not e
# check NOT exists :viewintro
css='yourcss'; e=wd.execute_script(f"return document.querySelector('{css}')") ; assert not e
Use assertFalse :)
assertFalse(isElementPresent(By.className("commentEdit")));