Adding testID to your components
This guide is applicable only for React Native applications.
It is always the best idea to match your element by something unique. We recommend using testID
property supported by most React Native components:
<View>
<TouchableOpacity testID="MyUniqueId123">
<Text>Some text</Text>
</TouchableOpacity>
</View>
Pass testID to your native components
Passing a testID
to your custom component props has no effect until you forward it down to a native component like <View />
or <TouchableOpacity />
that implements rendering it as an accessibility identifier in the native component hierarchy:
For example, you have <YourCustomComponent />
and you pass a testID
to it:
function YourScreen() {
return (
<YourCustomComponent testID="YourCustomComponent" />
);
}
Make sure that your implementation passes testID
to some React Native component that supports it:
function YourCustomComponent(props) {
return (
<View testID={props.testID}>
<Text>Some text</Text>
</View>
);
}
Child elements
If your component has several useful child elements, it is even a better idea to assign them some derived test IDs, e.g.:
function YourCustomComponent(props) {
return (
<View testID={props.testID}>
<Text testID={`${props.testID}.label`}>Some text</Text>
</View>
);
}
That way, you could refer to specific elements in Detox tests via the most basic and least ambiguous by.id
matchers, e.g.:
expect(element(by.id('YourCustomComponent'))).toBeVisible(); // the view is visible
expect(element(by.id('YourCustomComponent.label'))).toHaveText('Some text'); // the label has some text
Repetitive components
It is highly not recommended to use non-unique testID
, e.g. when your components get rendered in any sort of repeater or virtualized list:
const ITEMS = [
{ title: 'First Item' },
{ title: 'Second Item' },
{ title: 'Third Item' },
];
function YourScreen() {
const renderItem = ({ item }) => (
<YourCustomComponent testID={'listItem'} label={item.title} />
);
return (
<FlatList
data={ITEMS}
renderItem={renderItem}
/>
);
}
This would be a violation of accessibility guidelines and unnecessary complication for your test matchers.
You’d also have to use extra matchers and .atIndex
clarification:
expect(element(by.id('listItem')).atIndex(2)).toHaveText('Third Item');
Instead, you could generate a unique testID
for every list item with the index
property:
const renderItem = ({ item, index }) => (
<YourCustomComponent testID={`listItem.${index + 1}`} label={item.title} />
);
That way, your assertion would become simpler and more deterministic:
expect(element(by.id('listItem.3'))).toHaveText('Third Item');
Find your testID
Incorrect or absent testID
is a common cause for test failure.
If your test can't find your testID
and you can't see it either using tools described below, that usually means you haven't passed it down to this component.
Make sure you keep forwarding it down until it reaches a native component.
To make sure your testID
is indeed rendered in your app, you can use such tools as "View Hierarchy" for iOS and "Layout Inspector" for Android.
- iOS
- Android
- Build and start your app in debug mode as you usually do, e.g.:
detox build -c ios.sim.debug
npx react-native start
npx react-native run-ios - Open your iOS project in Xcode, e.g.
YourProject/ios/YourProject.xcworkspace
. - Go to
Debug > Attach to Process
and select your app process (it is usually on top of the list). You will see a new device started with your app. - Open the
AppDelegate
file: - Click
Debug View Hierarchy
button on the bottom panel: - Select the component you need, and you will see your actual
testID
value under theAccessibility > Identifier
attribute.
- Make sure that React Native packager is already running. If not, you can start it with:
npx react-native start
- Launch Android Studio.
- Open
Tools > Layout Inspector
tool: - Build your application from Android Studio.
- After you run your app from Android Studio, the
Layout Inspector
should automatically attach to the process and show the hierarchy of your screen. You will see the snapshot of your screen, where you can focus on any component with a click.tipIf
Layout Inspector
doesn't attach to process from Android Studio, or you build it in a different way – you can attach to your app process manually usingSelect Process
dropdown. - Select the component you need, and you will see your actual testID value under the
tag
attribute.