You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Widget: Not all element look up options work when using multiple locators #1816
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 #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 = "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.
Activity
Auto81 commentedon Jan 3, 2023
Does trying the following style yield any different results?
Ganesh2325 commentedon Oct 30, 2026
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 #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.
PR: #2493