Skip to content

Commit

Permalink
chore(tests): implement e2e test harness outside of docs app
Browse files Browse the repository at this point in the history
Included:

- A sample test fixture
- A sample test
- Server middleware to serve the E2E harness
- Convenient test helpers to simplify loading the right fixture

Closes angular#9557
Closes angular#9527
  • Loading branch information
caitp committed Oct 20, 2014
1 parent fc56c9b commit 2240c11
Show file tree
Hide file tree
Showing 16 changed files with 278 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var files = require('./angularFiles').files;
var util = require('./lib/grunt/utils.js');
var versionInfo = require('./lib/versions/version-info');
var path = require('path');
var e2e = require('./test/e2e/tools');

module.exports = function(grunt) {
//grunt plugins
Expand Down Expand Up @@ -50,6 +51,7 @@ module.exports = function(grunt) {
return [
util.conditionalCsp(),
util.rewrite(),
e2e.middleware(),
connect.favicon('images/favicon.ico'),
connect.static(base),
connect.directory(base)
Expand All @@ -76,6 +78,7 @@ module.exports = function(grunt) {
next();
},
util.conditionalCsp(),
e2e.middleware(),
connect.favicon('images/favicon.ico'),
connect.static(base)
];
Expand Down
1 change: 1 addition & 0 deletions protractor-conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var config = require('./protractor-shared-conf').config;

config.specs = [
'test/e2e/tests/**/*.js',
'build/docs/ptore2e/**/*.js',
'docs/app/e2e/**/*.scenario.js'
];
Expand Down
3 changes: 2 additions & 1 deletion protractor-jenkins-conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ exports.config = {
allScriptsTimeout: 11000,

specs: [
'test/e2e/tests/**/*.js',
'build/docs/ptore2e/**/*.js',
'docs/app/e2e/*.scenario.js'
],
Expand All @@ -30,7 +31,7 @@ exports.config = {

require('jasmine-reporters');
jasmine.getEnv().addReporter(
new jasmine.JUnitXmlReporter('test_out/e2e-' + exports.config.capabilities.browserName + '-', true, true));
new jasmine.JUnitXmlReporter('test_out/docs-e2e-' + exports.config.capabilities.browserName + '-', true, true));
},

jasmineNodeOpts: {
Expand Down
6 changes: 6 additions & 0 deletions scripts/travis/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ if [ $JOB = "unit" ]; then
grunt tests:docs --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
grunt test:travis-protractor --specs "docs/app/e2e/**/*.scenario.js"
elif [ $JOB = "e2e" ]; then
if [ $TEST_TARGET = "jquery" ]; then
export USE_JQUERY=1
fi

export TARGET_SPECS="build/docs/ptore2e/**/default_test.js"
if [ $TEST_TARGET = "jquery" ]; then
TARGET_SPECS="build/docs/ptore2e/**/jquery_test.js"
fi

export TARGET_SPECS="test/e2e/tests/**/*.js,$TARGET_SPECS"
grunt test:travis-protractor --specs "$TARGET_SPECS"
else
echo "Unknown job type. Please set JOB=unit or JOB=e2e-*."
Expand Down
8 changes: 8 additions & 0 deletions test/e2e/fixtures/.jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"browser": true,
"globals": {
"angular": false,
"jQuery": false,
"$": false
}
}
9 changes: 9 additions & 0 deletions test/e2e/fixtures/sample/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html ng-app="test">
<div ng-controller="TestCtrl">
<p>{{text}}</p>
</div>

<script src="angular.js"></script>
<script src="script.js"></script>
</html>
4 changes: 4 additions & 0 deletions test/e2e/fixtures/sample/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
angular.module("test", []).
controller("TestCtrl", function($scope) {
$scope.text = "Hello, world!";
});
23 changes: 23 additions & 0 deletions test/e2e/templates/test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
{% if eq(test.ngAppTag, "html") %}
<html ng-app="{{ test.ngApp }}">
{% else %}
<html>
{% endif %}
<head>
{% if scripts.jQuery %}
<script src="{{ scripts.jQuery }}"></script>
{% endif %}
{% for script in test.scripts %}
<script src="{{ test.scripts[script] }}"></script>
{% endfor %}
{{ test.head }}
</head>
{% if test.ngAppTag === "body" %}
<body ng-app="{{ test.ngApp }}">
{% else %}
<body>
{% endif %}
{% test.body %}
</body>
</html>
11 changes: 11 additions & 0 deletions test/e2e/tests/.jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"node": true,
"globals": {
"describe": false,
"ddescribe": false,
"xdescribe": false,
"it": false,
"xit": false,
"iit": false
}
}
23 changes: 23 additions & 0 deletions test/e2e/tests/helpers/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var helper = {
andWaitForAngular: function() {
browser.waitForAngular();
},
loadFixture: function(fixture) {
var i = 0;
while (fixture[i] === '/') ++i;
fixture = fixture.slice(i);
if (!/\/(index\.html)?$/.test(fixture)) {
fixture += '/';
}

if (process.env.USE_JQUERY) {
fixture += '?jquery';
}

browser.get('/e2e/fixtures/' + fixture);
return helper;
}
};

global.test = helper;
global.loadFixture = helper.loadFixture;
12 changes: 12 additions & 0 deletions test/e2e/tests/sampleSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Sample E2E test:
//
describe('Sample', function() {
beforeEach(function() {
loadFixture("sample").andWaitForAngular();
});

it('should have the interpolated text', function() {
expect(element(by.binding('text')).getText())
.toBe('Hello, world!');
});
});
3 changes: 3 additions & 0 deletions test/e2e/tools/.jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"node": true
}
83 changes: 83 additions & 0 deletions test/e2e/tools/fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict';

