So, you have an existing Ionic project and now you want to start unit testing and end-to-end testing it. A great way to configure your existing project for testing is use the ionic-unit-testing-example project on Github. This post will provide you with step-by-step instructions on how to add modules and files from that project into your own project so you may begin testing your project.

While the name of the project is ionic-unit-testing-example, the project actually sets up two kinds of testing: unit testing and end-to-end (E2E) testing. For the purposes of this tutorial, unit testing is isolating components for testing, and end-to-end testing automates the browser and simulates user interactivity to allow the testing of how the whole application works.

Testing and Test Driven Development can be controversial topics in some circles. How you go about testing is up to you and your team. Personally, I believe that you should have both unit tests for your components and E2E tests for your application. How you get there is up to you.

Trigger Warning: Unit testing and end-to-end testing can be challenging and frustrating even for experienced developers. Getting tests to pass can take patience and experience. You should learn as much as possible about testing before beginning your testing practice. Take your time, ask questions of your peers, seek assistance online, and above all, don’t let a continuosly failing test get the better of you. You will overcome it.

This tutorial was assembled with the following software installed (this information gathered by using the ionic info command):

$ ionic info

cli packages: (/Users/leifwells/.nvm/versions/node/v6.11.2/lib/node_modules)

    @ionic/cli-utils  : 1.9.2
    ionic (Ionic CLI) : 3.9.2

local packages:

    @ionic/app-scripts : 2.1.3
    Ionic Framework    : ionic-angular 3.6.0

System:

    Node : v6.11.2
    npm  : 3.10.10 
    OS   : macOS Sierra

Step 1: Create a Project to Test (Optional)

Since we do not know anything about your project, so we will be using an Ionic starter project as our starting point. To create it, open up your terminal application, navigate to the folder where you would like to add a new project, and run the following command:

ionic start starter-with-testing sidemenu

This command will create a directory named starter-with-testing and install the code for an Ionic application using the side menu template.

Please Note: This step is not necessary if you are adding content to your own project. Since we can’t see your project, we needed a point of reference to get these instructions started.

Now, navigate your terminal window to the installed folder and run the following command:

cd starter-with-testing
ionic serve

Once you have the application running, you have completed this step.

Step 2: Get the Example Code

Head over to ionic-unit-testing-example and download the code. You don’t need to load or run the project. We’ll be moving files and code from that project into our project code.

You can use the green “Clone or download” to download a .zip file of the project. Click the button to reveal the “Clone with SSH” popover and click on the “Download ZIP” button to begin the process.

Figure 1: The Clone or download popover.


Once the file is downloaded, decompress it and open the containing folder so that it is available when we need it.

Step 3: Install Required Node Modules

There are a handfull of Node modules required for testing to work with and Ionic application and need to be added to our project. While you can install each of these modules separately, we’ve organized the install process into one handy command:

npm install --save-dev angular2-template-loader html-loader jasmine jasmine-spec-reporter karma karma-chrome-launcher karma-jasmine karma-jasmine-html-reporter karma-sourcemap-loader karma-webpack karma-coverage-istanbul-reporter istanbul-instrumenter-loader null-loader protractor ts-loader ts-node @types/jasmine @types/node

This command adds these modules to the "devDependencies" node of your project’s package.json file. There are quite a few modules here, but the important modules are karma, jasmine and protractor. karma is the Karma module which is our testing environment for unit testing. jasmine is the Jasmine module which is the unit testing framework. protractor is the Protractor module which is our testing environment for our end-to-end tests. The rest of the modules are utilities that allow this configuration to work.

Step 4: Add Scripts to the package.json

There are a couple of scripts that need to be added to the package.json to make running tests from the command-line possible. Open the package.json file and add the following scripts to your "scripts" node:

"test": "karma start ./test-config/karma.conf.js",
"test-ci": "karma start ./test-config/karma.conf.js --single-run",
"test-coverage": "karma start ./test-config/karma.conf.js --coverage",
"e2e": "npm run e2e-update && npm run e2e-test",
"e2e-test": "protractor ./test-config/protractor.conf.js",
"e2e-update": "webdriver-manager update --standalone false --gecko false"

Important: Make sure you add a trailing comma on the line above this code or your package.json will stop working. Your code editor should inform you of the missing comma.

With the addition of these items, you will be able to enter the npm run test command to begin unit testing, or npm run e2e to begin end-to-end testing.

Step 5: Add the Configuration Files

The control center for this testing configuration are a set of files that are inside the ionic-unit-testing-example project which need to be added to our project. Open the folder where ionic-unit-testing-example was decompressed earlier and locate the test-config folder. Copy and paste that folder into the root of our project. Open the folder in your code editor and take a look. You should see five files:

karma-test-shim.js
karma-config.js
mocks-ionic.js
protractor.conf.js
webpack.test.js

The karma-config.js file is the configuration file for Karma. It uses karma-test-shim.js to link more modules required for testing and webpack.test.js to configure and compile our code for testing.

The protractor.conf.js file is the configuration file for Protractor.

The mocks-ionic.js file is a collection of classes that are used to as a substitute for classes in the ionic-angular module for testing. We will discuss mocking further later in this tutorial.

