CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-seleniumhq-selenium--selenium-support

Selenium WebDriver support utilities providing Page Object Model, waiting mechanisms, event handling, and UI utilities for robust test automation

Pending
Overview
Eval results
Files

pagefactory.mddocs/

Page Object Factory

The Page Factory provides a comprehensive implementation of the Page Object Model pattern, offering annotations for element location, automatic element initialization, and flexible locator strategies. It simplifies page object creation by automatically initializing WebElement fields with proxies that locate elements dynamically.

Core Factory Methods

public class PageFactory {
    /**
     * Create and initialize a new page object instance
     */
    public static <T> T initElements(WebDriver driver, Class<T> pageClassToProxy);
    
    /**
     * Initialize an existing page object instance with element proxies
     */
    public static void initElements(WebDriver driver, Object page);
    
    /**
     * Initialize page object with custom element locator factory
     */
    public static void initElements(ElementLocatorFactory factory, Object page);
    
    /**
     * Initialize page object with custom field decorator
     */
    public static void initElements(FieldDecorator decorator, Object page);
}

Usage Examples

// Create and initialize new page object
LoginPage loginPage = PageFactory.initElements(driver, LoginPage.class);

// Initialize existing page object
LoginPage loginPage = new LoginPage();
PageFactory.initElements(driver, loginPage);

// Initialize with custom timeout for AJAX elements
AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 15);
PageFactory.initElements(factory, loginPage);

Element Location Annotations

@FindBy Annotation

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface FindBy {
    /**
     * Location strategy to use
     */
    How how() default How.UNSET;
    
    /**
     * Value to use with the location strategy
     */
    String using() default "";
    
    /**
     * Locate by ID attribute
     */
    String id() default "";
    
    /**
     * Locate by name attribute  
     */
    String name() default "";
    
    /**
     * Locate by CSS class name
     */
    String className() default "";
    
    /**
     * Locate by CSS selector
     */
    String css() default "";
    
    /**
     * Locate by HTML tag name
     */
    String tagName() default "";
    
    /**
     * Locate by exact link text
     */
    String linkText() default "";
    
    /**
     * Locate by partial link text
     */
    String partialLinkText() default "";
    
    /**
     * Locate by XPath expression
     */
    String xpath() default "";
}

@FindBys Annotation (AND Logic)

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface FindBys {
    /**
     * Array of @FindBy annotations to chain together (all must match)
     */
    FindBy[] value();
}

@FindAll Annotation (OR Logic)

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface FindAll {
    /**
     * Array of @FindBy annotations (any can match)
     */
    FindBy[] value();
}

@CacheLookup Annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CacheLookup {
    // Marker annotation - element lookups will be cached after first access
}

Location Strategy Enum

public enum How {
    CLASS_NAME, CSS, ID, ID_OR_NAME, LINK_TEXT, NAME, 
    PARTIAL_LINK_TEXT, TAG_NAME, XPATH, UNSET;
    
    /**
     * Build a By locator for this strategy with the given value
     */
    public abstract By buildBy(String value);
}

Page Object Examples

Basic Page Object

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class LoginPage {
    @FindBy(id = "username")
    private WebElement usernameField;
    
    @FindBy(name = "password")
    private WebElement passwordField;
    
    @FindBy(css = "button[type='submit']")
    private WebElement submitButton;
    
    @FindBy(xpath = "//div[@class='error-message']")
    private WebElement errorMessage;
    
    public LoginPage(WebDriver driver) {
        PageFactory.initElements(driver, this);
    }
    
    public void login(String username, String password) {
        usernameField.clear();
        usernameField.sendKeys(username);
        passwordField.clear();
        passwordField.sendKeys(password);
        submitButton.click();
    }
    
    public String getErrorMessage() {
        return errorMessage.getText();
    }
}

Advanced Locator Strategies

public class AdvancedPage {
    // Using How enum with using attribute
    @FindBy(how = How.CSS, using = ".submit-btn")
    private WebElement submitButton;
    
    // Chained locators (AND logic) - both conditions must match
    @FindBys({
        @FindBy(className = "form-group"),
        @FindBy(tagName = "input")
    })
    private WebElement nestedInput;
    
    // Multiple possible locators (OR logic) - any condition can match
    @FindAll({
        @FindBy(id = "submit"),
        @FindBy(name = "submit"),
        @FindBy(xpath = "//input[@type='submit']")
    })
    private WebElement submitByAny;
    
    // Cached lookup - element located once and reused
    @CacheLookup
    @FindBy(id = "static-header")
    private WebElement header;
    
    // List of elements
    @FindBy(className = "menu-item")
    private List<WebElement> menuItems;
}

Element Locator Infrastructure

ElementLocator Interface

public interface ElementLocator {
    /**
     * Find a single element
     */
    WebElement findElement();
    
    /**
     * Find multiple elements
     */
    List<WebElement> findElements();
}

