Skip to content

fix: look up a missing page object element once per wait attempt - #2472

Merged
mykola-mokhnach merged 1 commit into
appium:masterfrom
theluckystrike:fix/javaclient-2034
Oct 8, 2026
Merged

mykola-mokhnach merged 1 commit into
appium:masterfrom
theluckystrike:fix/javaclient-2034

Conversation

@theluckystrike

Copy link
Copy Markdown
Contributor

Change list

  • pagefactory.bys.builder.ByChained.findElement() runs its locator chain once instead of inside its own FluentWait.
  • New MissingElementLookupTest checks that a page object field with a missing element and Duration.ZERO sends one lookup and doesn't wait.

Types of changes

  • No changes in production code.
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Details

Fixes #2034.

Fields with mobile annotations such as @AndroidFindBy resolve through ByChained, even with a single annotation. ByChained.findElement() wrapped the chain in new FluentWait<>(context), which has the default 500 ms timeout and 500 ms polling interval. AppiumElementLocator already waits with the timeout given to AppiumFieldDecorator (or @WithTimeout). So a missing element got a hidden second wait inside each attempt of the real one, with two POST /element calls and at least 500 ms per attempt, also for Duration.ZERO. The locator now owns the wait alone, which matches support.pagefactory.ByChained and plain driver.findElement().

Results from my runs on this branch (JDK 26.0.2, Gradle 9.8.0 wrapper, Selenium 4.50.0).

  • ./gradlew :test --tests 'io.appium.java_client.pagefactory_tests.MissingElementLookupTest' fails on master 92c2dc8 with expected: <[AppiumBy.accessibilityId: Not Exists]> but was: <[AppiumBy.accessibilityId: Not Exists, AppiumBy.accessibilityId: Not Exists]> and passes with the change.
  • ./gradlew clean build passes, with 206 core tests and 12 selenium-bridge tests, 0 failures, plus checkstyle and javadoc.
  • The page object from the issue (@AndroidFindBy(accessibility = "Not Exists"), new AppiumFieldDecorator(driver, Duration.ZERO), then click()) ran against a local HTTP endpoint that records requests and answers no such element. The 11.0.0 jar from Maven Central sends 2 POST /element per click for Duration.ZERO and for Duration.ofMillis(-1). The jar built from this branch sends 1 for each, and the -1 ms case drops from 880 ms to 315 ms.

The Android, iOS and Flutter e2e lanes need devices and didn't run here.

This PR was prepared with Claude Code. Every result above comes from a local run.

Fixes appium#2034

Fields with mobile annotations resolve through
pagefactory.bys.builder.ByChained, even with one annotation. Its
findElement() wrapped the chain in a FluentWait with the default 500 ms
timeout and interval, inside the wait that AppiumElementLocator already
runs with the decorator timeout. A missing element got two lookups and
at least 500 ms per attempt, also with Duration.ZERO. The chain now runs
once and the locator owns the wait.

Commands I ran, with the result.

    ./gradlew :test, filtered to MissingElementLookupTest
      master 92c2dc8  expected [accessibilityId: Not Exists] but was
                       [accessibilityId: Not Exists, accessibilityId: Not Exists]
      this commit      1 test, 0 failures

    ./gradlew clean build   (JDK 26.0.2, Selenium 4.50.0)
      BUILD SUCCESSFUL, core 206 tests and selenium-bridge 12 tests, 0 failures

    page object from the issue, Duration.ZERO and -1 ms, local endpoint
      11.0.0 jar     2 POST /element per click
      this commit    1 POST /element per click

I didn't run the Android, iOS and Flutter e2e lanes.
@mykola-mokhnach
mykola-mokhnach merged commit f8e328b into appium:master Oct 8, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] [PageObject] AppiumDriver.findElement() called twice

2 participants