redfin / patient-selenium

A customizable, fluent wrapper for Selenium WebDriver. By default it includes the ability to set a default wait behavior for locating elements that isn't stored as a global state (unlike implicit timeouts). It also allows for re-finding elements when they throw a StaleElementReferenceException.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Build Status License

Patient-Selenium

Overview

Selenium is a library which allows you to automate user interactions with a web browser. Patient-Selenium is a wrapper built around Selenium which allows for lazily located elements, waiting for elements to be in a desired state, customizable automatic retries of located elements, and customizable page object definition. These features together make it useful when trying to write automated tests for a site that heavily use asynchronous JavaScript. It is intended to be used by a single thread (the same one that is driving the implementing Selenium web driver) and the classes are not intended to be shared across multiple threads. The library has a minimal set of methods exposed and is intended to be sub-classed by users. This allows the end users to expose which methods make sense for the type of browser and/or tests they are writing while still gaining the previously mentioned benefits. See the Patience library for more details regarding the specifics of how waiting occurs.

Installation

Via maven:

<dependency>
    <groupId>com.redfin</groupId>
    <artifactId>patient-selenium</artifactId>
    <version>3.1.4</version>
</dependency>

AbstractPatientElement

The AbstractPatientElement type is the wrapper of a Selenium WebElement. It has a cached reference to a Selenium element to allow for fewer element location requests which is useful in the case of a networked Selenium grid architecture. Multiple actions on the same Element will continue to use the same web element reference object. In the case of an exception being thrown by the web element, the cache will be cleared, the Selenium web element will be relocated, and the action attempted again (up to a customizable number of times). Interacting with the selenium element is done via two methods accept(Consumer) and apply(Function), sub classes that want to expose additional methods can simply call into those methods directly and the cache manipulation will be done for them.

If the actual backing Selenium WebElement needs to be looked up and it can't find a matching one, a NoSuchElementException will be thrown. There are also two methods on the Element type that will not check the cache but trigger another Selenium element location call. These are isPresent and isAbsent(Duration) which will return true or false depending on the page state and will never cause a NoSuchElementException.

if (element.isPresent()) {
    element.accept(WebElement::click);
}

AbstractPatientElementLocator

The AbstractPatientElementLocator type is the base class for a type used on page objects and whose job is to create concrete AbstractPatientElement instances. It allows for customization of the PatientWait and Duration timeout to be used by the Element instance when it is locating Selenium WebElement objects. The get(int) method creates individual element instances that are lazily initialized (e.g. the actual Selenium element hasn't been looked up yet). The getAll() method returns a list of element instances that are eagerly initialized (e.g. the actual Selenium element list has been located). Note that for an individual element, it will know the particular index on the page it is for. So, if there are 4 <div> tags on the page, and you have an element instance that has the index of 1 attached to it, it will correspond to the second matching Selenium element that is found (0 based indexing). If there is a filter that is applied to located elements to further refine if they are matches in addition to the base Selenium element location (e.g. you only want elements that return true for WebElement::isDisplayed, etc) then the located elements will only keep applying the filter until the desired n-th matching element is found. This also reduces network calls in a remote web driver situation if the Selenium By locator used returns a lot of matches and you only need the first one that isDisplayed().

elementFactory.get(1).accept(WebElement::click);
elementFactory.getAll().size();

PageObjectInitializer

The AbstractPageObjectInitializer type is the base class for an instance that will be used to initialize fields of an already created instance of a specific type. It is intended to be used to create concrete AbstractPatientElementLocator instances on a page object based upon custom annotations on the fields, but that is entirely customizable. Any field on the page that is also a non-null PageObject will be initialized as well. Any null field will be handed to a method implemented by the subclass of the page object initializer. If that method returns a non-empty optional, then the value in the optional will be set to that field on the page being initialized. Before being initialized each recursive page object will also be handed to a pre processing method callback implementing by the concrete subclass.

About

A customizable, fluent wrapper for Selenium WebDriver. By default it includes the ability to set a default wait behavior for locating elements that isn't stored as a global state (unlike implicit timeouts). It also allows for re-finding elements when they throw a StaleElementReferenceException.

License:Apache License 2.0


Languages

Language:Java 100.0%