Testing React Native Apps on Android and iOS

Testing React Native Apps on Android and iOS Devices

Dear Testdroiders,

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.

react-native-apps-twitter

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 a 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 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.

In short, React Native is 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 works for them: Robotium, Appium, Calabash, uiautomator, Espresso, Jasmine, UI Automation, TestNG, Frank, KIF and many others! Therefore, you do have a 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-820-600

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:

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 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!

  • Is this just like a webview automation? In appium do you have to do switch context to webview before running tests?

    • Ville-Veikko Helppi

      These are all native components from OS platform/API, no webviews or HTML.

  • Guilhem

    Is it possible to set up Espresso test in a react Native project ? And how to do it because I’m trying actually and doesn’t manage to set it up properly .. Thank you

  • jsdevel

    I have a PR against react-native to add proper support for `resource-id`. Check it out and up-vote please: https://github.com/facebook/react-native/pull/9942

    Once that’s merged in `testID` will add `resource-id` so long as the Id is defined in `res/values/ids.xml`.

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close