Tutorial hero
Lesson icon

E2E (End-to-End) Testing in Ionic: An Introduction

Originally published March 02, 2017 Time 10 mins

Over the past few weeks, I have been releasing a series of tutorials about creating automated tests for Ionic (Angular) applications. The tutorials so far have focused on how to apply the Test Driven Development (TDD) methodology to unit test an Ionic application.

If the concept of automated tests is new to you, or if you don’t understand why you would want to create automated tests for an application, I would recommend reading through my Test Driven Development series of tutorials.

In this tutorial, we will be covering another type of automated test called End-to-End Testing, or E2E for short, and how to apply that to an Ionic/Angular application. We will just be focusing on the bare bones set up, for now, to get a simple E2E test running, I will cover strategies for creating effective E2E tests in future tutorials (like how to incorporate E2E tests into a TDD approach alongside your unit tests).

This tutorial has been updated since it was originally published, and fortunately now unit and end-to-end tests are included in Ionic projects by default, so it is significantly easier to get started now.

Before We Get Started

Before you go through this tutorial, you should have at least a basic understanding of general Ionic and Angular concepts. You must also already have an appropriate development environment for these frameworks set up on your machine.

You will also need to have a basic understanding of Jasmine and creating unit tests, as I will not be covering the theory behind creating tests with Jasmine in this tutorial. If these concepts are new to you, you should read An Introduction to TDD first.

If you’re not familiar with Ionic/Angular already, I’d recommend reading my beginner Ionic tutorials first to get up and running and understand the basic concepts. If you want a much more detailed guide for learning Ionic/Angular, then take a look at Building Mobile Apps with Ionic & Angular.

What is an E2E Test?

So far, we have covered unit tests which test isolated units or chunks of your code. You might create unit tests for a single class in isolation to make sure its methods do what they are supposed to do. You don’t worry about any dependencies that class might have or anything it interacts with, all we are interested in is if that one unit is doing what it is supposed to do. A single unit test might test something as small and simple as whether a particular method makes a call to some other method when it runs.

To create unit tests in Ionic we generally use two tools: Jasmine to create the tests, and Karma to automatically run the tests through a browser.

An E2E test, on the other hand, allows us to test interactions between various components in our application. Basically, it allows us to test the application in a way that the user would actually use it. We can essentially simulate a user’s behaviour in our application (like a bot), and test for what is happening in the application. An E2E test might look something like this, for example:

  1. Go to the index page
  2. Click on the menu icon
  3. Click on the ‘Products’ page
  4. Expect the ‘Featured’ product category to be displayed

To create E2E tests we will be using a tool called Protractor which will allow us to simulate user behaviour in this way, and it will run our tests for us automatically through a browser (you can actually see the actions being performed in real time, which is pretty cool) by using a Selenium server. We still use Jasmine with Protractor in order to define our E2E tests.

1. Generate a new Ionic/Angular Application

We’re going to start off by generating a new Ionic application. Instead of using the blank template, which we would typically use, we are going to use the default tabs template so that we have something a little more interesting to test with Protractor.

Run the following command to generate a new Ionic 2 application:

ionic start ionic-e2e-example tabs --type=angular

Once generated, make it your working directory by running the following command:

cd ionic-e2e-example

2. Setting up E2E Tests

This section used to be a lot longer, but fortunately now E2E tests are set up by default for us in new Ionic/Angular applications. All you need to do to run the E2E tests is run the following command:

npm run e2e

If you’re paying attention you might see the browser window pop up briefly to execute your tests. The default Ionic/Angular applications already have some tests included, so you should see a message like this indicating the successful execution of the default E2E test:

  new App
    should display welcome message

Executed 1 of 1 spec SUCCESS in 2 secs.

NOTE: You may get a warning about not having the correct version of Chrome, e.g:

E/launcher - session not created: This version of ChromeDriver only supports Chrome version 77

Make sure that you upgrade your Chrome browser to solve this issue.

3. Understanding an E2E Test

In a moment we will try to implement our own E2E test, but first, let’s take a look at the existing E2E test that we just executed. You can find this test at e2e/src/app.e2e-spec.ts:

import { AppPage } from './app.po';

