Differences in iOS vs. Android Hierarchy and Behavior

We are working on implementing automated testing for the iOS version of our app and have encountered some issues and differences between iOS and our Android counterparts. For instance, in one area of the app we are showing a modal and the hierarchy is completely different- on Android we are only able to interact with elements in the top most modal (which is ideal) and iOS hierarchy shows elements from screens that are not visible. Why are they so vastly different in this way? How do I ensure that automation is only interacting with the topmost elements- i.e. if there is more than one closeButton in the hierarchy how can I ensure that I am tapping the correct one?

In addition, I am finding that android deals with item indexes but iOS does not- so if we had two inputs on the page and we are trying to the the text of the second input we do something like this for android input[1] and we can get the text of that element but on iOS it interprets this as the first letter and often returns a failure of being unable to find element i- is there a way to use indexes on iOS?

It is our hope to run the tests on iOS that were made for our android app- is this not common practice?

Appium uses NATIVE test frameworks. All differences there. XCUITest with iOS shows elements outside screen, Android UIAutomator2 shows only what on screen, Android Espresso also shows outside.

Now your closeButton. It has attribute visibility. Use it when you specify element.

we have 600+ tests written for both platforms (iOS and Android). Sometimes we have element differences, sometimes flow a bit different. All magic is hidden behind in page objects.

e.g. input difference behavior when we need clear input while setValue does not work correctly on iOS:

    @Step("Set 'FirstName' input {name}")
    public EditContactPage setFirstNameInput(String name) {
        Logger.log("name: " + name + "'");
        if (isIOS())
            clearInput(firstNameInput);
        Assert.assertTrue(setValue(firstNameInput, name), createAssertionLog("FAILED"));
        return this;
    }

test flow itself looks same e.g.:

        login(getCustomer());

        navigateToPayContactsList()
                .editContact(payee)
                .isEditContactPageLoaded()
                .setFirstNameInput(newName)
                .setLastNameInput(newLastName)
                .tapSaveButton()
                .isPayContactsPageLoaded();

It seems to me that most start out with this as a goal but end up dedicating one team to each os and creating frameworks that diverge.

My opinion is that it can be done, but you’ll have to decouple the tests from libraries that support them. You’ll need some decision tree that will point the test to the proper supporting library based on os.

Of course, on the Android side you’ll probably end up doing the above once you figure out how different your app looks on different Android versions. I’m guessing that you haven’t gotten to that point so fair warning. Android fragmentation is a real thing.

ok- thank you Aleksei! We do have some of those differences we are accommodating for in a similar way. What do you mean by attribute visibility? This is new to me- would you mind providing an example? I looked around in the appium documentation and was unable to find anything.

here it is:

    @iOSXCUITFindBy(iOSNsPredicate = "name == 'titleLabel' AND visible == 1")
    @AndroidFindBy(id = "titleLabel")
    MobileElement currentAccountText;