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