ProtractorJs is an end-to-end framework written for AngularJS applications. It uses Selenium WebDriver features internally. The main advantage of the regular WebDriver test is an ability to cooperate well with SPA application. The main problem with this type of systems is asynchronization. Single Page Applications change their look without reloading the whole page. So it is very hard to determine when the application is ready for action. Fortunately, Protractor knows the Angular internal mechanisms, so he is aware when application finish all operations.

The biggest problem with this framework is writing them in JavaScript. It is very powerful language, but not efficient enough for writing fast and without errors. Moreover, because it is not typed language and we don’t rely on IntelliSense in the editor, starting to work in the new library is hard. The best solution for this would be TypeScript. It is actively developed superset of JavaScript that gives us a power of static typing and hints in code. That’s why I decided to combine each other.

In this example, we will use a combination of TypeScript, Gulp and Jasmine to run Protractor tests.

Installing dependencies

Before start ensure that we have NodeJs installed. Then we can configure our build system. We will use gulp to do this. If we already have an existing project, we will need to modify our package.json and gulpfile.js files.

However, let’s start with an empty project.

At first create package.json file using

npm init

Ensure that you install following packages globally:

npm install -g gulp typings typescript

Then we can install all dependencies used in this tutorial.

npm install browser-sync gulp gulp-protractor gulp-typescript typescript --save-dev

To use TypeScript features correctly, we will also need definitions for our library

typings install dt~angular-protractor --global --save

Additionally, we would need to add one extra typing. Most of the basic TypeScript definitions will be loaded automatically from npm packages, but this one is an exception because we want to choose the specific version.

Our package.json the file should contains following dependencies.

"devDependencies": { "@types/selenium-webdriver": "^2.44.29", "browser-sync": "^2.17.3", "gulp": "^3.9.1", "gulp-protractor": "^3.0.0", "gulp-typescript": "^3.0.2", "typescript": "^2.0.3" }

Simple test

Out development environment is configured now. We can create a simple end-to-end test. It is a sample test from Protractor website.

e2e/test.ts file

describe('angularjs homepage todo list', function() { it('should add a todo', function() { browser.get('https://angularjs.org'); element(by.model('todoList.todoText')).sendKeys('write first protractor test'); element(by.css('[value="add"]')).click(); var todoList = element.all(by.repeater('todo in todoList.todos')); expect(todoList.count()).toEqual(3); expect(todoList.get(2).getText()).toEqual('write first protractor test'); // You wrote your first test, cross it off the list todoList.get(2).element(by.css('input')).click(); var completedAmount = element.all(by.css('.done-true')); expect(completedAmount.count()).toEqual(2); }); });

As you can see, it enters the AngularJs website and tries to add a task to the sample page. It is a perfect example for our configuration case.

To execute this test, we will need to configure a method how Protractor should search for them.

protractor.conf.js file

'use strict'; exports.config = { // Capabilities to be passed to the WebDriver instance. capabilities: { 'browserName': 'chrome' }, baseUrl: 'http://localhost:3000', specs: ['tmp/e2e/**/*.js'], jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 10000 } };

With these two files, we can try to run Protractor manually. However, it will not be a success, because we don’t have JavaScript files in a proper place yet.

Configure build system

As the last step, we will need to setup a Gulp task. We will define it in a separate file and include into the main gulpfile.js file.

This task compile TypeScript tests put them in specified directory and execute Protractor tests using given configuration file. It sounds quite easy. Below I show you complete code of this solution.

e2e.js file

'use strict'; var path = require('path'); var gulp = require('gulp'); var conf = require('./conf'); //var browserSync = require('browser-sync'); var protractor = require('gulp-protractor'); var ts = require('gulp-typescript'); // Downloads the selenium webdriver gulp.task('webdriver-update', protractor.webdriver_update); var tsProject = ts.createProject('./tsconfig.json'); gulp.task('webdriver-standalone', protractor.webdriver_standalone); function runProtractor(done) { var params = process.argv; var args = params.length > 3 ? [params[3], params[4]] : []; gulp.src([conf.paths.typings, path.join(conf.paths.e2e, '/**/*.ts')]) .pipe(ts({ out: 'output.js' })) //protractor needs files on disk, cannot get them from stream .pipe(gulp.dest(conf.paths.e2eOutput)) .pipe(protractor.protractor({ configFile: 'protractor.conf.js', args: args })) .on('error', function (err) { // Make sure failed tests cause gulp to exit non-zero throw err; }) .on('end', function () { // Close browser sync server //browserSync.exit(); done(); }); } gulp.task('e2e', ['protractor:src']); gulp.task('protractor:src', ['webdriver-update'], runProtractor);

You can add it to the main gulp configuration file using one line.

gulpfile.js file

... require('./gulp_tasks/e2e.js'); ...

After all these configurations we are ready to execute our test. We should execute above task to see how tests click on the page.

gulp protractor

That’s it. This configuration is very easy, but you can find it hard to manage type definitions for these libraries. I attach some additional resources to help you with it.

Source code for this post:

https://github.com/suvroc/protractor-typescript-template

Other resources:

https://github.com/angular/protractor-cookbook/tree/master/protractor-typescript

https://github.com/skovmand/angular-protractor-typescript

You can find more information about end-to-end testing in my book and newsletter

[chimpmate]