Test Automation

Your app is looking great! 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.

Jest

Let’s make some changes to the app to do snapshot testing of the button component using Jest.

Set Up for Jest

The output of youi-tv init includes the basic setup your application needs to work with Jest, but you need to install the rest of the Jest framework with yarn.

Install Jest-related dependencies.

yarn add --dev jest@^24.0.0 babel-jest@^24.9.0 babel-preset-env@^1.7.0 metro-react-native-babel-preset@^0.45.0 react-test-renderer@16.6.3

Important: After adding the new packages, check package.json to make sure it shows the same versions for react and react-test-renderer. Also ensure the jest version is not above 24.x.0.

Add and Run a Jest Test

Tests are JavaScript files located in <AppName>/__tests__; for example MyApp/__tests__. Let’s add a new test for snapshot testing of the button component and run the test successfully.

  1. Copy and paste the following test file into a new file called button-test.js in the __tests__ folder.

    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();
    });
    
  2. Switch to the app’s main folder, for example, cd MyApp, and run the Jest test.

    yarn test
    

    Under __tests__ you’ll see a new __snapshots__ folder that contains button-test.js.snap and your terminal shows the progress of the test command:

    yarn run v1.17.3
    $ jest
    [ '/Users/username/MyApp/node_modules/react-native/',
    '/Users/username/MyApp/node_modules/@youi/react-native-youi/' ]
    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 new snapshot of the button. The next time you run it, a new snapshot will be generated and compared with the saved one. The snapshot test ensures that the structure of the Button component doesn’t change. To learn more, see Snapshot Testing.

Great Job! Keep it Up With More Tests

To add new tests to your app, see React Native with Jest.

Appium

You.i Engine One 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.

Pro Tip: The instructions below are for macOS. You can easily extrapolate instructions for other supported platforms by reading the README files in our Appium Driver repo.

Setup

The output of youi-tv init includes the basic setup your application needs to work with Appium, but you need to install the rest of the Appium framework.

  1. Install Appium using the method of your choice from their installation guide.

  2. Verify that your installed node version is supported by comparing with our third-party tools page. For You.i Engine One release 5.18, your node version should be between version 10.9.0 and 12.

    node --version
    

    Pro Tip: To manage multiple node versions on your development system, take a look at NVM.

  3. 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
    npm install
    

    If you see brew errors, you may need to clean up some brew dependencies such as upgrading certain packages with brew upgrade.

  4. Finally, 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 a relative path, you can also use the absolute path to your app. In some cases, as we’ll see later, the absolute path is preferred.

Run the Default Tests

Now you’re ready to run the default Appium tests.

  1. Open a new terminal window and start the Metro bundler for your application. You may be able to skip the yarn step below, but due to the changes we made earlier, it’s wise to make sure yarn has all its dependencies.

    # in a new terminal window
    cd MyApp
    yarn
    yarn start
    
  2. Go to your original terminal window, and from the MyApp/__tests__/appium folder, execute the tests.

    npm run-script yimac
    

    The app opens! All by itself.

    The tests run, then it closes again.

    Note: If you get an error when running npm run-script yimac, change app in the configuration file to the absolute path of your executable. For example, /Users/<yourname>/git/MyApp/youi/build/osx/Debug/MyApp.

  3. Look at the terminal you used to launch the Appium tests to see the results. One of one test passed (100% completed).

    Screen capture of Appium tests running with a You.i React Native application

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!

Create New Test Cases

Based on the work we did in the customize section of this quickstart guide, your app is 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”.

Understand the Existing Test

Before we get started with the 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:

  1. The pass/fail condition?
  2. Which element is under test?

The pass/fail condition is that a particular element is displayed:

  • It uses the keywords expect and to.be.true,
  • the attribute checked is 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.

Discover How to Reference the App’s Button and Button Text in Tests

Note: Appium is used for integration testing of React Native apps. It verifies if the button is working properly as expected in a real app. It also mimics a user’s interaction with the app. For example, if you push the button and the app’s screen goes dark. 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.

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!

  1. Download and install Appium Desktop, following the instructions on their website.

  2. Launch Appium Desktop.

  3. Click Start Server to start the Appium server with the default settings (host 0.0.0.0 and port 4723).

    Screen capture of Appium Desktop

  4. Click the magnifying glass at the top-right corner of the window to start an Inspector session.

    Screen capture of Appium Desktop in inspection mode

  5. Notice the area highlighted in red in the above screen capture (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.

    capabilities: [{
      app: '../../youi/build/osx/Debug/MyApp',
      automationName: 'YouiEngine',
      deviceName: 'Mac',
      platformName: 'yimac',
      youiEngineAppAddress: 'localhost'
    }],
    
  6. A few small changes are needed to convert from the format used in the conf file to the format used by Appium Desktop. In Appium Inspector, click the Pencil icon in the JSON Representation area to begin editing.

    • Paste the copied capabilities into the editor, between the curly braces.
    • If you copied the top and bottom lines from the sample above, remove them.
    • If you had been using a relative path to your app (with ../.. in the path), change it to the absolute path.
    • Surround each key and each value with double quotes ", as shown below (change single quotes ' to double ", and add double quotes to the keys).

    Screen capture of Appium Desktop, JSON Representation section

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

    Screen capture of Appium Desktop in inspection mode, with JSON Representation added

  8. 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
    
  9. 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.

    Screen capture of Appium Desktop inspecting your You.i Engine One application

    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.

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

    Screen capture of Appium Desktop showing the details of Button Text in your You.i Engine One application

  11. Look at the Attribute > Name row, highlighted above. The name of our selected element is React:RCTText:9.

    Pro Tip: 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.

  12. Close the interactive session and quit Appium Desktop. Leaving it running can interfere with the tests below.

Create the New Tests

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.

  1. 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"); }
    

    Pro Tip: Try it out. Go back to the Inspector and select the image. Confirm that the image element’s name is React:RCTImageView:3.

  2. 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"); }
    

    Save and close the file.

  3. 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', function() {
          // 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', function(){
          // 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');
       });
    });
    

Run Your New Tests

It’s time to see it all in action!

  1. From the MyApp/__tests__/appium folder, run the following command to launch your tests.

    npm run-script yimac
    

    If your tests fail with an Appium error, make sure you’ve closed Appium Desktop and try again.

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

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

    Screen capture of Appium Desktop showing the details of Button Text in your You.i Engine One application

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:

  • Test that the logo changes successfully.
  • Test that the background color changes successfully.
  • Test that the text color changes successfully.

These are left as exercises for you to try.

Up Next

Next, you’ll learn how to extend your app’s functionality through a native module.