[ospec] revamp async testing finalization
This commit is contained in:
parent
ff1a07df1b
commit
89b665fbf6
1 changed files with 32 additions and 24 deletions
|
|
@ -5,12 +5,10 @@ if (typeof module !== "undefined") module["exports"] = m()
|
|||
else window.o = m()
|
||||
})(function init(name) {
|
||||
var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty
|
||||
var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName
|
||||
|
||||
if (name != null) spec[name] = ctx = {}
|
||||
|
||||
try {throw new Error} catch (e) {
|
||||
var ospecFileName = e.stack && (/[\/\\](.*?):\d+:\d+/).test(e.stack) ? e.stack.match(/[\/\\](.*?):\d+:\d+/)[1] : null
|
||||
}
|
||||
function o(subject, predicate) {
|
||||
if (predicate === undefined) {
|
||||
if (results == null) throw new Error("Assertions should not occur outside test definitions")
|
||||
|
|
@ -72,8 +70,8 @@ else window.o = m()
|
|||
}
|
||||
if (ospecFileName == null) return stack.join("\n")
|
||||
// skip ospec-related entries on the stack
|
||||
while (stack[i] && stack[i].indexOf(ospecFileName) !== -1) i++
|
||||
// now we're in user code
|
||||
while (stack[i] != null && stack[i].indexOf(ospecFileName) !== -1) i++
|
||||
// now we're in user code (or past the stack end)
|
||||
return stack[i]
|
||||
}
|
||||
o.run = function(reporter) {
|
||||
|
|
@ -81,6 +79,7 @@ else window.o = m()
|
|||
start = new Date
|
||||
test(spec, [], [], new Task(function() {
|
||||
setTimeout(function () {
|
||||
timeoutStackName = getStackName({stack: o.cleanStackTrace(ensureStackTrace(new Error))}, /([\w \.]+?:\d+:\d+)/)
|
||||
if (typeof reporter === "function") reporter(results)
|
||||
else {
|
||||
var errCount = o.report(results)
|
||||
|
|
@ -119,50 +118,54 @@ else window.o = m()
|
|||
if (cursor === tasks.length) return
|
||||
|
||||
var task = tasks[cursor++]
|
||||
var current = cursor
|
||||
var fn = task.fn
|
||||
var timeout = 0, delay = 200, s = new Date
|
||||
var isDone = false
|
||||
var arg
|
||||
|
||||
var isDone = false
|
||||
// public API, may only be called once from use code (or after returned Promise resolution)
|
||||
function done(err) {
|
||||
if (!isDone) isDone = true
|
||||
else throw new Error("`" + arg + "()` should only be called once")
|
||||
|
||||
if (timeout === undefined) console.warn("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms\n" + o.cleanStackTrace(task.err))
|
||||
finalizeAsync(err)
|
||||
}
|
||||
// for internal use only
|
||||
function finalizeAsync(err) {
|
||||
if (err) {
|
||||
if (err instanceof Error) record(err.message, err)
|
||||
else record(String(err))
|
||||
subjects.pop()
|
||||
next()
|
||||
if (err instanceof Error) record(err.message, err, task.err)
|
||||
else record(String(err), null, task.err)
|
||||
}
|
||||
if (timeout !== undefined) {
|
||||
timeout = clearTimeout(timeout)
|
||||
if (delay !== Infinity) record(null)
|
||||
if (!isDone) next()
|
||||
else throw new Error("`" + arg + "()` should only be called once")
|
||||
isDone = true
|
||||
}
|
||||
else console.log("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms")
|
||||
if (current === cursor) next()
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
timeout = setTimeout(function() {
|
||||
timeout = undefined
|
||||
record("async test timed out", task.err)
|
||||
next()
|
||||
finalizeAsync("async test timed out")
|
||||
}, Math.min(delay, 2147483647))
|
||||
}
|
||||
|
||||
if (fn.length > 0) {
|
||||
var body = fn.toString()
|
||||
var arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop()
|
||||
arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop()
|
||||
if (body.indexOf(arg) === body.lastIndexOf(arg)) throw new Error("`" + arg + "()` should be called at least once")
|
||||
try {
|
||||
fn(done, function(t) {delay = t})
|
||||
}
|
||||
catch (e) {
|
||||
done(e)
|
||||
finalizeAsync(e)
|
||||
}
|
||||
if (timeout === 0) {
|
||||
startTimer()
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
var p = fn()
|
||||
if (p && p.then) {
|
||||
startTimer()
|
||||
|
|
@ -245,14 +248,13 @@ else window.o = m()
|
|||
}
|
||||
}
|
||||
}
|
||||
function record(message, error) {
|
||||
function record(message, error, fallbackError) {
|
||||
var result = {pass: message === null}
|
||||
if (result.pass === false) {
|
||||
if (error == null) error = ensureStackTrace(new Error)
|
||||
result.context = subjects.join(" > ")
|
||||
result.message = message
|
||||
result.error = error
|
||||
|
||||
result.error = error != null ? error : ensureStackTrace(new Error)
|
||||
result.fallbackError = fallbackError
|
||||
}
|
||||
results.push(result)
|
||||
}
|
||||
|
|
@ -279,11 +281,17 @@ else window.o = m()
|
|||
if (error.stack === undefined) try { throw error } catch(e) {return e}
|
||||
else return error
|
||||
}
|
||||
function getStackName(e, exp) {
|
||||
return e.stack && exp.test(e.stack) ? e.stack.match(exp)[1] : null
|
||||
}
|
||||
|
||||
o.report = function (results) {
|
||||
var errCount = 0
|
||||
for (var i = 0, r; r = results[i]; i++) {
|
||||
if (!r.pass) {
|
||||
var stackTrace = o.cleanStackTrace(r.error)
|
||||
var couldHaveABetterStackTrace = !stackTrace || timeoutStackName != null && stackTrace.indexOf(timeoutStackName) !== -1
|
||||
if (couldHaveABetterStackTrace) stackTrace = r.fallbackError != null ? o.cleanStackTrace(r.fallbackError) : r.error.stack || ""
|
||||
console.error(
|
||||
(hasProcess ? "\n" : "") +
|
||||
highlight(r.context + ":", "red2") + "\n" +
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue