/bower_components/fingerprintjs2/specs/phantomjs-testrunner.js |
@@ -0,0 +1,230 @@ |
/* globals jasmineRequire, phantom */ |
// Verify arguments |
var system = require('system'); |
var args; |
|
if(phantom.args) { |
args = phantom.args; |
} else { |
args = system.args.slice(1);//use system args for phantom 2.0+ |
} |
|
if (args.length === 0) { |
console.log("Simple JasmineBDD test runner for phantom.js"); |
console.log("Usage: phantomjs-testrunner.js url_to_runner.html"); |
console.log("Accepts http:// and file:// urls"); |
console.log(""); |
console.log("NOTE: This script depends on jasmine.HtmlReporter being used\non the page, for the DOM elements it creates.\n"); |
phantom.exit(2); |
} |
else { |
var fs = require("fs"), |
pages = [], |
page, address, resultsKey, i, l; |
|
|
var setupPageFn = function(p, k) { |
return function() { |
overloadPageEvaluate(p); |
setupWriteFileFunction(p, k, fs.separator); |
}; |
}; |
|
for (i = 0, l = args.length; i < l; i++) { |
address = args[i]; |
console.log("Loading " + address); |
|
// if provided a url without a protocol, try to use file:// |
address = address.indexOf("://") === -1 ? "file://" + address : address; |
|
// create a WebPage object to work with |
page = require("webpage").create(); |
page.url = address; |
|
// When initialized, inject the reporting functions before the page is loaded |
// (and thus before it will try to utilize the functions) |
resultsKey = "__jr" + Math.ceil(Math.random() * 1000000); |
page.onInitialized = setupPageFn(page, resultsKey); |
page.open(address, processPage(null, page, resultsKey)); |
pages.push(page); |
|
page.onConsoleMessage = logAndWorkAroundDefaultLineBreaking; |
} |
|
// bail when all pages have been processed |
setInterval(function(){ |
var exit_code = 0; |
for (i = 0, l = pages.length; i < l; i++) { |
page = pages[i]; |
if (page.__exit_code === null) { |
// wait until later |
return; |
} |
exit_code |= page.__exit_code; |
} |
phantom.exit(exit_code); |
}, 100); |
} |
|
// Thanks to hoisting, these helpers are still available when needed above |
/** |
* Logs a message. Does not add a line-break for single characters '.' and 'F' or lines ending in ' ...' |
* |
* @param msg |
*/ |
function logAndWorkAroundDefaultLineBreaking(msg) { |
var interpretAsWithoutNewline = /(^(\033\[\d+m)*[\.F](\033\[\d+m)*$)|( \.\.\.$)/; |
if (navigator.userAgent.indexOf("Windows") < 0 && interpretAsWithoutNewline.test(msg)) { |
try { |
system.stdout.write(msg); |
} catch (e) { |
var fs = require('fs'); |
fs.write('/dev/stdout', msg, 'w'); |
} |
} else { |
console.log(msg); |
} |
} |
|
/** |
* Stringifies the function, replacing any %placeholders% with mapped values. |
* |
* @param {function} fn The function to replace occurrences within. |
* @param {object} replacements Key => Value object of string replacements. |
*/ |
function replaceFunctionPlaceholders(fn, replacements) { |
if (replacements && typeof replacements === "object") { |
fn = fn.toString(); |
for (var p in replacements) { |
if (replacements.hasOwnProperty(p)) { |
var match = new RegExp("%" + p + "%", "g"); |
do { |
fn = fn.replace(match, replacements[p]); |
} while(fn.indexOf(match) !== -1); |
} |
} |
} |
return fn; |
} |
|
/** |
* Replaces the "evaluate" method with one we can easily do substitution with. |
* |
* @param {phantomjs.WebPage} page The WebPage object to overload |
*/ |
function overloadPageEvaluate(page) { |
page._evaluate = page.evaluate; |
page.evaluate = function(fn, replacements) { return page._evaluate(replaceFunctionPlaceholders(fn, replacements)); }; |
return page; |
} |
|
/** Stubs a fake writeFile function into the test runner. |
* |
* @param {phantomjs.WebPage} page The WebPage object to inject functions into. |
* @param {string} key The name of the global object in which file data should |
* be stored for later retrieval. |
*/ |
// TODO: not bothering with error checking for now (closed environment) |
function setupWriteFileFunction(page, key, path_separator) { |
page.evaluate(function(){ |
window["%resultsObj%"] = {}; |
window.fs_path_separator = "%fs_path_separator%"; |
window.__phantom_writeFile = function(filename, text) { |
window["%resultsObj%"][filename] = text; |
}; |
}, {resultsObj: key, fs_path_separator: path_separator.replace("\\", "\\\\")}); |
} |
|
/** |
* Returns the loaded page's filename => output object. |
* |
* @param {phantomjs.WebPage} page The WebPage object to retrieve data from. |
* @param {string} key The name of the global object to be returned. Should |
* be the same key provided to setupWriteFileFunction. |
*/ |
function getXmlResults(page, key) { |
return page.evaluate(function(){ |
return window["%resultsObj%"] || {}; |
}, {resultsObj: key}); |
} |
|
/** |
* Processes a page. |
* |
* @param {string} status The status from opening the page via WebPage#open. |
* @param {phantomjs.WebPage} page The WebPage to be processed. |
*/ |
function processPage(status, page, resultsKey) { |
if (status === null && page) { |
page.__exit_code = null; |
return function(stat){ |
processPage(stat, page, resultsKey); |
}; |
} |
if (status !== "success") { |
console.error("Unable to load resource: " + address); |
page.__exit_code = 2; |
} |
else { |
var isFinished = function() { |
return page.evaluate(function(){ |
// if there's a JUnitXmlReporter, return a boolean indicating if it is finished |
if (window.jasmineReporters && window.jasmineReporters.startTime) { |
return !!window.jasmineReporters.endTime; |
} |
// otherwise, scrape the DOM for the HtmlReporter "finished in ..." output |
var durElem = document.querySelector(".html-reporter .duration"); |
if (!durElem) { |
durElem = document.querySelector(".jasmine_html-reporter .duration"); |
} |
return durElem && durElem.textContent && durElem.textContent.toLowerCase().indexOf("finished in") === 0; |
}); |
}; |
var getResultsFromHtmlRunner = function() { |
return page.evaluate(function(){ |
var resultElem = document.querySelector(".html-reporter .alert .bar"); |
if (!resultElem) { |
resultElem = document.querySelector(".jasmine_html-reporter .alert .bar"); |
} |
return resultElem && resultElem.textContent && |
resultElem.textContent.match(/(\d+) spec.* (\d+) failure.*/) || |
["Unable to determine success or failure."]; |
}); |
}; |
var timeout = 60000; |
var loopInterval = 100; |
var ival = setInterval(function(){ |
if (isFinished()) { |
// get the results that need to be written to disk |
var fs = require("fs"), |
xml_results = getXmlResults(page, resultsKey), |
output; |
for (var filename in xml_results) { |
if (xml_results.hasOwnProperty(filename) && (output = xml_results[filename]) && typeof(output) === "string") { |
fs.write(filename, output, "w"); |
} |
} |
|
// print out a success / failure message of the results |
var results = getResultsFromHtmlRunner(); |
var failures = Number(results[2]); |
if (failures > 0) { |
page.__exit_code = 1; |
clearInterval(ival); |
} |
else { |
page.__exit_code = 0; |
clearInterval(ival); |
} |
} |
else { |
timeout -= loopInterval; |
if (timeout <= 0) { |
console.log('Page has timed out; aborting.'); |
page.__exit_code = 2; |
clearInterval(ival); |
} |
} |
}, loopInterval); |
} |
} |