О том как установить и запустить Protractor уже было в этом посте – Тестируем AngularJS используя Protractor. А сейчас мы сделаем фокус на том, как мы можем интегрировать Protractor в нашу систему и подкючить к Grunt.
Подключаем Protractor к Grunt
Для подключение нам необходимо поставить специальный таск-плагин grunt-protractor-runner к grunt путем выполнения следующей команды:
$ npm install grunt-protractor-runner
После чего можем дополнить наш конфигурационный файл секцией для него:
protractor: { options: { configFile: "protractor.conf.js" }, all: {} }
protractor.conf.js – конфигурационный файл, который уже у нас есть (создание подробно описано в предыдущем посте)
all: {} – grunt требует как минимум один “target”, поэтому, если все параметры уже указаны в конфиге протрактора, то можем просто добавить пустую сецию.
Проверим что мы все правильно настроили и команда выполняется без ошибок:
$ grunt protractor:all
PhantomJS и Protractor
В случае, когда мы хотим запускать наши тесты не только локально, но и на сервере, где нет возможности использовать браузер на помощь спешит PhantomJS. Ознакомиться с PhantomJS вы можете в посте – Создаем юнит-тесты с phantomjs, а сейчас мы поговорим о том как его встроить в Protractor.
Теперь вместо вебдрайвера мы должны запустить фантом-сервер:
$ phantomjs --webdriver=4444
а наша секция grunt конфига преобразиться следующим образом:
protractor: { options: { configFile: "protractor.conf.js" }, all: { options: { args:{ seleniumAddress: 'http://localhost:4444', capabilities: { browserName: 'phantomjs' } } } } }
иногда бывает необходимо специфицировать конкретную версию/путь к phantomjs, тогда добавляем еще одну опцию – phantomjs.binary.path, а аргументы к фантому можем передавать через опцию phantomjs.cli.args; итого получим:
protractor: { options: { configFile: "protractor.conf.js" }, all: { options: { args:{ seleniumAddress: 'http://localhost:4444', capabilities: { browserName: 'phantomjs', 'phantomjs.binary.path':'./node_modules/.bin/phantomjs', 'phantomjs.cli.args': ['--ignore-ssl-errors=true', '--web-security=false'] } } } } }
Если мы хотим, чтобы вебдрайвер запустил фантом за нас, то просто не указываем параметр seleniumAddress.
Отладка тест-сценариев в WebStorm
Пару слов о том как можно дебажить тесты в WebStorm. Что для этого нужно сделать:
Открываем настройки Run/Debug:
Добравляем новую конфигурацию для Node.js:
Прописываем следующие ключевые настройки:
- Working directory: корневой путь вашего проекта (например: ‘/Users/stevermeister/workspace/academy-js’)
- JavaScript file: путь к cli.js файлу протрактора (как правило это node_modules\protractor\lib\cli.js)
- Application parameters: путь к файлу конфиг файлу протрактора(например: protractor.conf.js)

Сохраняем. Готово:
Теперь можно проставлять бреймпоинты и дебажить.
Подключение вспомогательных файлов
Иногда возникает необходимость подключить файлы, которые не являются тест сценариями, но, в которых содержится вспомогательный функционал(например логин). Для этого необходимо подключаем файл сделать формата модуля node.js (module.exports), то есть(helpers.js):
function login(){ //... } function logout(){ //... } var Helper = {}; Helper.login = login; Helper.logout = logout;
и потом подключить в файле сценария:
var helpers = require('./helpers'); helpers.login();
Для тех, кто ранее не работал с таким синтаксисом, подчеркну: расширение “.js” в данном случае не пишется.
Примеры тест сценариев
Авторизация пользователя в приложении:
describe('Auth Module', function() { var ptor = protractor.getInstance(); it('should login user', function() { browser.get('/login'); browser.waitForAngular(); element(by.model('username')).sendKeys(browser.params.login.user); element(by.model('password')).sendKeys(browser.params.login.password); element.all(by.css('.button--primary')).first().click(); element(by.binding('user.name')).getText().then(function(username) { expect(username).equal(browser.params.login.username); }); ptor.getCurrentUrl().then(function(url) { expect(url.slice(-10)).equal('/dashboard'); }); }); });
Параметры типа пароля в тестах, понятное дело лучше не держать. Здесь они вынесены в отдельную секцию конфига протрактора (да, согласен, тоже не комильфо, но всеравно лучше, чем прям в тестах):
params: { login: { user: 'stepan@mail.com', password: 'XXXXXXXXX', username: 'Stepan Suvorov' } }
Покупка продукта
describe('Purchase item', function() { var ptor = protractor.getInstance(); beforeEach(function() { helpers.logout(); helpers.login(); browser.sleep(3000); }); it('should purchase an item', function() { browser.get('/items/552/buy'); browser.sleep(3000); element(by.css('.modal-window__block .button--primary')).click(); ptor.ignoreSynchronization = true; element(by.css('#mainSubmit')).click(); element(by.css('input[type="submit"]')).click(); ptor.ignoreSynchronization = false; }); });
хотел бы отметить очень важный момент в этом куске кода:
ptor.ignoreSynchronization = true;
этим мы говорим протрактору, что мы покидаем приложение и переходим на страницу без AngularJS.
Поиск по каталогу
describe('Search', function() { it('should do search', function() { browser.get('/items'); element(by.model('itemsSearch.query')).sendKeys('iBrick', protractor.Key.ENTER); element.all(by.repeater('item in items')).then(function(rows) { var itemTitleElement = rows[0].element(by.className('item-tile__name')); itemTitleElement.getText().then(function(itemTitle) { expect(itemTitle).equal('iBrick Plus'); }) }); }); });