Skip to content

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

Open
Ganesh2325/java-client
#4

Description

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Suppose we have 2 locators to look up a widget and 2 locators to look up a nested widget element.

In this case, looking up is performed only by the combinations

  • first widget locator + first element locator
  • first widget locator + second element locator

and the other two combinations are ignored

  • second widget locator + first element locator
  • second widget locator + second element locator

Expected Behavior

Looking up is performed on all 4 options

  • first widget locator + first element locator
  • first widget locator + second element locator
  • second widget locator + first element locator
  • second widget locator + second element locator

Minimal Reproducible Example

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

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

Calling a method on the element with its widget which can only be found by the second locator will throw NoSuchElementException.

Environment

  • OS: Ubuntu 22.04.1 LTS
  • Appium Desktop: v1.22.3-4
  • Appium driver: UIAutomator2
  • Platform: Android API level 30
  • Emulator

Link to Appium Logs

No response

Futher Information

No response

Activity

  1. ghost added on Dec 11, 2022
  2. Auto81 commented on Jan 3, 2023

    @Auto81
    Contributor

    Does trying the following style yield any different results?

    @AndroidFindAll({
      @AndroidBy(id = "widget1"),
      @AndroidBy(id = "widget2")
    })
    private SomeWidget widget;
    
    @AndroidFindAll({
      @AndroidBy(id = "element1"),
      @AndroidBy(id = "element2")
    })
    private WebElement element;
    
  3. Ganesh2325 commented on Oct 30, 2026

    @Ganesh2325
    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 #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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions