From d1f1b2720aeddeecbfeea87c66ae1b05b132465e Mon Sep 17 00:00:00 2001 From: Pushpak-Jaiswal Date: Sun, 11 Oct 2026 18:23:49 +0530 Subject: [PATCH 1/2] feat(locator): form actions: clear, check, uncheck, isChecked, selectOption, inputValue (#133) --- CHANGELOG.md | 2 + docs-site/docs/changelog.md | 4 + docs-site/docs/guides/semantic-locators.md | 4 +- .../com/seleniumboot/locator/Locator.java | 111 ++++++++++ .../unit/LocatorStaleElementTest.java | 114 +++++++++++ .../com/seleniumboot/unit/LocatorTest.java | 190 ++++++++++++++++++ 6 files changed, 423 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 862c23b..903d865 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ### Unreleased +- **`Locator` form actions: `clear()`, `check()`, `uncheck()`, `isChecked()`, `selectOption(text)`, `selectOptionByValue(value)`, `inputValue()`** — form controls can now be manipulated and inspected directly on `Locator` without falling back to `BasePage` helpers or raw `WebElement`s. `check()` and `uncheck()` are idempotent (no click if already in the target state), `isChecked()` queries checked state without waiting, and terminal actions (`clear`, `check`, `uncheck`, `selectOption`, `selectOptionByValue`, `inputValue`) auto-wait, re-resolving from scratch on every poll to survive stale or late-appearing elements. (#133) + - **HTML report: the "Avg Time (ms)" stat tile is now "Suite Time"** — the wall-clock suite duration in `hh:mm:ss`, matching the sidebar. - **HTML report: suite duration in `hh:mm:ss`, wall-clock.** The report previously showed the *sum* of every test's time in milliseconds, which overstates a parallel run. It now shows how long the suite actually ran (`01:42:07`; hours aren't capped). The metrics JSON gains `suiteDurationMs`; `totalTimeMs` (summed test time) is unchanged. diff --git a/docs-site/docs/changelog.md b/docs-site/docs/changelog.md index 70d29c4..e360994 100644 --- a/docs-site/docs/changelog.md +++ b/docs-site/docs/changelog.md @@ -9,6 +9,10 @@ sidebar_position: 99 All notable changes to Selenium Boot are documented here. +## [Unreleased] + +- **`Locator` form actions: `clear()`, `check()`, `uncheck()`, `isChecked()`, `selectOption(text)`, `selectOptionByValue(value)`, `inputValue()`** — form controls can now be manipulated and inspected directly on `Locator` without falling back to `BasePage` helpers or raw `WebElement`s. `check()` and `uncheck()` are idempotent (no click if already in the target state), `isChecked()` queries checked state without waiting, and terminal actions (`clear`, `check`, `uncheck`, `selectOption`, `selectOptionByValue`, `inputValue`) auto-wait, re-resolving from scratch on every poll to survive stale or late-appearing elements. (#133) + --- ## [3.7.0] — 2026-10-04 diff --git a/docs-site/docs/guides/semantic-locators.md b/docs-site/docs/guides/semantic-locators.md index 5065308..bbfa02c 100644 --- a/docs-site/docs/guides/semantic-locators.md +++ b/docs-site/docs/guides/semantic-locators.md @@ -27,8 +27,8 @@ on both `BaseTest` and `BasePage`. Auto-waiting covers the element *existing* as well as being visible: an action such as `click()` or `type()` keeps looking for the element until `timeouts.explicit` elapses, and looks it up afresh each time, so a page that re-renders it mid-action doesn't cause a stale-element error. If it never -appears you get a `LocatorException` after the timeout. `isVisible()`, `isHidden()`, `isEnabled()` -and `count()` never wait. +appears you get a `LocatorException` after the timeout. `isVisible()`, `isHidden()`, `isEnabled()`, +`isChecked()` and `count()` never wait. --- diff --git a/src/main/java/com/seleniumboot/locator/Locator.java b/src/main/java/com/seleniumboot/locator/Locator.java index 9a89a41..4080799 100644 --- a/src/main/java/com/seleniumboot/locator/Locator.java +++ b/src/main/java/com/seleniumboot/locator/Locator.java @@ -11,6 +11,7 @@ import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.Select; import org.openqa.selenium.support.ui.WebDriverWait; import java.time.Duration; @@ -260,6 +261,38 @@ public void click() { whenReady(el -> el.isDisplayed() && el.isEnabled(), el -> { el.click(); return null; }); } + /** + * Waits for the element to be visible and enabled, then checks it if it is not already checked. + * + *

Idempotent: does not click if the element is already checked. Works on checkboxes, + * radio buttons, and elements with {@code role="checkbox"}. Re-resolves on every poll + * and retries stale or not-yet-present elements until {@code timeouts.explicit} elapses. + */ + public void check() { + whenReady(el -> el.isDisplayed() && el.isEnabled(), el -> { + if (!isSelected(el)) { + el.click(); + } + return null; + }); + } + + /** + * Waits for the element to be visible and enabled, then unchecks it if it is currently checked. + * + *

Idempotent: does not click if the element is already unchecked. Works on checkboxes + * and elements with {@code role="checkbox"}. Re-resolves on every poll and retries stale + * or not-yet-present elements until {@code timeouts.explicit} elapses. + */ + public void uncheck() { + whenReady(el -> el.isDisplayed() && el.isEnabled(), el -> { + if (isSelected(el)) { + el.click(); + } + return null; + }); + } + /** Waits for the element to be visible, clears it, then types the given text. */ public void type(String text) { whenVisible(el -> { @@ -274,6 +307,19 @@ public void append(String text) { whenVisible(el -> { el.sendKeys(text); return null; }); } + /** + * Waits for the element to be visible and clears its text or value. + * + *

Re-resolves on every poll and retries stale or not-yet-present elements + * until {@code timeouts.explicit} elapses. + */ + public void clear() { + whenVisible(el -> { + el.clear(); + return null; + }); + } + /** Waits for the element to be visible and returns its trimmed visible text. */ public String getText() { return whenVisible(el -> el.getText().trim()); @@ -284,6 +330,25 @@ public String getAttribute(String name) { return whenVisible(el -> el.getAttribute(name)); } + /** + * Waits for the element to be visible and returns the current value of an {@code }, + * {@code