Lesson 13

Building out Core Functionality

WARNING: This module is deprecated and no longer receives updates. Protractor is likely being removed as the default from Angular applications and Protractor itself will likely stop receiving updates and development in the future. I would recommend checking out the Test Driven Development with Cypress/Jest as a replacement.

Adding more tests to cover our core requirements


Lesson Outline

Building out Core Functionality

So far, we've successfully implemented two of our original six requirements, and we are now up to the last requirement that we considered to be part of the "core functionality":

  • After selecting a specific lesson, the user should be able to see content for that lesson

In order to implement the E2E test for this, we will be creating a new E2E spec file. It doesn't particularly matter where you put your E2E tests, technically speaking they could all be in one giant spec file. However, if a test starts on a particular page then we should create a new spec file for that page. There are a couple of benefits to doing this:

  • It keeps your tests more organised
  • It allows you to more easily arrange your tests with the beforeEach function if all of the tests start from the same page

We will also be creating another page object since there will be a third page (the Lesson page) thrown into the mix now.

Create a New E2E Spec File

Let's start by creating a new E2E spec file for our LessonSelect page. Before we start working on the requirement that we will be focusing on this lesson, we are going to add in another E2E test related to the work we did in the last lesson. You may remember that for our Home page we added an additional E2E test to make sure that there was content in the list of modules (i.e. that it wasn't just a list of blank items, which would technically pass the original E2E test). We are going to do the same now for the LessonSelect page, and check that the list of lessons also contains some kind of text content.

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

import { LessonSelectPageObject } from './lesson-select.po';

describe('Lesson Select', () => {
  let lessonSelectPage: LessonSelectPageObject;

  beforeEach(async () => {
    lessonSelectPage = new LessonSelectPageObject();
    await lessonSelectPage.navigateTo();

  it('the list of lessons should contain the titles of the lessons', async () => {
      await lessonSelectPage.getLessonListItems().first().getText()
    ).toContain('lesson 1');

After running the E2E tests, we will get the following error:

*                    Failures                    *

1) Lesson Select the list of lessons should contain the titles of the lessons
  - Failed: Index out of bound. Trying to access element at index: 0, but there are only 0 elements that match locator By(css selector, .lesson-list ion-item)

The test failed, as we might have expected, but probably not for the reason you expected. We knew the list contained blank items, but this error is telling us that it couldn't find the list at all.

This is because our navigateTo() function for the the lesson select page object is not set up correctly. Currently, it is just pointing to the root URL, but that means the test would be starting on the Home page.

There are two ways we could approach implementing the navigateTo method. Since we are using Angular routing and we know that our routes expect an id, we could just navigate directly to the /module/1 URL or the /module/2 URL. Alternatively, you could take a more behaviour driven approach and instead simulate the steps required to actually get the application to the lesson select page (e.g. load the home page and trigger a click on a lesson). I don't think there is necessarily a "right" way here, just go with whatever makes more sense for your tests.

We're going to modify our navigateTo function for the lesson select page object to navigate to the page just like a user would through the application.

Modify e2e/src/lesson-select.po.ts to reflect the following:

import { browser, by, element, ElementFinder } from 'protractor';
import { HomePageObject } from './home.po';

export class LessonSelectPageObject {
  homePage = new HomePageObject();

  async navigateTo() {
    await this.homePage.navigateTo();
    return this.homePage.getModuleListItems().first().click();

  getLessonListItems() {
    return element.all(by.css('.lesson-list ion-item'));

We are now importing the Home page object and using that to browse to the home page first, and then we click on the first module in the list to navigate to the lesson select page.

If we run the E2E tests again now, it still fails, but we get a different error:

1) Lesson Select the list of lessons should contain the titles of the lessons
  - Expected '' to contain 'lesson 1'.

Let's fix this test by adding in the title to the template now.

Modify the list in src/app/lesson-select/lesson-select.page.html to reflect the following:


  <ion-list class="lesson-list">
    <ion-item button *ngFor="let lesson of module.lessons">

Now if we run the E2E tests:

1) Lesson Select the list of lessons should contain the titles of the lessons
  - Expected 'test' to contain 'lesson 1'.

We still get an error because, unlike with our unit tests, the data is being supplied by the real module service which looks like this:

  getModuleById(id: number) {
    return {
      id: 0,
      title: '',
      description: '',
      lessons: [{ title: 'test' }],

Let's modify that to include the type of lesson data we would expect.

Modify the getModuleById method in src/app/services/modules.service.ts to reflect the following:

  getModuleById(id: number) {
    return {
      id: 0,
      title: '',
      description: '',
      lessons: [
        { title: 'lesson 1' },
        { title: 'lesson 2' },
        { title: 'lesson 3' },
        { title: 'lesson 4' },

If we run the E2E tests once more:


Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).