Skip to content

Commit 392aa6d

Browse files
committed
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
1 parent a911a82 commit 392aa6d

13 files changed

+404
-1456
lines changed

Diff for: lib/guard/jasmine/phantomjs/guard-jasmine.coffee

+63-156
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,100 @@
1-
# This file is the script that runs within PhantomJS, requests the Jasmine specs
2-
# and waits until they are ready.
3-
phantom.injectJs 'lib/result.js'
4-
51
# Set default values
62
options =
73
url: phantom.args[0] || 'http://127.0.0.1:3000/jasmine'
84
timeout: parseInt(phantom.args[1] || 10000)
9-
specdoc: phantom.args[2] || 'failure'
10-
focus: /true/i.test phantom.args[3]
11-
console: phantom.args[4] || 'failure'
12-
errors: phantom.args[5] || 'failure'
13-
junit: /true/i.test phantom.args[6]
14-
junit_consolidate: /true/i.test phantom.args[7]
15-
junit_save_path: phantom.args[8] || ''
165

176
# Create the web page.
18-
#
197
page = require('webpage').create()
208

21-
# Used to collect log messages for later assignment to the spec
22-
#
23-
currentSpecId = -1
24-
logs = {}
25-
errors = {}
26-
resultsKey = "__jr" + Math.ceil(Math.random() * 1000000)
27-
fs = require("fs")
28-
299
# Catch JavaScript errors
30-
#
31-
page.onError = (msg, trace) ->
32-
if currentSpecId
33-
errors[currentSpecId] ||= []
34-
errors[currentSpecId].push({ msg: msg, trace: trace })
35-
36-
# Capture console.log output to add it to
37-
# the result when specs have finished.
38-
#
39-
page.onConsoleMessage = (msg, line, source) ->
40-
if /^RUNNER_END$/.test(msg)
41-
result = page.evaluate -> window.reporter.runnerResult
42-
console.log JSON.stringify(new Result(result, logs, errors, options).process())
43-
page.evaluate -> window.resultReceived = true
44-
45-
else if /^SPEC_START: (\d+)$/.test(msg)
46-
currentSpecId = Number(RegExp.$1)
10+
# abort the request and return the error
11+
page.onError = (message, trace) ->
12+
reportError "Javascript error encountered on Jasmine test page: #{ message }", trace
4713

48-
else
49-
logs[currentSpecId] ||= []
50-
logs[currentSpecId].push(msg)
51-
52-
# Initialize the page before the JavaScript is run.
53-
#
14+
# Once the page is initialized, setup the script for
15+
# the GuardReporter class
5416
page.onInitialized = ->
55-
overloadPageEvaluate(page)
56-
setupWriteFileFunction(page, resultsKey, fs.separator)
57-
58-
page.injectJs 'lib/console.js'
59-
page.injectJs 'lib/reporter.js'
60-
page.injectJs 'lib/junit_reporter.js'
61-
62-
setupReporters = ->
63-
# Attach the console reporter when the document is ready.
64-
window.onload = ->
65-
window.onload = null
66-
window.resultReceived = false
67-
window.reporter = new ConsoleReporter()
68-
if window.jasmine
69-
jasmine.getEnv().addReporter(new JUnitXmlReporter("%save_path%", "%consolidate%"))
70-
jasmine.getEnv().addReporter(window.reporter)
71-
72-
page.evaluate(setupReporters, {save_path: options.junit_save_path, consolidate: options.junit_consolidate})
73-
74-
75-
getXmlResults = (page, key) ->
76-
getWindowObj = ->
77-
window["%resultsObj%"] || {}
78-
page.evaluate getWindowObj, {resultsObj: key}
79-
80-
replaceFunctionPlaceholders= (fn, replacements) ->
81-
if replacements && typeof replacements == 'object'
82-
fn = fn.toString()
83-
for p of replacements
84-
if replacements.hasOwnProperty(p)
85-
match = new RegExp("%" + p + "%", "g")
86-
loop
87-
fn = fn.replace(match, replacements[p])
88-
break unless fn.indexOf(match) != -1
89-
fn
90-
91-
overloadPageEvaluate = (page) ->
92-
page._evaluate = page.evaluate
93-
page.evaluate = (fn, replacements) ->
94-
page._evaluate(replaceFunctionPlaceholders(fn, replacements))
95-
page
96-
97-
setupWriteFileFunction= (page,key, path_separator) ->
98-
saveData = () ->
99-
window["%resultsObj%"] = {}
100-
window.fs_path_separator = "%fs_path_separator%"
101-
window.__phantom_writeFile = (filename, text) ->
102-
window["%resultsObj%"][filename] = text;
103-
104-
page.evaluate saveData, {resultsObj: key, fs_path_separator: path_separator}
105-
106-
# Open web page and run the Jasmine test runner
107-
#
108-
page.open options.url, (status) ->
109-
# Avoid that a failed iframe load breaks the runner, see https://github.com/netzpirat/guard-jasmine/pull/19
110-
page.onLoadFinished = ->
111-
if status isnt 'success'
112-
console.log JSON.stringify({ error: "Unable to access Jasmine specs at #{ options.url }" })
113-
phantom.exit()
114-
else
115-
waitFor jasmineReady, jasmineAvailable, options.timeout, jasmineMissing
17+
page.injectJs 'guard-reporter.js'
18+
page.evaluate ->
19+
window.onload = ->
20+
window.reporter = new GuardReporter()
21+
window.jasmine.getEnv().addReporter(window.reporter)
22+
23+
# Once the page is finished loading
24+
page.onLoadFinished = (status)->
25+
if status isnt 'success'
26+
reportError "Unable to access Jasmine specs at #{ options.url }, page returned status: #{status}"
27+
else
28+
waitFor reporterReady, jasmineAvailable, options.timeout, reporterMissing
11629

117-
# Test if the jasmine has been loaded
118-
#
119-
jasmineReady = ->
120-
page.evaluate -> window.jasmine
30+
# Open web page, which will kick off the Jasmine test runner
31+
page.open options.url
32+
33+
# Test if Jasmine and guard has been loaded
34+
reporterReady = ->
35+
page.evaluate ->
36+
window.jasmine && window.reporter
12137

12238
# Start specs after they are have been loaded
123-
#
12439
jasmineAvailable = ->
125-
waitFor specsReady, specsDone, options.timeout, specsTimedout
40+
waitFor specsDone, exitSuccessfully, options.timeout, specsTimedout
12641

12742
# Error message for when jasmine never loaded asynchronously
128-
#
129-
jasmineMissing = ->
43+
reporterMissing = ->
13044
text = page.evaluate -> document.getElementsByTagName('body')[0]?.innerText
131-
132-
if text
133-
error = """
134-
The Jasmine reporter is not available!
45+
reportError """
46+
The reporter is not available!
47+
Perhaps the url ( #{ options.url } ) is incorrect?
13548
13649
#{ text }
13750
"""
138-
console.log JSON.stringify({ error: error })
139-
else
140-
console.log JSON.stringify({ error: 'The Jasmine reporter is not available!' })
14151

142-
# Test if the specs have finished.
143-
#
144-
specsReady = ->
145-
page.evaluate -> window.resultReceived
52+
# tests if the resultComplete flag is set on the reporter
53+
specsDone = ->
54+
result = page.evaluate ->
55+
window.reporter.resultComplete
56+
57+
# We should end up here. Logs the results as JSON and exits
58+
exitSuccessfully = ->
59+
results = page.evaluate -> window.reporter.results()
60+
console.log JSON.stringify( results )
61+
phantom.exit()
62+
14663

14764
# Error message for when specs time out
148-
#
14965
specsTimedout = ->
15066
text = page.evaluate -> document.getElementsByTagName('body')[0]?.innerText
151-
if text
152-
error = """
67+
reportError """
15368
Timeout waiting for the Jasmine test results!
15469
15570
#{ text }
15671
"""
157-
console.log JSON.stringify({ error: error })
158-
else
159-
console.log JSON.stringify({ error: 'Timeout for the Jasmine test results!' })
160-
161-
specsDone = ->
162-
if options.junit == true
163-
xml_results = getXmlResults(page, resultsKey)
164-
for filename of xml_results
165-
if xml_results.hasOwnProperty(filename) && (output = xml_results[filename]) && typeof(output) == 'string'
166-
fs.write(filename, output, 'w')
167-
168-
phantom.exit()
16972

17073
# Wait until the test condition is true or a timeout occurs.
17174
#
17275
# @param [Function] test the test that returns true if condition is met
17376
# @param [Function] ready the action when the condition is fulfilled
17477
# @param [Number] timeout the max amount of time to wait in milliseconds
17578
#
176-
waitFor = (test, ready, timeout = 10000, timeoutFunction) ->
177-
start = Date.now()
178-
condition = false
179-
interval = undefined
180-
181-
wait = ->
182-
if (Date.now() - start < timeout) and not condition
183-
condition = test()
184-
else
185-
clearInterval interval
186-
187-
if condition
188-
ready()
189-
else
190-
timeoutFunction()
191-
phantom.exit(1)
192-
193-
interval = setInterval wait, 250
79+
waitFor = (test, ready, timeout = 10000, timeoutFunction)->
80+
condition = false
81+
interval = undefined
82+
start = Date.now(0)
83+
wait = ->
84+
if !condition && (Date.now() - start < timeout)
85+
condition = test()
86+
else
87+
clearInterval interval
88+
if condition
89+
ready()
90+
else
91+
timeoutFunction()
92+
interval = setInterval( wait, 250 )
93+
94+
# Logs the error to the console as JSON and exits with status '1'
95+
reportError = (msg, trace=[])->
96+
if 0 == trace.length
97+
err = new Error();
98+
trace = err.stack
99+
console.log JSON.stringify({ error: msg, trace: trace })
100+
phantom.exit(1)

0 commit comments

Comments
 (0)