selenium filter with Predicate - java

I am looking to use and learn about the Predicate and Lambda expression. In particular using it with selenium.
Imagine you have a large selection(List) of WebElements and you want to apply a predicate filter to it so that the list is smaller .
Am I on the right track for 1,2,3 below what changes would I meed to make?
List<WebElement> webElements = driver.findElements(By.cssSelector(".someClassName")); // returns large list
// then try and filter down the list
Predicate<WebElement> hasRedClass -> Predicate.getAttribute("class").contains("red-background");
Predicate<WebElement> hasDataToggleAttr -> Predicate.getAttribute("data-toggle").size() > 0;
// without predicate probably looks like this
//driver.findElements(By.cssSelector(".someClassName .red-background"));
// 1. this is what I think it should look like???
List<WebElement> webElementsWithClass = webElements.filter(hasRedClass);
// 2. with hasDataToggleAttr
List<WebElement> webElementsWithDataToggleAttr = webElements.filter(hasDataToggleAttr);
// 3. with both of them together...
List<WebElement> webElementsWithBothPredicates = webElements.filter(hasRedClass, hasDataToggleAttr);

I hope here is what you are looking for:
List<WebElement> webElements = driver.findElements(By.cssSelector(".someClassName")); // returns large list
// then try and filter down the list
Predicate<WebElement> hasRedClass = we -> we.getAttribute("class").contains("red-background");
Predicate<WebElement> hasDataToggleAttr = we -> we.getAttribute("data-toggle").length() > 0;
// without predicate probably looks like this
//driver.findElements(By.cssSelector(".someClassName .red-background"));
// 1. this is what I think it should look like???
List<WebElement> webElementsWithClass = webElements.stream()
.filter(hasRedClass).collect(Collectors.toList());
// 2. with hasDataToggleAttr
List<WebElement> webElementsWithDataToggleAttr = webElements.stream()
.filter(hasDataToggleAttr).collect(Collectors.toList());
// 3. with both of them together...
List<WebElement> webElementsWithBothPredicates = webElements.stream()
.filter(hasDataToggleAttr.and(hasRedClass)).collect(Collectors.toList());

Related

How to get the inner texts of option tags in a List?

I've been trying to get all the elements of a dropdown list <option> tag inner texts with no avail,
I've been getting them into a List<WebElement> and trying to extract them into a List<String>
but I've been getting empty line breaks when I use System.out.println() on the List<String>
List<WebElement> saOptions = element("<omitted-xpath-element>",
tierType.getTierName().getRealValue(),
tierType.getTierDescription().getRealValue())
.getAllOptions();
List<String> oriSaRules = saOptions
.stream()
.map(e->e.getText())
.collect(Collectors.toList());
saOptions.forEach(e->System.out.println(e.getText()));
Also tried this to get a List:
List<String> saOptions = element("<omitted-xpath-element>",
tierType.getTierName().getRealValue(),
tierType.getTierDescription().getRealValue())
.getAllInnerTexts();
Returns nothing though
The below should work
Select dd = new Select(driver.findElement(By.id("cars")));
List<WebElement> dd_values = dd.getOptions();
for(WebElement element:dd_values)
System.out.println(element.getText());
Please import the select class as well

Extract text from multiple xpath and assert text - Selenium/Java

