Testing React Native Apps on Android and iOS

  January 29, 2016

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.

testing react native apps on android and ios

The Background and The Benefits of React Native Framework

Originally, Facebook created the React framework for its own engineering team that could use it to build user interfaces for all three platforms – Android, iOS and web – using exactly the same code. However, React itself wasn’t enough as it only providing a JavaScript library to build user interfaces and there was a long way to reach the native app compatibility. For this, they came up with React Native framework – a super powerful concept to get the best of both, JavaScript-based user interfaces and native compatibility, and bringing the benefits of modern web techniques to mobile platforms.

The major difference – and the benefit – between native mobile and web environment is that instead of running JavaScript-based implementation on a browser and showing up those HTML elements you can now rely on an embedded JavaScriptCore in apps that gets the user interface elements rendered to platform-specific elements.

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 to the lack of display space, and computing power isn’t there yet what we’ve been used to get from the 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 a whole lot slower on mobile compared to the web.

Fortunately, there are great ways to automate that regression testing with smart use of continuous integration, real device access from the 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 the app. For example, mobile game testing that we solved with the image recognition implementation has been one of the only solutions to reliably test mobile games.

In short, React Native is a pretty cool framework as it allows you to edit JavaScript files and the application reads the content and those JavaScript elements become native components. These apps are regular native Android and iOS apps, and basically any test automation frameworks work for them: Robotium, Appium, Calabash, uiautomator, Espresso, Jasmine, UI Automation, TestNG, Frank, KIF and many others! Therefore, you do have great freedom of choice when you build your apps based on React Native framework.

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.

uiautomatorviewer

All elements in this the right-side view are now native and there is no problem parsing those in test scripts. Depending on the 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 another 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 at some examples of UI element identification and use with different test automation frameworks.

Testing React Native Android and iOS Apps with Appium

If we want to do a click on ‘Use Bitbar Testing’ radio button, we can create a script line as follows:

driver.findElement(By.id("com.bitbar.testdroid:id/radio1")).click();

And naturally, getting all radio buttons clicked through, highlighting an EditText, writing ‘Simple Test’ in the 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 testing React Native Apps and other apps as well. Appium is probably the most promising test automation framework out there with a 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.

Testing React Native Android and iOS Apps with Calabash

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, behavior-driven development framework. Calabash got the popularity of its easy-to-understand syntax among testers who are not necessarily coding experts.

Testing React Native Android Apps uiautomator

In a series of test automation frameworks, the uiautomator by Google used to be different from other frameworks. Since 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 the usage of uiautomator increased when it enabled interactions beyond apps under test. The uiautomator (at least) used to support clicks and interacts outside of the 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 the app is loading UI.

Happy React Native App Testing Folks!