Step 6: Adding End-to-end Testing

Now that our unit testing configuration is set up, we need to add one more folder to our project so we can implement the end-to-end testing solution. Copy the e2e folder found inside the location where you decompressed .zip file from the ionic-unit-testing-example and paste that folder into the root of your project. This folder has the following files:

app.e2e-spec.ts
app.po.ts
tsconfig.json

The tsconfig.json file is an important configuration file which assists with compiling the project and tests for end-to-end testing. The file is placed here because it isolates it from the project’s tsconfig.json file.

The app.e2e-spec.ts file is an actual E2E test file. Note the name of the test as our configuration file is looking for files that have the .e2e-spec.ts as part of the name to identify it as an E2E test and not an unit test. The app.po.ts is an example of a page object, a helper file that assists in providing utility methods for locating elements and processing expected results. You can find out more about page objects on the Protractor Website.

If you are following along with this tutorial, when you run the npm run e2e command in your terminal window, this test should work. If you run this test with your project, it will probably fail. You will need to update the test to make it work for you.

Important: When you run E2E tests, make sure you are running ionic serve in another terminal window. The E2E configuration expects to have a connection to the server and if it is not it will fail with an error.

Adding Your First Unit Test

Before you can begin testing, you need to have a test file. To make sure the testing configuration is working, we’ll add a file to our project to test that the application loads.

Open the src/app/ folder in your project and create a new file named app.component.spec.ts. This will be our unit test file for the MyApp class which is inside the app.component file. Inside this new file, copy and paste the following code:

This is not a tutorial on how to create tests, but let’s take a brief look at this test code.

Angular Testing Utilities

As you can see, the test file has the typical methods for unit testing: describe, beforeEach, and it. Inside the first beforeEach is a call to the TestBed object’s configureTestingModule() method. TestBed is a module provided by the Angular team to facilitate testing. To find out more about testing in Angular, please read the Angular Testing Guide. Seriously, read that documentation a few times and let it sink in.

Now, take a look at places where MyApp is listed. MyApp is the component being tested here, and appears in the class import, inside the TestBed.configureTestingModule() method inside the declarations array, inside the imports array, and also in the second beforeEach method when the component is actually created. This is how each of your test files will work.

The first test, the code inside the first it instance, checks to see if the MyApp component is created. The second test checks that the pages array created in the MyApp class has two items.

Mocking Ionic Classes

Another note of interest: mocking Ionic classes. With unit testing, developers should try to isolate the component to be tested. If you include the actual classes, technically you would be testing the Ionic framework, which is unnecessary.

To understand how mocking works, look at the structure of items inside the providers array. Typically,providers are listed simply by adding the class name to the array. In this case, we are mocking the classes using the provide property to identify the name of the class to be mocked, and the useClass property to identify the class to serve as the mock. We are using the mocks provided by the ionic-unit-testing-example project found in the test-config/mocks-ionic.ts file mentioned earlier.

If you choose to not use mocks for Ionic classes, what may happen is that errors will occur running you down a never-ending rabbit hole. Mocking Ionic classes is the best way to avoid this problem.

What to Expect When Unit Testing

This test is a sample test that will work with the project we are using in this tutorial and may not work for you. If you add this file to your own project and run the npm run test command, what you may expect is an error stating that no provider for or no declaration for, at which point you will import that class into this file, add the class name to the providers array or the declarations array inside the TestBed.configureTestingModule() method argument object.

You will probably need to create mock classes for your own providers. These mocks should accurately reflect the same methods but return expected values, for instance, mock data instead of data from a server.

Reviewing the Angular Testing documentation will help you with testing your Ionic application. There are concepts described there that will assist you with testing processes that are asynchronous, as well as best practices to follow.

Note: Sometimes when working on a unit test, you will not find a way to test a particular scenario. The problem may not be your test. It may be your code. Are the methods in your component too complex? Could you refactor your code to make your component more maintanable as well as more testable? Make sure you are looking at both sides, the test and the code you are testing, to ensure you have a successful testing practice.

Reviewing the E2E Test

Earlier, we added the e2e folder to our project which contained our first E2E test. Let’s take a look at it.

Again, we see the typical testing methods of describe, beforeEach and it. One this of note here is the use of a second describe method. This is used to help with organizing your tests.

Inside your E2E tests, you will be using Promises. A lot. Good tests will chain Promises. You can find out more about how to structure your tests by reviewing the Protractor Tutorial.

Summary

In this tutorial, we created an example Ionic (ionic-angular) project to configure for unit and end-to-end testing. We used the ionic-unit-testing-example project on Github as a guide for installing the necessary node modules and configuration files to the project to get unit testing and E2E testing to work. Then we took a brief look at the test files. Hopefully, this will give you enough information to get you started with testing your own Ionic applications.

Links for this article:

ionic-unit-testing-example
Ionic
Angular
Angular Testing
Karma
Jasmine
Protractor

Updates:

2017-09-06:

Added code coverage feature steps.

2017-09-02:

Replaced two Markdown code blocks with Github Gists.