I need to find the text in an element and assert whether it matches with my required result.
The thing is, there can be n number of element from 1-100 in the page. So I can't get the xpath of all those elements and then assert the text in it.
The xpath looks like this: (from the first element)
(//DIV[#class='issues-list-item clearfix'])[1]
(//DIV[#class='issues-list-item clearfix'])[2]
(//DIV[#class='issues-list-item clearfix'])[3]
(//DIV[#class='issues-list-item clearfix'])[4]
....
(//DIV[#class='issues-list-item clearfix'])[100]
How do I loop through these xpath and assert for my text?
I tried the below method after referring few articles and it really did not help.
private static WebElement element = null;
private static List<WebElement> elements = null;
public WebElement test() throws Exception {
elements = driver.findElements(By.xpath("(//DIV[#class='issues-list-item clearfix'])[1]"));
for (WebElement element : elements) {
List<WebElement> TE = element.findElements(By.xpath("(//DIV[#class='issues-list-item clearfix'])[1]"));
if (TE.size() > 0) {
String myText = TE.get(0).getText();
if (myText.contains("High")) {
return element;
}
}
}
return null;
You can try this :
public List<WebElement> test() throws Exception {
List<WebElement> TE = new ArrayList<WebElement>();
elements = driver.findElements(By.xpath("(//DIV[#class='issues-list-item clearfix'])"));
for (WebElement element : elements) {
if(element.getText().contains("High")) {
TE.add(element);
}
}
return TE;
}
Note that , it will return a list web element which contains High as text.
The more efficient way to do this is to add your check for "High" to the locator. That way you don't have to loop through all the elements to find only the ones you want. Your locator does all that work for you and more quickly. There's also a lot less code.
public List<WebElement> test() throws Exception {
return driver.findElements(By.xpath("(//DIV[#class='issues-list-item clearfix'][contains(.,'High')])"));
}
There are a number of ways you can verify that the desired element is found. One way would be to use a TestNG Assert like
Assert.assertTrue(test().size() > 0, "Verify an element containing 'High' was found.");
//DIV[#class='issues-list-item clearfix'])[1] your query is wrong. The [1] at the end means that it will select oinly teh first item from all the items matching the query before, aka you will only compare against the first one. The second query you won't need, neitehr the if checking for size (optionally before the for loop)

How to parameterize java method to iterate on elements in a table?

I have a table with products' names which locators differs only by index. I would like to use one method to iterate on all of the elements, because the number of elements can be changed up to 10 and I need to go through them all.
#FindBy(xpath="(//*[#class=\"product-name\"])[2]")
protected WebElement productName1;
#FindBy(xpath="(//*[#class=\"product-name\"])[3]")
protected WebElement productName2;
#FindBy(xpath="(//*[#class=\"product-name\"])[4]")
protected WebElement productName3;
A method that I want to parametrize is:
public String checkProductsInCart() {
wait.until(ExpectedConditions.visibilityOf(productName1));
String productName1String = productName1.getText();
return productName1String; }
How should I do that? I would appreciate your help.
Obtain all of the product name elements in a single list:
#FindBy(xpath="//*[#class=\"product-name\"]")
protected List<WebElement> productNameElements;
Then, in your test method, you can iterate over the elements (you could use for loop with an int index if you prefer):
List<String> productsInCart = new ArrayList<>();
for (WebElement element : productNameElements) {
productsInCart.add(nameOfProductInCart(element));
}
You can alter your check method to take a WebElement as a parameter:
public String nameOfProductInCart(WebElement element) {
wait.until(ExpectedConditions.visibilityOf(element));
return element.getText();
}
Alternatively, if this doesn't work (e.g. because the product list takes time to populate), you could use the WebDriver instance and programmatically perform each check:
List<String> productNames = new ArrayList<>();
for (int i = 2; i <= 10; i++) {
WebElement element = driver.findElement(By.xpath("(//*[#class=\"product-name\"])[" + i + "]"));
wait.until(ExpectedConditions.visibilityOf(element));
productNames.add(element.getText());
}
UPDATE: To answer the question in your comment, if you want the elements, rather than their text, you can store the elements themselves in a list:
List<WebElement> productNameElements = new ArrayList<>();
for (int i = 2; i <= 10; i++) {
WebElement element = driver.findElement(By.xpath("(//*[#class=\"product-name\"])[" + i + "]"));
wait.until(ExpectedConditions.visibilityOf(element));
productNameElements.add(element);
}
Now you can access the elements individually by getting them by index from the productNameElements list:
productNameElements.get(0); // First item
This should be easier to manage than having a separate variable for each item.
Just addendum to #ELEVATE's answer, You can find element via className:
#FindBy(className = "product-name")
private List<WebElement> tableItems;
or
#FindBy(xpath="//*[#class='product-name']")
private List<WebElement> tableItems;
but this depends if this is unique identifier...

Java Selenium webdriver filling list webelement manually

first of all:
I want to fill a List manually with element.add();
Because the elements of the page I am working with is just showing a specific range of elements, I can't just load all elements in a List<WebElement>.
That's why I want to do functions to check if an element exists in my List, if it doesn't exists there I will add it.
I want to know if there is a way to iterate specific elements like element.next();
Here is the xpath I am getting my elements:
###.findElement(By.xpath(".//a[starts-with(#href, '/p/')]"));
You ca use following snippet to fulfill your requirement
public boolean isDropdownOptionExists(String optionToBeVerified, By optionWhereToBeVerified) {
boolean isOptionFound = false;
Select optionsInDropDown = new Select(driver.findElement(optionWhereToBeVerified));
List<WebElement> availableOptions = optionsInDropDown.getOptions();
for(WebElement option: availableOptions) {
if(option.getText().equals(optionToBeVerified)) {
isOptionFound = true;
break;
}
}
return isOptionFound;
}

Split a list into multiple sublist based on element properties in Java

Is there a way to split a list to multiple list?. Given list into two or more list based on a particular condition of it elements.
final List<AnswerRow> answerRows= getAnswerRows(.........);
final AnswerCollection answerCollections = new AnswerCollection();
answerCollections.addAll(answerRows);
The AnswerRow has properties like rowId, collectionId
based on collectionId i want to create one or more AnswerCollections
If you just want to group elements by collectionId you could try something like
List<AnswerCollection> collections = answerRows.stream()
.collect(Collectors.groupingBy(x -> x.collectionId))
.entrySet().stream()
.map(e -> { AnswerCollection c = new AnswerCollection(); c.addAll(e.getValue()); return c; })
.collect(Collectors.toList());
Above code will produce one AnswerCollection per collectionId.
With Java 6 and Apache Commons Collections, the following code produce the same results as the above code using Java 8 streams:
ListValuedMap<Long, AnswerRow> groups = new ArrayListValuedHashMap<Long, AnswerRow>();
for (AnswerRow row : answerRows)
groups.put(row.collectionId, row);
List<AnswerCollection> collections = new ArrayList<AnswerCollection>(groups.size());
for (Long collectionId : groups.keySet()) {
AnswerCollection c = new AnswerCollection();
c.addAll(groups.get(collectionId));
collections.add(c);
}
Is there a way to split a list to multiple list?
Yes, You can do it like this:
answerRows.subList(startIndex, endIndex);
Given list into two or more list based on a particular condition of it
elements.
You'll have to calculate the start and end indices based on your specific condition and then you can mint the subList out of your ArrayList using the above function.
For Example, if you want to pass batches of 1000 answerRows to a specific function then you can do something like this:
int i = 0;
for(; i < max && i < answerRows.size(); i++) {
if((i+1) % 1000 == 0) {
/* Prepare SubList & Call Function */
someFunction(answerRows.subList(i, i+1000));
}
}
/* Final Iteration */
someFunction(answerRows.subList(i, answerRows.size() - 1));

Categories

Resources