var fs = require('fs');
var path = require('path');
var $ = require('cheerio');
var util = require('./util');

var root = path.resolve(__dirname, '..');
var fixtures = path.resolve(root, 'fixtures');

var projectRoot = path.resolve(__dirname, '../../..');
var build = path.resolve(projectRoot, 'build');

function rewriteAngularSrc(src, query) {
if (query) {
if (query.build) {
return query.build + '/' + src;
} else if (query.cdn) {
return '//ajax.googleapis.com/ajax/libs/angularjs/' + query.cdn + '/' + src;
}
}
return '/build/' + src;
}

function generateFixture(test, query) {
var indexFile = path.resolve(fixtures, test, 'index.html');
var text = fs.readFileSync(indexFile, 'utf8');

var $$ = $.load(text);

var firstScript = null;
var jquery = null;
var angular = null;
$$('script').each(function(i, script) {
var src = $(script).attr('src');
if (src === 'jquery.js' && jquery === null) jquery = script;
else if (src === 'angular.js' && angular === null) angular = script;
if (firstScript === null) firstScript = script;
if (src) {
var s = util.stat(path.resolve(build, src));
if (s && s.isFile()) {
$(script).attr('src', rewriteAngularSrc(src, query));
} else {
$(script).attr('src', util.rewriteTestFile(test, src));
}
}
});

if (jquery && (!('jquery' in query) || (/^(0|no|false|off|n)$/i).test(query.jquery))) {
$(jquery).remove();
} else if ('jquery' in query) {
if ((/^(0|no|false|off|n)$/i).test(query.jquery)) {
if (jquery) {
$(jquery).remove();
}
} else {
if (!jquery) {
jquery = $.load('<script></script>')('script')[0];
if (firstScript) {
$(firstScript).before(jquery);
} else {
var head = $$('head');
if (head.length) {
head.prepend(jquery);
} else {
$$.root().first().before(jquery);
}
}
}
if (!/^\d+\.\d+.*$/.test(query.jquery)) {
$(jquery).attr('src', '/bower_components/jquery/dist/jquery.js');
} else {
$(jquery).attr('src', '//ajax.googleapis.com/ajax/libs/jquery/' + query.jquery + '/jquery.js');
}
}
}

return $$.html();
}

module.exports = {
generate: generateFixture
};
5 changes: 5 additions & 0 deletions test/e2e/tools/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
middleware: require('./middleware')
};
44 changes: 44 additions & 0 deletions test/e2e/tools/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';

var url = require('url');
var util = require('./util');
var fixture = require('./fixture');

module.exports = middlewareFactory;

function middlewareFactory(base) {
base = base || '/e2e';
while (base.length && base[base.length-1] === '/') base = base.slice(0, base.length-1);
var fixture_regexp = new RegExp('^' + base + '/fixtures/([a-zA-Z0-9_-]+)(/(index.html)?)?$');
var static_regexp = new RegExp('^' + base + '/fixtures/([a-zA-Z0-9_-]+)(/.*)$');

return function(req, res, next) {
var match;
var basicUrl = req.url;
var idx = basicUrl.indexOf('?');
if (idx >= 0) {
basicUrl = basicUrl.slice(0, idx);
}
if ((match = fixture_regexp.exec(basicUrl))) {
if (util.testExists(match[1])) {
try {
var query = url.parse(req.url, true).query;
res.write(fixture.generate(match[1], query));
res.end();
} catch (e) {
return next(e);
}
} else {
return next('Fixture ' + match[1] + ' not found.');
}
} else if ((match = static_regexp.exec(basicUrl))) {
var rewritten = util.rewriteTestFile(match[1], match[2]);
if (rewritten !== false) {
req.url = rewritten;
}
next();
} else {
return next();
}
};
}
41 changes: 41 additions & 0 deletions test/e2e/tools/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

var fs = require('fs');
var path = require('path');
var url = require('url');

var root = path.resolve(__dirname, '..');
var tests = path.resolve(root, 'fixtures');

function stat(path) {
try {
return fs.statSync(path);
} catch (e) {
// Ignore ENOENT.
if (e.code !== 'ENOENT') {
throw e;
}
}
}

function testExists(testname) {
var s = stat(path.resolve(tests, testname));
return s && s.isDirectory();
}

function rewriteTestFile(testname, testfile) {
var i = 0;
while (testfile[i] === '/') ++i;
testfile = testfile.slice(i);
var s = stat(path.resolve(tests, testname, testfile));
if (s && (s.isFile() || s.isDirectory())) {
return ['/test/e2e/fixtures', testname, testfile].join('/');
}
return false;
}

module.exports = {
stat: stat,
testExists: testExists,
rewriteTestFile: rewriteTestFile
};

0 comments on commit 2240c11

Please sign in to comment.