Skip to content

Angular / End-to-End Testing

In this section you will run simple Protractor tests in TypeScript.

Intro to Protractor:

Protractor is a Node.js program, and helps you write your browser tests. Protractor also send commands to a Selenium Server, which controls the browser via WebDriver commands and JavaScript functions.

Writing your first Protractor Test

This demonstration is a walk through of Jonas Felix's Angular End to End Testing code.

In the first part of this demonstration the following will take place:

  1. Compare Unit testing with E2E testing
  2. Create or use an @angular/cli based project
  3. Adapt the e2e page object to match out app
  4. Write E2E Tests
  5. Run the tests

Additionally, after you have testing your first end 2 end test we will move on to test a more complex example. For the next part of the testing demonstration you will test the tour of heroes application provided by Angular with both unit tests and end to end tests. More on this will be covered in later portions of this documentation.

It is important to note that the completed code for this end to end testing demonstration, along with all testing examples can be found in the owf-learn-angular repository. This specific demonstration is titled simple-e2e-testing-app within that repository.

Unit Testing vs End 2 End Testing

Unit testing

  • Tests a single Component, Service, Pipe ect
  • Tests a single specific behavior in a controlled environment
  • Mock everything you need to test specific functionality
  • Uses code coverage analysis to make sure everything is covered
  • (Usually) Improves code structure and quality
  • Tests edge cases on the most detailed level
  • Know whether a change breaks a specific behaviour
  • Does not test if the whole application or a process works in real life

End 2 End Testing

  • Tests complete processes "End 2 End"
  • Tests in real environments with the whole application
  • Tests real live situations
  • Know if most important features work with the complete application
  • Focused the overall functionality and not the specific code structure
  • Does not test Edge cases
  • Des not necessarily improve code quality

Creating a Mini Example

You will create a new angular project for this testing example named letsLearn-e2e. To create a new angular project navigate to the directory you wish to hold the project and insert the following command into your command prompt:

ng new letsLearn-e2e

For this simple application we want to create a points variable that will increase by one every time the 'Plus 1' button is pressed and we also want the points variable to reset whenever the 'Reset' button is clicked. To create this application replace any code in the app.component.html file with the following code:

<h1>{{title}}</h1>

<div>
    Points: <span>{{points}}</span>
</div>

<button (click)="plus1()">Plus 1</button>
<button (click)="reset()">Reset</button>

Next, replace the code in app.component.ts with the following code:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Letslearn';
  points = 1;

  plus1() {
    this.points++;
  }

  reset() {
    this.points = 0;
  }
}

When you click the plus1 button, the points will be increased, and when you click the reset button the points will be reset to 0.

Prepare End 2 End Page Object to Access the Elements

With @angular/cli, you get an e2e folder and structure that suggests to create a page object which helps you access the elements. The page object for the default page is found in ./e2e/app.po.ts.

Define:

Page Object: A page object is a class with functions that return element like Buttons, Texts, or whatever you need for a test.

The code for your Page Object file should look like the code below:

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

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

  getTitle() {
    return element(by.css('lsl-root h1')).getText();
  }

  getPoints() {
    return element(by.cssContainingText('div', 'Points')).$('span').getText();
  }

  getPlus1Button() {
    return element(by.cssContainingText('button', 'Plus 1'));
  }

  getResetButton() {
    return element(by.cssContainingText('button', 'Reset'));
  }
}

The Page Object files is useful because if you change your site's page structure, you only have to change the Page Object, and your tests can stay the same.

Writing E2E Tests

Test should be written in a way that allows them to be read through as if a story.

Bellow is the test code for file app.e2e-spec.ts:

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

describe('letslearn App', () => {
  let page: LetslearnPage;

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

  it('Should display Letslearn title', () => {
    page.navigateTo();
    expect(page.getTitle()).toEqual('Letslearn');
  });

  it('Should start with 1 point', () => {
    page.navigateTo();
    expect(page.getPoints()).toEqual('1');
  });

  it('Should increase points by clicking plus1', () => {
    page.navigateTo();

    expect(page.getPoints()).toEqual('1');
    page.getPlus1Button().click();

    expect(page.getPoints()).toEqual('2');

    page.getPlus1Button().click();
    page.getPlus1Button().click();
    page.getPlus1Button().click();

    expect(page.getPoints()).toEqual('5');
  });

  it('Should rest points by clicking plus1', () => {
    page.navigateTo();

    page.getPlus1Button().click();
    page.getPlus1Button().click();
    page.getPlus1Button().click();

    expect(page.getPoints()).toEqual('4');

    page.getResetButton().click();

    expect(page.getPoints()).toEqual('0');
  });

});

Running the tests

To run you End-2-End test, type the following command in your terminal from within your site directory:

ng e2e

Final Code

Your final testing code should mirror the code found in the OpenWaterFoundation/owf-learn-angular-test repository under the simpe-e2e-testing-app angular project.