/*
* Runs QUnit tests in PhantomJS and outputs test result data, in JSON format, to stdout. * * Tokens are placed around each test result to allow them to be parsed individually. The tokens * match the constants in QUnited::Driver::ResultsCollector. * * Usage: * phantomjs runner.js PATH_TO_TESTS_HTML_PAGE */
var system = require(‘system’),
webpage = require('webpage');
if (system.args.length < 2) {
console.log('No tests file specified'); phantom.exit(1);
}
var page = webpage.create(),
testsHtmlFile = system.args[1], config = { resultsCheckInterval: 200, // Check for new results at this interval testsCompletedCheckInterval: 100, // Check for all tests completing at this interval testsTimeout: 10001 // Time out and indicate error after this many millis };
/*
* Writes any collected QUnit results that are pending output to stdout (this is done with * console.log in PhantomJS). * * Tokens are placed around each test result to allow them to be parsed out later. Note that the * tokens must match the constants in QUnited::Driver::ResultsCollector. * * JSON.stringify must be called in the context of the page to properly serialize null values in * results. If it is called here in the PhantomJS interpreter code then null values are serialized * as empty strings. Finding out exactly why this happens would take more investigation. For now * it seems that stringifying on the page is a decent solution, though it is slightly less robust * since JSON serialization may be tampered with in user code. */
function writePendingTestResults() {
var serializedResults = page.evaluate(function() { var pendingResults = []; while (QUnited.testResultsPendingOutput.length > 0) { pendingResults.push(QUnited.util.jsonStringify(QUnited.testResultsPendingOutput.shift())); } return pendingResults; }); var i, output; for (i = 0; i < serializedResults.length; i++) { output = 'QUNITED_TEST_RESULT_START_TOKEN'; output += serializedResults[i]; output += 'QUNITED_TEST_RESULT_END_TOKEN'; console.log(output); }
}
/*
* Executes the given function once all tests have completed. If a timeout occurs then exit * with a status code of 1. */
function whenTestsHaveCompleted(fn) {
var start = new Date().getTime(), testsHaveCompleted = false, interval = setInterval(function() { if ( (new Date().getTime() - start < config.testsTimeout) && !testsHaveCompleted ) { testsHaveCompleted = page.evaluate(function() { return QUnited.testsHaveCompleted; }); } else { if (testsHaveCompleted) { fn(); clearInterval(interval); } else { // Tests took too long console.log("ERROR: Timeout waiting for tests to complete"); phantom.exit(1); } } }, config.testsCompletedCheckInterval);
};
/*
* Open the HTML page that contains all of our QUnit tests. As it is running, check for collected * test results and output them if we have any. Also check whether tests have completed. Once they * have completed, output any remaining results and exit. */
page.open(testsHtmlFile, function(status) {
if (status !== "success") { console.log("Could not open tests file"); phantom.exit(1); } else { setInterval(writePendingTestResults, config.resultsCheckInterval); whenTestsHaveCompleted(function() { writePendingTestResults(); phantom.exit(0); }); }
});