hem
Version:
stitches CommonJS, and ties up other lose ends of web-app development.
199 lines (155 loc) • 6.1 kB
text/coffeescript
log = require("./log")
# attempt to load the phantom module, which is an optional
# dependency. If not available return an empty object
try
phantom = require 'phantom'
catch err
phantom = undefined
# ------- Test Result Formatters
# TODO: need to make this work with mocha at some point
reporters =
errorsOnly: (el, level, strong) ->
indent = (level) ->
ret = ''
ret = ret + ' ' for i in [0..level]
ret
desc = (el) -> $(el).find('> a.description')[0].text
tick = (el) -> if $(el).is('.passed') then '✓ ' else '✖ '
if typeof el is 'number'
return "Passed: " + el + ", Failed: " + level
else if (!$(el).is(".passed"))
return indent(level) + tick(el) + desc(el)
silent: -> return ""
passOrFail: (el, level, strong) ->
if typeof el is 'number'
return "Passed: " + el + ", Failed: " + level
formatColors: (el, level, strong) ->
indent = (level) ->
ret = ''
ret = ret + ' ' for i in [0..level]
ret
tick = (el) ->
if $(el).is('.passed') then '\x1B[32m✓\x1B[0m' else '\x1B[31m✖'
desc = (el, strong = false) ->
ret = $(el).find('> a.description')
ret = strong and '\x1B[1m' + ret[0].text or ret[0].text
# display final results
if typeof el is 'number'
results= "-------------------------------------\n"
results += "\x1B[32m✓\x1B[0m\x1B[1m Passed: \x1B[0m" + el
if level > 0
results += "\n\x1B[31m✖ \x1B[0m\x1B[1mFailed: \x1B[0m" + level
return results
# format output
else
return '\x1B[1m' + indent(level) + tick(el) + ' ' + desc(el, strong)
# ------- Wait for certain page elements to become visible
waitFor = (->
getTime = -> (new Date).getTime()
return (test, doIt, duration) ->
duration or= 60000
start = getTime()
finish = start + duration
int = undefined
# looop function to call using setInterval
looop = ->
time = getTime()
timeout = (time >= finish)
# callback for page evaluate that receives results
testCallback = (condition) ->
# No more time or condition fulfilled
if condition
clearInterval(int)
doIt(time - start)
# THEN, no moretime but condition unfulfilled
if timeout and not condition
clearInterval(int)
doIt(0, "Timeout for page condition.")
# perform the test evaluation
test(testCallback)
# the intervale number
int = setInterval(looop, 1000 )
)()
# ------- Jasmine Functions
jasmine_parseTestResults = (report) ->
# parameters need to be passed in as a simple string so we
# need to turn report back into a real javascript function
eval("report = " + report)
# handle looping over suites
printSuites = (root, level) ->
level or= 0
$(root).find('div.suite').each( (i, el) ->
output = report(el, level, true)
if $(el).parents('div.suite').length is level
window.callPhantom(output) if output
printSpecs(el, level + 1)
printSuites(el, level + 1)
)
# handle looping over specs
printSpecs = (root, level) ->
level or= 0
$(root).find('> .specSummary').each( (i, el) ->
output = report(el, level)
window.callPhantom(output) if output
)
# our starting point
printSuites($('div.jasmine_reporter'))
# handle results
failed = document.body.querySelectorAll('div.jasmine_reporter div.specSummary.failed').length
passed = document.body.querySelectorAll('div.jasmine_reporter div.specSummary.passed').length
window.callPhantom(report(passed, failed))
# return results, these will be eventually passed to the
# the callback function that was provided initially.
return passed: passed, failed: failed
jasmine_checkTestResults = (page) ->
(checkComplete) ->
isCheckComplete = -> document.querySelector(".duration")?.innerText
page.evaluate(isCheckComplete, checkComplete)
# ------- Public Functions
run = (filepath, options, callback, port = 12300) ->
log.info "Testing file <yellow>#{filepath}</yellow> on port <blue>#{port}</blue>"
phantom.create( (ph) ->
ph.createPage( (page) ->
# print console.log output from the webpage
page.set('onConsoleMessage', (msg) -> console.log(msg))
# page callback, kind of a hackish way to only allow our phantom
# script to make use of console.log so we only see test results.
page.set('onCallback', (msg) -> console.log(msg) if msg)
# open the filepath and beging tests
page.open filepath, (status) ->
if status isnt "success"
ph.exit()
callback({ error: "Cannot open URL" })
return
# assign the appropiate framework functions
checkTestResults = jasmine_checkTestResults(page)
parseTestResults = jasmine_parseTestResults
# function to call upon completion of test parsing
complete = (results) ->
ph.exit()
callback?(results)
# ability to request different type of outputs, default to formatColors
reporter = reporters[options.output]
# function to call the parsing function, along with callback once
# everything is complete and the reporter instance that is passed
# to the parseTestResults function. If time parameter is 0 then
# assume that the tests never fully completed.
evalTestResults = (time, err) ->
if err
complete({error: err})
else
page.evaluate( parseTestResults, complete, new String(reporter))
# wait for indication tests are done and then
# eval/print the test results, all passing, yay!
waitFor(checkTestResults, evalTestResults)
)
, { port: port } )
# ------- Exports
# check to make sure phantom is loaded correctly and if
# not then display an appropiate error message...
if phantom
module.exports.run = run
else
module.exports.run = -> log.error "Unable to require('phantom') npm module..."
# export reporters object to allow custom code
module.exports.reporters = reporters