forked from google/closure-library
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Run all Closure tests on Travis using protractor.
- Loading branch information
Showing
9 changed files
with
209 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,30 @@ | ||
var httpServer = require('http-server'); | ||
var PROTRACTOR_TIMEOUT = process.env.PROTRACTOR_TIMEOUT ? | ||
parseInt(process.env.PROTRACTOR_TIMEOUT, 10) : 10 * 60 * 1000; | ||
// See https://github.com/angular/protractor/blob/master/docs/referenceConf.js | ||
// for full protractor config reference. | ||
exports.config = { | ||
directConnect: false, | ||
seleniumAddress: 'http://localhost:4444/wd/hub', | ||
sauceUser: process.env.SAUCE_USERNAME, | ||
|
||
// Capabilities to be passed to the webdriver instance. | ||
sauceKey: process.env.SAUCE_ACCESS_KEY, | ||
|
||
// Options specific to which browser tests are run on. | ||
capabilities: { | ||
'browserName': 'firefox' | ||
'browserName': 'chrome', | ||
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER, | ||
'build': process.env.TRAVIS_BUILD_NUMBER, | ||
'name': process.env.TRAVIS_PULL_REQUEST == 'false' ? | ||
'CO-' + process.env.TRAVIS_BRANCH + '-' + | ||
process.env.TRAVIS_COMMIT : | ||
'PR-' + process.env.TRAVIS_PULL_REQUEST + '-' + | ||
process.env.TRAVIS_BRANCH + '-' + process.env.TRAVIS_COMMIT | ||
}, | ||
|
||
// Testing framework used for spec file. | ||
framework: 'jasmine2', | ||
|
||
// Relative path to spec (i.e., tests). | ||
specs: ['protractor_spec.js'], | ||
|
||
jasmineNodeOpts: { | ||
//default timeout plus 10 seconds to make sure spec times out before runner | ||
defaultTimeoutInterval: PROTRACTOR_TIMEOUT + 10000 | ||
}, | ||
|
||
beforeLaunch: function () { | ||
httpServer.createServer({ | ||
showDir: false | ||
}).listen('8080', 'localhost'); | ||
// Timeout in ms before a test fails. 30 minutes. | ||
defaultTimeoutInterval: 30 * 60 * 1000 | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,125 @@ | ||
var EC = protractor.ExpectedConditions; | ||
var PROTRACTOR_TIMEOUT = process.env.PROTRACTOR_TIMEOUT ? | ||
parseInt(process.env.PROTRACTOR_TIMEOUT, 10) : 10 * 60 * 1000 | ||
|
||
describe('alltests', function() { | ||
beforeEach(function() { browser.ignoreSynchronization = true; }); | ||
|
||
it('should successfully run all tests', function(done) { | ||
browser.get('http://localhost:8080/all_tests.html'); | ||
$('.goog-testrunner-buttons button:first-child').click(); | ||
var summary = $('.goog-testrunner-progress-summary'); | ||
//Same timeout as parent global timeout | ||
browser.wait(EC.textToBePresentInElement(summary, 'passed'), PROTRACTOR_TIMEOUT) | ||
.then(function() { | ||
console.log('done waiting'); | ||
summary.getText().then(function(text) { | ||
$('.goog-testrunner-report') | ||
.getText() | ||
.then(function(failures) { | ||
console.log(failures); | ||
expect(text.split('\n')[1]).toContain('0 failed'); | ||
done(); | ||
}); | ||
// TODO(joeltine): Remove promise module when stable node version supports it | ||
// natively. | ||
var Promise = require('promise'); | ||
var allTests = require('./alltests'); | ||
|
||
// Timeout for individual test package to complete. | ||
var TEST_TIMEOUT = 45 * 1000; | ||
var TEST_SERVER = 'http://localhost:8080'; | ||
var IGNORED_TESTS = ['closure/goog/i18n/currency_test.html']; | ||
|
||
describe('Run all Closure unit tests', function() { | ||
var removeIgnoredTests = function(tests) { | ||
for (var i = 0; i < IGNORED_TESTS.length; i++) { | ||
var index = tests.indexOf(IGNORED_TESTS[i]); | ||
if (index != -1) { | ||
tests.splice(index, 1); | ||
} | ||
} | ||
return tests; | ||
}; | ||
|
||
beforeAll(function() { | ||
allTests = removeIgnoredTests(allTests); | ||
}); | ||
|
||
beforeEach(function() { | ||
// Ignores synchronization with angular loading. Since we don't use angular, | ||
// enable it. | ||
browser.ignoreSynchronization = true; | ||
}); | ||
|
||
// Polls currently loaded test page for test completion. Returns Promise that | ||
// will resolve when test is finished. | ||
var waitForTestSuiteCompletion = function(testPath) { | ||
var testStartTime = +new Date(); | ||
|
||
var waitForTest = function(resolve, reject) { | ||
// executeScript runs the passed method in the "window" context of | ||
// the current test. JSUnit exposes hooks into the test's status through | ||
// the "G_testRunner" global object. | ||
browser.executeScript(function() { | ||
if (window['G_testRunner'] && | ||
window['G_testRunner']['isFinished']()) { | ||
var status = {}; | ||
status['isFinished'] = true; | ||
status['isSuccess'] = window['G_testRunner']['isSuccess'](); | ||
status['report'] = window['G_testRunner']['getReport'](); | ||
return status; | ||
} else { | ||
return {'isFinished': false}; | ||
} | ||
}) | ||
.then( | ||
function(status) { | ||
if (status && status.isFinished) { | ||
resolve(status); | ||
} else { | ||
var currTime = +new Date(); | ||
if (currTime - testStartTime > TEST_TIMEOUT) { | ||
status.isSuccess = false; | ||
status.report = testPath + ' timed out after ' + | ||
(TEST_TIMEOUT / 1000) + 's!'; | ||
// resolve so tests continue running. | ||
resolve(status); | ||
} else { | ||
// Check every 300ms for completion. | ||
setTimeout(waitForTest.bind(undefined, resolve, reject), | ||
300); | ||
} | ||
} | ||
}, | ||
function(err) { reject(err); }); | ||
}; | ||
|
||
return new Promise(function(resolve, reject) { | ||
waitForTest(resolve, reject); | ||
}); | ||
}; | ||
|
||
it('should run all tests with 0 failures', function(done) { | ||
var failureReports = []; | ||
|
||
// Navigates to testPath to invoke tests. Upon completion inspects returned | ||
// test status and keeps track of the total number failed tests. | ||
var runNextTest = function(testPath) { | ||
return browser.navigate() | ||
.to(TEST_SERVER + '/' + testPath) | ||
.then(function() { return waitForTestSuiteCompletion(testPath); }) | ||
.then(function(status) { | ||
if (!status.isSuccess) { | ||
failureReports.push(status.report); | ||
} | ||
|
||
return status; | ||
}); | ||
}); | ||
}; | ||
|
||
// Chains the next test to the completion of the previous through its | ||
// promise. | ||
var chainNextTest = function(promise, test) { | ||
return promise.then(function() { runNextTest(test); }); | ||
}; | ||
|
||
var testPromise = null; | ||
for (var i = 0; i < allTests.length; i++) { | ||
if (testPromise != null) { | ||
testPromise = chainNextTest(testPromise, allTests[i]); | ||
} else { | ||
testPromise = runNextTest(allTests[i]); | ||
} | ||
} | ||
|
||
testPromise.then(function() { | ||
var totalFailures = failureReports.length; | ||
if (totalFailures > 0) { | ||
console.error('There was ' + totalFailures + ' test failure(s)!'); | ||
for (var i = 0; i < failureReports.length; i++) { | ||
console.error(failureReports[i]); | ||
} | ||
} | ||
expect(failureReports.length).toBe(0); | ||
done(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#!/bin/bash | ||
# | ||
# Script to install dependencies and bootstrap protractor to run all Closure | ||
# tests. | ||
|
||
HTTP_PORT=8080 | ||
|
||
# Make sure to kill both servers on exit (e.g., CTRL+C). | ||
trap 'fuser -k $HTTP_PORT/tcp' EXIT | ||
|
||
# Start web server, with POST support. | ||
python scripts/http/simple_http_server.py 2> /dev/null & sleep 5 | ||
|
||
# Invoke protractor to run tests. | ||
./node_modules/.bin/protractor protractor.conf.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import SimpleHTTPServer | ||
import SocketServer | ||
import cgi | ||
import sys | ||
|
||
PORT = 8080 | ||
|
||
# Simple server to respond to both POST and GET requests. POST requests will | ||
# just respond as normal GETs. | ||
class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): | ||
|
||
def do_GET(self): | ||
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) | ||
|
||
def do_POST(self): | ||
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) | ||
|
||
Handler = ServerHandler | ||
|
||
# Allows use to restart server immediately after restarting it. | ||
SocketServer.ThreadingTCPServer.allow_reuse_address = True | ||
|
||
httpd = SocketServer.TCPServer(("", PORT), Handler) | ||
|
||
print ("Serving at: http://%s:%s" % ("localhost", PORT)) | ||
httpd.serve_forever() |