Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Principle:SeleniumHQ Selenium Page Object Annotation

From Leeroopedia
Knowledge Sources
Domains Test_Design, Design_Patterns, Browser_Automation
Last Updated 2026-02-11 00:00 GMT

Overview

Declarative annotation mechanism for binding web page element locators to Java fields in Page Object classes, enabling maintainable and readable test automation.

Description

The Page Object Annotation system allows developers to declare element locators as Java annotations on class fields rather than writing imperative lookup code. @FindBy binds a single locator strategy (ID, CSS, XPath, etc.) to a WebElement or List<WebElement> field. @FindAll combines multiple @FindBy annotations with OR semantics (matches any), delegating to ByAll internally. @FindBys chains multiple @FindBy annotations with AND semantics (all must match), delegating to ByChained internally. The How enum provides the complete set of locator strategies. These annotations are processed at runtime by PageFactory to create lazy-loading element proxies.

Usage

Use @FindBy for single-strategy element location (the most common case). Use @FindAll when an element might match multiple different locators. Use @FindBys when you need to chain locators (find within find). Choose the locator strategy based on stability: prefer IDs and data-test attributes over XPath and CSS class names. The @FindBy annotation supports two forms: shorthand (@FindBy(id = "foo")) and long form (@FindBy(how = How.ID, using = "foo")).

Theoretical Basis

# Annotation Processing Model
1. Developer annotates WebElement fields with @FindBy
2. PageFactory scans class fields at runtime via reflection
3. For each annotated field:
   a. AbstractFindByBuilder converts annotation to By locator
   b. DefaultFieldDecorator wraps the By in a lazy-loading proxy
   c. Proxy replaces the field value
4. First access to the proxied field triggers findElement(by)
5. Subsequent accesses may re-query or return cached result

The How enum maps to By factory methods via the buildBy(String value) abstract method:

How.CLASS_NAME      -> By.className(value)
How.CSS             -> By.cssSelector(value)
How.ID              -> By.id(value)
How.ID_OR_NAME      -> new ByIdOrName(value)
How.LINK_TEXT       -> By.linkText(value)
How.NAME            -> By.name(value)
How.PARTIAL_LINK_TEXT -> By.partialLinkText(value)
How.TAG_NAME        -> By.tagName(value)
How.XPATH           -> By.xpath(value)
How.UNSET           -> By.id(value)  (defaults to ID)

The shorthand form is resolved by AbstractFindByBuilder.buildByFromShortFindBy() which checks each annotation attribute (className, css, id, linkText, name, partialLinkText, tagName, xpath) for a non-empty value. The long form is resolved by buildByFromLongFindBy() which calls findBy.how().buildBy(findBy.using()). Validation via assertValidFindBy() ensures at most one location strategy is specified per @FindBy annotation.

Related Pages

Implemented By

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment