Внедрение e2e- и unit-тестов в сборку AngularJS-приложения: Protractor, Karma и gulp
Допустим, у нас уже есть сборка проекта на gulp.
И нужно добавить в процедуру сборки релиза e2e-тесты на protractor.
Добавляем в зависимости protractor и gulp-protractor.
gulp/package.json
{
"name": "",
"version": "0.0.1",
"dependencies": {
"gulp": "=3.6.2",
"gulp-util": "=2.2.14",
"gulp-uglify": "=0.3.0",
"gulp-minify-html": "=0.1.3",
"gulp-browserify": "=0.5.0",
"gulp-concat": "=2.2.0",
"gulp-imagemin": "=0.5.1",
"gulp-clean": "=0.3.0",
"gulp-livereload": "=1.5.0",
"gulp-rename": "=1.2.0",
"gulp-connect": "~2.0.6",
"connect-route": "~0.1.4",
"tiny-lr": "=0.0.7",
"connect-livereload": "=0.4.0",
"run-sequence": "=0.3.6",
"gulp-csso": "=0.2.9",
"gulp-rev": "=0.4.0",
"gulp-replace": "=0.3.0",
"gulp-sass": "~0.7.1",
"gulp-protractor": "0.0.11",
"protractor": "~1.3.1",
"phantomjs": "~1.9.10",
"gulp-karma": "0.0.4",
"karma": "^0.12.24",
"karma-chrome-launcher": "^0.1.5",
"karma-firefox-launcher": "^0.1.3",
"karma-jasmine": "^0.1.5",
"karma-junit-reporter": "^0.2.2",
"karma-phantomjs-launcher": "~0.1.4"
},
"engines": {
"node": "=0.10.25"
},
"description": "",
"main": "index.js",
"authors": [
"bullgare "
],
"private": true,
"license": "proprietary"
}
gulp/gulpfile.js
require('events').EventEmitter.prototype._maxListeners = 30;
var fs = require('fs'),
_path = require('path'),
gulp = require('gulp'),
...
connect = require('gulp-connect'), // Webserver
connectRoute = require("connect-route"),
protractor = require("gulp-protractor").protractor,
webdriver_update = require("gulp-protractor").webdriver_update,
karma = require('gulp-karma');
...
gulp.task('http-server-dev', function () {
connect.server({
root: pathBuildDev,
port: 9000,
middleware: function (connect, opt) {
return [
connectRoute(connectMockRoutes)
];
}
});
console.log('Dev Server listening on http://localhost:9000');
});
gulp.task('http-server-stop', function () {
connect.serverClose();
console.log('Server is shutting down');
});
...
// Downloads the selenium webdriver
gulp.task('webdriver-update', webdriver_update);
// Setting up the test task
gulp.task('protractor'/*, ['webdriver-update']*/, function(callback) {
// TODO path into variables
gulp.src([pathTestsE2e + "tests/*.js"])
.pipe(protractor({
configFile: pathTestsE2e + "protractor_config.js",
debug: true,
args: [
//'--capabilities.browserName', 'firefox'
//'--capabilities.browserName', 'chrome'
'--capabilities.browserName', 'phantomjs',
'--capabilities.phantomjs.binary.path', './node_modules/.bin/phantomjs'
]
}))
.on('error', function (e) {
throw e
});
});
gulp.task('e2e', ['webdriver-update', 'protractor'], function(callback) {callback();});
gulp.task('unit', function () {
return gulp.src([pathBuildProd + 'js/libs.js', pathApp + 'libs/angular-mocks/angular-mocks.js', pathBuildProd + 'js/app.js', pathTestsUnit + 'tests/**/*.js'])
.pipe(karma({
configFile: pathTestsUnit + 'karma_config.js',
action: 'run',
//browsers: ['Firefox']
browsers: ['Chrome']
} ) )
.on('error', function (err) {
// Make sure failed tests cause gulp to exit non-zero
throw err;
});
});
...
gulp.task('build-and-test', function (callback) {
runSequence(
'build',
'http-server-prod',
'unit',
'e2e',
'http-server-stop', callback);
});
<путь к e2e-тестам>protractor_config.js
// example from https://raw.github.com/angular/protractor/master/example/conf.js
exports.config = {
// The address of a running selenium server.
seleniumServerJar: '../../scripts/gulp/node_modules/protractor/selenium/selenium-server-standalone-2.43.1.jar', // Make use you check the version in the folder
//seleniumAddress: 'http://localhost:4444/wd/hub',
// Capabilities to be passed to the webdriver instance.
capabilities: {
// this could be overwritten by --capabilities.browserName=firefox
'browserName': 'chrome'
},
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
showTiming: true,
defaultTimeoutInterval: 30000
}
};
<путь к e2e-тестам>tests/spec.js
describe('my tests', function ()
{
it('should search for address', function ()
{
browser.get('/');
element(by.model('address.dirty')).sendKeys('тверская 8');
element(by.css('.search-submit-icon')).click();
var firstResult = element.all(by.repeater('item in addressItems | first_item'));
expect(firstResult.count()).toEqual(1);
expect(firstResult.get(0).getText()).toContain('улица Тверская, 8');
expect(firstResult.get(0).getText()).toContain('Россия, Москва');
var otherResults = element.all(by.repeater('item in addressItems | except_first_item'));
expect(otherResults.count()).toBeGreaterThan(-1);
});
it('should build routes', function ()
{
browser.get('/#?type=routes');
element(by.model('from.title')).sendKeys('москва тверская 8');
element(by.model('from.title')).sendKeys(protractor.Key.ENTER)/*.perform()*/;
element(by.model('to.title')).sendKeys('москва пушкинская 10');
element(by.model('to.title')).sendKeys(protractor.Key.ENTER)/*.perform()*/;
var routes = element.all(by.repeater('route in routes'));
expect(routes.count()).toBeGreaterThan(0);
routes.get(0).click();
var instructions = element.all(by.repeater('item in route.instructions'));
expect(instructions.count()).toBeGreaterThan(5);
});
});
<путь к unit-тестам>karma_config.js
module.exports = function(config) {
config.set({
frameworks: ['jasmine'],
reporters: ['progress', 'junit'],
junitReporter: {
outputFile: 'test-results.xml'
},
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
captureTimeout: 20000,
singleRun: true,
reportSlowerThan: 500,
plugins: [
'karma-jasmine',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-phantomjs-launcher',
'karma-junit-reporter'
]
});
};
<путь к unit-тестам>tests/spec.js
'use strict';
/* jasmine specs for filters */
describe('Filters:', function() {
beforeEach(angular.mock.module('SmMapApp'));
describe('lat:', function() {
var lat;
beforeEach(inject(function ($filter) {
lat = $filter('lat');
}));
it('should exist', inject(function() {
expect(lat).not.toEqual(null);
}));
it('should work properly', inject(function() {
expect(lat(undefined)).toEqual(undefined);
expect(lat('')).toEqual('');
expect(lat({})).toEqual('');
expect(lat({position: 1})).toEqual('');
expect(lat({position: {lat: 1}})).toEqual(1);
expect(lat({location: 1})).toEqual('');
expect(lat({location: {lat: 1}})).toEqual(1);
}));
});
describe('lng:', function() {
var lng;
beforeEach(inject(function ($filter) {
lng = $filter('lng');
}));
it('should exist', inject(function() {
expect(lng).not.toEqual(null);
}));
it('should work properly', inject(function() {
expect(lng(undefined)).toEqual(undefined);
expect(lng('')).toEqual('');
expect(lng({})).toEqual('');
expect(lng({position: 1})).toEqual('');
expect(lng({position: {lng: 1}})).toEqual(1);
expect(lng({position: {lon: 1}})).toEqual(1);
expect(lng({location: 1})).toEqual('');
expect(lng({location: {lng: 1}})).toEqual(1);
expect(lng({location: {lon: 1}})).toEqual(1);
}));
});
});
После чего в консоли
cd ./gulp npm install gulp build-and-test
Это запустит webdriver-update, который скажет, куда поставил selenium, например:
... selenium-server-standalone-2.43.1.jar downloaded to /home/user/projects/maps_ui/scripts/gulp/node_modules/protractor/selenium/selenium-server-standalone-2.43.1.jar
Есть большая вероятность, что путь не совпадёт с указанным в конфиге <путь к тестам>protractor_config.js, и нужно будет поправить параметр seleniumServerJar.
После этого снова запускаем в консоли
gulp build-and-test
и видим, как у нас автоматически стартует хром и проходят тесты.
Полезные ссылки:
http://angular.github.io/protractor/
https://github.com/mllrsohn/gulp-protractor
http://stackoverflow.com/questions/23135649/how-can-i-use-command-line-arguments-in-angularjs-protractor
http://jasmine.github.io/2.0/introduction.html
https://github.com/jtomaszewski/ionic-cordova-gulp-seed/blob/master/gulpfile.coffee
http://karma-runner.github.io/0.8/intro/configuration.html
LEAVE A COMMENT
Для отправки комментария вам необходимо авторизоваться.