There are few frameworks that are suitable for React Native apps testing, the most popular is Appium and Detox. Appium is a standalone testing application and Detox is more of a grey box testing tool that can be easily integrated with your application. While both of those tools have pros and cons, both tools have a common issue to solve and it is how react rendering application to the native platforms.
First of all React Native use testID’s to populate accessibility id which works in favor of both Appium and Detox. The problem is that those testID’s getting picked up only by iOS, Android has problems with it, so you would add accessibilityLabel to solve it. Here is what Jonathon Lips from Appium suggested to do:
export function testProps (id) {
return {testID: id, accessibilityLabel: id};
}
And then you can call testProps in your react native component:
<Component {...testProps('foo')} />
I have 50/50 chances that complex React Native app actually will propagate that id’s as you would expect it.
Now we go look for some other solutions, let’s set accessible to true:
export function testProps (id) {
return {
testID: id,
accessibilityLabel: id,
accessible: true
};
}
This might seem like a good solution, but there is a place for improvement, we shouldn’t propagate testID and accessibilityLabel to both platforms, Android does not really care about testID’s, here is what we can do:
export const testProps = (testID: string) => {
if (isIOS) {
return {
testID,
accessible: false,
};
}
return {
accessible: true,
accessibilityLabel: testID,
};
};
Now it’s better, well, not really. You still going to face problems with iOS not respecting rules set by React Native. Here is what I mean, testIDs works perfectly with Buttons and Views, but it handling Text elements in a unique way. Basically iOS takes the text and renders it as accessibility id, and it is great until you need static id. This can be sensitive when you supporting different languages in your React Native app. I found myself adding accessibilityLabel to Text element solving the problem.
<Text
{...testProps('my_test_id')}
accessibilityLabel={'my_test_id'}
>
{whatever_text_here}
</Text>
Let’s make it a little more cleaner:
<Text
{...testProps('my_test_id', true)}
>
{whatever_text_here}
</Text>
export const testProps = (testID: string, isText: boolean=false) => {
if (isIOS) {
if(isText){
return {
testID,
accessibilityLabel: testID,
};
} else {
return {
testID,
accessible: false,
};
};
};
return {
accessible: true,
accessibilityLabel: testID,
};
};
Ok now all great, until you hit tabs in iOS, then none of those settings that we have going to work, what you would need to do is add tabBarTestID
property to navigationOptions (as suggested in here).
One other thing to keep in mind while testing React Native applications is that Appium and Detox having a hard time dealing with background animation and it is better to set it to false and save time on test execution.
Hope this blog post helps, feel free post your comments bellow.