Skip to content

Instantly share code, notes, and snippets.

@cpoDesign
Last active August 29, 2015 14:05
Show Gist options
  • Save cpoDesign/a72845a4c703793bdaab to your computer and use it in GitHub Desktop.
Save cpoDesign/a72845a4c703793bdaab to your computer and use it in GitHub Desktop.
PhantomJS and Team cityAdded description how to put test runner together Source for the script: - http://stackoverflow.com/questions/21185246/how-to-run-jasmine-tests-in-teamcity
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Spec Runner</title>
<!-- Do not delete - vital to test runner-->
<link href="./css/jasmine.css" rel="stylesheet" />
<script src="./lib/jasmine.js"></script>
<script src="./lib/jasmine-html.js"></script>
<script src="./lib/underscore-min.js"></script>
<!-- Do not delete - depnedant js for implementation-->
<script src="./lib/angular.min.js"></script>
<script src="./lib/angular-sanitize.min.js"></script>
<script src="./lib/angular-route.min.js"></script>
<script src="./lib/angular-resource.min.js"></script>
<script src="./lib/angular-mocks.js"></script>
<!-- include source files here... -->
<script src="./js/app.js"></script>
<!-- specs -->
<script src="./js/tests/appSpec.js"></script>
<!-- test runner-->
<script type="text/javascript">
(function () {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function (spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function () {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
<br />
</body>
</html>
var system = require('system'),
env = system.env;
/**
* Wait until the test condition is true or a timeout occurs. Useful for waiting
* on a server response or for a ui change (fadeIn, etc.) to occur.
*
* @param testFx javascript condition that evaluates to a boolean,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param onReady what to do when testFx condition is fulfilled,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
*/
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timeout is 3s
start = new Date().getTime(),
condition = false,
interval = setInterval(function () {
if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
// If not time-out yet and condition not yet fulfilled
condition = (typeof (testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
} else {
if (!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("'waitFor()' timeout");
phantom.exit(1);
} else {
// Condition fulfilled (timeout and/or condition is 'true')
console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
typeof (onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
clearInterval(interval); //< Stop this interval
}
}
}, 100); //< repeat check every 100ms
};
if (system.args.length !== 2) {
console.log('Usage: run-jasmine.js URL');
phantom.exit(1);
}
var page = require('webpage').create();
/**
*
##teamcity[testSuiteStarted name='suite.name']
##teamcity[testSuiteStarted name='nested.suite']
##teamcity[testStarted name='package_or_namespace.ClassName.TestName']
##teamcity[testFailed name='package_or_namespace.ClassName.TestName' message='The number should be 20000' details='expected:<20000> but was:<10000>']
##teamcity[testFinished name='package_or_namespace.ClassName.TestName']
##teamcity[testSuiteFinished name='nested.suite']
##teamcity[testSuiteFinished name='suite.name']
*/
// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function (msg) {
var teamCityMessage = msg.indexOf('TEAMCITY_') === 0;
if (teamCityMessage) {
if (!env.hasOwnProperty('TEAMCITY_PROJECT_NAME')) return;
var separatorIndex = msg.indexOf(':');
var command = msg.substring(0, separatorIndex);
var data = JSON.parse(msg.substring(separatorIndex + 1));
switch (command) {
case 'TEAMCITY_TESTSTARTED': {
console.log("##teamcity[testStarted name='" + escape(data.name) + "']");
break;
}
case 'TEAMCITY_TESTFINISHED': {
console.log("##teamcity[testFinished name='" + escape(data.name) + "']");
break;
}
case 'TEAMCITY_SUITESTARTED': {
console.log("##teamcity[testSuiteStarted name='" + escape(data.suite) + "']");
break;
}
case 'TEAMCITY_SUITEFINISHED': {
console.log("##teamcity[testSuiteFinished name='" + escape(data.suite) + "']");
break;
}
case 'TEAMCITY_TESTFAILED': {
console.log("##teamcity[testFailed name='" + escape(data.name) + "' message='" + escape(data.message) + "']");
break;
}
}
}
else {
if (env.hasOwnProperty('TEAMCITY_PROJECT_NAME')) return;
console.log(msg);
}
function escape(message) {
while (message.indexOf("'") >= 0) message = message.replace("'", '"');
return message;
}
};
page.open(system.args[1], function (status) {
if (status !== "success") {
console.log("Unable to access network");
phantom.exit();
} else {
waitFor(function () {
return page.evaluate(function () {
return document.body.querySelector('.symbolSummary .pending') === null
});
}, function () {
var exitCode = page.evaluate(function () {
var currentSuite;
var successList = document.body.querySelectorAll('.results > .summary .specSummary.passed');
var suites = {};
if (successList && successList.length > 0) {
for (var i = 0; i < successList.length; ++i) {
var el = successList[i],
name = el.children[0].title,
suite = name.substring(0, name.indexOf(' '));
suites[suite] = suites[suite] || [];
suites[suite].push({ status: 'success', name: name });
}
}
var failedList = document.body.querySelectorAll('.results > #details > .specDetail.failed');
if (failedList && failedList.length > 0) {
console.log('');
console.log(failedList.length + ' test(s) FAILED:');
for (var i = 0; i < failedList.length; ++i) {
var el = failedList[i],
name = el.querySelector('.description').innerText,
msg = el.querySelector('.resultMessage.fail').innerText,
suite = name.substring(0, name.indexOf(' '));
// remove trailing period
name = name.substring(0, name.length - 1);
suites[suite] = suites[suite] || [];
suites[suite].push({ suite: suite, status: 'failed', name: name, message: name + ': ' + msg });
}
}
for (var suite in suites) {
var tests = suites[suite];
console.log('TEAMCITY_SUITESTARTED:' + JSON.stringify({ suite: suite }));
for (var i in tests) {
var test = tests[i];
console.log('TEAMCITY_TESTSTARTED:' + JSON.stringify({ name: test.name }));
if (test.status === 'success') {
}
else if (test.status === 'failed') {
console.log('TEAMCITY_TESTFAILED:' + JSON.stringify({ name: test.name, message: test.message }));
console.log('');
console.log(test.suite);
console.log(test.message);
}
console.log('TEAMCITY_TESTFINISHED:' + JSON.stringify({ name: test.name }));
}
console.log('TEAMCITY_SUITEFINISHED:' + JSON.stringify({ suite: suite }));
}
if (failedList && failedList.length > 0) {
return 1;
} else {
console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText);
return 0;
}
});
phantom.exit(exitCode);
});
}
});
Runner type: Command line
Step name: your step name
Execute step: your condition
Working directory: MyDemoProject
- (Project with tests directory - I have the jstests.js and jstests.html files there. Optional, set if differs from the checkout directory where the command will be executed)
Run: Execute with parameters
Command executable: C:\phantomjs-1.9.7\phantomjs.exe
- (update to your correct configuration)
Command parameters: jstests.js jstests.html
-(keep order of files and spacing between files-> they are arguments)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment