[ospec] cleanup in code and tests, better error messages
This commit is contained in:
parent
e473536866
commit
9c1f8d5f35
2 changed files with 119 additions and 100 deletions
|
|
@ -7,17 +7,21 @@ else window.o = m()
|
||||||
var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty
|
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
|
var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName
|
||||||
var globalTimeout = noTimeoutRightNow
|
var globalTimeout = noTimeoutRightNow
|
||||||
|
var hooks = {
|
||||||
|
__before: true,
|
||||||
|
__beforeEach: true,
|
||||||
|
__after: true,
|
||||||
|
__afterEach: true
|
||||||
|
}
|
||||||
if (name != null) spec[name] = ctx = {}
|
if (name != null) spec[name] = ctx = {}
|
||||||
|
|
||||||
function o(subject, predicate) {
|
function o(subject, predicate) {
|
||||||
if (predicate === undefined) {
|
if (predicate === undefined) return new Assert(subject)
|
||||||
if (results == null) throw new Error("Assertions should not occur outside test definitions")
|
else {
|
||||||
return new Assert(subject)
|
subject = String(subject)
|
||||||
}
|
if (hasOwn.call(hooks, subject)) throw new Error("'" + subject + "' is a reserved test name")
|
||||||
else if (results == null) {
|
if (subject.slice(0, 2) === "__") console.warn("test names starting with '__' are reserved for internal use\n" + o.cleanStackTrace(ensureStackTrace(new Error)))
|
||||||
ctx[unique(subject)] = new Task(predicate, ensureStackTrace(new Error))
|
ctx[unique(subject)] = new Task(predicate, ensureStackTrace(new Error))
|
||||||
} else {
|
|
||||||
throw new Error("Test definition shouldn't be nested. To group tests use `o.spec()`")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o.before = hook("__before")
|
o.before = hook("__before")
|
||||||
|
|
@ -36,7 +40,6 @@ else window.o = m()
|
||||||
highlight("/!\\ WARNING /!\\ o.only() mode") + "\n" + o.cleanStackTrace(ensureStackTrace(new Error)) + "\n",
|
highlight("/!\\ WARNING /!\\ o.only() mode") + "\n" + o.cleanStackTrace(ensureStackTrace(new Error)) + "\n",
|
||||||
cStyle("red"), ""
|
cStyle("red"), ""
|
||||||
)
|
)
|
||||||
|
|
||||||
o(subject, only = predicate)
|
o(subject, only = predicate)
|
||||||
}
|
}
|
||||||
o.spy = function(fn) {
|
o.spy = function(fn) {
|
||||||
|
|
@ -93,23 +96,25 @@ else window.o = m()
|
||||||
function test(spec, pre, post, finalize) {
|
function test(spec, pre, post, finalize) {
|
||||||
pre = [].concat(pre, spec["__beforeEach"] || [])
|
pre = [].concat(pre, spec["__beforeEach"] || [])
|
||||||
post = [].concat(spec["__afterEach"] || [], post)
|
post = [].concat(spec["__afterEach"] || [], post)
|
||||||
series([].concat(spec["__before"] || [], Object.keys(spec).map(function(key) {
|
series([].concat(spec["__before"] || [], Object.keys(spec).reduce(function(tasks, key) {
|
||||||
return new Task(function(done, timeout) {
|
if (!hasOwn.call(hooks, key)) {
|
||||||
timeout(Infinity)
|
tasks.push(new Task(function(done, timeout) {
|
||||||
if (key.slice(0, 2) === "__") return done()
|
timeout(Infinity)
|
||||||
if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done()
|
if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done()
|
||||||
|
|
||||||
subjects.push(key)
|
subjects.push(key)
|
||||||
var pop = new Task(function pop() {
|
var pop = new Task(function pop() {
|
||||||
subjects.pop()
|
subjects.pop()
|
||||||
done()
|
done()
|
||||||
}, null)
|
}, null)
|
||||||
|
|
||||||
if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop))
|
if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop))
|
||||||
else test(spec[key], pre, post, pop)
|
else test(spec[key], pre, post, pop)
|
||||||
|
|
||||||
}, null)
|
}, null))
|
||||||
}), spec["__after"] || [], finalize))
|
}
|
||||||
|
return tasks
|
||||||
|
}, []), spec["__after"] || [], finalize))
|
||||||
}
|
}
|
||||||
|
|
||||||
function series(tasks) {
|
function series(tasks) {
|
||||||
|
|
@ -162,7 +167,8 @@ else window.o = m()
|
||||||
fn(done, setDelay)
|
fn(done, setDelay)
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
finalizeAsync(e)
|
if (task.err != null) finalizeAsync(e)
|
||||||
|
else throw e
|
||||||
}
|
}
|
||||||
if (timeout === 0) {
|
if (timeout === 0) {
|
||||||
startTimer()
|
startTimer()
|
||||||
|
|
@ -239,8 +245,16 @@ else window.o = m()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function Assert(value) {this.value = value}
|
function isRunning() {return results != null}
|
||||||
function Task(fn, err) {this.fn = fn, this.err = err}
|
function Assert(value) {
|
||||||
|
if (!isRunning()) throw new Error("Assertions should not occur outside test definitions")
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
function Task(fn, err) {
|
||||||
|
if (err != null && isRunning()) throw new Error("Test definitions and hooks shouldn't be nested. To group tests use `o.spec()`")
|
||||||
|
this.fn = fn
|
||||||
|
this.err = err
|
||||||
|
}
|
||||||
function define(name, verb, compare) {
|
function define(name, verb, compare) {
|
||||||
Assert.prototype[name] = function assert(value) {
|
Assert.prototype[name] = function assert(value) {
|
||||||
if (compare(this.value, value)) record(null)
|
if (compare(this.value, value)) record(null)
|
||||||
|
|
|
||||||
|
|
@ -3,91 +3,96 @@
|
||||||
var callAsync = require("../../test-utils/callAsync")
|
var callAsync = require("../../test-utils/callAsync")
|
||||||
var o = require("../ospec")
|
var o = require("../ospec")
|
||||||
|
|
||||||
new function(o) {
|
o("o.only", function(done) {
|
||||||
o = o.new()
|
var oo = o.new()
|
||||||
|
|
||||||
o.spec("ospec", function() {
|
oo.spec("ospec", function() {
|
||||||
o("skipped", function() {
|
oo("skipped", function() {
|
||||||
o(true).equals(false)
|
oo(true).equals(false)
|
||||||
})
|
})
|
||||||
o.only(".only()", function() {
|
oo.only(".only()", function() {
|
||||||
o(2).equals(2)
|
oo(2).equals(2)
|
||||||
}, true)
|
}, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
o.run()
|
oo.run(function(results){
|
||||||
}(o)
|
o(results.length).equals(1)
|
||||||
|
o(results[0].pass).equals(true)
|
||||||
new function(o) {
|
done()
|
||||||
var clone = o.new()
|
|
||||||
|
|
||||||
clone.spec("clone", function() {
|
|
||||||
clone("fail", function() {
|
|
||||||
clone(true).equals(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
clone("pass", function() {
|
|
||||||
clone(true).equals(true)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// Predicate test passing on clone results
|
// Predicate test passing on clone results
|
||||||
o.spec("reporting", function() {
|
o.spec("reporting", function() {
|
||||||
o("reports per instance", function(done, timeout) {
|
var oo
|
||||||
timeout(100) // Waiting on clone
|
o.beforeEach(function(){
|
||||||
|
oo = o.new()
|
||||||
|
|
||||||
clone.run(function(results) {
|
oo.spec("clone", function() {
|
||||||
o(typeof results).equals("object")
|
oo("fail", function() {
|
||||||
o("length" in results).equals(true)
|
oo(true).equals(false)
|
||||||
o(results.length).equals(2)("Two results")
|
})
|
||||||
|
|
||||||
o("error" in results[0] && "pass" in results[0]).equals(true)("error and pass keys present in failing result")
|
oo("pass", function() {
|
||||||
o(!("error" in results[1]) && "pass" in results[1]).equals(true)("only pass key present in passing result")
|
oo(true).equals(true)
|
||||||
o(results[0].pass).equals(false)("Test meant to fail has failed")
|
|
||||||
o(results[1].pass).equals(true)("Test meant to pass has passed")
|
|
||||||
|
|
||||||
done()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
o("o.report() returns the number of failures", function () {
|
})
|
||||||
var log = console.log, error = console.error
|
o("reports per instance", function(done, timeout) {
|
||||||
console.log = o.spy()
|
timeout(100) // Waiting on clone
|
||||||
console.error = o.spy()
|
|
||||||
|
|
||||||
function makeError(msg) {try{throw msg ? new Error(msg) : new Error} catch(e){return e}}
|
oo.run(function(results) {
|
||||||
try {
|
o(typeof results).equals("object")
|
||||||
var errCount = o.report([{pass: true}, {pass: true}])
|
o("length" in results).equals(true)
|
||||||
|
o(results.length).equals(2)("Two results")
|
||||||
|
|
||||||
o(errCount).equals(0)
|
o("error" in results[0] && "pass" in results[0]).equals(true)("error and pass keys present in failing result")
|
||||||
o(console.log.callCount).equals(1)
|
o(!("error" in results[1]) && "pass" in results[1]).equals(true)("only pass key present in passing result")
|
||||||
o(console.error.callCount).equals(0)
|
o(results[0].pass).equals(false)("Test meant to fail has failed")
|
||||||
|
o(results[1].pass).equals(true)("Test meant to pass has passed")
|
||||||
|
|
||||||
errCount = o.report([
|
done()
|
||||||
{pass: false, error: makeError("hey"), message: "hey"}
|
|
||||||
])
|
|
||||||
|
|
||||||
o(errCount).equals(1)
|
|
||||||
o(console.log.callCount).equals(2)
|
|
||||||
o(console.error.callCount).equals(1)
|
|
||||||
|
|
||||||
errCount = o.report([
|
|
||||||
{pass: false, error: makeError("hey"), message: "hey"},
|
|
||||||
{pass: true},
|
|
||||||
{pass: false, error: makeError("ho"), message: "ho"}
|
|
||||||
])
|
|
||||||
|
|
||||||
o(errCount).equals(2)
|
|
||||||
o(console.log.callCount).equals(3)
|
|
||||||
o(console.error.callCount).equals(3)
|
|
||||||
} catch (e) {
|
|
||||||
o(1).equals(0)("Error while testing the reporter")
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log = log
|
|
||||||
console.error = error
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}(o)
|
o("o.report() returns the number of failures", function () {
|
||||||
|
var log = console.log, error = console.error
|
||||||
|
console.log = o.spy()
|
||||||
|
console.error = o.spy()
|
||||||
|
|
||||||
|
function makeError(msg) {try{throw msg ? new Error(msg) : new Error} catch(e){return e}}
|
||||||
|
try {
|
||||||
|
var errCount = o.report([{pass: true}, {pass: true}])
|
||||||
|
|
||||||
|
o(errCount).equals(0)
|
||||||
|
o(console.log.callCount).equals(1)
|
||||||
|
o(console.error.callCount).equals(0)
|
||||||
|
|
||||||
|
errCount = o.report([
|
||||||
|
{pass: false, error: makeError("hey"), message: "hey"}
|
||||||
|
])
|
||||||
|
|
||||||
|
o(errCount).equals(1)
|
||||||
|
o(console.log.callCount).equals(2)
|
||||||
|
o(console.error.callCount).equals(1)
|
||||||
|
|
||||||
|
errCount = o.report([
|
||||||
|
{pass: false, error: makeError("hey"), message: "hey"},
|
||||||
|
{pass: true},
|
||||||
|
{pass: false, error: makeError("ho"), message: "ho"}
|
||||||
|
])
|
||||||
|
|
||||||
|
o(errCount).equals(2)
|
||||||
|
o(console.log.callCount).equals(3)
|
||||||
|
o(console.error.callCount).equals(3)
|
||||||
|
} catch (e) {
|
||||||
|
o(1).equals(0)("Error while testing the reporter")
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log = log
|
||||||
|
console.error = error
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
o.spec("ospec", function() {
|
o.spec("ospec", function() {
|
||||||
o.spec("sync", function() {
|
o.spec("sync", function() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue