Overview:
As an automation engineer , often, we might have to find / interact with some web elements of a HTML Web Table based on certain conditions. There are various approaches to do that. We will see how to use Java Streams to play with HTML tables.
Sample HTML Table:
I create a Simple HTML page with below table.
Our requirement is to select check boxes based on some conditions like – DOB should match ’01/01/1970′ or Country should be ‘USA’ etc – basically any given condition at run time.
Filter Rows Using Java Streams:
- First, I launch site as shown here.
WebDriver driver = new ChromeDriver();
driver.get("sample.html");
WebElement table = driver.findElement(By.tagName("table"));
- Get the column names
List<String> columnNames = table.findElements(By.tagName("th")) // get table headers
.stream()
.map(WebElement::getText) // get the text
.map(String::trim) // trim - no space
.collect(Collectors.toList()); // collect to a list
// columnNames prints [Row Index, Name, DOB, City, Country, Checkbox]
- Do a mapping of column name and the corresponding index
Map<String, Integer> columnMap = IntStream.range(0, columnNames.size())
.boxed()
.collect(Collectors.toMap(columnNames::get,
Function.identity()));
//columnMap {Row Index=0, Name=1, DOB=2, City=3, Country=4, Checkbox=5}
- Now we want to select all check boxes when the DOB is 01/01/1960
table.findElements(By.tagName("tr")) //get all rows
.stream()
.skip(1) // skip first row as we do not need header
.map(tr -> tr.findElements(By.tagName("td"))) // get all cells for each rows
.filter(tds -> tds.get(columnMap.get("DOB")).getText().equals("01/01/1960")) // find the row which has DOB as 01/01/1960
.map(tds -> tds.get(columnMap.get("Checkbox"))) // get cell which contains checkbox
.map(td -> td.findElement(By.tagName("input"))) // get checkbox
.forEach(WebElement::click); // click checkbox
- Our aim is to choose different filters at run time – so that appropriate check boxes can be selected. So, I create a function which accepts a Predicate – It is basically a filter.
private void filterRows(Predicate<List<WebElement>> compositeCheck){
table.findElements(By.tagName("tr"))
.stream()
.skip(1)
.map(tr -> tr.findElements(By.tagName("td")))
.filter(compositeCheck) // passed as argument
.map(tds -> tds.get(columnMap.get("Checkbox")))
.map(td -> td.findElement(By.tagName("input")))
.forEach(WebElement::click);
}
- We might want to include AND, OR conditions as well in our filters. Lets create below conditions.
Predicate<List<WebElement>> dobCheck = (tds) -> tds.get(columnMap.get("DOB")).getText().equals("01/01/1960"); // check if DOB is '01/01/1960'
Predicate<List<WebElement>> countryCheck = (tds) -> tds.get(columnMap.get("Country")).getText().equals("USA"); // check Country is 'USA'
Predicate<List<WebElement>> cityCheck = (tds) -> tds.get(columnMap.get("City")).getText().equals("Oran"); // check City is 'Oran'
- To select all the rows for which DOB is 01/01/1960 OR city is Oran – use the below Predicate for the filter.
dobCheck.or(cityCheck)
- To select the rows DOB is 01/01/1960 AND country is USA
dobCheck.and(countryCheck)
- Below check will select all the rows.
dobCheck.or(countryCheck).or(cityCheck)
- If you have multiple columns and would like to create Predicate at run time, You can create a function which returns a Predicate.
private Predicate<List<WebElement>> getPredicate(String col, String text){
return (tds) -> tds.get(columnMap.get(col)).getText().equals(text);
}
getPredicate("DOB", "01/01/1960").and(getPredicate("City", "Oran"))
Happy Testing & Subscribe 🙂
Hey, I love your code and Im trying to implement something similar using the getPredicate. However Im trying to return the a List of table rows instead of a Predicate<List>. Would you be able to guide me on this please. That way I can choose which elements in the row I want to interact with.