Why using a list of elements in selenium won't work but if I use WebDriver it works - selenium-webdriver

I have this code which locate div elements in the dom I used selenium in order to find elements in the HTML page:
package com.indeni.automation.ui.model.alerts;
import com.indeni.automation.ui.model.PageElement;
import com.indeni.automation.ui.selenium.DriverWrapper;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import java.util.List;
public class FilterBar extends PageElement {
private List<WebElement> edgeDropDownMenus = driver.findElements(By.cssSelector("div.dropdown-menu.left"));
private List<WebElement> middleDropDownMenus = driver.findElements(By.cssSelector("div.combo-menu.left"));
public FilterBar(DriverWrapper driver){
super(driver);
}
public void clickOnIssuesDropDownMenu(){
clickButton(edgeDropDownMenus.get(0));
}
}
And this is clickButton function:
protected void clickButton(WebElement bthElm){
bthElm.click();
printClick(bthElm);
}
I am getting the following error:
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
but if I am using the following line of code it is working:
clickButton(driver.findElements(By.cssSelector("div.dropdown-menu.left")).get(0));
But I want to use the first elegant way but I can't figure out why am I getting this error message and how to fix it.

I am sorry to say that the first approach is not elegant. It is wrong to find the element when the class is initialized. When the class is initialized, those elements were not available. So the list would be basically empty. If you try to access any element from the list, it would throw the exception.
In your second approach, you find the element just before you click on it. That time it presents, so it works. This is the right way to do it.
If you want something elegant, Try something like this. With FindBy, we find the element, only when it is required. Not when the class is initialized. This is elegant and it will also work.
public class FilterBar extends PageElement {
#FindBy(css = "div.dropdown-menu.left" )
private List<WebElement> edgeDropDownMenus;
#FindBy(css = "div.combo-menu.left")
private List<WebElement> middleDropDownMenus;
public FilterBar(DriverWrapper driver){
super(driver);
PageFactory.initElements(driver, this);
}
public void clickOnIssuesDropDownMenu(){
clickButton(edgeDropDownMenus.get(0));
}
}

Related

Powermock of static class gives error: java.lang.NoClassDefFoundError: Could not initialize class XXX

Problem
Could not initialize class ...
...javax.xml.transform.FactoryFinder (in our case).
In the article, where we found the solution, it was the class SessionFactory.
Class Under Test
We wanted to write a test for a utils class with static members.
We got the error when trying to create a Mock of a class, which contained a new statement as an initialization of a static field.
public class ClassUnderTest{
private static JavaType javaType = new JavaType();
// ...
}
Test Class
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassUnderTest.class)
public class TestForClassUnderTest {
#Test
public void testCase() {
PowerMockito.mockStatic(ClassUnderTest.class);
Solution
The solution was adding another class level annotation to the test class:
#SuppressStaticInitializationFor("com.example.package.util.ClassUnderTest")
Note, that you have to give the package path and no .class at the end. Unlike #PrepareFor.
Thanks to this article: http://www.gitshah.com/2010/06/how-to-suppress-static-initializers.html
Test Class with Solution
//...
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassUnderTest.class)
#SuppressStaticInitializationFor("com.example.package.util.ClassUnderTest") // <-- this is it :)
public class TestForClassUnderTest {
#Test
public void testCase() {
PowerMockito.mockStatic(ClassUnderTest.class);
//...
}
}

Report Test Case Names for #TestFactory

I have a Junit #TestFactory method, and I would like to create a report of all the test case names. This is easily viewed in Eclipse, but I would also like to do some text processing on the names at the command line. Is there any way that I can get this reported by Surefire at the command line?
You could implement and register a custom TestExecutionListener.
For example, you could implement something similar to the following.
package my.example.package;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.junit.platform.engine.TestDescriptor.Type;
import org.junit.platform.engine.TestExecutionResult;
public class DynamicTestListener implements TestExecutionListener {
private final Set<TestIdentifier> dynamicTests = Collections.synchronizedSet(new LinkedHashSet<>());
#Override
public void dynamicTestRegistered(TestIdentifier testIdentifier) {
if (testIdentifier.getType() == Type.TEST) {
this.dynamicTests.add(testIdentifier);
}
}
#Override
public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
if (this.dynamicTests.contains(testIdentifier)) {
System.out.println(testIdentifier.getDisplayName());
}
}
}
The above example can be automatically registered via Java's ServiceLoader mechanism by putting the following in src/test/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener (or under src/main/resources if you are publishing a library):
my.example.package.DynamicTestListener

