Автоматизируем тестирование AngularJS с Protractor

О том как установить и запустить Protractor уже было в этом посте – Тестируем AngularJS используя Protractor. А сейчас мы сделаем фокус  на том, как мы можем интегрировать Protractor в нашу систему и подкючить к Grunt.

Подключаем Protractor к Grunt

Для подключение нам необходимо поставить специальный таск-плагин grunt-protractor-runner к grunt путем выполнения следующей команды:

$ npm install grunt-protractor-runner

После чего можем дополнить наш конфигурационный файл секцией для него:

[javascript]
protractor: {
options: {
configFile: "protractor.conf.js"
},
all: {}
}
[/javascript]

protractor.conf.js – конфигурационный файл, который уже у нас есть (создание подробно описано в предыдущем посте)

all: {} – grunt требует как минимум один “target”, поэтому, если все параметры уже указаны в конфиге протрактора, то можем просто добавить пустую сецию.

Проверим что мы все правильно настроили и команда выполняется без ошибок:

[bash]
$ grunt protractor:all
[/bash]

PhantomJS и Protractor

В случае, когда мы хотим запускать наши тесты не только локально, но и на сервере, где нет возможности использовать браузер на помощь спешит PhantomJS. Ознакомиться с PhantomJS вы можете в посте – Создаем юнит-тесты с phantomjs, а сейчас мы поговорим о том как его встроить в Protractor.

Теперь вместо вебдрайвера мы должны запустить фантом-сервер:

$ phantomjs --webdriver=4444

а наша секция grunt конфига преобразиться следующим образом:

[javascript]
protractor: {
options: {
configFile: "protractor.conf.js"
},
all: {
options: {
args:{
seleniumAddress: ‘http://localhost:4444’,
capabilities: {
browserName: ‘phantomjs’
}
}
}
}
}
[/javascript]

иногда бывает необходимо специфицировать конкретную версию/путь к phantomjs, тогда добавляем еще одну опцию – phantomjs.binary.path, а аргументы к фантому можем передавать через опцию phantomjs.cli.args; итого получим:

[javascript]
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’]
}
}
}
}
}
[/javascript]

Если мы хотим, чтобы вебдрайвер запустил фантом за нас, то просто не указываем параметр 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):

[javascript]
function login(){
//…
}
function logout(){
//…
}
var Helper = {};
Helper.login = login;
Helper.logout = logout;
[/javascript]

и потом подключить в файле сценария:

[javascript]
var helpers = require(‘./helpers’);
helpers.login();
[/javascript]

Для тех, кто ранее не работал с таким синтаксисом, подчеркну: расширение “.js” в данном случае не пишется.

Примеры тест сценариев

Авторизация пользователя в приложении:

[javascript]
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’);
});
});
});
[/javascript]

Параметры типа пароля в тестах, понятное дело лучше не держать. Здесь они вынесены в отдельную секцию конфига протрактора (да, согласен, тоже не комильфо, но всеравно лучше, чем прям в тестах):

[javascript]
params: {
login: {
user: ‘stepan@mail.com’,
password: ‘XXXXXXXXX’,
username: ‘Stepan Suvorov’
}
}
[/javascript]

Покупка продукта

[javascript]
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;
});
});
[/javascript]

хотел бы отметить очень важный момент в этом куске кода:

[javascript]
ptor.ignoreSynchronization = true;
[/javascript]

этим мы говорим протрактору, что мы покидаем приложение и переходим на страницу без AngularJS.

Поиск по каталогу

[javascript]
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’);
})

});
});
});
[/javascript]

 

Дополнительно