Your app is looking great! Let’s add some test cases with Jest and Appium.
How do you make sure that future development doesn’t break something that’s working today? By integrating automated tests with tools like Jest and Appium. Jest is a JavaScript testing framework that is often used to do snapshot testing of React Native apps, whereas the Appium framework is used for the integration testing of React Native apps.
Let’s update your app to incorporate snapshot testing for the button component.
The output of youi-tv init
includes the basic setup your application needs to work with Jest.
Each test is defined in a JavaScript file located in your project’s __tests__
folder.
Copy and paste the following test file into a new file called button-test.js
in MyApp/__tests__
.
import Button from "./../button.js";
import React from "react";
import renderer from "react-test-renderer";
test("renders correctly", () => {
const tree = renderer.create(<Button />).toJSON();
expect(tree).toMatchSnapshot();
});
From your app’s top-level project folder (MyApp
) run Jest with the command below.
yarn test
The terminal shows the progress of the test command:
yarn run v1.22.10
$ jest
PASS __tests__/button-test.js (5.021s)
✓ renders correctly (3068ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 passed, 1 total
Time: 6.627s
Ran all test suites.
✨ Done in 12.66s.
Since this is the first time you’re running it, the test generated and saved a snapshot for your button test.
You can find that file in __tests__/__snapshots__/button-test.js.snap
.
The next time you run Jest, a new snapshot will be generated and compared with the saved one.
By running this snapshot test between iterations of development, you can ensure that the structure of your Button
component doesn’t change.
To learn more, see Jest Snapshot Testing.
For more information on adding Jest tests to your app, see Testing React Native Apps in the Jest docs.
You.i Platform has an Appium Driver that you can use with both simulators and real devices. Even if you’re not familiar with Appium, it’s easy to get going. Follow this section of the tutorial to try it out.
The instructions below are for macOS. You can easily extrapolate instructions for other supported platforms using the README files in our Appium Driver repo.
The output of youi-tv init
includes the basics your application needs to work with Appium, but you need to install the Appium framework.
Start by installing Appium using the method of your choice from their installation guide.
Use node --version
to verify that your installed Node.js version is supported.
You.i Platform release 6.15 supports Node versions 12.10 to 12.x.
For information on other third party tools, verify our complete list for your development platform.
To manage multiple Node versions on your development system, take a look at NVM.
With a valid Node version installed, use brew
and node
to install the required dependencies for the Appium project within your app.
cd MyApp/__tests__/appium
brew bundle
yarn
If the brew bundle
command gives you errors, run brew upgrade
to upgrade problem packages and clean up dependencies, and then repeat the commands above.
Customize the default value in the Appium configuration file with your application’s name and path.
With your favorite editor, open MyApp/__tests__/appium/wdio.yimac.conf.js
and change app:
to point to your application.
Change the app
line in this section:
// change the "app:" value below from this
exports.config = merge(wdioConf.config, {
capabilities: [{
app: '../../../../../allinone/osx/react/samples/ReactTemplateProject/youi/Release/MyApp',
To this:
// to this (which points to your app)
exports.config = merge(wdioConf.config, {
capabilities: [{
app: '../../youi/build/osx/Debug/MyApp',
While the example above uses the relative path to your app, you can also use the absolute path to your app. We’ll see later that in some cases, the absolute path is preferred.
Now you’re ready to run the default Appium tests.
Open a new terminal window and start the Metro bundler for your application.
Due to the changes we made earlier, we add an extra yarn
step before yarn start
to be sure yarn has everything it needs.
# in a new terminal window
cd MyApp
yarn
yarn start
Go to your original terminal window, and from the MyApp/__tests__/appium
folder, execute the tests.
yarn yimac
The app opens! All by itself.
The tests run, then it closes again.
If you get an error when running yarn yimac
, change the app:
line in the configuration file to the absolute path of your executable.
For example, /Users/<yourname>/git/MyApp/youi/build/osx/Debug/MyApp
.
Look at the terminal you used to launch the Appium tests to see the results.
This default test confirmed that when your application runs, the You.i TV logo is present.
It’s pretty boring as far as tests go, right?
But if someone accidentally removed the logo section in index.youi.js
, the tests would fail.
Go ahead and try it!
Based on the work we did in the Components section of this quick start guide, your app switches between light and dark modes when you click a button.
Let’s see how to exercise that button using Appium.
Since the button text changes depending on the value of this.state.lightTheme
, we can create the following two test cases:
Test Case 1 - Before clicking the button, ensure that the button’s text says “Switch to the dark theme”.
Test Case 2 - After clicking the button, ensure that the button’s text says “Switch to the light theme”.
You may be wondering at this point why we want to test the app’s button with Appium, given that we already tested it with Jest. Appium is used for integration testing of React Native apps. It verifies that the button is working as expected by mimicking a user’s interaction with your app. For example, if the user pushes the button, the app’s theme switches from light to dark.
By contrast, Jest is JavaScript-only testing framework, which checks the structure of the Button
component using snapshot testing and verifies if the JavaScript-side logic is correct.
Both are useful, and test different aspects of the Button code.
Before we get started with new tests, let’s take a look at the test we already ran.
Open MyApp/__tests__/appium/test/specs/app.test.js
in your favorite text editor.
Notice the following:
context('when in App', () => {
it('displays logo image', function() {
// Wait until the screen is loaded and displayed.
expect(AppScreen.react_image_node.getAttribute("isdisplayed")).to.be.true;
});
This is the default test case we ran above. Can you guess:
The pass/fail condition is that a particular element is displayed:
expect
and to.be.true
,isdisplayed
.The element under test is the AppScreen.react_image_node
.
But what is that?
AppScreen.react_image_node
is a user-defined method that returns the name of a scene tree element to test.
In this case, it returns a value corresponding to the ImageView with the logo image.
In the next steps, you’ll see where to find those values and configure your tests to use them.
For our two new proposed test cases, we need to verify the button text and click the button. But how do we know the name of the scene tree element that identifies the button we want to test? With Appium Desktop!
Start by downloading and installing Appium Desktop version 1.21, following the instructions on their website.
This tutorial requires Appium Desktop version 1.21.
Once it’s installed, launch it and click Start Server to start the Appium server with the default settings (host 0.0.0.0
and port 4723
).
Click the magnifying glass at the top-right corner of the window to start an Inspector session. Notice the area highlighted in red below (JSON Representation).
We need to provide a JSON schema for our app.
The JSON schema is found in MyApp/__tests__/appium/wdio.yimac.conf.js
.
Open this file and copy the contents of the capabilities
section into the JSON Representation in Appium Desktop.
capabilities: [{
app: '../../youi/build/osx/Debug/MyApp',
automationName: 'YouiEngine',
deviceName: 'Mac',
platformName: 'yimac',
youiEngineAppAddress: 'localhost'
}],
The format of the JSON schema is a bit different in Appium Desktop, so a few small changes are needed. In Appium Inspector, click the Pencil icon in the JSON Representation area to begin editing.
../..
in the path), change it to the absolute path."
, as shown below (change single quotes '
to double "
, and add double quotes to the keys).Click the Save icon (floppy disk) in Appium Inspector to save the JSON Representation. The Inspector is updated with your app’s capabilities listed on the left side.
It’s time to run an Inspector session. If your Metro Bundler isn’t running, open a terminal window and start it.
# in a new terminal window
cd MyApp
yarn start
From the Appium Inspector, click Start Session at the bottom-right corner. Your app launches, as well as the screen shown below. If your app hides the Inspector screen, switch back to Appium to see the Inspector screen.
From here we can see the entire scene tree of the app in the “App Source” column. Play with it a bit to see the information it gives you. Click the drop-down toggle for each section, then click the drop-down item again to see its nested elements.
Move the cursor over your app on the left side of the Inspector page. As you move your cursor over areas of the screen, sections are highlighted. These are elements in the scene tree. For our test, we want to find the name of the element containing the button text. So highlight the button element’s text (not just the button) and click it. Information about this element is shown in the Selected Element column on the right:
Look at the Attribute > Name row, highlighted above.
The name of our selected element is React:RCTText:9
.
Note that the name of the selected element in your running session may not be React:RCTText:9
.
Choosing to use the element’s name as a selector is OK for this simple app.
However, as your app becomes more complex, you may run into issues if two or more elements in the scene tree have the exact same value for name
.
To solve this issue, use elementId
(which is unique) instead of name
to identify the elements in your scripts.
Close the interactive session and quit Appium Desktop. Leaving it running can interfere with the tests below.
Now that we know the name of the element we want to test, we can use it as an identifier in our test script. We can check that the text rendered on the button is correct, and we can even instruct Appium to click it for us!
Remember the AppScreen.react_image_node
method from the default test we ran earlier?
We need to define a similar abstraction function that returns React:RCTText:9
for our new tests.
Open MyApp/__tests__/appium/test/pageobjects/app.page.js
.
Here you’ll see the definition for react_image_node
.
get react_image_node() { return $("~React:RCTImageView:3"); }
Try it out.
Go back to the Inspector and select the image.
Confirm that the image element’s name is React:RCTImageView:3
.
Following the lead of the default test case, add a new function get react_button_node()
to app.page.js
.
Have your new function return the attribute name of the button text element:
get react_image_node() { return $("~React:RCTImageView:3"); }
get react_button_node() { return $("~React:RCTText:9"); }
Remember to replace ~React:RCTText:9
in the above with whatever number you discovered during the Appium session, for instance, ~React:RCTText:13
.
Without the correct number for your session you will see errors about not finding the element in the following section.
Save and close the file.
Open MyApp/__tests__/appium/test/specs/app.test.js
to add the two test cases.
Test Case 1 - For this case, we want to check the button text before we click the button.
We can get the button’s text with AppScreen.react_button_node.getText()
.
Then we can use expect
and to.equal
to test that the text matches our expected value.
context('before clicking the button', () => {
it('displays text to switch to the dark theme', () => {
// Wait until the screen is loaded and displayed.
expect(AppScreen.react_button_node.getText()).to.equal(
'Switch to the dark theme'
);
});
});
Test Case 2 - We want to have Appium click the button, then verify the new button text.
As above, we use AppScreen.react_button_node
to find the button, then .click()
to click it.
In this case, we add a bit more logic to give the button a few seconds to change before we check the text again.
context('after clicking the button', () => {
it('displays text to switch back to the light theme', () => {
// Once the screen is loaded, click the theme change button
AppScreen.react_button_node.click();
// Give the screen 5 seconds to update
browser.waitUntil(
() => {
return (
AppScreen.react_button_node.getText() === 'Switch to the light theme'
);
},
5000,
'expected text to be different after 5s'
);
// Check that the text is changed
expect(AppScreen.react_button_node.getText()).to.equal(
'Switch to the light theme'
);
});
});
It’s time to see it all in action!
From the MyApp/__tests__/appium
folder, run the following command to launch your tests.
yarn yimac
If your tests fail with an Appium error, make sure you’ve closed Appium Desktop and try again.
Watch as your app launches and the theme button is clicked. The app closes again.
If your app fails to close automatically (there’s a known Appium issue that can cause this to happen), close it manually before proceeding.
Your shell window shows the success (or failure) of your tests.
If your tests failed, check all your spelling carefully, including the actual button text in index.youi.js
.
You now know how to automate test cases using Appium. If you’d like more practice automating test cases using Appium with Your First App, here are some things you can test for when the button is clicked:
These are left as exercises for you to try.
Now you have a working app that you can run automated tests against with Jest and Appium.
Next, you’ll learn how to extend your app’s functionality through a native module.