Detox uses Matchers to find UI elements in your app, Actions to emulate user interaction with those elements and Expectations to verify values on those elements.
Matchers find elements in your app that match one or more properties.
NOTE: Whenever possible we recommend to match elements by.id, these are more resilient to layout restructuring and text/language changes
by.id will match an id that is given to the view via testID prop.
In a React Native component add testID like so:
<TouchableOpacity testID={'tap_me'}>
...Then match with by.id:
element(by.id('tap_me'));For other cases, and only if you can't use by.id there is a variety of options:
Find an element by text, useful for text fields, buttons.
element(by.text('Tap Me'));Find an element by accessibilityLabel on iOS, or by contentDescription on Android.
element(by.label('Welcome'));Find an element by native view type. View types differ between iOS and Android.
on iOS:
element(by.type('RCTImageView'));on Android, provide the class canonical name:
element(by.type('android.widget.ImageView'));Find an element with an accessibility trait. (iOS only)
element(by.traits(['button']));element(by.id('uniqueId').and(by.text('some text')));element(by.id('child').withAncestor(by.id('parent')));element(by.id('parent').withDescendant(by.id('child')));-
To find the view with the id
child<View testID='grandparent' style={{padding: 8, backgroundColor: 'red', marginBottom: 10}}> <View testID='parent' style={{padding: 8, backgroundColor: 'green'}}> <View testID='child' style={{padding: 8, backgroundColor: 'blue'}}> <View testID='grandchild' style={{padding: 8, backgroundColor: 'purple'}} /> </View> </View> </View>
Use:
// any of the following will work element(by.id('child')); element(by.id('child').withAncestor(by.id('parent'))); element(by.id('child').withDescendant(by.id('grandchild')));
When a matcher matches multiple views, there are three possible solutions:
-
Use multiple matchers to narrow down the matched results.
-
Add unique identifiers (testIDs) to the view which need to matched. A common use-case, is adding identifiers to list items. testIDs for FlatList items can be assigned dynamically, by passing
indexinrenderItem({item, index})and using it in the component's render function.FlatList
renderItemfunction:renderItem({item, index}) { return ( <CustomComponent index={index} ... /> ); }
CustomComponent'srenderfunction:render() { return ( <View testID={'listitem' + this.props.index} ... /> ); }
-
Select a matched view from the matched view list using
atIndexelement(by.text('Product')).atIndex(2);
Usage of atIndex is not recommended!, since the order of matched views can not be guaranteed by the system. Recyclable views in UITableView / UICollectionView / RecyclerView or any custom view may even change during scroll, while views are being recycled with new data.
React Native FlatList items are being traversed in different ways on the different platforms, causing atIndex to return the opposite indexes on iOS than what it does on Android.
on iOS 11:
element(by.traits(['button']).and(by.label('Back')));on iOS 10:
element(by.type('_UIModernBarButton').and(by.label('Back')));