How To Write Automated Tests For Your Ionic App - Part 3

If you've followed along with the previous post, you know how to write unit tests with Jasmine and run them with Karma. In order to write and run end-to-end tests, you will need to use Protractor instead of Karma. Protractor enables you to write tests that interact with your app through the UI.

The app we're testing is from my Build Your First Mobile App With The Ionic Framework tutorial, the same one we used for writing the unit tests.

This tutorial is split up in 3 parts:
Part 1 - Introduction to Automated Testing & Frameworks
Part 2 - Unit Tests With Jasmine & Karma
Part 3 - End-To-End Tests With Jasmine & Protractor (this post)


We'll start by installing Protractor and Webdriver/Selenium (these are being used by Protractor).

$ npm install -g protractor
$ webdriver-manager update


Go to the root of your Ionic project and create a folder to contain the end-to-end test files:

$ mkdir -p tests/e2e-tests
$ cd tests

Next, create a configuration file for Protractor in the tests folder, we'll call it e2e-tests.conf.js and copy in the following code:

exports.config = {  
        capabilities: {
            'browserName': 'chrome',
            'chromeOptions': {                
                args: ['--disable-web-security']
        baseUrl: 'http://localhost:8100',
        specs: [
        jasmineNodeOpts: {
            isVerbose: true,

The configuration is pretty straightforward, for this specific app we need to use Chrome with the --disable-web-security setting, otherwise we won't be able to do HTTP requests to the server.

We also define a baseUrl for our Ionic app, which will be used in the tests when we need to instruct the browser to navigate to views.

In specs we define where to find our tests and I also enabled verbose logging so you can see which tests were executed.

If you want to know more about the configuration settings, have a look at the Reference Configuration File.

Writing The Tests

Now we are going to write our tests. These are not that much different from the unit tests we wrote before, since we are using Jasmine for the end-to-end tests as well, but this is where the magic of Protractor will come in, so let's start!

Create a file inside the e2e-tests directory and call it login.tests.js. Copy the code below into this test file. I've left a few pieces of code out, we'll have a look at these later.

describe('Clicking on the login button ', function(){  
    var username, password, loginButton;

    beforeEach(function() {
        username = element(by.model('vm.username'));
        password = element(by.model('vm.password'));
        loginButton = element(by.linkText('Log in'));

    it('should validate the credentials for a successful login and display the My Dinners view', function() {
        // TODO: test successful login

    it('should display a popup for an unsuccessful login', function() {
        // TODO: test unsuccessful login

As you can see, we are going to test clicking on the login button.

In the beforeEach function we instruct the browser to load the login view, this automatically uses the baseUrl we set in the configuration file. The element and by.* functions are part of Protractor and make it super easy for you to find elements on the view.

Learn more about element locators here. You can also use Elementor to help you with writing the code to find elements. Watch this video on how to use it.

Now let's write the code for a successful login, we'll fill in the username and password, click the login button and expect the my-dinners view to display.

it('should validate the credentials for a successful login and display the My Dinners view', function() {  
    password.sendKeys('password'); {

        var dinners = element.all(by.repeater('dinner in vm.dinners'));

On an unsuccessful login we want to test that the user is still on the login view and that a popup is displayed.

it('should display a popup for an unsuccessful login', function() {  
    password.sendKeys('idontknow'); {

        var popup = element(by.css(''));

As you can see, we don't need to write any code to wait for the browser to load the view before we can "talk" to the elements on it. That's all done by Protractor, so you can focus on writing your tests.

We are ready to run our tests now, let's go to the root of our Ionic app and fire it up:

$ ionic serve --nobrowser

And instruct Protractor to run the tests:

$ protractor e2e-tests.conf.js

You should see Chrome start up, load the login view and fill in the details for the tests. It's like magic! ;)

The output should look something like this:

Clicking on the login button  
  should validate the credentials for a successful login and display the My Dinners view - pass
  should display a popup for an unsuccessful login - pass

Finished in 3.304 seconds  
2 tests, 4 assertions, 0 failures  

And that means our tests have passed!

Now, these are very simple tests that don't use any Cordova plugins. If you need to test with plugins on the desktop browser, have a look at using the Ripple emulator.

Or even better, run your tests on a device with Appium.

Final Thoughts

It's up to you to decide how many end-to-end tests you should have. The more your tests depend on actual data, the more maintenance that means and that can eventually end in failing tests that never get updated.

My suggestion is to focus more on unit testing your code and write a small number of end-to-end tests to verify the UI and integration with the services your app uses.

Useful Resources

End2end Testing Ionic collection-repeat with Protractor
Official Ionic Framework Tutorial: Protractor e2e Testing
End-to-end testing an Ionic application with Appium and Protractor