Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Robust React Native element finding using Appium

I'm using React Native to develop an app that requires end-to-end testing.

Coming from a Selenium WebDriver background, it seems to me that element finding in Appium can be very awkward compared to WebDriver, since native components only have ID and a single non-user-defined class.

  1. Is there a way I can add some sort of metadata to elements to make them easy to find?

Say if I have a table with complex elements inside a cell, and I need to first find the right row, then the cell, and then find the right components to manipulate inside the cell.

Ideally I'd want to be able to enumerate rows by searching for something like "myTargetRows". That would give me a list of rows.

  1. If I understand it correctly, no two components can have the same ID in native applications, so I can't use ID just like that, right? (I.e. use the same ID, "myTargetRows", for multiple row components).
  2. If not, should I use numbered IDs like "myTargetRow0", "myTargetRow1", etc, and then use XPath to partially match the ID?
  3. Isn't there a better way?
  4. If I can do something like that, can I then just chain those findElement calls to find the right nested elements I want?

P.s.: I don't want to hardcode the exact component hierarchies in my locators to avoid invalidating them should I move anything around in my views, so those point-and-click solutions won't help.

P.s. 2: Solutions must work both on Android and iOS, even if I need to implement some sort of abstraction for it myself.

like image 371
Gui Prá Avatar asked Jul 22 '16 15:07

Gui Prá


Video Answer


2 Answers

Since appium supports different search strategies which are also slightly different per platform I am using the following approach in one of my projects:

I have a helper which can be easily imported into each class which returns cross platform (iOS and Android) test ID props

export function getTestIdProps (id) {
    return { accessible: true, accessibilityLabel: id, testID: id }
}

During Development we make sure that each to be tested component receives those test IDs similar to this:

return (
    <ComponentToBeTested>
       <View {...getTestIdProps('unique-test-id-goes-here')} moreProps>
       </View>
    </ComponentToBeTested>
)

Careful Make sure to check the react native docs to see which basic element supports theses props. Not all react native elements support the testID or accessibilityLabel. If they don't, these props will be ignored.

Finally, in your Appium Test (Example in Java) you can then identify the element easily by its accessibility ID, similar to this:

public static By byAccessibilityId(final String id) {
    return MobileBy.AccessibilityId(id);
}

For further reading also see http://appium.io/docs/en/commands/element/find-elements/

like image 126
Christian.D Avatar answered Oct 16 '22 23:10

Christian.D


You should use accessibilityLabel props of View.

accessibilityLabel PropTypes.node

Overrides the text that's read by the screen reader when the user interacts with the element. By default, the label is constructed by traversing all the children and accumulating all the Text nodes separated by space.

More info can be found here

For unique ids, lets say you have a listview and 100 rows. You can combine rowId and static text for accessibilityLabel.

eg: 0_MyCustomRow, 1_MyCustomRow

like image 27
Melih Mucuk Avatar answered Oct 17 '22 00:10

Melih Mucuk