Get Started with Appium for React Native Apps

This topic contains the following sections:

Getting Started with Appium in You.i React Native

For You.i React Native, everything related to Appium is already set up when you create a new RN project using youi-tv init. The Appium test scripts are in the following subfolder of a new RN project: _tests_/appium/.

Note You.i TV uses WebdriverIO to create our test scripts. You.i TV recommends that before you start, go to webdriver.io to get familiar with it.

General Prerequisites

Run node --version to see what version of node is installed. You must use one of our supported versions. For You.i Engine One release 6.13, your node version should be between version 10.9.0 and 12.

Note Ensure that babel-preset-react-native is part of package.json for Appium to work with the app you build. If babel-preset-react-native is not part of package.json, run yarn add babel-preset-react-native@4.0.0 on the terminal to add it to package.json.

Prerequisites for iOS and tvOS

The prerequisites for iOS and tvOS are:

  • Brew is installed on your machine. If not, go to Homebrew’s site for download instructions.
  • Brew dependencies are installed on your machine. If they’re not, run brew bundle from the appium folder of the newly created RN project; for example MyApp/_tests_/appium.

Steps to Run the Test Scripts

Note Once you’ve created the new project, all commands are run from the _tests_/appium subfolder of your RN project folder. For brevity, we refer to this folder as MyApp/_tests_/appium in this topic.

To run the test scripts:

  1. Connect your device to the machine where test scripts will be running.

    This step doesn’t apply if you’re running the app on the machine itself, such as for macOS.

  2. From MyApp/_tests_/appium, run yarn.
  3. Configure the capabilities for your platform in the wdio.[platformName].conf.js file based on your target platform requirements. Consult our listing of minimum required capabilities per platform, and Appium’s documentation of desired capabilities for this information.
  4. Run the scripts using the following command on the required target platform:

    yarn platform-name

    where platform-name is one of: android, ios, connect-to-app (ignores installer/launcher), yimac, or yitvos.

For more details on supported search strategies, commands, and attributes, see our GitHub documentation on Appium You.i Engine Driver.

Things to Consider Before Creating New Test Scripts

Consider the following before you create new test cases:

  • All Appium test scripts are inside the __tests__/appium folder of any RN project directory. Put any new test cases there too.
  • Test scripts are JavaScript files inside the _tests_/appium/spec folder.
  • Page objects are located inside the _tests_/appium/pageobjects folder.

Using Appium and WebdriverIO

This section covers the following topics:

Creating a Test Plan

Before writing tests, define a test plan. For example, let’s say we want to test the following:

  • On an app’s PDP screen:
    • Validate that all elements are displayed on the screen
    • Validate that all elements are displayed with correct text
  • Validate that the NEXT button navigates to the correct screen
  • Validate that PREVIOUS button navigates to the correct screen

Basic Test Components

The test framework to organize and execute tests is based on Mocha. A test written with the Mocha framework looks like this:

var assert = require('assert');
describe('Array', function() {
  describe('#indexOf()', function() {
    it('should return -1 when the value is not present', function(){
      assert.equal(-1, [1,2,3].indexOf(4));
    });
  });
});

When writing a test, there are two basic function calls you should be aware of: describe() and it(). Both are used in the previous example. context() is another useful function:

  • describe() is simply a way to group our tests in Mocha. You can nest our tests in groups as deep as you deem necessary. describe() takes two arguments, the first is the name of the test group, and the second is a callback function.

     describe('string name describing test group', function(){
       // can nest more describe()'s here, or tests go here
     });
    
  • it() is used for an individual test case. it() should be written as if you were saying it out loud; for example, “It should equal zero”, “It should log the user in”, and so on. it() takes two arguments, a string explaining what the test should do, and a callback function which contains our actual test:

     it('should do something measurable', function(){
       // Test case goes here
     });
    
  • context() is an alias for describe(), and behaves the same way. It provides a way to keep tests easier to read and organized:

     context('string name', function(){
       // can nest more context()'s here, or tests go here
     });
    