How use waits in Html Elements framework

I have tried to use Html Elements framework. Here are one of my blocks:
#Block(#FindBy(id = "test"))
public class FirstBlock extends HtmlElement {
#FindBy(id = "nameS")
private TextInput id;
#FindBy(id = "saveBt")
private Button add;
public void addNewClient(String idText) {
add.click();
id.sendKeys(idText);
}
}
I have initialized page factory like:
PageFactory.initElements(new HtmlElementDecorator(driver), this);
Now I want to wait after add.click(); until next element is present.
As I found out where is possibility to use AjaxElementLocatorFactory
But how can I make this using Html Elements framework?
HtmlElements use AjaxElementLocatorFactory by default, so you don't need any explicit waits in your code. It will try to find your id element until succeed and then executes sendKeys() on it. In case element wait timeout will be reached, it'll throw ElementNotFound exception.

two elements of same class in selenium webdriver

I am working on selenium web driver using the language "Java" and want to access two elements of same classname. Actually, both the elements are error messages which are coming in small popup having the same class. But the problem is that every time it only picks the first element of the class which is coming. Please suggest which method I should use to get both the elements.
Also, I need to compare both the messages with the string that I have added. Here is the code I have tried:
public class mysignup {
public static WebDriver d;
public static void main(String []args)throws Exception{
d = new FirefoxDriver();
d.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
d.findElement(By.name("firstname")).sendKeys("qwertyuiokjhgfdsazxcvbnmkloiuytr");
d.findElement(By.name("firstname")).click();
d.findElement(By.name("lastname")).sendKeys("singh");
d.findElement(By.name("email_id")).sendKeys("abcgmail.com");
d.findElement(By.name("firstname")).click();
d.findElement(By.name("email_id")).click();
String bodyText = d.findElement(By.cssSelector(".popover-content")).getText();
While findElement returns you a single WebElement, findElements will return all elements that match given conditions.
In such a scenario I would suggest using findElements method. It will return you a list of all elements if found or an empty list. So you can try out with:
List<WebElement> lstEle = d.findElements(By.cssSelector(".popover-content"));
List<String> strLst = new ArrayList<String>();// list to contain all texts in each element
lst.forEach(new Consumer<WebElement>() { // foreach element add text to strLst
#Override
public void accept(WebElement t) {
strLst.add(t.getText());
}
});

Using Collection sort for ArrayList

class UnfairContainer<T> implements Comparable<UnfairContainer>
{
private ArrayList<T> array = new ArrayList<T>();
public void sort()
{
Collections.sort(array);
}
public int compareTo(UnfairContainer o)
{
}
}
So i have my class that implements comparable but when i try to create the sort method that calls Collections.sort(), it gives me an error that says i can't call collection sort with an ArrayList . Can anyone help? and help me with my compareTo method, i'm stuck on how i'm suppose to compare each element within my ArrayList
The problem is that the list is not guaranteed to be sort-able. This is because with your current setup, T could be anything- including a class that does not implement Comparable and hence cannot be sorted by Collections. The type signature of Collections.sort() reflects this:
public static <T extends Comparable<? super T>> void sort(List<T> list);
To fix this, you need to put an upper bound on T to ensure that it is sort-able:
class UnfairContainer<T extends Comparable<T> >
implements Comparable<UnfairContainer<T> >
{
...
The T extends Comparable<T> means that T must be a class that implements Comparable. This lets Collections know that the ArrayList can be sorted, and everything works.
For more information, please refer to the java trail on bounded wildcards in generics

Resources