describe('new App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();
  });

  it('should display welcome message', () => {
    page.navigateTo();
    expect(page.getPageTitle()).toContain('Tab One');
  });
});

This test also imports an AppPage “page object”. We are going to cover this concept in future tutorials, but the basic idea is that a “page object” will provide us with some helper functions related to a specific page that we are running tests on (in this case, the logic for grabbing the page title is in the page object file, which makes the test in this file a bit cleaner and we can also share that logic in other tests).

This E2E test is quite similar to a normal unit test that we create with Jasmine, except for a few key differences. One thing you might notice if you are already familiar with creating unit tests in Angular, is that we aren’t using TestBed and we don’t have to import or set up any components in the test. We are just using the application, so we point the browser to the root of the application and start interacting with it. It is the page object that handles navigating to the correct place in the browser with the navigateTo method:

import { browser, by, element } from 'protractor';

export class AppPage {
  navigateTo() {
    return browser.get('/');
  }

  getPageTitle() {
    return element(by.css('ion-title')).getText();
  }
}

You can see that we use browser.get('/') to navigate the browser to the root of the application (e.g. the / route).

It also uses a few imports from the protractor library. The browser will allow us to control the browser like by directing it to certain URLs, or asking it to wait a certain amount of time before continuing the test. The element and by imports allow us to find elements on the page and interact with them (e.g. get the text content of the element that matches the CSS selector ion-title).

4. Creating an E2E Test

Now we are going to create our own simple E2E test and execute it. We are not going to worry too much about best practices or good testing methods here, we just want to get a simple test running. Future tutorials will cover various testing strategies and best practices in more depth.

NOTE: If you want an in-depth introduction to Unit and E2E testing for Ionic and Angular, you might be interested in checking out my advanced course: Elite Ionic (Angular).

Create a file at e2e/src/tabs.e2e-spec.ts and add the following:

import { browser, element, by } from 'protractor';

describe('tabs', () => {
  beforeEach(() => {
    browser.get('/');
  });

  it('the Tab One tab is displayed by default', () => {
    expect(element(by.css('.tab-selected ion-label')).getText()).toContain(
      'Tab One'
    );
  });

  it('the user can navigate to the Tab Two tab', async () => {
    await element(by.css('[tab=tab2]')).click();

    browser.driver.sleep(500);
    expect(element(by.css('.tab-selected ion-label')).getText()).toContain(
      'Tab Two'
    );
  });
});

In the test above, we have created two tests, and before each of the tests we redirect the browser back to the initial page with browser.get('/').

The first test checks that the Tab One tab is displayed by default. To do that it first uses a CSS attribute to grab the appropriate element, which is the tab button for the currently selected tab. You can use any normal CSS selector with by.css, and since the currently selected tab in an Ionic/Angular application will have the .tab-selected class we use that to grab the currently selected tab. We then check the getText to see if it is indeed the Tab One tab (in which case, it would contain the text Tab One).

The next test is similar, except this time we grab a different tab and trigger a click on it to test that the user can browse to that tab. We tell the browser to wait for 500ms whilst the page transition occurs (which is likely longer than needed), and then we check that the <ion-label> element of the selected tab contains Tab Two. There are better ways to “wait” for things to happen rather than setting a manual “sleep” time for the browser, but we will be getting into that in future tutorials.

We are also using an async test function here, and we use await to wait for the click Promise to resolve. If you aren’t familiar with async/await you can check out this video: Async / Await Basics in JavaScript Explained. If you prefer, you can also just use the standard then() promise syntax.

If we run these tests with npm run e2e now, we should see the following result:

  new App
    ✓ should display welcome message

  tabs
    ✓ the Tab One tab is displayed by default
    ✓ the user can navigate to the Tab Two tab

Executed 3 of 3 specs SUCCESS in 3 secs.

Our default test is still passing, but now our two additional tests inside of the tabs test suite are also passing.

Summary

This is a reasonably basic introduction to Protractor and E2E tests in general, but hopefully, it helps explain some of the key concepts. I will be covering End-to-End testing more in future tutorials, including how to better structure your E2E tests and how you can incorporate E2E tests into a Test Driven Development approach.

Learn to build modern Angular apps with my course