Assertion Library

You can use assertion libraries within our testing framework (Mocha). An assertion library is a tool to verify things are correct. It’s what actually verifies the test results. The tests in these topics use Chai.

Page Object Pattern

Structure and organize the code using the Page Object Pattern.

The goal behind page objects is to abstract any page information away from the actual tests. Ideally you should store all selectors or specific instructions that are unique for a certain page in a page object, so that you can still run your test after you’ve completely redesigned your page. Consider each Page Object as a screen or UI the end user interacts with; the Page Object’s attributes are individual UI components (such as buttons or text fields), while actions you perform on that Page Object would be methods you write.

Using the Page Object Pattern, the folder structure is as follows:

├── test
│   ├── pageobjects
│   │   ├── page.js
│   │   └── pdp.page.js
│   └── specs
│       └── pdp.test.js
File Description
page.js Contains general selectors or methods all page objects inherit from.
pdp.page.js Contains all the selectors and methods specific to that screen.
pdp.test.js Contains the tests. In this case, they are specific to pdp.js.

Search Strategies

The appium-youiengine-driver supports the following search strategies:

Search strategy WebdriverIO command
accessibility id browser.element("accessibility id:Btn-Next")
$("~Btn-Next")
name browser.element("name:Btn-Next")
rntestID browser.element("id:Poster")
$("id:Poster")
id browser.element("id:100001")
$("id:100001")
class browser.element("class name:CYISceneView")
$("class name:CYISceneView")

Notes:

  • appium-youiengine-driver does not support xpath.
  • accessibility id redirects to name and it is recommended to use it over name.
  • rntestID can be added as a prop of your react components.

  • rntestID and id share the same search strategy and rntestID is returned first when the selector exists in both.

The best way to search for selectors is using Appium Desktop. In the following image of Appium Desktop, the unique or valid search strategies and selectors are highlighted for the selected elements.

Image

If a unique search strategy is not displayed, you can do one of the following:

  • Add a testID prop to the react component (index.youi.js)
  • Add an xpath-style filter to the search strategy. This is done by appending an attribute to the selector in the following format:

More Information on WebdriverIO

Debugging

To debug your code, enter the following line in your tests: browser.debug();

This command helps you debug your integration tests. It stops the running browser and gives you time to access the test and check the state of your application (for example, using the dev tools). Your terminal transforms into a REPL interface that allows you to try out certain commands, find elements, and test actions on them.

For more details, see WebdriverIO Debug.

Boilerplate Projects

The WebdriverIO community has developed many boilerplate projects that can be used as inspiration for your own test suite. See WebdriverIO Boilerplate Projects.

Jenkins Integration

See WebdriverIO Jenkins Integration.

Writing Tests: Validating PDP’s Elements

This topic introduces you to writing tests and shows you how to write an initial set of tests, using a movies app as an example.

Creating PDP Page Objects

In appium/test/pageobjects, create a file called page.js.

// page.js

export default class Page {
  // Empty for now
}

Let’s test our movie app’s PDP screen by building a page object example. The first step is to write all important selectors that are required in our pdp.page object as getter functions.

In appium/test/pageobjects, create a file called pdp.page.js.

// pdp.page.js

import Page from './page';

class PDPScreen extends Page {

  get btn_next()  { return $("~Btn-Next"); }
  get btn_previous()  { return $("~Btn-Previous"); }
  get title_text()  { return $("~Title-Text"); }
  get details_text()  { return $("~Details-Text"); }
  get body_text()  { return $("~Body-Text"); }
  get poster_image()  { return $("~Image-2x3"); }
  get background_image()  { return $("~Image-16x9"); }

}

export default new PDPScreen()

Creating the Test File and an Initial Test: ‘Element is displayed’ Test

In appium/test/specs, create a file called pdp.test.js.

import { expect } from 'chai';  // Using Expect style.
import PDPScreen from '../pageobjects/pdp.page'

