# Selenium - Notes - 2
## 0. Modularize functions and everything that can be modularized
For example, need to check if a class of an element contains `disabled` before clicking (such as the next and previous icons). Thus, create another function to check if `disabled` is not in WebElement, then click the WebElement.
## 1. Check if an element class contains `disabled`
Or check other attributes of the element that indicate the element's displayed or interactable status.
Get the element first, get the class attribute of the element, and check if it contains the keyword `disabled`. Interact with the element if it does not contain `disabled`. (or remove the `disabled` attribute before interacting with the element)
For example,
```
WebElement lastPageLink = new WebDriverWait(driver, elementTimeout).until(ExpectedConditions.visibilityOfElementLocated(lastPageLinkBy));
if (!(lastPageLink.getAttribute("class").contains("disabled"))) {
lastPageLink.click();
}
```
## 2. Interact with Pagination
An example of what pagination looks like:
https://community.jaspersoft.com/blog/java-selenium-how-navigate-through-web-data-table-using-pagination-buttons-and-verify-displayed

### Check elements loading completed
Check the texts of the pagination information elements should display the correct information.
For example, from 101 to 111 in total 2001
### Check whether page navigation is available or not
If the current page is at the end of the pagination, the next page navigation element should contain `disabled`, and should not be clickable.
### Wait for the page to be ready after the navigation
Wait until the target element with the correct index is displayed or exists.
### Navigate to the next page or the previous page
Wait until the currently selected element (focused page) is different from the previously selected element.
For example, the selected index of the next page is `current page +1` (the selected index of the previous page is `current page -1`) :
```
private By currentFocusBy = By.cssSelector("span[class='k-state-selected']");
public Pagination clickNextPage() {
// Check if element contains disable class attribute
WebElement nextLink = waitVisible(nextLinkBy));
if (!(nextLink.getAttribute("class").contains("disabled"))) {
// Keep the index from the text in currently selected element
final String preIndex = waitVisible(currentFocusBy).getText();
final String afterIndex = Integer.toString((Integer.parseInt(preIndex) + 1));
// Wait until the next page icon exists and click
waitAndClick(nextLinkBy);
// Wait until the index of current selected is the previous +1
final By currentBy = By.xpath("//span[@class='k-state-selected' and text()='" + afterIndex + "']");
waitVisible(currentBy);
}
return this;
}
```
### Navigate to the first or the last page
* The first page
* Wait until the index of the currently selected element is 1
* The last page
* Wait until the index of the currently selected element is `Math.ceil((number of total rows) / (number of rows per page))`
Get total count from pagination information element (the information of current display and count of total items might need to be parsed from element text).
Method to get the information string from the information element:
```
public final String getPaginationInfoText() {
return waitVisible(paginationInfoBy).getText();
}
```
Method to parse numbers in information string:
```
public final Map<String, Integer> getNumbersFromItemsInfoText() {
Map<String, Integer> itemCountsMap = new HashMap<String, Integer>();
String[] keys = new String[] { "From", "To", "Total" };
int keyIndex = 0;
// Parse all numbers from the information string text
String[] dataLs = getPaginationInfoText().split(" ");
for (String data : dataLs) {
if (NumberUtils.isCreatable(data)) {
itemCountsMap.put(keys[keyIndex], Integer.parseInt(data));
keyIndex += 1;
}
}
return dataMap;
}
```
Get current rows per page from the selected item in the dropdown list, and wait until the element is visible:
```
public final int getCurrentDisplayedPerPage() {
return Integer.parseInt(waitVisible(currentDisplayedBy).getText());
}
```
Calculate the page index of the last page:
```
private final int getLastPageIndex(){
final Map<String, Integer> infoMap = getNumbersFromItemsInfoText();
final int displayedPerPage = getCurrentDisplayedPerPage();
final int lastPageIndex = Math.round((float) infoMap.get("Total") / displayedPerPage);
return lastPageIndex;
}
```
Click the `lastPageLink` and verify the currently selected element is the last page:
```
public Pagination clickLastPage() {
// Check contain disable
WebElement lastPageLink = waitVisible(lastPageLinkBy);
if (!(lastPageLink.getAttribute("class").contains("disabled"))) {
// Click the last page element
lastPageLink.click();
// Wait for the current selected element to be the last page element
final By currentBy = By.xpath("//span[@class='k-state-selected' and text()='" + getLastPageIndex() + "']");
waitVisible(currentBy);
}
return this;
}
```
## 3. Need to clear input fields before keying in new data
Common way:
```
inputElement.clear();
```
When the previous one does not work, try to use send keyboard key to clear the text in the input fields:
```
inputElement.sendKeys(Keys.chord(Keys.CONTROL,"a", Keys.DELETE));
```
For example:
```
WebElement inputElement = new WebDriverWait(driver, elementTimeout)
.until(ExpectedConditions.elementToBeClickable(by));
inputElement.sendKeys(Keys.chord(Keys.CONTROL,"a", Keys.DELETE));
inputElement.sendKeys(text);
```
## 4. Access data in **tb** in a table element
Loop the current page table rows by using indexes to access data in each row in the table:
```
public List<String> getDataListFromTableRow(final int numberOfRows) {
List<String> dataLs = new ArrayList<String>();
String text = "";
for (int i = 0; i < numberOfRows; i++) {
text = waitVisible(By.xpath("//div[@id=\"dataGrid\"]/div[3]/table/tbody/tr[" + (i + 1) + "]/td[1]"))
.getText();
dataLs.add(text);
}
return dataLs;
}
```
When landing on a new page of pagination, get the latest row counts of the current page.
An example of getting all data from the current page, and navigating to the next page:
```
final int totalPageCount = pagination.getTotalPageCount();
int rowCount = 0;
for (int pageIndex = 0; pageIndex < totalPageCount; pageIndex++) {
rowCount = pagination.getPageRowCount();
nameLs = Stream.concat(nameLs.stream(), unitAssetsPage.getAssetIdContentsText().stream()) .collect(Collectors.toList());
}
```
Methods that are used in the previous block:
```
protected List<WebElement> getVisibleElements(final By by) {
return new WebDriverWait(driver, elementTimeout).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(by));
}
private By tableRow = By.xpath("//tr[@class='k-master-row' or @class='k-alt k-master-row']");
public final int getPageRowCount() {
return getVisibleElements(tableRow).size();
}
```
## 5. Use proper data structures to load data from page elements
It is important to choose the proper data structure/ interface/ class to load data from elements based on CRUD needs.
For example, using 2D lists to store the table elements data.
```
Map<String, List<String>>
```
## 6. Locate row elements of a table by class name of the row elements
Need to be aware of the class name of **odd** and **even** rows might be different.
## 7. Load data from tags elements
Need to understand how tags are designed.
For example, a tag can be a composition of **multiple** texts or only allow **single** text. (I think a tag should only have one text, it is a bad design to contain multiple texts in one tag)
One text in one tag

Multiple texts in one tag

## 8. Handling dynamic elements
Check whether the target element exists or not beforehand.
## 9. Handling Selenium Exception using `try catch`
Refer to: https://www.softwaretestinghelp.com/exception-handling-framework-selenium-tutorial-19/
To return `null` or display error messages, use `try catch` to get certain exceptions and deal with them.
Need to use the correct exceptions to catch the correct exception when under certain conditions.
### Example of the usage
#### Do something when cannot find the element
Find element use `org.openqa.selenium.By` without `org.openqa.selenium.support.ui.WebDriverWait`, and the corresponding Exception:
```
try {
WebElement webElement = driver.findElement(by);
}
catch(org.openqa.selenium.NoSuchElementException ex) {
// do something
}
```
#### Do something when timeout of waiting for the element
Find element use `org.openqa.selenium.support.ui.WebDriverWait`, and the corresponding Exception:
```
try {
WebElement webElement = new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(by));
}
catch(org.openqa.selenium.TimeoutException ex) {
// do something
}
```
#### Test clean-up e even though exceptions happen
Add finally after `try catch` and call close browser no matter test pass or failed to clean up the tests
```
def test_search():
try:
driver = BrowserFactory.get_chrome()
driver.get("https://blog.testproject.io/")
driver.maximize_window()
home = HomePage(driver)
home.keyin_search("selenium")
except Exception:
assert False
finally:
driver.close()
```
##### Common Exceptions:
* org.openqa.selenium.NoSuchElementException
* org.openqa.selenium.NoSuchWindowException
* org.openqa.selenium.NoSuchFrameException
* org.openqa.selenium.NoAlertPresentException
* org.openqa.selenium.InvalidSelectorException
* org.openqa.selenium.ElementNotVisibleException
* org.openqa.selenium.ElementNotSelectableException
* org.openqa.selenium.TimeoutException
* org.openqa.selenium.NoSuchSessionException
* org.openqa.selenium.StaleElementReferenceException
## 10. Handle **Element not interactable** error
When using `presence_of_element_located()` to locate and interact with the element, sometimes get this error.
### Solution
Can use `element_to_be_clickable()` before clicking, to make sure the element can be interacted.
```
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(self.driver, self.waittime).until(EC.element_to_be_clickable(self.elementBy))
element.click()
```
###### tags: `selenium` `java` `test automation` `software test`