Try   HackMD

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

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

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.

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;
}
  • 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