This is going to be a rather complex post, that will show how to easily check for values of similar UI elements. By similar i mean elements that share some kind of properties: whether they have the same CSS selector, or are part of the same group of elements. Some examples will be shown below. Performing the testing part will imply the use of @FindBy (of Selenium WebDriver) and List (of Java). Read on to get an idea of where this approach can be used, how @FindBy is ideal for such a task, what the basics of working with List are, and what an actual test looks like.
The task
Let's say you have one of the following tasks:
checking that a menu that is displayed on top of a webpage displays all the labels that are required
checking that a dropdown contains all the required values (all the options)
checking that all the elements in a list have the labels that you would expect (list here being the <li> elements of a <ul> or <ol> element)
In each of these cases, you might initially want to:
in your PageObject, for each element you need to check, create their own webElement representation. Thus resulting in N webElements, where N can be quite high
for each of them create an assertion that will check their labels
This is inefficient as you will generate too many webElements and too many asserts for solving the task. As a better approach, you might want to use List (from Java) and @FindBy, together with just one assert.
@FindBy
When identifying webElements in your PageObject class, you are using @FindBy by providing it the elements’ unique identifiers. This annotation looks for all the elements having the identifier you provided, and it can return as many elements as it finds on the page, that have that same identifier. The only restriction is what type of a variable you assign the result of @FindBy to.
Let me exemplify: let’s say you provide class identifier to the @FindBy operation. As we know, a class can appear several times on a page. Now, depending on how many elements with that class appear on the page, and what type of storage you defined for the webElements identified based on that class, you can have the following situations: Number of elements identified (how many occurrences of that class appear on the page)Storage usedResult1WebElementThe only WebElement on the page having the specified class.1List<WebElement>A list containing the only WebElement. List size is 1.N (where N > 1)WebElementThe first WebElement that appears on the page having the specified class.N (where N > 1)List<WebElement>A list containing ALL the WebElements that have the specified class. List size is N.
So, storing the results of the @FindBy operation, can be done:
@FindBy(….) public WebElement element;
@FindBy(…) public List<WebElement> list;
The basics of lists
For the basic understanding of how to use lists in Java, I will go over the methods that you will use when working with them. For comprehensive info on lists, please refer to the Java documentation:
https://docs.oracle.com/javase/8/docs/api/java/util/List.html
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html
Creating an empty list (in this example, a list of Strings):
List<String> newList = new ArrayList<String>();
Adding a new element to the list (in this case, a String). Elements are added one at a time.
newList.add("firstItem");
Going over the list or iterating it
for (String itemOfList : newList) {
doSomething(itemOfList);
}
Getting the size of the list:
newList.size();
Getting the Nth element of the list:
newList.get(N);
Example
In my GitHub project you will find a complete example of approaching the task of checking for the elements in a dropdown. All the code is found inside the project, including the HTML that will be checked against.
The HTML
So first things first. The HTML will contain only the dropdown that needs to be checked. It is a very plain file, i did not even bother to add an id or class to the element representing the dropdown. The whole code looks like this (and it can be found in the GitHub project in this location):
<select>
<option value="espresso">Espresso</option>
<option value="espressomilk">Espresso with milk</option>
<option value="latte">Latte</option>
<option value="lattecaramel">Latte Caramel</option>
<option value="capuccino">Capuccino</option>
</select>
As can be seen here, the test needs to check that the dropdown labels that customers will see can only be the following: Espresso, Espresso with milk, Latter, Latte Caramel, Capuccino.
The PageObject class
In order to store the label texts so they can be used in testing, the PageObject that identifies the associated WebElements will be created (it can be found here).
In the import section, the List import will be declared:
import java.util.List;
Using @FindBy, a list of elements will be created as follows:
@FindBy(how = CSS, using = "option") private List<WebElement> webElements;
Each entry in the dropdown is represented by its' own webElement.
The above just means you now have a list of WebElements, but you do not have access to the labels themselves. The text of the labels will be obtained with a bit of processing: the webElements list must be iterated, and each elements' label (extracted with getText()) will be added to another list. That list will be responsible for storing all the labels that are seen in the dropdown, as Strings.
Since the labels are going to be used in the test, within an assertion, the labels list, called labelsList, will be generated and returned by a method inside the PageObject class. It will look like this:
public List<String> getLabelsList() {
//create an empty list in which the label texts will be stored
List<String> labelsList = new ArrayList<>();
//iterate through all the webElements
for (WebElement webElement : webElements) {
//add each webElements label to the labelsList
labelsList.add(webElement.getText());
}
//return all the label texts that are visible in the dropdown
return labelsList;
}
If you were to print the resulting list to the console you would get this output:
The test class
Now getting to the test class, which is found here. First you will define the expected list, which contains the Strings you expect to see in the dropdown. This can be done really easy, by using the concept of ImmutableLists, which i already wrote a post about. Defining the expected list is a one liner:
private List<String> expectedLabelsList = ImmutableList.of("Espresso", "Espresso with milk", "Latte",
"Latte Caramel", "Capuccino");
And now, the actual check, of course, after opening the page on which the dropdown is displayed:
@Test
public void successfulTest() {
//open the page on which the elements to test are displayed
//this is a simple page with basic HTML stored in src/test/resources/htmls/forLists.html
webDriver.get(new File("src/test/resources/htmls/forLists.html").getAbsolutePath());
//compare the list of labels read from the open page with the expected list of labels
assertEquals(page.getLabelsList(), expectedLabelsList);
}
The assertEquals will check that the two lists have identical sizes and that the elements are the same in both lists, in the same order (you can think of it as element by element comparison - first element of first list gets compared to first element of the second list; second element of first list gets compared to second element of the second list; and so on).
In case you are not interested in the order in which the labels appear in the dropdown, you can use assertEqualsNoOrder. It will check that both lists have the same elements, but it will not fail if any of them are found on a different position in one list than the position where they are in the other list.
Something i need to mention again: by writing the code above, the List called webElements from the PageObject class stores the handle to each element from the dropdown. In case you want to select an element from the dropdown, let's say the second element (which displays "Espresso with milk"), you will easily do this like:
webElements.get(1).click();
You will use "get(1)" because the index of the list starts with 0: the first element of the list is webElements.get(0). Therefore in case interaction with the page is also required, not just reading the properties of the webElements, there is no need to additionally define separate webElements for the required interaction.
Summary
In the example i omitted parts of the code that deal with opening and closing the browser, initializing the PageObject class and so on. You can find all these in GitHub in their respective classes, so go ahead and check them out for a clear understanding of how to solve the given task: