Simplify your Protractor tests using Generator functions

by Auke — 3 minutes

Writing protractor tests can be quite difficult, because of all the asynchronous calls you have to deal with. Even promise-chaining does not help when your tests become longer and more complex. With Javascript generator functions it is possible to simplify your tests.

Example

Let’s say we have a todo-app created in AngularJS with two pages: a page with a list of todos and a page where a user can create a todo-item. We have two page objects created that can communicate with the pages in our Protractor tests. This is an example of an actual testcase with the use of promise chaining:

todo.spec.js - with promises.

describe("todo test", function () {
  const todoListPage = require("../page-objects/todo-list.page.po");
  const todoCreatePage = require("../page-objects/todo-create.page.po");

  beforeEach(() => {
    browser.get("/");
  });

  it("should create a todo item", () => {
    //Check that number of items is 0 to begin with.
    todoListPage
      .open()
      .then(() => todoListPage.getNumberOfItems())
      .then((nrOfItems) => {
        expect(nrOfItems).toBe(0);
      })
      .then(() => todoCreatePage.open())
      .then(() => todoCreatePage.createTodoItem("test"))
      .then(() => todoListPage.open())
      .then(() => todoListPage.getNumberOfItems())
      .then((nrOfItems) => {
        //number of todos should now be 1
        expect(nrOfItems).toBe(1);
      });
  });
});

todo.spec.js - with generators.

describe("todo test", function () {
  const todoListPage = require("../page-objects/todo-list.page.po");
  const todoCreatePage = require("../page-objects/todo-create.page.po");

  beforeEach(() => {
    browser.get("/");
  });

  it("should create a todo item", function* () {
    //Check that number of items is 0 to begin with.
    yield todoListPage.open();
    expect(yield todoListPage.getNumberOfItems()).toBe(0);

    //Add
    yield todoCreatePage.open();
    yield todoCreatePage.createTodoItem("test");
    yield todoListPage.open();

    //number of todos should now be 1
    expect(yield todoListPage.getNumberOfItems()).toBe(1);
  });
});

As you can see, the testcode is much easier to understand when the generator method is used.

How does it work?

The generator method which is defined with the function*(){} syntax can be used together with the jasmine-co library. jasmine-co wraps all methods and waits for each yield statement to be resolved before continuing to the next yield statement, even if this yield statement is resolved asynchronously.

Setup

Install jasmine-co dependency.

npm install jasmine-co --save-dev --save-exact

Install jasmine-co in the protractor.conf.js file.

Example protractor.conf.js.

```javascript exports.config = { seleniumAddress: "http://localhost:4444/wd/hub",

getPageTimeout: 60000, allScriptsTimeout: 500000, baseUrl: "http://localhost:3000",

capabilities: { browserName: "chrome", chromeOptions: { args: ["--disable-extensions", "--start-maximized"], }, },

specs: ["test/component-tests//.spec.js"], framework: "jasmine", jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 3000000, },

onPrepare: function () { //This will wrap every test with jasmineCo(); Just like in the docs: https://www.npmjs.com/package/jasmine-co require("jasmine-co").install();

//Define a shortcut for protractor.ExpectedConditions
global.EC = protractor.ExpectedConditions;

}, }; ```

Start rewriting your tests incremently.

Important: It is not necessary to rewrite all your tests to generators, so you can try it out on one test first.

Source code

Look at the complete source code https://github.com/baconcutter/protractor-generator-example.

meerdivotion

Cases

Blogs

Event