lib/jspec.js in jspec-2.11.13 vs lib/jspec.js in jspec-3.0.0
- old
+ new
@@ -1,22 +1,22 @@
// JSpec - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-(function(){
+;(function(){
JSpec = {
-
- version : '2.11.13',
+ version : '3.1.0',
+ assert : true,
cache : {},
suites : [],
modules : [],
allSuites : [],
matchers : {},
stubbed : [],
+ options : {},
request : 'XMLHttpRequest' in this ? XMLHttpRequest : null,
stats : { specs: 0, assertions: 0, failures: 0, passes: 0, specsFinished: 0, suitesFinished: 0 },
- options : { profile: false },
/**
* Default context in which bodies are evaluated.
*
* Replace context simply by setting JSpec.context
@@ -49,40 +49,33 @@
an_instance_of : function(constructor) {
return { an_instance_of : constructor }
},
/**
- * Load fixture at _path_. This utility function
- * supplies the means to resolve, and cache fixture contents
- * via the DOM or Rhino.
+ * Load fixture at _path_.
*
* Fixtures are resolved as:
*
* - <path>
- * - fixtures/<path>
- * - fixtures/<path>.html
+ * - <path>.html
*
* @param {string} path
* @return {string}
* @api public
*/
fixture : function(path) {
if (JSpec.cache[path]) return JSpec.cache[path]
return JSpec.cache[path] =
- JSpec.tryLoading(path) ||
- JSpec.tryLoading('fixtures/' + path) ||
- JSpec.tryLoading('fixtures/' + path + '.html') ||
- JSpec.tryLoading('spec/' + path) ||
- JSpec.tryLoading('spec/fixtures/' + path) ||
- JSpec.tryLoading('spec/fixtures/' + path + '.html')
+ JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) ||
+ JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.html')
}
},
// --- Objects
- formatters : {
+ reporters : {
/**
* Report to server.
*
* Options:
@@ -121,11 +114,11 @@
})
if ('close' in main) main.close()
},
/**
- * Default formatter, outputting to the DOM.
+ * Default reporter, outputting to the DOM.
*
* Options:
* - reportToId id of element to output reports to, defaults to 'jspec'
* - failuresOnly displays only suites with failing specs
*
@@ -147,10 +140,11 @@
}
report.innerHTML = '<div id="jspec-report" class="' + classes + '"><div class="heading"> \
<span class="passes">Passes: <em>' + results.stats.passes + '</em></span> \
<span class="failures">Failures: <em>' + results.stats.failures + '</em></span> \
+ <span class="passes">Duration: <em>' + results.duration + '</em> ms</span> \
</div><table class="suites">' + map(results.allSuites, function(suite) {
var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
if (displaySuite && suite.hasSpecs())
return '<tr class="description"><td colspan="2">' + escape(suite.description) + '</td></tr>' +
map(suite.specs, function(i, spec) {
@@ -168,19 +162,20 @@
}).join('') + '</tr>'
}).join('') + '</table></div>'
},
/**
- * Terminal formatter.
+ * Terminal reporter.
*
* @api public
*/
Terminal : function(results, options) {
failuresOnly = option('failuresOnly')
print(color("\n Passes: ", 'bold') + color(results.stats.passes, 'green') +
- color(" Failures: ", 'bold') + color(results.stats.failures, 'red') + "\n")
+ color(" Failures: ", 'bold') + color(results.stats.failures, 'red') +
+ color(" Duration: ", 'bold') + color(results.duration, 'green') + " ms \n")
function indent(string) {
return string.replace(/^(.)/gm, ' $1')
}
@@ -206,11 +201,11 @@
quit(results.stats.failures)
},
/**
- * Console formatter.
+ * Console reporter.
*
* @api public
*/
Console : function(results, options) {
@@ -244,11 +239,12 @@
expected: expected,
// Report assertion results
report : function() {
- this.passed ? JSpec.stats.passes++ : JSpec.stats.failures++
+ if (JSpec.assert)
+ this.passed ? JSpec.stats.passes++ : JSpec.stats.failures++
return this
},
// Run the assertion
@@ -268,11 +264,11 @@
var old = object[method]
// Proxy
object[method] = function(){
- args = argumentsToArray(arguments)
+ args = toArray(arguments)
result = old.apply(object, args)
self.calls.push({ args : args, result : result })
return result
}
@@ -300,31 +296,31 @@
},
// Proxy arguments passed
with_args : function() {
- this.expectedArgs = argumentsToArray(arguments)
+ this.expectedArgs = toArray(arguments)
return this
},
// Check if any calls have failing results
anyResultsFail : function() {
return any(this.calls, function(call){
return self.expectedResult.an_instance_of ?
call.result.constructor != self.expectedResult.an_instance_of:
- hash(self.expectedResult) != hash(call.result)
+ !equal(self.expectedResult, call.result)
})
},
// Check if any calls have passing results
anyResultsPass : function() {
return any(this.calls, function(call){
return self.expectedResult.an_instance_of ?
call.result.constructor == self.expectedResult.an_instance_of:
- hash(self.expectedResult) == hash(call.result)
+ equal(self.expectedResult, call.result)
})
},
// Return the passing result
@@ -344,11 +340,11 @@
return any(this.calls, function(call){
return any(self.expectedArgs, function(i, arg){
if (arg == null) return call.args[i] == null
return arg.an_instance_of ?
call.args[i].constructor != arg.an_instance_of:
- hash(arg) != hash(call.args[i])
+ !equal(arg, call.args[i])
})
})
},
@@ -357,11 +353,11 @@
anyArgsPass : function() {
return any(this.calls, function(call){
return any(self.expectedArgs, function(i, arg){
return arg.an_instance_of ?
call.args[i].constructor == arg.an_instance_of:
- hash(arg) == hash(call.args[i])
+ equal(arg, call.args[i])
})
})
},
@@ -378,11 +374,12 @@
},
// Report assertion results
report : function() {
- this.passed ? ++JSpec.stats.passes : ++JSpec.stats.failures
+ if (JSpec.assert)
+ this.passed ? ++JSpec.stats.passes : ++JSpec.stats.failures
return this
},
// Run the assertion
@@ -504,18 +501,18 @@
// Add passing assertion
pass : function(message) {
this.assertions.push({ passed: true, message: message })
- ++JSpec.stats.passes
+ if (JSpec.assert) ++JSpec.stats.passes
},
// Add failing assertion
fail : function(message) {
this.assertions.push({ passed: false, message: message })
- ++JSpec.stats.failures
+ if (JSpec.assert) ++JSpec.stats.failures
},
// Run deferred assertions
runDeferredAssertions : function() {
@@ -677,22 +674,22 @@
},
/**
* Include _object_ which may be a hash or Module instance.
*
- * @param {has, Module} object
+ * @param {hash, Module} object
* @return {JSpec}
* @api public
*/
include : function(object) {
var module = object.constructor == JSpec.Module ? object : new JSpec.Module(object)
this.modules.push(module)
if ('init' in module) module.init()
if ('utilities' in module) extend(this.defaultContext, module.utilities)
if ('matchers' in module) this.addMatchers(module.matchers)
- if ('formatters' in module) extend(this.formatters, module.formatters)
+ if ('reporters' in module) extend(this.reporters, module.reporters)
if ('DSLs' in module)
each(module.DSLs, function(name, methods){
JSpec.DSLs[name] = JSpec.DSLs[name] || {}
extend(JSpec.DSLs[name], methods)
})
@@ -709,11 +706,11 @@
* @return {array}
* @api private
*/
hook : function(name, args) {
- args = argumentsToArray(arguments, 1)
+ args = toArray(arguments, 1)
return inject(JSpec.modules, [], function(results, module){
if (typeof module[name] == 'function')
results.push(JSpec.evalHook(module, name, args))
})
},
@@ -803,11 +800,11 @@
* @param {int} offset
* @return {array}
* @api public
*/
- argumentsToArray : function(arguments, offset) {
+ toArray : function(arguments, offset) {
return Array.prototype.slice.call(arguments, offset || 0)
},
/**
* Return ANSI-escaped colored string.
@@ -840,11 +837,13 @@
defaultMatcherMessage : function(actual, expected, negate, name) {
return 'expected ' + puts(actual) + ' to ' +
(negate ? 'not ' : '') +
name.replace(/_/g, ' ') +
- ' ' + puts.apply(this, expected.slice(1))
+ ' ' + (expected.length > 1 ?
+ puts.apply(this, expected.slice(1)) :
+ '')
},
/**
* Normalize a matcher message.
*
@@ -905,40 +904,41 @@
option : function(key) {
return (value = query(key)) !== null ? value :
JSpec.options[key] || null
},
+
+ /**
+ * Check if object _a_, is equal to object _b_.
+ *
+ * @param {object} a
+ * @param {object} b
+ * @return {bool}
+ * @api private
+ */
+
+ equal: function(a, b) {
+ if (typeof a != typeof b) return
+ if (a === b) return true
+ if (a instanceof RegExp)
+ return a.toString() === b.toString()
+ if (a instanceof Date)
+ return Number(a) === Number(b)
+ if (typeof a != 'object') return
+ if (a.length !== undefined)
+ if (a.length !== b.length) return
+ else
+ for (var i = 0, len = a.length; i < len; ++i)
+ if (!equal(a[i], b[i]))
+ return
+ for (var key in a)
+ if (!equal(a[key], b[key]))
+ return
+ return true
+ },
/**
- * Generates a hash of the object passed.
- *
- * @param {object} object
- * @return {string}
- * @api private
- */
-
- hash : function(object) {
- if (object == null) return 'null'
- if (object == undefined) return 'undefined'
- function serialize(prefix) {
- return inject(object, prefix + ':', function(buffer, key, value){
- return buffer += hash(value)
- })
- }
- switch (object.constructor) {
- case Array : return serialize('a')
- case RegExp: return 'r:' + object.toString()
- case Number: return 'n:' + object.toString()
- case String: return 's:' + object.toString()
- case Object: return 'o:' + inject(object, [], function(array, key, value){
- array.push([key, hash(value)])
- }).sort()
- default: return object.toString()
- }
- },
-
- /**
* Return last element of an array.
*
* @param {array} array
* @return {object}
* @api public
@@ -955,34 +955,39 @@
* @return {string}
* @api public
*/
puts : function(object) {
- if (arguments.length > 1) {
- return map(argumentsToArray(arguments), function(arg){
+ if (arguments.length > 1)
+ return map(toArray(arguments), function(arg){
return puts(arg)
}).join(', ')
- }
- if (object === undefined) return ''
+ if (object === undefined) return 'undefined'
if (object === null) return 'null'
if (object === true) return 'true'
if (object === false) return 'false'
if (object.an_instance_of) return 'an instance of ' + object.an_instance_of.name
- if (object.jquery && object.selector.length > 0) return 'selector ' + puts(object.selector) + ''
+ if (object.jquery && object.selector.length > 0) return 'selector ' + puts(object.selector)
if (object.jquery) return object.get(0).outerHTML
if (object.nodeName) return object.outerHTML
switch (object.constructor) {
- case String: return "'" + object + "'"
- case Number: return object
case Function: return object.name || object
+ case String:
+ return '"' + object
+ .replace(/"/g, '\\"')
+ .replace(/\n/g, '\\n')
+ .replace(/\t/g, '\\t')
+ + '"'
case Array:
return inject(object, '[', function(b, v){
return b + ', ' + puts(v)
}).replace('[,', '[') + ' ]'
case Object:
+ object.__hit__ = true
return inject(object, '{', function(b, k, v) {
- return b + ', ' + puts(k) + ' : ' + puts(v)
+ if (k == '__hit__') return b
+ return b + ', ' + k + ': ' + (v && v.__hit__ ? '<circular reference>' : puts(v))
}).replace('{,', '{') + ' }'
default:
return object.toString()
}
},
@@ -1022,11 +1027,11 @@
* @return {mixed}
* @api private
*/
does : function(actual, matcher, expected) {
- var assertion = new JSpec.Assertion(JSpec.matchers[matcher], actual, argumentsToArray(arguments, 2))
+ var assertion = new JSpec.Assertion(JSpec.matchers[matcher], actual, toArray(arguments, 2))
return assertion.run().result
},
/**
* Perform an assertion.
@@ -1040,11 +1045,11 @@
* @api public
*/
expect : function(actual) {
assert = function(matcher, args, negate) {
- var expected = argumentsToArray(args, 1)
+ var expected = toArray(args, 1)
matcher.negate = negate
assertion = new JSpec.Assertion(matcher, actual, expected, negate)
hook('beforeAssertion', assertion)
if (matcher.defer) assertion.run()
else JSpec.currentSpec.assertions.push(assertion.run().report()), hook('afterAssertion', assertion)
@@ -1112,21 +1117,24 @@
},
/**
* Iterate an object, invoking the given callback.
*
- * @param {hash, array, string} object
+ * @param {hash, array} object
* @param {function} callback
* @return {JSpec}
* @api public
*/
each : function(object, callback) {
- if (typeof object == 'string') object = object.split(' ')
- for (key in object)
- if (object.hasOwnProperty(key))
- callIterator(callback, key, object[key])
+ if (object.constructor == Array)
+ for (var i = 0, len = object.length; i < len; ++i)
+ callIterator(callback, i, object[i])
+ else
+ for (var key in object)
+ if (object.hasOwnProperty(key))
+ callIterator(callback, key, object[key])
},
/**
* Iterate with memo.
*
@@ -1324,11 +1332,11 @@
var dsl = this.DSL || this.DSLs.snake
var matchers = this.matchers
var context = this.context || this.defaultContext
var contents = this.contentsOf(body)
hook('evaluatingBody', dsl, matchers, context, contents)
- try { eval('with (dsl){ with (context) { with (matchers) { ' + contents + ' }}}') }
+ try { with (dsl){ with (context) { with (matchers) { eval(contents) }}} }
catch(e) { error(errorMessage, e) }
},
/**
* Pre-process a string of JSpec.
@@ -1342,11 +1350,11 @@
if (typeof input != 'string') return
input = hookImmutable('preprocessing', input)
return input.
replace(/\t/g, ' ').
replace(/\r\n|\n|\r/g, '\n').
- replace(/__END__[^]*/, '').
+ split('__END__')[0].
replace(/([\w\.]+)\.(stub|destub)\((.*?)\)$/gm, '$2($1, $3)').
replace(/describe\s+(.*?)$/gm, 'describe($1, function(){').
replace(/^\s+it\s+(.*?)$/gm, ' it($1, function(){').
replace(/^ *(before_each|after_each|before|after)(?= |\n|$)/gm, 'JSpec.currentSuite.addHook("$1", function(){').
replace(/^\s*end(?=\s|$)/gm, '});').
@@ -1379,12 +1387,13 @@
*
* @api public
*/
report : function() {
+ this.duration = Number(new Date) - this.start
hook('reporting', JSpec.options)
- new (JSpec.options.formatter || JSpec.formatters.DOM)(JSpec, JSpec.options)
+ new (JSpec.options.reporter || JSpec.reporters.DOM)(JSpec, JSpec.options)
},
/**
* Run the spec suites. Options are merged
* with JSpec options when present.
@@ -1395,13 +1404,12 @@
*/
run : function(options) {
if (any(hook('running'), haveStopped)) return this
if (options) extend(this.options, options)
- if (option('profile')) console.group('Profile')
+ this.start = Number(new Date)
each(this.suites, function(suite) { JSpec.runSuite(suite) })
- if (option('profile')) console.groupEnd()
return this
},
/**
* Run a suite.
@@ -1460,14 +1468,12 @@
* @api public
*/
runSpec : function(spec) {
this.currentSpec = spec
- if (option('profile')) console.time(spec.description)
try { this.evalBody(spec.body) }
catch (e) { fail(e) }
- if (option('profile')) console.timeEnd(spec.description)
spec.runDeferredAssertions()
destub()
this.stats.specsFinished++
this.stats.assertions += spec.assertions.length
},
@@ -1586,12 +1592,11 @@
* @return {string}
* @api public
*/
tryLoading : function(file) {
- try { return JSpec.load(file) }
- catch (e) {}
+ try { return JSpec.load(file) } catch (e) {}
},
/**
* Load a _file_'s contents.
*
@@ -1636,18 +1641,19 @@
// --- Utility functions
var main = this
var find = JSpec.any
var utils = 'haveStopped stub hookImmutable hook destub map any last pass fail range each option inject select \
- error escape extend puts hash query strip color does addMatchers callIterator argumentsToArray'.split(/\s+/)
- while (utils.length) util = utils.shift(), eval('var ' + util + ' = JSpec.' + util)
+ error escape extend puts query strip color does addMatchers callIterator toArray equal'.split(/\s+/)
+ while (utils.length) eval('var ' + utils[0] + ' = JSpec.' + utils.shift())
if (!main.setTimeout) main.setTimeout = function(callback){ callback() }
// --- Matchers
addMatchers({
equal : "===",
+ eql : "equal(actual, expected)",
be : "alias equal",
be_greater_than : ">",
be_less_than : "<",
be_at_least : ">=",
be_at_most : "<=",
@@ -1662,17 +1668,10 @@
match : "typeof actual == 'string' ? actual.match(expected) : false",
respond_to : "typeof actual[expected] == 'function'",
have_length : "actual.length == expected",
be_within : "actual >= expected[0] && actual <= last(expected)",
have_length_within : "actual.length >= expected[0] && actual.length <= last(expected)",
-
- eql : function(actual, expected) {
- return actual.constructor == Array ||
- actual instanceof Object ?
- hash(actual) == hash(expected):
- actual == expected
- },
receive : { defer : true, match : function(actual, method, times) {
proxy = new JSpec.ProxyAssertion(actual, method, times, this.negate)
JSpec.currentSpec.assertions.push(proxy)
return proxy
@@ -1699,11 +1698,11 @@
case Object:
state = arg in actual
break
case Array:
- state = any(actual, function(value){ return hash(value) == hash(arg) })
+ state = any(actual, function(value){ return equal(value, arg) })
break
}
if (!state) return false
}
return true
@@ -1713,13 +1712,13 @@
try { actual() }
catch (e) {
this.e = e
var assert = function(arg) {
switch (arg.constructor) {
- case RegExp : return arg.test(e)
+ case RegExp : return arg.test(e.message || e.toString())
case String : return arg == (e.message || e.toString())
- case Function : return (e.name || 'Error') == arg.name
+ case Function : return e instanceof arg || e.name == arg.name
}
}
return message ? assert(expected) && assert(message) :
expected ? assert(expected) :
true
@@ -1769,8 +1768,6 @@
value == null ? true:
value === actual[property]
}
})
- if ('exports' in main) exports.JSpec = JSpec
-
})()
\ No newline at end of file