describe('PDP Tests', function() {
  it('displays title', function() {
    expect(PDPScreen.title_text.getAttribute("isdisplayed")).to.be.true;
  });
});

This test finds the element title_text and querying its isdisplayed attribute. To do so, the test file uses the getAttribute command from WebdriverIO.

See also all of appium-youiengine-driver’s supported commands.

Running the Test File

In the __tests__/appium folder of our movies app, let’s run our tests: yarn yimac

We’d see output similar to the following:

$ yarn yimac

> appium-tests@1.0.0 yimac /Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium
> wdio wdio.yimac.conf.js

[15:07:46]  COMMAND POST     "/wd/hub/session"
[15:07:46]  DATA        {"desiredCapabilities":{"javascriptEnabled":true,"locationContextEnabled":true,"handlesAlerts":true,"rotatable":true,"app":"../../../../allinone/osx/react/ReactTemplateProject/youi/Debug/YiRNTemplateApp","automationName":"YouiEngine","deviceName":"dummy","platformName":"yimac","youiEngineAppAddress":"localhost","requestOrigins":{"url":"http://webdriver.io","version":"4.14.0","name":"webdriverio"}}}
[15:07:50]  INFO    SET SESSION ID 965b2e86-e178-45ce-994b-eab83eb9e5b7
[15:07:50]  RESULT      {"shell":null,"reboot":false,"ipa":null,"address":"0.0.0.0","port":4723,"callbackAddress":null,"callbackPort":null,"bootstrapPort":4724,"backendRetries":3,"sessionOverride":false,"launch":false,"log": ... (1989 more bytes)
[15:08:01]  COMMAND POST     "/wd/hub/session/965b2e86-e178-45ce-994b-eab83eb9e5b7/element"
[15:08:01]  DATA        {"using":"accessibility id","value":"Title-Text"}
[15:08:01]  RESULT      {"ELEMENT":"140707419133952"}
[15:08:01]  COMMAND GET      "/wd/hub/session/965b2e86-e178-45ce-994b-eab83eb9e5b7/element/140707419133952/attribute/isdisplayed"
[15:08:01]  DATA        {}
[15:08:01]  RESULT      true
[15:08:01]  COMMAND DELETE   "/wd/hub/session/965b2e86-e178-45ce-994b-eab83eb9e5b7"
[15:08:01]  DATA        {}
------------------------------------------------------------------
[dummy yimac undefined #0-0] Session ID: 965b2e86-e178-45ce-994b-eab83eb9e5b7
[dummy yimac undefined #0-0] Spec: /Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium/test/specs/pdp.test.js
[dummy yimac undefined #0-0] Running: dummy on yimac undefined executing ../../../../allinone/osx/react/ReactTemplateProject/youi/Debug/SampleApp
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] PDP Tests
[dummy yimac undefined #0-0]   ✓ displays title
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 1 passing (15s)
[dummy yimac undefined #0-0]

Common Mistake: Querying an element before it’s loaded

Although the test runs, it may fail on slower devices because it may query an element before it’s actually loaded.

To solve this issue, define an implicit wait with the following statement: browser.timeoutsImplicitWait(10000);

This statement sets the maximum amount of time the driver waits for an element to be available. It’s important to note this isn’t the same as a “sleep” type mechanism which idles for a given time. Instead, with the implicit wait statement, the driver repeatedly executes the selector code and only fails after that time.

Common Mistake: Querying an element before it’s displayed

A second reason the test may fail is that the element may have been found but it’s not yet displayed. The selector finds the object, checks the attribute and sees that it doesn’t have the expected the state, so it returns immediately.

To solve this issue, use the waitUntil command:

browser.waitUntil(function () {
  return PDPScreen.title_text.getAttribute("isdisplayed") === true
}, 5000, 'expected text to be different after 5s');

Again, this statement causes the test to wait up to five seconds for the attribute to have the expected value. If the attribute has the expected value before the five-second interval is over, the test returns immediately.

Updated Test File

Our updated pdp.test.js now looks like this:

import { expect } from 'chai';  // Using Expect style.
import PDPScreen from '../pageobjects/pdp.page'

browser.timeoutsImplicitWait(10000);

describe('PDP Tests', function() {
  it('displays title', function() {
    browser.waitUntil(function () {
      return PDPScreen.title_text.getAttribute("isdisplayed") === true
    }, 5000, 'expected text to be different after 5s');

    expect(PDPScreen.title_text.getAttribute("isdisplayed")).to.be.true;
  });
});

Adding the “Validating the displayed text” Test

Next, compare the text to make sure it matches the text meant to be displayed.

For our movies app, we could add the following code to import a list of movies for the PDP: import movies from '../../../../movies.js'

Then we’d add a new test to compare it:

import { expect } from 'chai';  // Using Expect style.
import PDPScreen from '../pageobjects/pdp.page'
import movies from '../../../../movies.js'

browser.timeoutsImplicitWait(10000);

describe('PDP Tests', function() {
  it('displays title', function() {
    browser.waitUntil(function () {
      return PDPScreen.title_text.getAttribute("isdisplayed") === true
    }, 5000, 'expected text to be different after 5s');

    expect(PDPScreen.title_text.getAttribute("isdisplayed")).to.be.true;
   });

  it('displays correct text for title', function() {
    expect(PDPScreen.title_text.getText()).to.equal(movies[0].title);
  });
});

We’d then see two passing tests:

[dummy yimac undefined #0-0] PDP Tests
[dummy yimac undefined #0-0]   ✓ displays title
[dummy yimac undefined #0-0]   ✓ displays correct text for title
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 2 passing (16s)
[dummy yimac undefined #0-0]

Adding Final PDP Element Tests

After adding tests for all the other elements of the PDP file, our pdp.test.js file looks something like this:

import { expect } from 'chai';  // Using Expect style.
import PDPScreen from '../pageobjects/pdp.page'

browser.timeoutsImplicitWait(10000);

describe('PDP Tests', function() {
  context('when in PDP', () => {
    it('displays title', function() {
      // Wait until the screen is loaded and displayed.
      browser.waitUntil(function () {
        return PDPScreen.title_text.getAttribute("isdisplayed") === true
      }, 5000, 'expected text to be different after 5s');

      expect(PDPScreen.title_text.getAttribute("isdisplayed")).to.be.true;
    });

    it('displays correct text for title', function() {
      expect(PDPScreen.title_text.getText()).to.equal(movies[0].title);
    });

    it('displays details', function() {
      expect(PDPScreen.details_text.getAttribute("isdisplayed")).to.be.true;
    });

    it('displays correct text for details', function() {
      expect(PDPScreen.details_text.getText()).to.equal(movies[0].details);
    });

    it('displays body', function() {
      expect(PDPScreen.body_text.getAttribute("isdisplayed")).to.be.true;
    });

    it('displays correct text for body', function() {
      expect(PDPScreen.body_text.getText()).to.equal(movies[0].synopsis);
    });

    it('displays NEXT button', function() {
      expect(PDPScreen.btn_next.getAttribute("isdisplayed")).to.be.true;
    });

    it('displays correct text for NEXT button', function() {
      expect(PDPScreen.btn_next.getText()).to.equal("Next");
    });

    it('displays PREVIOUS button', function() {
      expect(PDPScreen.btn_previous.getAttribute("isdisplayed")).to.be.true;
    });

    it('displays correct text for PREVIOUS button', function() {
      expect(PDPScreen.btn_previous.getText()).to.equal("Previous");
    });

    it('displays poster image', function() {
      expect(PDPScreen.poster_image.getAttribute("isdisplayed")).to.be.true;
    });

    it('displays background image', function() {
      expect(PDPScreen.background_image.getAttribute("isdisplayed")).to.be.true;
    });
  });
});

In our example, the expected test results are:

[dummy yimac undefined #0-0] PDP Tests
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]   when in PDP
[dummy yimac undefined #0-0]       ✓ displays title
[dummy yimac undefined #0-0]       ✓ displays correct text for title
[dummy yimac undefined #0-0]       ✓ displays details
[dummy yimac undefined #0-0]       ✓ displays correct text for details
[dummy yimac undefined #0-0]       ✓ displays body
[dummy yimac undefined #0-0]       ✓ displays correct text for body
[dummy yimac undefined #0-0]       ✓ displays NEXT button
[dummy yimac undefined #0-0]       ✓ displays correct text for NEXT button
[dummy yimac undefined #0-0]       ✓ displays PREVIOUS button
[dummy yimac undefined #0-0]       ✓ displays correct text for PREVIOUS button
[dummy yimac undefined #0-0]       ✓ displays poster image
[dummy yimac undefined #0-0]       ✓ displays background image
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 12 passing (15s)
[dummy yimac undefined #0-0]

Writing Tests: Validating Behavior of Navigation Buttons

This section presents additional concepts and extends the tests created in Writing tests: Validating PDP’s Elements.

Writing “PDP screen navigation” Tests

This second group of tests validates navigation to the second PDP and back by exercising the NEXT and PREVIOUS buttons.

  1. We start by adding a test to validate that we’re in the original PDP by checking its title.
  2. Then we use the click command on btn_next defined in our page object. See also the list of supported commands for appium-youiengine-driver.
  3. Once the click is done, we add a test to confirm we’re on the new PDP.
  4. Then we do the same for the button to return to the original PDP.

Our additions to the pdp.test.js file could look like this:

const pdp_title_1 = movies[0].title;
const pdp_title_2 = movies[1].title;

context('when clicking on NEXT button and PREVIOUS buttons', () => {
  it('transitions to another PDP', function() {

    let original_title = PDPScreen.title_text.getText();
    expect(original_title).to.equal(pdp_title_1);

    PDPScreen.btn_next.click;

    expect(PDPScreen.title_text.getText()).to.equal(pdp_title_2);
  });

  it('transitions back to the original PDP', function() {
    PDPScreen.btn_previous.click;

    expect(PDPScreen.title_text.getText()).to.equal(pdp_title_1);
  });
});

Running these tests for our movies app yields the following:

[dummy yimac undefined #0-0] PDP Tests
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]     when clicking on NEXT button and PREVIOUS buttons
[dummy yimac undefined #0-0]       1) transitions to another PDP
[dummy yimac undefined #0-0]       ✓ transitions back to the original PDP
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 1 passing (15s)
[dummy yimac undefined #0-0] 1 failing
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 1) when clicking on NEXT button and PREVIOUS buttons transitions to another PDP:
[dummy yimac undefined #0-0] expected 'Dino World' to equal 'Fairy Tales'
[dummy yimac undefined #0-0] AssertionError: expected 'Dino World' to equal 'Fairy Tales'
[dummy yimac undefined #0-0]     at Context. <anonymous>  (/Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium/test/specs/pdp.test.js:24:49)
[dummy yimac undefined #0-0]     at new Promise ( <anonymous> )
[dummy yimac undefined #0-0]     at new F (/Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium/node_modules/core-js/library/modules/_export.js:36:28)

Handling Test Failures: Example

Here’s a simple example that shows how to handle a test failure that occurs when the test tries to click on the button before the button is ready to handle the click.

There are many ways to solve this issue, but the best solution is to query the isHittable attribute with the waitUntil command.

Since this solution can be used by other screens as well, we’ll add it to the page class in appium/test/pageobjects/pdp.js, as follows:

// page.js

export default class Page {
  yi_click(element) {
    browser.waitUntil(function () {
      return element.getAttribute('ishittable') === true
    }, 5000, 'expected element to be hittable after 5s');
    element.click();
  }
}

Then use that command in the test:

const pdp_title_1 = movies[0].title;
const pdp_title_2 = movies[1].title;

context('when clicking on NEXT button and PREVIOUS buttons', () => {
  it('transitions to another PDP', function() {

    let original_title = PDPScreen.title_text.getText();
    expect(original_title).to.equal(pdp_title_1);

    PDPScreen.yi_click(PDPScreen.btn_next);

    expect(PDPScreen.title_text.getText()).to.equal(pdp_title_2);
  });

  it('transitions back to the original PDP', function() {

    PDPScreen.yi_click(PDPScreen.btn_previous);

    expect(PDPScreen.title_text.getText()).to.equal(pdp_title_1);
  });
});

Running the tests for our movies app now yields the following:

[dummy yimac undefined #0-0] PDP Tests
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]     when clicking on NEXT button and PREVIOUS buttons
[dummy yimac undefined #0-0]       1) transitions to another PDP
[dummy yimac undefined #0-0]       2) transitions back to the original PDP
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 2 failing (17s)
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 1) when clicking on NEXT button and PREVIOUS buttons transitions to another PDP:
[dummy yimac undefined #0-0] expected 'Dino World' to equal 'Fairy Tales'
[dummy yimac undefined #0-0] AssertionError: expected 'Dino World' to equal 'Fairy Tales'
[dummy yimac undefined #0-0]     at Context. <anonymous>  (/Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium/test/specs/pdp.test.js:109:49)
[dummy yimac undefined #0-0]     at new Promise ( <anonymous> )
[dummy yimac undefined #0-0]     at new F (/Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium/node_modules/core-js/library/modules/_export.js:36:28)
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 2) when clicking on NEXT button and PREVIOUS buttons transitions back to the original PDP:
[dummy yimac undefined #0-0] expected 'Fairy Tales' to equal 'Dino World'
[dummy yimac undefined #0-0] AssertionError: expected 'Fairy Tales' to equal 'Dino World'
[dummy yimac undefined #0-0]     at Context.<anonymous> (/Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium/test/specs/pdp.test.js:118:49)
[dummy yimac undefined #0-0]     at new Promise (<anonymous>)
[dummy yimac undefined #0-0]     at new F (/Users/janesmith/git/uswish/react/ReactTemplateProject/__tests__/appium/node_modules/core-js/library/modules/_export.js:36:28)

Adding Screenshots

As a final exercise, add a screen capture so you can do a (manual) visual inspection of the screens after the tests have run. To do this, use the saveScreenshot command. Add the following to the page.js file so it can be used elsewhere:

// http://webdriver.io/guide/testrunner/pageobjects.html

export default class Page {

  // Save a screenshot to jestHelpers directory.
  saveScreenshot(dir, filename) {
    let fs = require('fs');
    // Create directory if it doesn't exist.
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir);
    }
    browser.saveScreenshot(dir + filename);
  }

  yi_click(element) {
    browser.waitUntil(function () {
      return element.getAttribute('ishittable') === true
    }, 5000, 'expected element to be hittable after 5s');
    element.click();
  }

}

Completed Test File and Results

Once all the tests have been added, our pdp.test.js file contains the following:

import { expect } from 'chai';  // Using Expect style.
import movies from '../../../../movies.js'

import PDPScreen from '../pageobjects/pdp.page'

// http://webdriver.io/api/protocol/timeoutsImplicitWait.html
browser.timeoutsImplicitWait(10000);

const pdp_title_1 = movies[0].title;
const pdp_title_2 = movies[1].title;

// This group represents the tests for the screen.
describe('PDP Tests', function() {

  context('when in PDP', () => {
    it('displays title', function() {
      // Wait until the screen is loaded and displayed.
      browser.waitUntil(function () {
        return PDPScreen.title_text.getAttribute("isdisplayed") === true
      }, 5000, 'expected text to be different after 5s');

      expect(PDPScreen.title_text.getAttribute("isdisplayed")).to.be.true;
    });
    it('displays correct text for title', function() {
      expect(PDPScreen.title_text.getText()).to.equal(movies[0].title);
    });

    it('displays details', function() {
      expect(PDPScreen.details_text.getAttribute("isdisplayed")).to.be.true;
    });
    it('displays correct text for details', function() {
      expect(PDPScreen.details_text.getText()).to.equal(movies[0].details);
    });

    it('displays body', function() {
      expect(PDPScreen.body_text.getAttribute("isdisplayed")).to.be.true;
    });
    it('displays correct text for body', function() {
      expect(PDPScreen.body_text.getText()).to.equal(movies[0].synopsis);
    });

    it('displays NEXT button', function() {
      expect(PDPScreen.btn_next.getAttribute("isdisplayed")).to.be.true;
    });
    it('displays correct text for NEXT button', function() {
      expect(PDPScreen.btn_next.getText()).to.equal("Next");
    });

    it('displays PREVIOUS button', function() {
      expect(PDPScreen.btn_previous.getAttribute("isdisplayed")).to.be.true;
    });
    it('displays correct text for PREVIOUS button', function() {
      expect(PDPScreen.btn_previous.getText()).to.equal("Previous");
    });

    it('displays poster image', function() {
      expect(PDPScreen.poster_image.getAttribute("isdisplayed")).to.be.true;
    });
    it('displays background image', function() {
      expect(PDPScreen.background_image.getAttribute("isdisplayed")).to.be.true;
    });
  });

  context('when clicking on NEXT button and PREVIOUS buttons', () => {
    it('transitions to another PDP', function() {

      let original_title = PDPScreen.title_text.getText();
      expect(original_title).to.equal(pdp_title_1);

      PDPScreen.yi_click(PDPScreen.btn_next);

      // Wait until the screen transitions.
      browser.waitUntil(function () {
        return PDPScreen.title_text.getText() !== original_title
      }, 5000, 'expected text to be different after 5s');

      expect(PDPScreen.title_text.getText()).to.equal(pdp_title_2);

      // Take a screenshot
      PDPScreen.saveScreenshot('./screenshots/', 'pdp2.png');
    });
    it('transitions back to the original PDP', function() {
      PDPScreen.yi_click(PDPScreen.btn_previous);

      // Wait until the screen transitions.
      browser.waitUntil(function () {
        return PDPScreen.title_text.getText() !== original_title
      }, 5000, 'expected text to be different after 5s');

      expect(PDPScreen.title_text.getText()).to.equal(pdp_title_1);

      // Take a screenshot
      PDPScreen.saveScreenshot('./screenshots/', 'pdp1.png');
    });
  });
});

Running these tests for our movies app now yields the following:

[dummy yimac undefined #0-0] PDP Tests
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]   when in PDP
[dummy yimac undefined #0-0]       ✓ displays title
[dummy yimac undefined #0-0]       ✓ displays correct text for title
[dummy yimac undefined #0-0]       ✓ displays details
[dummy yimac undefined #0-0]       ✓ displays correct text for details
[dummy yimac undefined #0-0]       ✓ displays body
[dummy yimac undefined #0-0]       ✓ displays correct text for body
[dummy yimac undefined #0-0]       ✓ displays NEXT button
[dummy yimac undefined #0-0]       ✓ displays correct text for NEXT button
[dummy yimac undefined #0-0]       ✓ displays PREVIOUS button
[dummy yimac undefined #0-0]       ✓ displays correct text for PREVIOUS button
[dummy yimac undefined #0-0]       ✓ displays poster image
[dummy yimac undefined #0-0]       ✓ displays background image
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]     when clicking on NEXT button and PREVIOUS buttons
[dummy yimac undefined #0-0]       ✓ transitions to another PDP
[dummy yimac undefined #0-0]       ✓ transitions back to the original PDP
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0]
[dummy yimac undefined #0-0] 14 passing (19s)

All tests have passed.