-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New reporter that supports Jasmine 2 API
This adds a new reporter that uses the Jasmine 2 JsApiReporter API. It creates an almost identical JSON response to the old API but with a few differences. The main one being that it's unable to create the "messages" array for each spec. Instead it puts the messages on the "errors" array, but has more detail about the expectation that failed. It's a first pass at resolving # 161
- Loading branch information
1 parent
a911a82
commit 392aa6d
Showing
13 changed files
with
404 additions
and
1,456 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,193 +1,100 @@ | ||
# This file is the script that runs within PhantomJS, requests the Jasmine specs | ||
# and waits until they are ready. | ||
phantom.injectJs 'lib/result.js' | ||
|
||
# Set default values | ||
options = | ||
url: phantom.args[0] || 'http://127.0.0.1:3000/jasmine' | ||
timeout: parseInt(phantom.args[1] || 10000) | ||
specdoc: phantom.args[2] || 'failure' | ||
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. | ||
# | ||
page = require('webpage').create() | ||
|
||
# Used to collect log messages for later assignment to the spec | ||
# | ||
currentSpecId = -1 | ||
logs = {} | ||
errors = {} | ||
resultsKey = "__jr" + Math.ceil(Math.random() * 1000000) | ||
fs = require("fs") | ||
|
||
# Catch JavaScript errors | ||
# | ||
page.onError = (msg, trace) -> | ||
if currentSpecId | ||
errors[currentSpecId] ||= [] | ||
errors[currentSpecId].push({ msg: msg, trace: trace }) | ||
|
||
# Capture console.log output to add it to | ||
# the result when specs have finished. | ||
# | ||
page.onConsoleMessage = (msg, line, source) -> | ||
if /^RUNNER_END$/.test(msg) | ||
result = page.evaluate -> window.reporter.runnerResult | ||
console.log JSON.stringify(new Result(result, logs, errors, options).process()) | ||
page.evaluate -> window.resultReceived = true | ||
|
||
else if /^SPEC_START: (\d+)$/.test(msg) | ||
currentSpecId = Number(RegExp.$1) | ||
# abort the request and return the error | ||
page.onError = (message, trace) -> | ||
reportError "Javascript error encountered on Jasmine test page: #{ message }", trace | ||
|
||
else | ||
logs[currentSpecId] ||= [] | ||
logs[currentSpecId].push(msg) | ||
|
||
# Initialize the page before the JavaScript is run. | ||
# | ||
# Once the page is initialized, setup the script for | ||
# the GuardReporter class | ||
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' | ||
|
||
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) -> | ||
# Avoid that a failed iframe load breaks the runner, see https://github.com/netzpirat/guard-jasmine/pull/19 | ||
page.onLoadFinished = -> | ||
if status isnt 'success' | ||
console.log JSON.stringify({ error: "Unable to access Jasmine specs at #{ options.url }" }) | ||
phantom.exit() | ||
else | ||
waitFor jasmineReady, jasmineAvailable, options.timeout, jasmineMissing | ||
page.injectJs 'guard-reporter.js' | ||
page.evaluate -> | ||
window.onload = -> | ||
window.reporter = new GuardReporter() | ||
window.jasmine.getEnv().addReporter(window.reporter) | ||
|
||
# Once the page is finished loading | ||
page.onLoadFinished = (status)-> | ||
if status isnt 'success' | ||
reportError "Unable to access Jasmine specs at #{ options.url }, page returned status: #{status}" | ||
else | ||
waitFor reporterReady, jasmineAvailable, options.timeout, reporterMissing | ||
|
||
# Test if the jasmine has been loaded | ||
# | ||
jasmineReady = -> | ||
page.evaluate -> window.jasmine | ||
# Open web page, which will kick off the Jasmine test runner | ||
page.open options.url | ||
|
||
# Test if Jasmine and guard has been loaded | ||
reporterReady = -> | ||
page.evaluate -> | ||
window.jasmine && window.reporter | ||
|
||
# Start specs after they are have been loaded | ||
# | ||
jasmineAvailable = -> | ||
waitFor specsReady, specsDone, options.timeout, specsTimedout | ||
waitFor specsDone, exitSuccessfully, options.timeout, specsTimedout | ||
|
||
# Error message for when jasmine never loaded asynchronously | ||
# | ||
jasmineMissing = -> | ||
reporterMissing = -> | ||
text = page.evaluate -> document.getElementsByTagName('body')[0]?.innerText | ||
|
||
if text | ||
error = """ | ||
The Jasmine reporter is not available! | ||
reportError """ | ||
The reporter is not available! | ||
Perhaps the url ( #{ options.url } ) is incorrect? | ||
#{ text } | ||
""" | ||
console.log JSON.stringify({ error: error }) | ||
else | ||
console.log JSON.stringify({ error: 'The Jasmine reporter is not available!' }) | ||
|
||
# Test if the specs have finished. | ||
# | ||
specsReady = -> | ||
page.evaluate -> window.resultReceived | ||
# tests if the resultComplete flag is set on the reporter | ||
specsDone = -> | ||
result = page.evaluate -> | ||
window.reporter.resultComplete | ||
|
||
# We should end up here. Logs the results as JSON and exits | ||
exitSuccessfully = -> | ||
results = page.evaluate -> window.reporter.results() | ||
console.log JSON.stringify( results ) | ||
phantom.exit() | ||
|
||
|
||
# Error message for when specs time out | ||
# | ||
specsTimedout = -> | ||
text = page.evaluate -> document.getElementsByTagName('body')[0]?.innerText | ||
if text | ||
error = """ | ||
reportError """ | ||
Timeout waiting for the Jasmine test results! | ||
#{ text } | ||
""" | ||
console.log JSON.stringify({ error: error }) | ||
else | ||
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. | ||
# | ||
# @param [Function] test the test that returns true if condition is met | ||
# @param [Function] ready the action when the condition is fulfilled | ||
# @param [Number] timeout the max amount of time to wait in milliseconds | ||
# | ||
waitFor = (test, ready, timeout = 10000, timeoutFunction) -> | ||
start = Date.now() | ||
condition = false | ||
interval = undefined | ||
|
||
wait = -> | ||
if (Date.now() - start < timeout) and not condition | ||
condition = test() | ||
else | ||
clearInterval interval | ||
|
||
if condition | ||
ready() | ||
else | ||
timeoutFunction() | ||
phantom.exit(1) | ||
|
||
interval = setInterval wait, 250 | ||
waitFor = (test, ready, timeout = 10000, timeoutFunction)-> | ||
condition = false | ||
interval = undefined | ||
start = Date.now(0) | ||
wait = -> | ||
if !condition && (Date.now() - start < timeout) | ||
condition = test() | ||
else | ||
clearInterval interval | ||
if condition | ||
ready() | ||
else | ||
timeoutFunction() | ||
interval = setInterval( wait, 250 ) | ||
|
||
# Logs the error to the console as JSON and exits with status '1' | ||
reportError = (msg, trace=[])-> | ||
if 0 == trace.length | ||
err = new Error(); | ||
trace = err.stack | ||
console.log JSON.stringify({ error: msg, trace: trace }) | ||
phantom.exit(1) |
Oops, something went wrong.
392aa6d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nathanstitt Does the new jasmine reporter still support dumping an xunit results file which can be consumed by tools like Jenkins? This was a feature that @edspencer implemented in 2013 using @larrymyers junit reporter but seems to have been lost since this commit.
392aa6d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately yes, the unit reporter was removed there. I'm trying to remember the reasoning but I suspect it was because the junit reporter wasn't compatible with Jasmine 2.
here's the old reporter https://github.com/guard/guard-jasmine/blob/840b385df59a5c9624d4ebf65c974f105f6d29c4/lib/guard/jasmine/phantomjs/lib/junit_reporter.js
The current Guard Jasmine reporter: https://github.com/guard/guard-jasmine/blob/master/lib/guard/jasmine/phantomjs/src/guard-jasmine.coffee
If someone was interested in migrating the junit reporter to Jasmine2 I'd be willing to help. I don't know anything about junit though so probably wouldn't be the best to take the lead on it.
392aa6d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latest report claims compatibility with Jasmine 2.0
https://github.com/larrymyers/jasmine-reporters
Would you be able to swap in the new reporter (https://github.com/larrymyers/jasmine-reporters/blob/master/src/junit_reporter.js)? The arguments to dump the report are still in the code but not functional at the moment.