neft
Version:
Universal Platform
196 lines (147 loc) • 5.16 kB
text/coffeescript
# Testing
'use strict'
{utils, log, assert} = Neft
stack = require './stack'
logger = require './logger'
screenshot = require './screenshot/client'
{isArray} = Array
{push} = Array::
{Scope, Test, Listener} = require './structure'
scopes = [new Scope]
currentScope = scopes[0]
ONLY_OPT = 1 << 1
raportOnlyUsed = ->
if process.env.CI
throw new Error "Cannot use describe.only and it.only on CI"
else
log.warn "describe.only or it.only is used"
# describe(*String* message, *Function* tests)
exports.describe = (msg, func, opts = 0) ->
beforeEach = utils.NOP
# new scope
scope = new Scope
scope.message = msg
if scope.isOnly = (opts & ONLY_OPT) > 0
stack.onlyScopes += 1
scopes.push scope
# before/after functions
push.apply scope.beforeFunctions, currentScope.beforeFunctions
push.apply scope.afterFunctions, currentScope.afterFunctions
# save scope to parent
currentScope.children.push scope
scope.parent = currentScope
# save as last
currentScope = scope
# children tests
func()
# set parent as last
scopes.pop()
currentScope = utils.last scopes
return
# describe.only(*String* message, *Function* tests)
exports.describe.only = (msg, func) ->
raportOnlyUsed()
exports.describe msg, func, ONLY_OPT
# it(*String* message, *Function* test)
The given test function can contains optional *callback* argument.
exports.it = (msg, func, opts = 0) ->
testScope = currentScope
# new test
test = new Test
test.message = msg
test.testFunction = func
if test.isOnly = (opts & ONLY_OPT) > 0
stack.onlyTests += 1
# add test into scope
scope = utils.last scopes
scope.children.push test
test.parent = scope
return
# it.only(*String* message, *Function* test)
exports.it.only = (msg, func) ->
raportOnlyUsed()
exports.it msg, func, ONLY_OPT
# beforeEach(*Function* code)
exports.beforeEach = (func) ->
currentScope.beforeFunctions.push func
return
# afterEach(*Function* code)
exports.afterEach = (func) ->
currentScope.afterFunctions.push func
return
# whenChange(*Object* watchObject, *Function* callback, [*Integer* maxDelay = `1000`])
exports.whenChange = do ->
listeners = []
checkListeners = ->
i = 0
while i < listeners.length
listener = listeners[i]
if listener.test()
listeners.splice i, 1
else
i++
if listeners.length > 0
setImmediate checkListeners
return
(obj, callback, maxDelay = 1000) ->
listener = new Listener
listener.object = obj
listener.objectCopy = utils.clone(obj)
listener.callback = callback
listener.maxDelay = maxDelay
if listeners.length is 0
setImmediate checkListeners
listeners.push listener
return
# takeScreenshot(*String|Object* options, [*Function* callback])
screenshotInitialized = false
exports.takeScreenshot = (opts, callback) ->
if typeof opts is 'string'
opts = expected: opts
unless opts?.expected
throw new Error "'expected' path not set in takeScreenshot"
{currentTest} = Test
assert.notOk currentTest.callbackCalled, """
takeScreenshot called but current test '#{currentTest.getFullMessage()}' \
is not pending
"""
currentTest.preventEnding = true
endCurrentTest = (err) ->
callback? err
currentTest.preventEnding = false
currentTest.onEnd err
unless screenshotInitialized
screenshotInitialized = true
screenshot.initialize (err) ->
if err
endCurrentTest err
else
exports.takeScreenshot opts, callback
return
screenshot.take opts, endCurrentTest
return
runTests = ->
[mainScope] = scopes
logger.onTestsStart()
mainScope.run ->
logger.onTestsEnd()
onTestsEnd
status: if stack.errors.length is 0 then 'success' else 'error'
testsAmount: stack.testsAmount
errors: stack.errors
onTestsEnd = (result) ->
code = if result.status is 'success' then 0 else 1
if utils.isServer
# give logs some time to be printed int stdout
setTimeout ->
process.exit code
, 100
runAutomatically = do ->
val = process?.env.RUN_TESTS
if typeof val is 'string'
val = try JSON.parse val
val ?= true
val
setImmediate ->
if runAutomatically
runTests()