It was roughly a year ago when Facebook announced their intention to open source the React Native framework for building native apps. This wasn’t a big surprise considering their own experiences with the HTML5 based application which got lots of negative feedback. Moving to native was clearly the right move and as they had some good and popular implementation for writing web apps (with React) there was a need to bridge the gap between the native and web/hybrid apps. With this combo, writing native apps for mobile platforms (Android and iOS) is actually very easy and it seems to work well across different setups. But, how to test – and automate the testing of these sort of apps? We’ll take a look at this topic in this blog.
The Background and The Benefits of React Native Framework
Challenges with Native Apps Compared to Web
No question, mobile app development is definitely more challenging than building web stuff. Primarily, mobile devices have smaller displays, the entire user experience design is more challenging due the lack of display space, and computing power isn’t there yet what we’ve been used to get from desktop. With native mobile apps you also need to recompile your APK / IPA to run it on devices or emulators to see how recent regressions have impacted your app. This naturally isn’t as fast as reloading a web page to see how what has changed and how the new implementation works. When adding a full blown test suite with potentially hundreds of test scripts/cases in this formula, development can get whole lot slower on mobile compared to web.
Fortunately there are great ways to automate that regression testing with smart use of continuous integration, real device access from cloud, test automation frameworks and even REST API access to all of that. Now, when adding the benefits of React Native framework into this, you probably get rid of nasty UI element identification issues. It’s highly recommended to use continuous integrations with all mentioned setup and push the app to cloud and get it running on real mobile devices.
Using Test Automation Frameworks with React Native
We’ve been working with many of you to get all sorts of implementations, with an array of different libraries, frameworks and proprietary setups, to work on open source test automation frameworks, and in this context the React Native framework could be a solution for many of you. Historically, one of the biggest hurdle with mobile test automation has been the identification and finding of UI elements in app. For example, mobile game testing that we solved with the image recognition implementation has been one of the only solution to reliably test mobile games.
Let’s start with a glance through uiautomatorviewer. This is the basic native sample application that has a version for both Android and iOS. The uiautomatorviewer naturally only works only for Android so you might want to use Appium Inspector to get specific IDs spot out with iOS.
All elements in this the right-side view are now native and there is no problem parsing those in test scripts. Depending on test automation framework, but it’s always recommended to implement automation logic and interactions with these priorities:
1) Use resource ID as it is the most reliable and unique identifier for any UI element.
2) Use and identify elements by name or other reliable identifier. This can be pretty much any UI element character – e.g. name, description, index, object specific item.
3) XPath gives you one way to recognize elements, but if these two prior methods are in use, you should stick with them as quite many things can go wrong in XPath formulation.
I’ll be using Java in these examples, so let’s look some examples of UI element identification and use with different test automation frameworks.
Appium with React Native Android and iOS
If we want to do a click on ‘Use Testdroid Cloud’ radio button, we can create a script line as follows:
And naturally, getting all radio buttons clicked through, highlighting an EditText, writing ‘Simple Test’ in input field and finally clicking the ‘Answer’ button would go as follows:
driver.findElement(By.id("com.bitbar.testdroid:id/radio0")).click(); driver.findElement(By.id("com.bitbar.testdroid:id/radio1")).click(); driver.findElement(By.id("com.bitbar.testdroid:id/radio2")).click(); driver.findElement(By.id("com.bitbar.testdroid:id/editText1")).click(); driver.findElement(By.id("com.bitbar.testdroid:id/editText1")).sendKeys("Simple Test"); driver.findElement(By.name("Answer")).click(); // or alternatively with driver.findElement(By.id("com.bitbar.testdroid:id/button1")).click();
We recommend Appium for React Native Apps and other apps as well. Appium is probably the most promising test automation framework out there with rapidly growing community. It works (perfectly) for both Android and iOS native apps, but more importantly also for mobile games and web related stuff. The web support comes from its WebDriver foundation as Appium and Selenium use the pretty much the same foundation.
Robotium with React Native Android
Robotium is already pretty ancient, but in fact it has always worked well with native apps, unfortunately only for Android (no iOS supported). Robotium is very accurate as it relies on resource IDs and you can use some content identification with it too. Here is the example for that basic application:
solo.clickOnView(solo.findViewById("com.bitbar.testdroid:id/radio0")); solo.clickOnView(solo.findViewById("com.bitbar.testdroid:id/radio1")); solo.clickOnView(solo.findViewById("com.bitbar.testdroid:id/radio2")); solo.enterText((EditText) solo.findViewById("com.bitbar.testdroid:id/editText1"), "Simple Test"); solo.clickOnView(solo.findViewById("com.bitbar.testdroid:id/button1"));
Using Robotium is definitely up to you. As said, it works well for native apps and there is even some level of web app support in it. Unfortunately, Robotium hasn’t take any significant steps further since it’s glory of early days. We’ve also extended the standard Solo library with Testdroid ExtSolo that introduced variety of handy functions (e.g. mocking up GPS of Android device, doing clicks outside of UI elements). For reason or another, these never ended in up the base Robotium and since then Robotium has faded in use and in popularity.
Calabash with React Native Android and iOS
Calabash is probably the most human-friendly and everyone can understand it. One of the greatest benefits of Calabash is that works for both Android and iOS, and in case your application is identical for both platforms those test scripts are usable for both.
Feature: Answer the Question feature Scenario: As a valid user I want to answer app question I wait for text "What is the best way to test application on hundred devices?" Then I press Radio button 0 Then I press Radio button 1 Then I press Radio button 2 Then I enter text "Simple Test" into field with id "editText1" Then I press view with id "Button1"
Calabash is a cucumber-based, behaviour driven development framework. Calabash got popularity of its easy-to-understand syntax among testers who are not necessarily coding experts.
uiautomator with React Native Android
In series of test automation frameworks, the uiautomator by Google used to be different from other frameworks. Since the version 2.0 it was based on instrumentation and now works pretty much like any other framework. However, uiautomator may not scale perfectly with all different kinds of apps out there and is available only for Android.
UiObject(new UiSelector().className("com.bitbar.testdroid:id/radio").index(0)).click(); UiObject(new UiSelector().className("com.bitbar.testdroid:id/radio").index(1)).click(); UiObject(new UiSelector().className("com.bitbar.testdroid:id/radio").index(2)).click(); UiSelector().className("com.bitbar.testdroid:id/editText1").instance(0)).setText("Simple Test"); UiObject(new UiSelector().text("Answer")).click(); // or ... UiObject(new UiSelector().className("com.bitbar.testdroid:id/Button1").click();
It seems that uiautomator got more usage when it enabled interactions beyond apps under test. The uiautomator (at least) used to support clicks and interacts outside of application and for example home screen interactions used to be possible.
Espresso with React Native Android
From the API point of view, Espresso by Google is extremely simple. And it is FAST!
// R class ID identifier for radio buttons onView(withId(R.id.radio0)).perform(click()); onView(withId(R.id.radio1)).perform(click()); onView(withId(R.id.radio2)).perform(click()); onView(withId(R.id.EditText1)).perform(click()); // Instead of R we use getIdentifier onView(withId(getInstrumentation().getTargetContext().getResources() .getIdentifier("com.bitbar.testdroid:id/EditText1", null, null))).perform((typeText("Simple Test"))); onView(withId(getInstrumentation().getTargetContext().getResources() .getIdentifier("com.bitbar.testdroid:id/Button1", null, null))).perform(click());
If you code only for Android you should seriously consider Espresso. It’s nice, easy and fastest framework out there. That comes from its nature to interact only with UI elements that are visible/accessible on screen and nothing happens if app is loading UI.
Let us know in comment section below what is your favourite!
Happy React Native App Testing Folks!