ElementLocatorFactory Interface

public interface ElementLocatorFactory {
    /**
     * Create an ElementLocator for the given field
     */
    ElementLocator createLocator(Field field);
}

DefaultElementLocator

public class DefaultElementLocator implements ElementLocator {
    public DefaultElementLocator(SearchContext searchContext, Field field);
    public DefaultElementLocator(SearchContext searchContext, AbstractAnnotations annotations);
    
    public WebElement findElement();
    public List<WebElement> findElements();
    protected boolean shouldCache();
}

AjaxElementLocator

public class AjaxElementLocator extends DefaultElementLocator {
    /**
     * Element locator that waits for elements to appear (for AJAX content)
     */
    public AjaxElementLocator(SearchContext context, int timeOutInSeconds, AbstractAnnotations annotations);
    public AjaxElementLocator(SearchContext searchContext, Field field, int timeOutInSeconds);
    
    public WebElement findElement();
    public List<WebElement> findElements();
    protected long sleepFor();
    protected boolean isElementUsable(WebElement element);
}

AjaxElementLocatorFactory

public class AjaxElementLocatorFactory implements ElementLocatorFactory {
    /**
     * Factory for creating AjaxElementLocator instances with timeout
     */
    public AjaxElementLocatorFactory(SearchContext searchContext, int timeOutInSeconds);
    
    public ElementLocator createLocator(Field field);
}

Field Decoration

FieldDecorator Interface

public interface FieldDecorator {
    /**
     * Decorate a field with a proxy or return null if field should not be decorated
     */
    Object decorate(ClassLoader loader, Field field);
}

DefaultFieldDecorator

public class DefaultFieldDecorator implements FieldDecorator {
    public DefaultFieldDecorator(ElementLocatorFactory factory);
    
    public Object decorate(ClassLoader loader, Field field);
    protected boolean isDecoratableList(Field field);
    protected WebElement proxyForLocator(ClassLoader loader, ElementLocator locator);
    protected List<WebElement> proxyForListLocator(ClassLoader loader, ElementLocator locator);
}

Advanced Locator Classes

ByAll (OR Logic)

public class ByAll extends By {
    /**
     * Locator that finds elements matching any of multiple By instances
     */
    public ByAll(By... bys);
    
    public WebElement findElement(SearchContext context);
    public List<WebElement> findElements(SearchContext context);
}

ByChained (AND Logic)

public class ByChained extends By {
    /**
     * Locator that finds elements using chained lookups
     */
    public ByChained(By... bys);
    
    public WebElement findElement(SearchContext context);
    public List<WebElement> findElements(SearchContext context);
}

Annotation Processing

AbstractAnnotations

public abstract class AbstractAnnotations {
    /**
     * Build a By locator from field annotations
     */
    public abstract By buildBy();
    
    /**
     * Check if element lookup should be cached
     */
    public abstract boolean isLookupCached();
}

Annotations

public class Annotations extends AbstractAnnotations {
    /**
     * Standard implementation for processing Page Object annotations
     */
    public Annotations(Field field);
    
    public boolean isLookupCached();
    public By buildBy();
    protected Field getField();
    protected By buildByFromDefault();
    protected void assertValidAnnotations();
}

AbstractFindByBuilder

public abstract class AbstractFindByBuilder {
    /**
     * Abstract base class for building By instances from annotations
     */
    public abstract By buildIt(Object annotation, Field field);
    
    protected By buildByFromFindBy(FindBy findBy);
    protected By buildByFromShortFindBy(FindBy findBy);
    protected By buildByFromLongFindBy(FindBy findBy);
    protected void assertValidFindBy(FindBy findBy);
    protected void assertValidFindBys(FindBys findBys);
    protected void assertValidFindAll(FindAll findAll);
}

Usage Patterns

AJAX-Enabled Page Objects

public class DynamicPage {
    private WebDriver driver;
    
    public DynamicPage(WebDriver driver) {
        this.driver = driver;
        // Use AjaxElementLocatorFactory for dynamic content
        AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 15);
        PageFactory.initElements(factory, this);
    }
    
    @FindBy(id = "dynamic-content")
    private WebElement dynamicContent;
    
    @FindBy(className = "async-loaded")
    private List<WebElement> asyncElements;
}

Inheritance and Page Object Hierarchies

public abstract class BasePage {
    @FindBy(id = "header")
    protected WebElement header;
    
    @FindBy(id = "footer")  
    protected WebElement footer;
    
    public BasePage(WebDriver driver) {
        PageFactory.initElements(driver, this);
    }
}

public class HomePage extends BasePage {
    @FindBy(id = "welcome-message")
    private WebElement welcomeMessage;
    
    public HomePage(WebDriver driver) {
        super(driver);
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-support

docs

events.md

index.md

pagefactory.md

utilities.md

waiting.md

tile.json