Skip to content

fix: try later ALL_POSSIBLE widget roots when a nested lookup misses - #2493

Open
Ganesh2325 wants to merge 1 commit into
appium:masterfrom
Ganesh2325:cursor/fix-widget-multiple-locators-7a1e
Open

Ganesh2325 wants to merge 1 commit into
appium:masterfrom
Ganesh2325:cursor/fix-widget-multiple-locators-7a1e

Conversation

@Ganesh2325

@Ganesh2325 Ganesh2325 commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Change list

  • When a widget is declared with alternative locators (@HowToUseLocators(... = ALL_POSSIBLE) or @AndroidFindAll, and the same shapes on other platforms), a nested lookup that misses inside the first matching root is retried against each later root.
  • Chained locators are unchanged. They still describe one path, not a set of alternative roots.
  • Add WidgetMultipleLocatorLookupTest, a device-free unit test for the combinations reported in Widget: Not all element look up options work when using multiple locators #1816.

Fixes #1816

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

Repro

Widget field:

@HowToUseLocators(androidAutomation = LocatorGroupStrategy.ALL_POSSIBLE)
@AndroidFindBy(id = "widget1")
@AndroidFindBy(id = "widget2")
private SampleWidget widget;

Nested element:

@HowToUseLocators(androidAutomation = LocatorGroupStrategy.ALL_POSSIBLE)
@AndroidFindBy(id = "element1")
@AndroidFindBy(id = "element2")
private WebElement element;

widget1 is present and contains neither nested element. widget2 is present and contains element2. Calling a widget method that reads element threw NoSuchElementException. The only lookups were widget1 -> element1 and widget1 -> element2.

The same miss happens with @AndroidFindAll on the widget and on the nested element. If widget1 does not exist at all, the second root was already used. Chained @AndroidFindBy pairs still describe one path and do not fall through.

Root cause

ByAll.findElement returns the first root that matches and stops. The widget is bound to that element, and nested locators run only inside it. A miss on the nested locators was never a reason to try the next widget locator.

WidgetInterceptor now catches that NoSuchElementException and repeats the widget method against the first element of each later alternative locator. @AndroidFindAll is stored as a one-locator chain around a ByAll, so that wrapper is unwrapped before the alternatives are read. A chain of more than one locator is left alone.

Test command

./gradlew test checkstyleMain checkstyleTest javadoc

BUILD SUCCESSFUL in 33s. 234 tests, 0 failures, 0 errors, 0 skipped. checkstyleMain, checkstyleTest, and javadoc passed.

This change was AI-assisted; I reviewed and tested it myself.

A widget with several alternative locators kept the first matching
root. Nested locators were searched only inside that root, so an
element that exists only under a later widget locator was not found.

Fixes appium#1816
@cursor
cursor Bot force-pushed the cursor/fix-widget-multiple-locators-7a1e branch from 6206e61 to a7f3320 Compare November 3, 2026 07:15

This branch has not been deployed

No deployments
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.

Widget: Not all element look up options work when using multiple locators

1 participant