diff --git a/lib/guard/jasmine.rb b/lib/guard/jasmine.rb
index b57d258..3586330 100644
--- a/lib/guard/jasmine.rb
+++ b/lib/guard/jasmine.rb
@@ -49,7 +49,10 @@ class Jasmine < Guard
statements_threshold: 0,
functions_threshold: 0,
branches_threshold: 0,
- lines_threshold: 0
+ lines_threshold: 0,
+ junit: false,
+ junit_consolidate: true,
+ junit_save_path: ''
}
# Initialize Guard::Jasmine.
diff --git a/lib/guard/jasmine/cli.rb b/lib/guard/jasmine/cli.rb
index 995e74c..f84ac1f 100644
--- a/lib/guard/jasmine/cli.rb
+++ b/lib/guard/jasmine/cli.rb
@@ -137,6 +137,21 @@ class CLI < Thor
default: 0,
desc: 'Lines coverage threshold'
+ method_option :junit,
+ type: :boolean,
+ default: false
+ desc: 'Whether to save jasmine test results in JUnit-compatible xml files'
+
+ method_option :junit_consolidate,
+ type: :boolean,
+ default: false
+ desc: 'Whether to save nested describes within the same xml file as their parent'
+
+ method_option :junit_save_path,
+ type: :string,
+ default: ''
+ desc: 'The directory to save junit xml files into'
+
# Run the Guard::Jasmine::Runner with options from
# the command line.
#
@@ -169,6 +184,9 @@ def spec(*paths)
runner_options[:notification] = false
runner_options[:hide_success] = true
runner_options[:max_error_notify] = 0
+ runner_options[:junit] = options.junit
+ runner_options[:junit_consolidate] = options.junit_consolidate
+ runner_options[:junit_save_path] = options.junit_save_path
::Guard::UI.options = ::Guard::UI.options.merge({ :template => ':message' })
diff --git a/lib/guard/jasmine/phantomjs/guard-jasmine.coffee b/lib/guard/jasmine/phantomjs/guard-jasmine.coffee
index 1666e60..348c88a 100644
--- a/lib/guard/jasmine/phantomjs/guard-jasmine.coffee
+++ b/lib/guard/jasmine/phantomjs/guard-jasmine.coffee
@@ -10,6 +10,9 @@ options =
focus: /true/i.test phantom.args[3]
console: phantom.args[4] || 'failure'
errors: phantom.args[5] || 'failure'
+ junit: /true/i.test phantom.args[6]
+ junit_consolidate: /true/i.test phantom.args[7]
+ junit_save_path: phantom.args[8] || ''
# Create the web page.
#
@@ -20,6 +23,8 @@ page = require('webpage').create()
currentSpecId = -1
logs = {}
errors = {}
+resultsKey = "__jr" + Math.ceil(Math.random() * 1000000)
+fs = require("fs")
# Catch JavaScript errors
#
@@ -47,18 +52,57 @@ page.onConsoleMessage = (msg, line, source) ->
# Initialize the page before the JavaScript is run.
#
page.onInitialized = ->
+ overloadPageEvaluate(page)
+ setupWriteFileFunction(page, resultsKey, fs.separator)
+
page.injectJs 'lib/console.js'
page.injectJs 'lib/reporter.js'
+ page.injectJs 'lib/junit_reporter.js'
- page.evaluate ->
+ setupReporters = ->
# Attach the console reporter when the document is ready.
window.onload = ->
window.onload = null
window.resultReceived = false
window.reporter = new ConsoleReporter()
if window.jasmine
+ jasmine.getEnv().addReporter(new JUnitXmlReporter("%save_path%", "%consolidate%"))
jasmine.getEnv().addReporter(window.reporter)
+ page.evaluate(setupReporters, {save_path: options.junit_save_path, consolidate: options.junit_consolidate})
+
+
+getXmlResults = (page, key) ->
+ getWindowObj = ->
+ window["%resultsObj%"] || {}
+ page.evaluate getWindowObj, {resultsObj: key}
+
+replaceFunctionPlaceholders= (fn, replacements) ->
+ if replacements && typeof replacements == 'object'
+ fn = fn.toString()
+ for p of replacements
+ if replacements.hasOwnProperty(p)
+ match = new RegExp("%" + p + "%", "g")
+ loop
+ fn = fn.replace(match, replacements[p])
+ break unless fn.indexOf(match) != -1
+ fn
+
+overloadPageEvaluate = (page) ->
+ page._evaluate = page.evaluate
+ page.evaluate = (fn, replacements) ->
+ page._evaluate(replaceFunctionPlaceholders(fn, replacements))
+ page
+
+setupWriteFileFunction= (page,key, path_separator) ->
+ saveData = () ->
+ window["%resultsObj%"] = {}
+ window.fs_path_separator = "%fs_path_separator%"
+ window.__phantom_writeFile = (filename, text) ->
+ window["%resultsObj%"][filename] = text;
+
+ page.evaluate saveData, {resultsObj: key, fs_path_separator: path_separator}
+
# Open web page and run the Jasmine test runner
#
page.open options.url, (status) ->
@@ -70,7 +114,6 @@ page.open options.url, (status) ->
else
waitFor jasmineReady, jasmineAvailable, options.timeout, jasmineMissing
-
# Test if the jasmine has been loaded
#
jasmineReady = ->
@@ -116,6 +159,12 @@ specsTimedout = ->
console.log JSON.stringify({ error: 'Timeout for the Jasmine test results!' })
specsDone = ->
+ if options.junit == true
+ xml_results = getXmlResults(page, resultsKey)
+ for filename of xml_results
+ if xml_results.hasOwnProperty(filename) && (output = xml_results[filename]) && typeof(output) == 'string'
+ fs.write(filename, output, 'w')
+
phantom.exit()
# Wait until the test condition is true or a timeout occurs.
diff --git a/lib/guard/jasmine/phantomjs/guard-jasmine.js b/lib/guard/jasmine/phantomjs/guard-jasmine.js
index 05debfc..b3cc35d 100644
--- a/lib/guard/jasmine/phantomjs/guard-jasmine.js
+++ b/lib/guard/jasmine/phantomjs/guard-jasmine.js
@@ -1,5 +1,6 @@
+// Generated by CoffeeScript 1.6.3
(function() {
- var currentSpecId, errors, jasmineAvailable, jasmineMissing, jasmineReady, logs, options, page, specsDone, specsReady, specsTimedout, waitFor;
+ var currentSpecId, errors, fs, getXmlResults, jasmineAvailable, jasmineMissing, jasmineReady, logs, options, overloadPageEvaluate, page, replaceFunctionPlaceholders, resultsKey, setupWriteFileFunction, specsDone, specsReady, specsTimedout, waitFor;
phantom.injectJs('lib/result.js');
@@ -9,7 +10,10 @@
specdoc: phantom.args[2] || 'failure',
focus: /true/i.test(phantom.args[3]),
console: phantom.args[4] || 'failure',
- errors: phantom.args[5] || 'failure'
+ errors: phantom.args[5] || 'failure',
+ junit: /true/i.test(phantom.args[6]),
+ junit_consolidate: /true/i.test(phantom.args[7]),
+ junit_save_path: phantom.args[8] || ''
};
page = require('webpage').create();
@@ -20,6 +24,10 @@
errors = {};
+ resultsKey = "__jr" + Math.ceil(Math.random() * 1000000);
+
+ fs = require("fs");
+
page.onError = function(msg, trace) {
if (currentSpecId) {
errors[currentSpecId] || (errors[currentSpecId] = []);
@@ -32,7 +40,6 @@
page.onConsoleMessage = function(msg, line, source) {
var result;
-
if (/^RUNNER_END$/.test(msg)) {
result = page.evaluate(function() {
return window.reporter.runnerResult;
@@ -50,17 +57,78 @@
};
page.onInitialized = function() {
+ var setupReporters;
+ overloadPageEvaluate(page);
+ setupWriteFileFunction(page, resultsKey, fs.separator);
page.injectJs('lib/console.js');
page.injectJs('lib/reporter.js');
- return page.evaluate(function() {
+ page.injectJs('lib/junit_reporter.js');
+ setupReporters = function() {
return window.onload = function() {
window.onload = null;
window.resultReceived = false;
window.reporter = new ConsoleReporter();
if (window.jasmine) {
+ jasmine.getEnv().addReporter(new JUnitXmlReporter("%save_path%", "%consolidate%"));
return jasmine.getEnv().addReporter(window.reporter);
}
};
+ };
+ return page.evaluate(setupReporters, {
+ save_path: options.junit_save_path,
+ consolidate: options.junit_consolidate
+ });
+ };
+
+ getXmlResults = function(page, key) {
+ var getWindowObj;
+ getWindowObj = function() {
+ return window["%resultsObj%"] || {};
+ };
+ return page.evaluate(getWindowObj, {
+ resultsObj: key
+ });
+ };
+
+ replaceFunctionPlaceholders = function(fn, replacements) {
+ var match, p;
+ if (replacements && typeof replacements === 'object') {
+ fn = fn.toString();
+ for (p in replacements) {
+ if (replacements.hasOwnProperty(p)) {
+ match = new RegExp("%" + p + "%", "g");
+ while (true) {
+ fn = fn.replace(match, replacements[p]);
+ if (fn.indexOf(match) === -1) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return fn;
+ };
+
+ overloadPageEvaluate = function(page) {
+ page._evaluate = page.evaluate;
+ page.evaluate = function(fn, replacements) {
+ return page._evaluate(replaceFunctionPlaceholders(fn, replacements));
+ };
+ return page;
+ };
+
+ setupWriteFileFunction = function(page, key, path_separator) {
+ var saveData;
+ saveData = function() {
+ window["%resultsObj%"] = {};
+ window.fs_path_separator = "%fs_path_separator%";
+ return window.__phantom_writeFile = function(filename, text) {
+ return window["%resultsObj%"][filename] = text;
+ };
+ };
+ return page.evaluate(saveData, {
+ resultsObj: key,
+ fs_path_separator: path_separator
});
};
@@ -88,10 +156,8 @@
jasmineMissing = function() {
var error, text;
-
text = page.evaluate(function() {
var _ref;
-
return (_ref = document.getElementsByTagName('body')[0]) != null ? _ref.innerText : void 0;
});
if (text) {
@@ -114,10 +180,8 @@
specsTimedout = function() {
var error, text;
-
text = page.evaluate(function() {
var _ref;
-
return (_ref = document.getElementsByTagName('body')[0]) != null ? _ref.innerText : void 0;
});
if (text) {
@@ -133,12 +197,20 @@
};
specsDone = function() {
+ var filename, output, xml_results;
+ if (options.junit === true) {
+ xml_results = getXmlResults(page, resultsKey);
+ for (filename in xml_results) {
+ if (xml_results.hasOwnProperty(filename) && (output = xml_results[filename]) && typeof output === 'string') {
+ fs.write(filename, output, 'w');
+ }
+ }
+ }
return phantom.exit();
};
waitFor = function(test, ready, timeout, timeoutFunction) {
var condition, interval, start, wait;
-
if (timeout == null) {
timeout = 10000;
}
diff --git a/lib/guard/jasmine/phantomjs/lib/console.js b/lib/guard/jasmine/phantomjs/lib/console.js
index 34cc39b..97aea14 100644
--- a/lib/guard/jasmine/phantomjs/lib/console.js
+++ b/lib/guard/jasmine/phantomjs/lib/console.js
@@ -1,3 +1,4 @@
+// Generated by CoffeeScript 1.6.3
(function() {
var Console,
__slice = [].slice;
@@ -5,35 +6,29 @@
Console = (function() {
function Console(console) {
var log;
-
log = console.log;
console.log = function() {
var args;
-
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return log.call(console, Console.format.apply(Console, args));
};
console.info = function() {
var args;
-
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return log.call(console, "INFO: " + (Console.format.apply(Console, args)));
};
console.warn = function() {
var args;
-
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return log.call(console, "WARN: " + (Console.format.apply(Console, args)));
};
console.error = function() {
var args;
-
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return log.call(console, "ERROR: " + (Console.format.apply(Console, args)));
};
console.debug = function() {
var args;
-
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return log.call(console, "DEBUG: " + (Console.format.apply(Console, args)));
};
@@ -44,7 +39,6 @@
Console.format = function() {
var arg, args, result, _i, _len,
_this = this;
-
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
result = [];
if (typeof args[0] === 'string' && /%[sdifo]/gi.test(args[0])) {
@@ -62,7 +56,6 @@
Console.inspect = function(object, type) {
var match, result;
-
switch (type) {
case '%s':
result = String(object);
@@ -100,7 +93,6 @@
Console.pp = function(object, depth) {
var key, result, type, value, _i, _len;
-
if (depth == null) {
depth = 0;
}
diff --git a/lib/guard/jasmine/phantomjs/lib/junit_reporter.js b/lib/guard/jasmine/phantomjs/lib/junit_reporter.js
new file mode 100644
index 0000000..0f8df05
--- /dev/null
+++ b/lib/guard/jasmine/phantomjs/lib/junit_reporter.js
@@ -0,0 +1,224 @@
+(function() {
+ function elapsed(startTime, endTime) {
+ return (endTime - startTime)/1000;
+ }
+
+ function ISODateString(d) {
+ function pad(n) { return n < 10 ? '0'+n : n; }
+
+ return d.getFullYear() + '-' +
+ pad(d.getMonth()+1) + '-' +
+ pad(d.getDate()) + 'T' +
+ pad(d.getHours()) + ':' +
+ pad(d.getMinutes()) + ':' +
+ pad(d.getSeconds());
+ }
+
+ function trim(str) {
+ return str.replace(/^\s+/, "" ).replace(/\s+$/, "" );
+ }
+
+ function escapeInvalidXmlChars(str) {
+ return str.replace(/\&/g, "&")
+ .replace(//g, ">")
+ .replace(/\"/g, """)
+ .replace(/\'/g, "'");
+ }
+
+ /**
+ * Generates JUnit XML for the given spec run.
+ * Allows the test results to be used in java based CI
+ * systems like CruiseControl and Hudson.
+ *
+ * @param {string} savePath where to save the files
+ * @param {boolean} consolidate whether to save nested describes within the
+ * same file as their parent; default: true
+ * @param {boolean} useDotNotation whether to separate suite names with
+ * dots rather than spaces (ie "Class.init" not
+ * "Class init"); default: true
+ */
+ var JUnitXmlReporter = function(savePath, consolidate, useDotNotation) {
+ this.savePath = savePath || '';
+ this.consolidate = consolidate === jasmine.undefined ? true : consolidate;
+ this.useDotNotation = useDotNotation === jasmine.undefined ? true : useDotNotation;
+ };
+ JUnitXmlReporter.finished_at = null; // will be updated after all files have been written
+
+ JUnitXmlReporter.prototype = {
+ reportSpecStarting: function(spec) {
+ spec.startTime = new Date();
+
+ if (!spec.suite.startTime) {
+ spec.suite.startTime = spec.startTime;
+ }
+ },
+
+ reportSpecResults: function(spec) {
+ var results = spec.results();
+ spec.didFail = !results.passed();
+ spec.duration = elapsed(spec.startTime, new Date());
+ spec.output = '';
+ if(results.skipped) {
+ spec.output = spec.output + "";
+ }
+
+ var failure = "";
+ var failures = 0;
+ var resultItems = results.getItems();
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'expect' && result.passed && !result.passed()) {
+ failures += 1;
+ failure += '';
+ failure += escapeInvalidXmlChars(result.trace.stack || result.message);
+ failure += "";
+ }
+ }
+ if (failure) {
+ spec.output += failure;
+ }
+ spec.output += "";
+ },
+
+ reportSuiteResults: function(suite) {
+ var results = suite.results();
+ var specs = suite.specs();
+ var specOutput = "";
+ // for JUnit results, let's only include directly failed tests (not nested suites')
+ var failedCount = 0;
+
+ suite.status = results.passed() ? 'Passed.' : 'Failed.';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ suite.status = 'Skipped.';
+ }
+
+ // if a suite has no (active?) specs, reportSpecStarting is never called
+ // and thus the suite has no startTime -- account for that here
+ suite.startTime = suite.startTime || new Date();
+ suite.duration = elapsed(suite.startTime, new Date());
+
+ for (var i = 0; i < specs.length; i++) {
+ failedCount += specs[i].didFail ? 1 : 0;
+ specOutput += "\n " + specs[i].output;
+ }
+ suite.output = '\n';
+ suite.output += specOutput;
+ suite.output += "\n";
+ },
+
+ reportRunnerResults: function(runner) {
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var fileName = 'TEST-' + this.getFullName(suite, true) + '.xml';
+ var output = '';
+ // if we are consolidating, only write out top-level suites
+ if (this.consolidate && suite.parentSuite) {
+ continue;
+ }
+ else if (this.consolidate) {
+ output += "\n";
+ output += this.getNestedOutput(suite);
+ output += "\n";
+ this.writeFile(this.savePath, fileName, output);
+ }
+ else {
+ output += suite.output;
+ this.writeFile(this.savePath, fileName, output);
+ }
+ }
+ // When all done, make it known on JUnitXmlReporter
+ JUnitXmlReporter.finished_at = (new Date()).getTime();
+ },
+
+ getNestedOutput: function(suite) {
+ var output = suite.output;
+ for (var i = 0; i < suite.suites().length; i++) {
+ output += this.getNestedOutput(suite.suites()[i]);
+ }
+ return output;
+ },
+
+ writeFile: function(path, filename, text) {
+ function getQualifiedFilename(separator) {
+ if (path && path.substr(-1) !== separator && filename.substr(0) !== separator) {
+ path += separator;
+ }
+ return path + filename;
+ }
+
+ // Rhino
+ try {
+ // turn filename into a qualified path
+ if (path) {
+ filename = getQualifiedFilename(java.lang.System.getProperty("file.separator"));
+ // create parent dir and ancestors if necessary
+ var file = java.io.File(filename);
+ var parentDir = file.getParentFile();
+ if (!parentDir.exists()) {
+ parentDir.mkdirs();
+ }
+ }
+ // finally write the file
+ var out = new java.io.BufferedWriter(new java.io.FileWriter(filename));
+ out.write(text);
+ out.close();
+ return;
+ } catch (e) {}
+ // PhantomJS, via a method injected by phantomjs-testrunner.js
+ try {
+ // turn filename into a qualified path
+ filename = getQualifiedFilename(window.fs_path_separator);
+ __phantom_writeFile(filename, text);
+ return;
+ } catch (f) {}
+ // Node.js
+ try {
+ var fs = require("fs");
+ var nodejs_path = require("path");
+ var fd = fs.openSync(nodejs_path.join(path, filename), "w");
+ fs.writeSync(fd, text, 0);
+ fs.closeSync(fd);
+ return;
+ } catch (g) {}
+ },
+
+ getFullName: function(suite, isFilename) {
+ var fullName;
+ if (this.useDotNotation) {
+ fullName = suite.description;
+ for (var parentSuite = suite.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ fullName = parentSuite.description + '.' + fullName;
+ }
+ }
+ else {
+ fullName = suite.getFullName();
+ }
+
+ // Either remove or escape invalid XML characters
+ if (isFilename) {
+ return fullName.replace(/[^\w]/g, "");
+ }
+ return escapeInvalidXmlChars(fullName);
+ },
+
+ log: function(str) {
+ var console = jasmine.getGlobal().console;
+
+ if (console && console.log) {
+ console.log(str);
+ }
+ }
+ };
+
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = JUnitXmlReporter;
+ } else {
+ window.JUnitXmlReporter = JUnitXmlReporter;
+ }
+}).call(this);
diff --git a/lib/guard/jasmine/phantomjs/lib/reporter.js b/lib/guard/jasmine/phantomjs/lib/reporter.js
index e18e225..6c0bdb0 100644
--- a/lib/guard/jasmine/phantomjs/lib/reporter.js
+++ b/lib/guard/jasmine/phantomjs/lib/reporter.js
@@ -1,3 +1,4 @@
+// Generated by CoffeeScript 1.6.3
(function() {
var ConsoleReporter;
@@ -26,7 +27,6 @@
ConsoleReporter.prototype.reportSpecResults = function(spec) {
var messages, result, specResult, _base, _i, _len, _name, _ref;
-
if (!spec.results().skipped) {
specResult = {
id: spec.id,
@@ -52,7 +52,6 @@
ConsoleReporter.prototype.reportSuiteResults = function(suite) {
var parent, suiteResult, _base, _ref;
-
if (!suite.results().skipped) {
suiteResult = {
id: suite.id,
@@ -78,7 +77,6 @@
ConsoleReporter.prototype.reportRunnerResults = function(runner) {
var end, runtime;
-
runtime = (new Date().getTime() - this.startTime) / 1000;
this.runnerResult['passed'] = runner.results().failedCount === 0;
this.runnerResult['stats'] = {
@@ -101,7 +99,6 @@
ConsoleReporter.prototype.addNestedSuites = function(suiteResult) {
var suite, _i, _len, _ref, _results;
-
if (this.nestedSuiteResults[suiteResult.id]) {
_ref = this.nestedSuiteResults[suiteResult.id];
_results = [];
@@ -116,7 +113,6 @@
ConsoleReporter.prototype.removeEmptySuites = function(suiteResult) {
var suite, suites, _i, _len, _ref;
-
suites = [];
_ref = suiteResult.suites;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
diff --git a/lib/guard/jasmine/phantomjs/lib/result.js b/lib/guard/jasmine/phantomjs/lib/result.js
index 1abdbb9..10decea 100644
--- a/lib/guard/jasmine/phantomjs/lib/result.js
+++ b/lib/guard/jasmine/phantomjs/lib/result.js
@@ -1,3 +1,4 @@
+// Generated by CoffeeScript 1.6.3
(function() {
var Result;
@@ -11,10 +12,8 @@
Result.prototype.addLogs = function(suite) {
var id, s, spec;
-
suite.suites = (function() {
var _i, _len, _ref, _results;
-
_ref = suite.suites;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@@ -26,7 +25,6 @@
if (suite.specs) {
suite.specs = (function() {
var _i, _len, _ref, _results;
-
_ref = suite.specs;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@@ -47,10 +45,8 @@
Result.prototype.addErrors = function(suite) {
var id, s, spec;
-
suite.suites = (function() {
var _i, _len, _ref, _results;
-
_ref = suite.suites;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@@ -62,7 +58,6 @@
if (suite.specs) {
suite.specs = (function() {
var _i, _len, _ref, _results;
-
_ref = suite.specs;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@@ -83,7 +78,6 @@
Result.prototype.addGlobalError = function(suite) {
var b, err, errMsg, globalErrors, noSpecs, noSuites, _i, _len, _ref;
-
noSuites = !suite.suites || suite.suites.length === 0;
noSpecs = !suite.specs || suite.specs.length === 0;
globalErrors = this.errors[-1] && this.errors[-1].length !== 0;
@@ -102,10 +96,8 @@
Result.prototype.cleanResult = function(suite) {
var s, spec, _i, _len, _ref;
-
suite.suites = (function() {
var _i, _len, _ref, _results;
-
_ref = suite.suites;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
diff --git a/lib/guard/jasmine/runner.rb b/lib/guard/jasmine/runner.rb
index cdca6f8..e98a496 100644
--- a/lib/guard/jasmine/runner.rb
+++ b/lib/guard/jasmine/runner.rb
@@ -94,7 +94,19 @@ def response_status_for(results)
def run_jasmine_spec(file, options)
suite = jasmine_suite(file, options)
Formatter.info("Run Jasmine suite at #{ suite }")
- IO.popen("#{ phantomjs_command(options) } \"#{ suite }\" #{ options[:timeout] * 1000 } #{ options[:specdoc] } #{ options[:focus] } #{ options[:console] } #{ options[:errors] }", 'r:UTF-8')
+
+ arguments = [
+ options[:timeout] * 1000,
+ options[:specdoc],
+ options[:focus],
+ options[:console],
+ options[:errors],
+ options[:junit],
+ options[:junit_consolidate],
+ "\"#{options[:junit_save_path]}\""
+ ]
+
+ IO.popen("#{ phantomjs_command(options) } \"#{ suite }\" #{arguments.collect {|i| i.to_s}.join(" ")}", 'r:UTF-8')
end
# Get the PhantomJS binary and script to execute.