diff --git a/.gitignore b/.gitignore index 18e6501d..b2bcef44 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ *.log -doc/*.html node_modules test/test.html diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 27b05769..00000000 --- a/.gitmodules +++ /dev/null @@ -1,9 +0,0 @@ -[submodule "vendor/buster-util"] - path = vendor/buster-util - url = https://gitorious.org/buster/buster-util.git -[submodule "vendor/buster-core"] - path = vendor/buster-core - url = https://gitorious.org/buster/buster-core.git -[submodule "vendor/sinon"] - path = vendor/sinon - url = https://github.com/cjohansen/Sinon.JS.git diff --git a/.npmignore b/.npmignore index eb5ab382..5d3628b1 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,3 @@ vendor .gitignore -.gitmodules .npmignore diff --git a/LICENSE b/LICENSE index e002c291..f00310bc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ (The BSD License) -Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no and +Copyright (c) 2010-2012, Christian Johansen, christian@cjohansen.no and August Lilleaas, august.lilleaas@gmail.com. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/Readme.md b/Readme.md deleted file mode 100644 index 3820f0e9..00000000 --- a/Readme.md +++ /dev/null @@ -1,16 +0,0 @@ -# buster-assertions - -[![Build status](https://secure.travis-ci.org/busterjs/buster-assertions.png?branch=master)](http://travis-ci.org/busterjs/buster-assertions) - -Test-framework agnostic assertions and expectations. Features an API for -adding custom assertions. - -# Running tests - -To run tests in the browser: - - vendor/buster-util/jstdhtml - -Open test/test.html in a browser - -You can also run JsTestDriver from the root directory. diff --git a/Readme.rst b/Readme.rst new file mode 100644 index 00000000..cdb21f7f --- /dev/null +++ b/Readme.rst @@ -0,0 +1,24 @@ +# referee + + Referee is in you unit tests, deciding who passes and who fails + +[![Build status](https://secure.travis-ci.org/busterjs/referee.png?branch=master)](http://travis-ci.org/busterjs/referee) + +``referee`` is a test-framework agnostic assertion and expectation library. +Some highlights: + +- Rich library of assertions +- Symmetric assert/refute (refute is ``referee``'s "assert.not*") +- Evented: Emits success and failure events +- Failing assertions throw exceptions by default, but can be configured to not +- API to add custom assertions that provides quite a bit of plumbing for free + +Developers - Running tests +========================== + +:: + + npm install + ./node_modules/.bin/buster-test --node + ./node_modules/.bin/buster-server + ./node_modules/.bin/buster-test --browser diff --git a/autolint.js b/autolint.js new file mode 100644 index 00000000..602bcfd8 --- /dev/null +++ b/autolint.js @@ -0,0 +1,21 @@ +module.exports = { + paths: [ + "lib/*.js", + "test/*.js" + ], + linterOptions: { + node: true, + browser: true, + plusplus: true, + sloppy: true, + vars: true, + nomen: true, + regexp: true, + predef: [ + "define", + "assert", + "refute", + "buster" + ] + } +}; diff --git a/buster.js b/buster.js new file mode 100644 index 00000000..fd875928 --- /dev/null +++ b/buster.js @@ -0,0 +1,18 @@ +exports["Browser"] = { + libs: [ + "node_modules/lodash/lodash.js", + "node_modules/samsam/lib/samsam.js", + "node_modules/bane/lib/bane.js" + ], + sources: [ + "lib/referee.js", + "lib/expect.js" + ], + testHelpers: ["test/test-helper.js"], + tests: ["test/*-test.js"] +}; + +exports["Node"] = { + extends: "Browser", + environment: "node" +}; diff --git a/jsTestDriver.conf b/jsTestDriver.conf deleted file mode 100644 index 9647bf96..00000000 --- a/jsTestDriver.conf +++ /dev/null @@ -1,22 +0,0 @@ -server: http://localhost:4224 - -load: - - vendor/buster-util/lib/buster-util/jstestdriver-shim.js - - vendor/buster-core/lib/buster-core.js - - vendor/buster-core/lib/buster-event-emitter.js - - vendor/sinon/lib/sinon.js - - vendor/sinon/lib/sinon/spy.js - - vendor/sinon/lib/sinon/stub.js - - vendor/sinon/lib/sinon/mock.js - - vendor/sinon/lib/sinon/collection.js - - vendor/sinon/lib/sinon/util/fake_timers.js - - vendor/sinon/lib/sinon/util/timers_ie.js - - vendor/sinon/lib/sinon/sandbox.js - - vendor/sinon/lib/sinon/test.js - - vendor/sinon/lib/sinon/test_case.js - - vendor/sinon/lib/sinon/assert.js - - lib/*.js - - lib/buster-assertions/*.js - - test/test-helper.js - - test/*.js - - test/buster-assertions/*.js diff --git a/jsl.conf b/jsl.conf deleted file mode 100644 index d8cb09f3..00000000 --- a/jsl.conf +++ /dev/null @@ -1,4 +0,0 @@ -+output-format __FILENAME__(__LINE__): __ERROR__ - -+define module -+define require diff --git a/lib/buster-assertions.js b/lib/buster-assertions.js deleted file mode 100644 index 8d038ac3..00000000 --- a/lib/buster-assertions.js +++ /dev/null @@ -1,797 +0,0 @@ -/*jslint eqeqeq: false, onevar: false, plusplus: false*/ -/*global buster, require, module*/ -(function () { - var isCommonJS = typeof require == "function" && typeof module == "object"; - if (isCommonJS) buster = require("buster-core"); - var toString = Object.prototype.toString; - var slice = Array.prototype.slice; - var assert, refute, ba = buster.assertions = buster.eventEmitter.create(); - - if (isCommonJS) { - module.exports = buster.assertions; - } - - function countAssertion() { - if (typeof ba.count != "number") { - ba.count = 0; - } - - ba.count += 1; - } - - ba.count = countAssertion; - - function assertEnoughArguments(name, args, num) { - if (args.length < num) { - ba.fail("[" + name + "] Expected to receive at least " + - num + " argument" + (num > 1 ? "s" : "")); - return false; - } - - return true; - } - - function defineAssertion(type, name, func, fl, messageValues) { - ba[type][name] = function () { - var fullName = type + "." + name; - countAssertion(); - if (!assertEnoughArguments(fullName, arguments, fl || func.length)) return; - - var failed = false; - - var ctx = { - fail: function () { - failed = true; - var failArgs = [type, name].concat(slice.call(arguments)); - fail.apply(this, failArgs); - return true; - } - }; - - var args = slice.call(arguments, 0); - - if (typeof messageValues == "function") { - args = messageValues.apply(this, args); - } - - if (!func.apply(ctx, arguments)) { - return fail.apply(ctx, [type, name, "message"].concat(args)); - } - - if (!failed) { - ba.emit.apply(ba, ["pass", fullName].concat(args)); - } - }; - } - - ba.add = function (name, options) { - var refuteArgs; - - if (options.refute) { - refuteArgs = options.refute.length; - } else { - refuteArgs = options.assert.length; - options.refute = function () { - return !options.assert.apply(this, arguments); - }; - } - - var values = options && options.values; // TODO: Remove - defineAssertion("assert", name, options.assert, options.assert.length, values); - defineAssertion("refute", name, options.refute, refuteArgs, values); - - assert[name].message = options.assertMessage; - refute[name].message = options.refuteMessage; - - if (options.expectation) { - if (ba.expect && ba.expect.wrapAssertion) { - ba.expect.wrapAssertion(name, options.expectation); - } else { - assert[name].expectationName = options.expectation; - refute[name].expectationName = options.expectation; - } - } - }; - - function interpolate(string, property, value) { - return string.replace(new RegExp("\\$\\{" + property + "\\}", "g"), value); - } - - function interpolatePosArg(message, values) { - var value; - values = values || []; - - for (var i = 0, l = values.length; i < l; i++) { - message = interpolate(message, i, ba.format(values[i])); - } - - return message; - } - - function interpolateProperties(msg, properties) { - for (var prop in properties) { - msg = interpolate(msg, prop, ba.format(properties[prop])); - } - - return msg || ""; - } - - function fail(type, assertion, msg) { - delete this.fail; - var message = interpolateProperties( - interpolatePosArg(ba[type][assertion][msg] || msg, - [].slice.call(arguments, 3)), this); - ba.fail("[" + type + "." + assertion + "] " + message); - } - - function isDate(value) { - // Duck typed dates, allows objects to take on the role of dates - // without actually being dates - return typeof value.getTime == "function" && - value.getTime() == value.valueOf(); - } - - ba.isDate = isDate; - - // Fixes NaN === NaN (should be true) and - // -0 === +0 (should be false) - // http://wiki.ecmascript.org/doku.php?id=harmony:egal - function egal(x, y) { - if (x === y) { - // 0 === -0, but they are not identical - return x !== 0 || 1 / x === 1 / y; - } - - // NaN !== NaN, but they are identical. - // NaNs are the only non-reflexive value, i.e., if x !== x, - // then x is a NaN. - // isNaN is broken: it converts its argument to number, so - // isNaN("foo") => true - return x !== x && y !== y; - } - - function areEqual(expected, actual) { - if (egal(expected, actual)) { - return true; - } - - // Elements are only equal if expected === actual - if (buster.isElement(expected) || buster.isElement(actual)) { - return false; - } - - // null and undefined only pass for null === null and - // undefined === undefined - /*jsl: ignore*/ - if (expected == null || actual == null) { - return actual === expected; - } - /*jsl: end*/ - - if (isDate(expected) || isDate(actual)) { - return isDate(expected) && isDate(actual) && - expected.getTime() == actual.getTime(); - } - - var useCoercingEquality = typeof expected != "object" || typeof actual != "object"; - - if (expected instanceof RegExp && actual instanceof RegExp) { - if (expected.toString() != actual.toString()) { - return false; - } - - useCoercingEquality = false; - } - - // Arrays can only be equal to arrays - var expectedStr = toString.call(expected); - var actualStr = toString.call(actual); - - // Coerce and compare when primitives are involved - if (useCoercingEquality) { - return expectedStr != "[object Array]" && actualStr != "[object Array]" && - expected == actual; - } - - var expectedKeys = ba.keys(expected); - var actualKeys = ba.keys(actual); - - if (isArguments(expected) || isArguments(actual)) { - if (expected.length != actual.length) { - return false; - } - } else { - if (typeof expected != typeof actual || expectedStr != actualStr || - expectedKeys.length != actualKeys.length) { - return false; - } - } - - var key; - - for (var i = 0, l = expectedKeys.length; i < l; i++) { - key = expectedKeys[i]; - if (!Object.prototype.hasOwnProperty.call(actual, key) || - !areEqual(expected[key], actual[key])) { - return false; - } - } - - return true; - } - - ba.deepEqual = areEqual; - - assert = ba.assert = function assert(actual, message) { - countAssertion(); - if (!assertEnoughArguments("assert", arguments, 1)) return; - - if (!actual) { - var val = ba.format(actual); - ba.fail(message || "[assert] Expected " + val + " to be truthy"); - } else { - ba.emit("pass", "assert", message || "", actual); - } - }; - - assert.toString = function () { - return "buster.assert"; - }; - - refute = ba.refute = function (actual, message) { - countAssertion(); - if (!assertEnoughArguments("refute", arguments, 1)) return; - - if (actual) { - var val = ba.format(actual); - ba.fail(message || "[refute] Expected " + val + " to be falsy"); - } else { - ba.emit("pass", "refute", message || "", actual); - } - }; - - assert.message = "[assert] Expected ${0} to be truthy"; - ba.count = 0; - - ba.fail = function (message) { - var exception = new Error(message); - exception.name = "AssertionError"; - - try { - throw exception; - } catch (e) { - ba.emit("failure", e); - } - - if (typeof ba.throwOnFailure != "boolean" || ba.throwOnFailure) { - throw exception; - } - }; - - ba.format = function (object) { - return "" + object; - }; - - function msg(message) { - if (!message) { return ""; } - return message + (/[.:!?]$/.test(message) ? " " : ": "); - } - - function actualAndExpectedMessageValues(actual, expected, message) { - return [actual, expected, msg(message)] - } - - function actualMessageValues(actual) { - return [actual, msg(arguments[1])]; - } - - function actualAndTypeOfMessageValues(actual) { - return [actual, typeof actual, msg(arguments[1])]; - } - - ba.add("same", { - assert: function (actual, expected) { - return egal(actual, expected); - }, - refute: function (actual, expected) { - return !egal(actual, expected); - }, - assertMessage: "${2}${0} expected to be the same object as ${1}", - refuteMessage: "${2}${0} expected not to be the same object as ${1}", - expectation: "toBe", - values: actualAndExpectedMessageValues - }); - - function multiLineStringDiff(actual, expected, message) { - if (actual == expected) return true; - - var message = interpolatePosArg(assert.equals.multiLineStringHeading, [message]), - actualLines = actual.split("\n"), - expectedLines = expected.split("\n"), - lineCount = Math.max(expectedLines.length, actualLines.length), - lines = []; - - for (var i = 0; i < lineCount; ++i) { - if (expectedLines[i] != actualLines[i]) { - lines.push("line " + (i + 1) + ": " + (expectedLines[i] || "") + - "\nwas: " + (actualLines[i] || "")); - } - } - - ba.fail("[assert.equals] " + message + lines.join("\n\n")); - return false; - } - - ba.add("equals", { - assert: function (actual, expected) { - if (typeof actual == "string" && typeof expected == "string" && - (actual.indexOf("\n") >= 0 || expected.indexOf("\n") >= 0)) { - var message = msg(arguments[2]); - return multiLineStringDiff.call(this, actual, expected, message); - } - - return areEqual(actual, expected); - }, - - refute: function (actual, expected) { - return !areEqual(actual, expected); - }, - - assertMessage: "${2}${0} expected to be equal to ${1}", - refuteMessage: "${2}${0} expected not to be equal to ${1}", - expectation: "toEqual", - values: actualAndExpectedMessageValues - }); - - assert.equals.multiLineStringHeading = "${0}Expected multi-line strings to be equal:\n"; - - ba.add("greater", { - assert: function (actual, expected) { - return actual > expected; - }, - - assertMessage: "${2}Expected ${0} to be greater than ${1}", - refuteMessage: "${2}Expected ${0} to be less than or equal to ${1}", - expectation: "toBeGreaterThan", - values: actualAndExpectedMessageValues - }); - - ba.add("less", { - assert: function (actual, expected) { - return actual < expected; - }, - - assertMessage: "${2}Expected ${0} to be less than ${1}", - refuteMessage: "${2}Expected ${0} to be greater than or equal to ${1}", - expectation: "toBeLessThan", - values: actualAndExpectedMessageValues - }); - - ba.add("defined", { - assert: function (actual) { - return typeof actual != "undefined"; - }, - assertMessage: "${2}Expected to be defined", - refuteMessage: "${2}Expected ${0} (${1}) not to be defined", - expectation: "toBeDefined", - values: actualAndTypeOfMessageValues - }); - - ba.add("isNull", { - assert: function (actual) { - return actual === null; - }, - assertMessage: "${1}Expected ${0} to be null", - refuteMessage: "${1}Expected not to be null", - expectation: "toBeNull", - values: actualMessageValues - }); - - function arrayContains(array, subset) { - var i, l, j, k; - for (i = 0, l = array.length; i < l; ++i) { - if (match(array[i], subset[0])) { - for (j = 0, k = subset.length; j < k; ++j) { - if (!match(array[i + j], subset[j])) { return false; } - } - return true; - } - } - return false; - } - - function match(object, matcher) { - if (matcher && typeof matcher.test == "function") { - return matcher.test(object); - } - - if (typeof matcher == "function") { - return matcher(object) === true; - } - - if (typeof matcher == "string") { - matcher = matcher.toLowerCase(); - var notNull = typeof object === "string" || !!object; - return notNull && ("" + object).toLowerCase().indexOf(matcher) >= 0; - } - - if (typeof matcher == "number") { - return matcher == object; - } - - if (typeof matcher == "boolean") { - return matcher === object; - } - - if (toString.call(object) == "[object Array]" && - toString.call(matcher) == "[object Array]") { - return arrayContains(object, matcher); - } - - if (matcher && typeof matcher == "object") { - for (var prop in matcher) { - if (!match(object[prop], matcher[prop])) { - return false; - } - } - - return true; - } - - throw new Error("Matcher (" + ba.format(matcher) + ") was not a " + - "string, a number, a function, a boolean or an object"); - } - - ba.match = match; - - ba.add("match", { - assert: function (actual, matcher) { - var passed; - - try { - passed = match(actual, matcher); - } catch (e) { - return this.fail("exceptionMessage", e.message, msg(arguments[2])); - } - - return passed; - }, - - refute: function (actual, matcher) { - var passed; - - try { - passed = match(actual, matcher); - } catch (e) { - return this.fail("exceptionMessage", e.message); - } - - return !passed; - }, - - assertMessage: "${2}${0} expected to match ${1}", - refuteMessage: "${2}${0} expected not to match ${1}", - expectation: "toMatch", - values: actualAndExpectedMessageValues - }); - - assert.match.exceptionMessage = "${1}${0}"; - refute.match.exceptionMessage = "${1}${0}"; - - ba.add("isObject", { - assert: function (actual) { - return typeof actual == "object" && !!actual; - }, - assertMessage: "${2}${0} (${1}) expected to be object and not null", - refuteMessage: "${2}${0} expected to be null or not an object", - expectation: "toBeObject", - values: actualAndTypeOfMessageValues - }); - - ba.add("isFunction", { - assert: function (actual) { - return typeof actual == "function"; - }, - assertMessage: "${2}${0} (${1}) expected to be function", - refuteMessage: "${2}${0} expected not to be function", - expectation: "toBeFunction", - values: function (actual) { - return [("" + actual).replace("\n", ""), typeof actual, msg(arguments[1])]; - } - }); - - ba.add("isTrue", { - assert: function (actual) { - return actual === true; - }, - assertMessage: "${1}Expected ${0} to be true", - refuteMessage: "${1}Expected ${0} to not be true", - expectation: "toBeTrue", - values: actualMessageValues - }); - - ba.add("isFalse", { - assert: function (actual) { - return actual === false; - }, - assertMessage: "${1}Expected ${0} to be false", - refuteMessage: "${1}Expected ${0} to not be false", - expectation: "toBeFalse", - values: actualMessageValues - }); - - ba.add("isString", { - assert: function (actual) { - return typeof actual == "string"; - }, - assertMessage: "${2}Expected ${0} (${1}) to be string", - refuteMessage: "${2}Expected ${0} not to be string", - expectation: "toBeString", - values: actualAndTypeOfMessageValues - }); - - ba.add("isBoolean", { - assert: function (actual) { - return typeof actual == "boolean"; - }, - assertMessage: "${2}Expected ${0} (${1}) to be boolean", - refuteMessage: "${2}Expected ${0} not to be boolean", - expectation: "toBeBoolean", - values: actualAndTypeOfMessageValues - }); - - ba.add("isNumber", { - assert: function (actual) { - return typeof actual == "number" && !isNaN(actual); - }, - assertMessage: "${2}Expected ${0} (${1}) to be a non-NaN number", - refuteMessage: "${2}Expected ${0} to be NaN or another non-number value", - expectation: "toBeNumber", - values: actualAndTypeOfMessageValues - }); - - ba.add("isNaN", { - assert: function (actual) { - return typeof actual == "number" && isNaN(actual); - }, - assertMessage: "${2}Expected ${0} to be NaN", - refuteMessage: "${2}Expected not to be NaN", - expectation: "toBeNaN", - values: actualAndTypeOfMessageValues - }); - - ba.add("isArray", { - assert: function (actual) { - return toString.call(actual) == "[object Array]"; - }, - assertMessage: "${2}Expected ${0} to be array", - refuteMessage: "${2}Expected ${0} not to be array", - expectation: "toBeArray", - values: actualAndTypeOfMessageValues - }); - - function isArrayLike(object) { - return toString.call(object) == "[object Array]" || - (!!object && typeof object.length == "number" && - typeof object.splice == "function") || - ba.isArguments(object); - } - - ba.isArrayLike = isArrayLike; - - ba.add("isArrayLike", { - assert: function (actual) { - return isArrayLike(actual); - }, - assertMessage: "${2}Expected ${0} to be array like", - refuteMessage: "${2}Expected ${0} not to be array like", - expectation: "toBeArrayLike", - values: actualAndTypeOfMessageValues - }); - - function captureException(callback) { - try { - callback(); - } catch (e) { - return e; - } - - return null; - } - - ba.captureException = captureException; - - assert.exception = function (callback, matcher, message) { - countAssertion(); - if (!assertEnoughArguments("assert.exception", arguments, 1)) { return; } - if (!callback) { return; } - - if (typeof matcher === "string") { - message = matcher; - matcher = undefined; - } - - var err = captureException(callback); - message = msg(message); - - if (!err) { - if (typeof matcher === "object") { - return fail.call({}, "assert", "exception", "typeNoExceptionMessage", - message, ba.format(matcher)); - } else { - return fail.call({}, "assert", "exception", "message", message); - } - } - - if (typeof matcher === "object" && !match(err, matcher)) { - return fail.call({}, "assert", "exception", "typeFailMessage", - message, ba.format(matcher), err.name, err.message); - } - - if (typeof matcher === "function" && matcher(err) !== true) { - return fail.call({}, "assert", "exception", "matchFailMessage", - message, err.name, err.message); - } - - ba.emit("pass", "assert.exception", message, callback, matcher); - }; - - assert.exception.typeNoExceptionMessage = "${0}Expected ${1} but no exception was thrown"; - assert.exception.message = "${0}Expected exception"; - assert.exception.typeFailMessage = "${0}Expected ${1} but threw ${2} (${3})"; - assert.exception.matchFailMessage = "${0}Expected thrown ${1} (${2}) to pass matcher function"; - assert.exception.expectationName = "toThrow"; - - refute.exception = function (callback) { - countAssertion(); - if (!assertEnoughArguments("refute.exception", arguments, 1)) return; - - var err = captureException(callback); - - if (err) { - fail.call({}, "refute", "exception", "message", - msg(arguments[1]), err.name, err.message, callback); - } else { - ba.emit("pass", "refute.exception", callback); - } - }; - - refute.exception.message = "${0}Expected not to throw but threw ${1} (${2})"; - refute.exception.expectationName = "toThrow"; - - ba.add("near", { - assert: function (actual, expected, delta) { - return Math.abs(actual - expected) <= delta; - }, - assertMessage: "${3}Expected ${0} to be equal to ${1} +/- ${2}", - refuteMessage: "${3}Expected ${0} not to be equal to ${1} +/- ${2}", - expectation: "toBeNear", - values: function (actual, expected, delta, message) { - return [actual, expected, delta, msg(message)]; - } - }); - - ba.add("hasPrototype", { - assert: function (actual, protoObj) { - return protoObj.isPrototypeOf(actual); - }, - assertMessage: "${2}Expected ${0} to have ${1} on its prototype chain", - refuteMessage: "${2}Expected ${0} not to have ${1} on its prototype chain", - expectation: "toHavePrototype", - values: actualAndExpectedMessageValues - }); - - ba.add("contains", { - assert: function (haystack, needle) { - for (var i = 0; i < haystack.length; i++) { - if (haystack[i] === needle) { - return true; - } - } - return false; - }, - assertMessage: "${2}Expected [${0}] to contain ${1}", - refuteMessage: "${2}Expected [${0}] not to contain ${1}", - expectation: "toContain", - values: actualAndExpectedMessageValues - }); - - ba.add("tagName", { - assert: function (element, tagName) { - if (!element.tagName) { - return this.fail("noTagNameMessage", tagName, element, msg(arguments[2])); - } - - return tagName.toLowerCase && - tagName.toLowerCase() == element.tagName.toLowerCase(); - }, - assertMessage: "${2}Expected tagName to be ${0} but was ${1}", - refuteMessage: "${2}Expected tagName not to be ${0}", - expectation: "toHaveTagName", - values: function (element, tagName, message) { - return [tagName, element.tagName, msg(message)]; - } - }); - - assert.tagName.noTagNameMessage = "${2}Expected ${1} to have tagName property"; - refute.tagName.noTagNameMessage = "${2}Expected ${1} to have tagName property"; - - function indexOf(arr, item) { - for (var i = 0, l = arr.length; i < l; i++) { - if (arr[i] == item) { - return i; - } - } - - return -1; - } - - ba.add("className", { - assert: function (element, className) { - if (typeof element.className == "undefined") { - return this.fail("noClassNameMessage", className, element, msg(arguments[2])); - } - - var expected = typeof className == "string" ? className.split(" ") : className; - var actual = element.className.split(" "); - - for (var i = 0, l = expected.length; i < l; i++) { - if (indexOf(actual, expected[i]) < 0) { - return false; - } - } - - return true; - }, - assertMessage: "${2}Expected object's className to include ${0} but was ${1}", - refuteMessage: "${2}Expected object's className not to include ${0}", - expectation: "toHaveClassName", - values: function (element, className, message) { - return [className, element.className, msg(message)]; - } - }); - - assert.className.noClassNameMessage = "${2}Expected object to have className property"; - refute.className.noClassNameMessage = "${2}Expected object to have className property"; - - if (typeof module != "undefined") { - ba.expect = function () { - ba.expect = require("./buster-assertions/expect"); - return ba.expect.apply(exports, arguments); - }; - } - - function isArguments(obj) { - if (typeof obj != "object" || typeof obj.length != "number" || - toString.call(obj) == "[object Array]") { - return false; - } - - if (typeof obj.callee == "function") { - return true; - } - - try { - obj[obj.length] = 6; - delete obj[obj.length]; - } catch (e) { - return true; - } - - return false; - } - - ba.isArguments = isArguments; - - ba.keys = function (object) { - var keys = []; - - for (var prop in object) { - if (Object.prototype.hasOwnProperty.call(object, prop)) { - keys.push(prop); - } - } - - return keys; - }; -}()); diff --git a/lib/buster-assertions/expect.js b/lib/buster-assertions/expect.js deleted file mode 100644 index 166bec79..00000000 --- a/lib/buster-assertions/expect.js +++ /dev/null @@ -1,63 +0,0 @@ -if (typeof module == "object" && typeof require == "function") { - var buster = require("buster-core"); - buster.assertions = require("../buster-assertions"); -} - -(function (ba) { - ba.expectation = {}; - - ba.expect = function (actual) { - var expectation = buster.extend(buster.create(ba.expectation), { - actual: actual, - assertMode: true - }); - expectation.not = buster.create(expectation); - expectation.not.assertMode = false; - return expectation; - }; - - ba.expect.wrapAssertion = function (assertion, expectation) { - ba.expectation[expectation] = function () { - var args = [this.actual].concat(Array.prototype.slice.call(arguments)); - var type = this.assertMode ? "assert" : "refute"; - var callFunc; - - if (assertion === "assert") { - callFunc = this.assertMode ? ba.assert : ba.refute; - } else if (assertion === "refute") { - callFunc = this.assertMode ? ba.refute : ba.assert; - } else { - callFunc = ba[type][assertion]; - } - - try { - return callFunc.apply(ba.expect, args); - } catch (e) { - e.message = (e.message || "").replace( - "[" + type + "." + assertion + "]", - "[expect." + (this.assertMode ? "" : "not.") + expectation + "]"); - throw e; - } - }; - }; - - var prop, expectationName; - - for (prop in ba.assert) { - if (ba.assert[prop].expectationName) { - expectationName = ba.assert[prop].expectationName; - ba.expect.wrapAssertion(prop, expectationName); - } - } - - ba.expect.wrapAssertion("assert", "toBeTruthy"); - ba.expect.wrapAssertion("refute", "toBeFalsy"); - - if (ba.expectation.toBeNear) { - ba.expectation.toBeCloseTo = ba.expectation.toBeNear; - } - - if (typeof module == "object") { - module.exports = ba.expect; - } -}(buster.assertions)); diff --git a/lib/expect.js b/lib/expect.js new file mode 100644 index 00000000..b95ec494 --- /dev/null +++ b/lib/expect.js @@ -0,0 +1,65 @@ +((typeof define === "function" && define.amd && function (m) { + define(["lodash", "referee"], m); +}) || (typeof module === "object" && function (m) { + module.exports = m(require("lodash"), require("./referee")); +}) || function (m) { this.referee.expect = m(this._, this.referee); } +)(function (_, referee) { + var expectation = {}; + function F() {} + var create = function (object) { F.prototype = object; return new F(); }; + + var expect = function (actual) { + var expectation = _.extend(create(expect.expectation), { + actual: actual, + assertMode: true + }); + expectation.not = create(expectation); + expectation.not.assertMode = false; + return expectation; + }; + + expect.expectation = expectation; + + expect.wrapAssertion = function (assertion, expectation) { + expect.expectation[expectation] = function () { + var args = [this.actual].concat(_.toArray(arguments)); + var type = this.assertMode ? "assert" : "refute"; + var callFunc; + + if (assertion === "assert") { + callFunc = this.assertMode ? referee.assert : referee.refute; + } else if (assertion === "refute") { + callFunc = this.assertMode ? referee.refute : referee.assert; + } else { + callFunc = referee[type][assertion]; + } + + try { + return callFunc.apply(referee.expect, args); + } catch (e) { + e.message = (e.message || "").replace( + "[" + type + "." + assertion + "]", + "[expect." + (this.assertMode ? "" : "not.") + + expectation + "]" + ); + throw e; + } + }; + }; + + _.each(_.keys(referee.assert), function (name) { + var expectationName = referee.assert[name].expectationName; + if (expectationName) { + expect.wrapAssertion(name, expectationName); + } + }); + + expect.wrapAssertion("assert", "toBeTruthy"); + expect.wrapAssertion("refute", "toBeFalsy"); + + if (expect.expectation.toBeNear) { + expect.expectation.toBeCloseTo = expect.expectation.toBeNear; + } + + return expect; +}); diff --git a/lib/referee.js b/lib/referee.js new file mode 100644 index 00000000..016a7eb5 --- /dev/null +++ b/lib/referee.js @@ -0,0 +1,647 @@ +((typeof define === "function" && define.amd && function (m) { + define(["lodash", "samsam", "bane"], m); +}) || (typeof module === "object" && function (m) { + module.exports = m(require("lodash"), require("samsam"), require("bane")); +}) || function (m) { this.referee = m(this._, this.samsam, this.bane); } +)(function (_, samsam, bane) { + "use strict"; + + var toString = Object.prototype.toString; + var slice = Array.prototype.slice; + var assert, refute, referee = bane.createEventEmitter(); + + referee.countAssertion = function countAssertion() { + if (typeof referee.count !== "number") { referee.count = 0; } + referee.count += 1; + }; + + function interpolate(string, prop, value) { + return string.replace(new RegExp("\\$\\{" + prop + "\\}", "g"), value); + } + + // Interpolate positional arguments. Replaces occurences of ${} in + // the string with the corresponding entry in values[] + function interpolatePosArg(message, values) { + return _.reduce(values, function (msg, value, index) { + return interpolate(msg, index, referee.format(value)); + }, message); + } + + function interpolateProperties(message, properties) { + return _.reduce(_.keys(properties), function (msg, name) { + return interpolate(msg, name, referee.format(properties[name])); + }, message || ""); + } + + // Fail an assertion. Interpolates message before calling referee.fail + function fail(type, assertion, msg) { + delete this.fail; + var message = interpolateProperties(interpolatePosArg( + referee[type][assertion][msg] || msg, + [].slice.call(arguments, 3) + ), this); + referee.fail("[" + type + "." + assertion + "] " + message); + } + + // Internal helper. Used throughout to fail assertions if they receive + // too few arguments. The name is provided for a helpful error message. + function assertArgNum(name, args, num) { + if (args.length < num) { + referee.fail("[" + name + "] Expected to receive at least " + + num + " argument" + (num > 1 ? "s" : "")); + return false; + } + return true; + } + + // Internal helper. Not the most elegant of functions, but it takes + // care of all the nitty-gritty of assertion functions: counting, + // verifying parameter count, interpolating messages with actual + // values and so on. + function defineAssertion(type, name, func, minArgs, messageValues) { + referee[type][name] = function () { + referee.countAssertion(); + var fullName = type + "." + name, failed = false; + + if (!assertArgNum(fullName, arguments, minArgs || func.length)) { + return; + } + + var ctx = { + fail: function () { + failed = true; + var failArgs = [type, name].concat(slice.call(arguments)); + fail.apply(this, failArgs); + return true; + } + }; + + var args = slice.call(arguments, 0); + + if (typeof messageValues === "function") { + args = messageValues.apply(this, args); + } + + if (!func.apply(ctx, arguments)) { + return fail.apply(ctx, [type, name, "message"].concat(args)); + } + + if (!failed) { + referee.emit.apply(referee, ["pass", fullName].concat(args)); + } + }; + } + + referee.add = function (name, opt) { + var refuteArgs; + + if (opt.refute) { + refuteArgs = opt.refute.length; + } else { + refuteArgs = opt.assert.length; + opt.refute = function () { + return !opt.assert.apply(this, arguments); + }; + } + + var values = opt.values; + defineAssertion("assert", name, opt.assert, opt.assert.length, values); + defineAssertion("refute", name, opt.refute, refuteArgs, values); + + assert[name].message = opt.assertMessage; + refute[name].message = opt.refuteMessage; + + if (opt.expectation) { + if (referee.expect && referee.expect.wrapAssertion) { + referee.expect.wrapAssertion(name, opt.expectation); + } else { + assert[name].expectationName = opt.expectation; + refute[name].expectationName = opt.expectation; + } + } + }; + + assert = referee.assert = function assert(actual, message) { + referee.countAssertion(); + if (!assertArgNum("assert", arguments, 1)) { return; } + + if (!actual) { + var v = referee.format(actual); + referee.fail(message || "[assert] Expected " + v + " to be truthy"); + } else { + referee.emit("pass", "assert", message || "", actual); + } + }; + + assert.toString = function () { + return "referee.assert()"; + }; + + refute = referee.refute = function (actual, message) { + referee.countAssertion(); + if (!assertArgNum("refute", arguments, 1)) { return; } + + if (actual) { + var v = referee.format(actual); + referee.fail(message || "[refute] Expected " + v + " to be falsy"); + } else { + referee.emit("pass", "refute", message || "", actual); + } + }; + + assert.message = "[assert] Expected ${0} to be truthy"; + referee.count = 0; + + referee.fail = function (message) { + var exception = new Error(message); + exception.name = "AssertionError"; + + try { + throw exception; + } catch (e) { + referee.emit("failure", e); + } + + if (typeof referee.throwOnFailure !== "boolean" || + referee.throwOnFailure) { + throw exception; + } + }; + + referee.format = function (object) { return String(object); }; + + function msg(message) { + if (!message) { return ""; } + return message + (/[.:!?]$/.test(message) ? " " : ": "); + } + + function actualAndExpectedMessageValues(actual, expected, message) { + return [actual, expected, msg(message)]; + } + + function actualMessageValues(actual, message) { + return [actual, msg(message)]; + } + + function actualAndTypeOfMessageValues(actual, message) { + return [actual, typeof actual, msg(message)]; + } + + referee.add("same", { + assert: function (actual, expected) { + return samsam.identical(actual, expected); + }, + refute: function (actual, expected) { + return !samsam.identical(actual, expected); + }, + assertMessage: "${2}${0} expected to be the same object as ${1}", + refuteMessage: "${2}${0} expected not to be the same object as ${1}", + expectation: "toBe", + values: actualAndExpectedMessageValues + }); + + // Extract/replace with separate module that does a more detailed + // visualization of multi-line strings + function multiLineStringDiff(actual, expected, message) { + if (actual === expected) { return true; } + + var heading = assert.equals.multiLineStringHeading; + message = interpolatePosArg(heading, [message]); + var actualLines = actual.split("\n"); + var expectedLines = expected.split("\n"); + var lineCount = Math.max(expectedLines.length, actualLines.length); + var i, lines = []; + + for (i = 0; i < lineCount; ++i) { + if (expectedLines[i] !== actualLines[i]) { + lines.push("line " + (i + 1) + ": " + (expectedLines[i] || "") + + "\nwas: " + (actualLines[i] || "")); + } + } + + referee.fail("[assert.equals] " + message + lines.join("\n\n")); + return false; + } + + referee.add("equals", { + // Uses arguments[2] because the function's .length is used to determine + // the minimum required number of arguments. + assert: function (actual, expected) { + if (typeof actual === "string" && typeof expected === "string" && + (actual.indexOf("\n") >= 0 || + expected.indexOf("\n") >= 0)) { + var message = msg(arguments[2]); + return multiLineStringDiff(actual, expected, message); + } + + return samsam.deepEqual(actual, expected); + }, + + refute: function (actual, expected) { + return !samsam.deepEqual(actual, expected); + }, + + assertMessage: "${2}${0} expected to be equal to ${1}", + refuteMessage: "${2}${0} expected not to be equal to ${1}", + expectation: "toEqual", + values: actualAndExpectedMessageValues + }); + + assert.equals.multiLineStringHeading = "${0}Expected multi-line strings " + + "to be equal:\n"; + + referee.add("greater", { + assert: function (actual, expected) { + return actual > expected; + }, + + assertMessage: "${2}Expected ${0} to be greater than ${1}", + refuteMessage: "${2}Expected ${0} to be less than or equal to ${1}", + expectation: "toBeGreaterThan", + values: actualAndExpectedMessageValues + }); + + referee.add("less", { + assert: function (actual, expected) { + return actual < expected; + }, + + assertMessage: "${2}Expected ${0} to be less than ${1}", + refuteMessage: "${2}Expected ${0} to be greater than or equal to ${1}", + expectation: "toBeLessThan", + values: actualAndExpectedMessageValues + }); + + referee.add("defined", { + assert: function (actual) { + return typeof actual !== "undefined"; + }, + assertMessage: "${2}Expected to be defined", + refuteMessage: "${2}Expected ${0} (${1}) not to be defined", + expectation: "toBeDefined", + values: actualAndTypeOfMessageValues + }); + + referee.add("isNull", { + assert: function (actual) { + return actual === null; + }, + assertMessage: "${1}Expected ${0} to be null", + refuteMessage: "${1}Expected not to be null", + expectation: "toBeNull", + values: actualMessageValues + }); + + + referee.match = function (actual, matcher) { + try { + return samsam.match(actual, matcher); + } catch (e) { + throw new Error("Matcher (" + referee.format(matcher) + + ") was not a string, a number, a function, " + + "a boolean or an object"); + } + }; + + referee.add("match", { + assert: function (actual, matcher) { + var passed; + + try { + passed = referee.match(actual, matcher); + } catch (e) { + // Uses arguments[2] because the function's .length is used + // to determine the minimum required number of arguments. + var message = msg(arguments[2]); + return this.fail("exceptionMessage", e.message, message); + } + + return passed; + }, + + refute: function (actual, matcher) { + var passed; + + try { + passed = referee.match(actual, matcher); + } catch (e) { + return this.fail("exceptionMessage", e.message); + } + + return !passed; + }, + + assertMessage: "${2}${0} expected to match ${1}", + refuteMessage: "${2}${0} expected not to match ${1}", + expectation: "toMatch", + values: actualAndExpectedMessageValues + }); + + assert.match.exceptionMessage = "${1}${0}"; + refute.match.exceptionMessage = "${1}${0}"; + + referee.add("isObject", { + assert: function (actual) { + return typeof actual === "object" && !!actual; + }, + assertMessage: "${2}${0} (${1}) expected to be object and not null", + refuteMessage: "${2}${0} expected to be null or not an object", + expectation: "toBeObject", + values: actualAndTypeOfMessageValues + }); + + referee.add("isFunction", { + assert: function (actual) { + return typeof actual === "function"; + }, + assertMessage: "${2}${0} (${1}) expected to be function", + refuteMessage: "${2}${0} expected not to be function", + expectation: "toBeFunction", + values: function (actual) { + // Uses arguments[1] because the function's .length is used to + // determine the minimum required number of arguments. + var message = msg(arguments[1]); + return [String(actual).replace("\n", ""), typeof actual, message]; + } + }); + + referee.add("isTrue", { + assert: function (actual) { + return actual === true; + }, + assertMessage: "${1}Expected ${0} to be true", + refuteMessage: "${1}Expected ${0} to not be true", + expectation: "toBeTrue", + values: actualMessageValues + }); + + referee.add("isFalse", { + assert: function (actual) { + return actual === false; + }, + assertMessage: "${1}Expected ${0} to be false", + refuteMessage: "${1}Expected ${0} to not be false", + expectation: "toBeFalse", + values: actualMessageValues + }); + + referee.add("isString", { + assert: function (actual) { + return typeof actual === "string"; + }, + assertMessage: "${2}Expected ${0} (${1}) to be string", + refuteMessage: "${2}Expected ${0} not to be string", + expectation: "toBeString", + values: actualAndTypeOfMessageValues + }); + + referee.add("isBoolean", { + assert: function (actual) { + return typeof actual === "boolean"; + }, + assertMessage: "${2}Expected ${0} (${1}) to be boolean", + refuteMessage: "${2}Expected ${0} not to be boolean", + expectation: "toBeBoolean", + values: actualAndTypeOfMessageValues + }); + + referee.add("isNumber", { + assert: function (actual) { + return typeof actual === "number" && !isNaN(actual); + }, + assertMessage: "${2}Expected ${0} (${1}) to be a non-NaN number", + refuteMessage: "${2}Expected ${0} to be NaN or a non-number value", + expectation: "toBeNumber", + values: actualAndTypeOfMessageValues + }); + + referee.add("isNaN", { + assert: function (actual) { + return typeof actual === "number" && isNaN(actual); + }, + assertMessage: "${2}Expected ${0} to be NaN", + refuteMessage: "${2}Expected not to be NaN", + expectation: "toBeNaN", + values: actualAndTypeOfMessageValues + }); + + referee.add("isArray", { + assert: function (actual) { + return toString.call(actual) === "[object Array]"; + }, + assertMessage: "${2}Expected ${0} to be array", + refuteMessage: "${2}Expected ${0} not to be array", + expectation: "toBeArray", + values: actualAndTypeOfMessageValues + }); + + function isArrayLike(object) { + return _.isArray(object) || + (!!object && typeof object.length === "number" && + typeof object.splice === "function") || + _.isArguments(object); + } + + referee.isArrayLike = isArrayLike; + + referee.add("isArrayLike", { + assert: function (actual) { + return isArrayLike(actual); + }, + assertMessage: "${2}Expected ${0} to be array like", + refuteMessage: "${2}Expected ${0} not to be array like", + expectation: "toBeArrayLike", + values: actualAndTypeOfMessageValues + }); + + function captureException(callback) { + try { callback(); } catch (e) { return e; } + return null; + } + + referee.captureException = captureException; + + assert.exception = function (callback, matcher, message) { + referee.countAssertion(); + if (!assertArgNum("assert.exception", arguments, 1)) { return; } + if (!callback) { return; } + + if (typeof matcher === "string") { + message = matcher; + matcher = undefined; + } + + var err = captureException(callback); + message = msg(message); + + if (!err) { + if (typeof matcher === "object") { + return fail.call( + {}, + "assert", + "exception", + "typeNoExceptionMessage", + message, + referee.format(matcher) + ); + } else { + return fail.call({}, "assert", "exception", "message", message); + } + } + + if (typeof matcher === "object" && !referee.match(err, matcher)) { + return fail.call( + {}, + "assert", + "exception", + "typeFailMessage", + message, + referee.format(matcher), + err.name, + err.message + ); + } + + if (typeof matcher === "function" && matcher(err) !== true) { + return fail.call({}, "assert", "exception", "matchFailMessage", + message, err.name, err.message); + } + + referee.emit("pass", "assert.exception", message, callback, matcher); + }; + + assert.exception.typeNoExceptionMessage = "${0}Expected ${1} but no " + + "exception was thrown"; + assert.exception.message = "${0}Expected exception"; + assert.exception.typeFailMessage = "${0}Expected ${1} but threw ${2} " + + "(${3})"; + assert.exception.matchFailMessage = "${0}Expected thrown ${1} (${2}) to " + + "pass matcher function"; + assert.exception.expectationName = "toThrow"; + + refute.exception = function (callback) { + referee.countAssertion(); + if (!assertArgNum("refute.exception", arguments, 1)) { return; } + var err = captureException(callback); + + if (err) { + // Uses arguments[1] because the function's .length is used to + // determine the minimum required number of arguments. + fail.call({}, "refute", "exception", "message", + msg(arguments[1]), err.name, err.message, callback); + } else { + referee.emit("pass", "refute.exception", callback); + } + }; + + refute.exception.message = "${0}Expected not to throw but " + + "threw ${1} (${2})"; + refute.exception.expectationName = "toThrow"; + + referee.add("near", { + assert: function (actual, expected, delta) { + return Math.abs(actual - expected) <= delta; + }, + assertMessage: "${3}Expected ${0} to be equal to ${1} +/- ${2}", + refuteMessage: "${3}Expected ${0} not to be equal to ${1} +/- ${2}", + expectation: "toBeNear", + values: function (actual, expected, delta, message) { + return [actual, expected, delta, msg(message)]; + } + }); + + referee.add("hasPrototype", { + assert: function (actual, protoObj) { + return protoObj.isPrototypeOf(actual); + }, + assertMessage: "${2}Expected ${0} to have ${1} on its prototype chain", + refuteMessage: "${2}Expected ${0} not to have ${1} on its " + + "prototype chain", + expectation: "toHavePrototype", + values: actualAndExpectedMessageValues + }); + + referee.add("contains", { + assert: function (haystack, needle) { + return _.include(haystack, needle); + }, + assertMessage: "${2}Expected [${0}] to contain ${1}", + refuteMessage: "${2}Expected [${0}] not to contain ${1}", + expectation: "toContain", + values: actualAndExpectedMessageValues + }); + + referee.add("tagName", { + assert: function (element, tagName) { + // Uses arguments[2] because the function's .length is used to + // determine the minimum required number of arguments. + if (!element.tagName) { + return this.fail( + "noTagNameMessage", + tagName, + element, + msg(arguments[2]) + ); + } + + return tagName.toLowerCase && + tagName.toLowerCase() === element.tagName.toLowerCase(); + }, + assertMessage: "${2}Expected tagName to be ${0} but was ${1}", + refuteMessage: "${2}Expected tagName not to be ${0}", + expectation: "toHaveTagName", + values: function (element, tagName, message) { + return [tagName, element.tagName, msg(message)]; + } + }); + + assert.tagName.noTagNameMessage = "${2}Expected ${1} to have tagName " + + "property"; + refute.tagName.noTagNameMessage = "${2}Expected ${1} to have tagName " + + "property"; + + referee.add("className", { + assert: function (element, name) { + if (typeof element.className === "undefined") { + // Uses arguments[2] because the function's .length is used to + // determine the minimum required number of arguments. + return this.fail( + "noClassNameMessage", + name, + element, + msg(arguments[2]) + ); + } + + var expected = typeof name === "string" ? name.split(" ") : name; + var actual = element.className.split(" "); + var i, l; + for (i = 0, l = expected.length; i < l; i++) { + if (!_.include(actual, expected[i])) { return false; } + } + + return true; + }, + assertMessage: "${2}Expected object's className to include ${0} " + + "but was ${1}", + refuteMessage: "${2}Expected object's className not to include ${0}", + expectation: "toHaveClassName", + values: function (element, className, message) { + return [className, element.className, msg(message)]; + } + }); + + assert.className.noClassNameMessage = "${2}Expected object to have " + + "className property"; + refute.className.noClassNameMessage = "${2}Expected object to have " + + "className property"; + + if (typeof module !== "undefined" && typeof require === "function") { + referee.expect = function () { + referee.expect = require("./expect"); + return referee.expect.apply(referee, arguments); + }; + } + + return referee; +}); diff --git a/package.json b/package.json index ab03e1c4..054414f8 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "buster-assertions", - "version": "0.10.3", + "name": "referee", + "version": "0.11.0", "description": "Assertions for any JavaScript test framework and environment", - "homepage": "http://busterjs.org/docs/buster-assertions", + "homepage": "http://busterjs.org/docs/referee", "author": { "name": "August Lilleaas and Christian Johansen" }, "contributors": [{ "name": "Christian Johansen", @@ -13,19 +13,21 @@ "email": "august.lilleaas@gmail.com", "url": "http://augustl.com" }], - "main": "./lib/buster-assertions", + "main": "./lib/referee", "repository": { "type": "git", - "url": "git://gitorious.org/buster/buster-assertions.git" + "url": "https://github.com/busterjs/referee" }, "scripts": { "test": "./run-tests" }, "dependencies": { - "buster-core": ">=0.6.2" + "underscore": "~0.4", + "samsam": "~0.1", + "bane": "~0.1" }, "devDependencies": { - "sinon": ">=1.3", + "sinon": ">=1.4", "buster-util": ">=0.5" } } diff --git a/run-tests b/run-tests index e3a6ae73..d60538e2 100755 --- a/run-tests +++ b/run-tests @@ -1,4 +1,4 @@ #!/usr/bin/env node -require("./test/buster-assertions-test.js"); -require("./test/buster-assertions/expect-test.js"); +require("./test/referee-.js"); +require("./test/expect-test.js"); diff --git a/test/buster-assertions-util-test.js b/test/buster-assertions-util-test.js deleted file mode 100644 index b4bc74a8..00000000 --- a/test/buster-assertions-util-test.js +++ /dev/null @@ -1,70 +0,0 @@ -if (typeof module === "object" && typeof require === "function") { - var assert = require("assert"); - - var buster = { - util: require("buster-util"), - assertions: require("../lib/buster-assertions") - }; -} - -(function () { - var create = function (obj) { - function F() {} - F.prototype = obj; - return new F(); - }; - - var ba = buster.assertions; - var expect = ba.expect; - expect(); - - buster.util.testCase("IsArgumentsTest", { - "should recognize real arguments object": function () { - assert.ok(ba.isArguments(arguments)); - }, - - "should reject primitive": function () { - assert.ok(!ba.isArguments(42)); - }, - - "should reject object without length": function () { - assert.ok(!ba.isArguments({})); - }, - - "should reject array": function () { - assert.ok(!ba.isArguments([])); - } - }); - - buster.util.testCase("KeysTest", { - "should return keys of object": function () { - var obj = { a: 1, b: 2, c: 3 }; - - assert.equal(ba.keys(obj).sort().join(""), "abc"); - }, - - "should exclude inherited properties": function () { - var obj = { a: 1, b: 2, c: 3 }; - var obj2 = create(obj); - obj2.d = 4; - obj2.e = 5; - - assert.deepEqual(ba.keys(obj2).sort().join(""), "de"); - } - }); - - buster.util.testCase("AddAssertionTest", { - "should add expectation if expect property is set": function () { - ba.add("isFoo", { - assert: function (actual) { - return actual == "foo"; - }, - assertMessage: "Expected ${1} to be foo!", - refuteMessage: "Expected not to be foo!", - expectation: "toBeFoo" - }); - - expect("foo").toBeFoo(); - } - }); -}()); diff --git a/test/buster-assertions/expect-test.js b/test/buster-assertions/expect-test.js deleted file mode 100644 index a1eac84c..00000000 --- a/test/buster-assertions/expect-test.js +++ /dev/null @@ -1,112 +0,0 @@ -/*jslint onevar: false, browser: true, eqeqeq: false, nomen: false, - plusplus: false, regexp: false*/ -/*global require, __dirname*/ -if (typeof module === "object" && typeof require === "function") { - var assert = require("assert"); - var sinon = require("sinon"); - var testHelper = require("../test-helper"); - - var buster = { - assertions: require("../../lib/buster-assertions"), - util: require("buster-util") - }; -} - -var expect = buster.assertions.expect; - -buster.util.testCase("ExpectTest", { - setUp: testHelper.setUp, - tearDown: testHelper.tearDown, - - "should be function": function () { - assert.equal(typeof expect, "function"); - }, - - "should bind assert.equals to argument": function () { - assert.doesNotThrow(function () { - expect({}).toEqual({}); - }); - }, - - "should fail assertion if a not equals b": function () { - try { - expect({ id: 42 }).toEqual({ bleh: "Nah" }); - throw new Error("Did not throw"); - } catch (e) { - assert.equal(e.message, "[expect.toEqual] [object Object] expected to be equal to [object Object]"); - } - }, - - "should fail assertion by calling buster.assert.fail": function () { - try { - expect({ id: 42 }).toEqual({ bleh: "Nah" }); - } catch (e) {} - - assert.ok(buster.assertions.fail.calledOnce); - }, - - "should emit assertion pass event": function () { - var listener = sinon.spy(); - buster.assertions.on("pass", listener); - - expect({ id: 42 }).toEqual({ id: 42 }); - - assert.ok(listener.calledOnce); - }, - - "should emit assertion fail event": function () { - var listener = sinon.spy(); - buster.assertions.on("failure", listener); - buster.assertions.throwOnFailure = false; - - expect({ id: 42 }).toEqual({ id: 22 }); - - assert.ok(listener.calledOnce); - }, - - "should expose refutation as expectation too": function () { - try { - expect({ id: 42 }).not.toEqual({ id: 42 }); - throw new Error("Did not throw"); - } catch (e) { - assert.equal(e.message, "[expect.not.toEqual] [object Object] expected not to be equal to [object Object]"); - } - }, - - "should expose all assertions": function () { - var obj = { id: 42 }; - - expect(obj).toBe(obj); - expect(obj).not.toBe({ id: 42 }); - expect(obj).toEqual({ id: 42 }); - expect(obj).not.toEqual({}); - expect(obj).toBeObject(); - expect(false).not.toBeObject(); - expect(function () {}).toBeFunction(); - expect({}).not.toBeFunction(); - expect(null).toBeDefined(); - expect(undefined).not.toBeDefined(); - expect(null).toBeNull(); - expect(42).not.toBeNull(); - expect(obj).toMatch({ id: 42 }); - expect(obj).not.toMatch({ id: 37 }); - expect(function () { throw new TypeError("Oops"); }).toThrow("TypeError"); - expect(function () {}).not.toThrow(); - expect({ tagName: "li" }).toHaveTagName("li"); - expect({ tagName: "ol" }).not.toHaveTagName("li"); - expect({ className: "a b c" }).toHaveClassName("b"); - expect({ className: "a b c" }).not.toHaveClassName("d"); - expect(true).toBeTruthy(); - expect(false).not.toBeTruthy(); - expect(false).toBeFalsy(); - expect(true).not.toBeFalsy(); - expect(3).toBeCloseTo(3, 0); - expect(2).not.toBeCloseTo(3, 0.5); - expect(2).toBeGreaterThan(1); - expect(1).not.toBeGreaterThan(2); - expect(1).toBeLessThan(2); - expect(2).not.toBeLessThan(1); - expect([0,1,2]).toContain(1); - expect([0,1,2]).not.toContain(3); - } -}); diff --git a/test/expect-test.js b/test/expect-test.js new file mode 100644 index 00000000..2197dbf0 --- /dev/null +++ b/test/expect-test.js @@ -0,0 +1,110 @@ +// if (typeof module === "object" && typeof require === "function") { +// var assert = require("assert"); +// var sinon = require("sinon"); +// var testHelper = require("./test-helper"); +// var buster = { util: require("buster-util") }; +// var referee = require("../lib/referee"); +// } + +// var expect = referee.expect; + +// buster.util.testCase("ExpectTest", { +// setUp: testHelper.setUp, +// tearDown: testHelper.tearDown, + +// "should be function": function () { +// assert.equal(typeof expect, "function"); +// }, + +// "should bind assert.equals to argument": function () { +// assert.doesNotThrow(function () { +// expect({}).toEqual({}); +// }); +// }, + +// "should fail assertion if a not equals b": function () { +// try { +// expect({ id: 42 }).toEqual({ bleh: "Nah" }); +// throw new Error("Did not throw"); +// } catch (e) { +// assert.equal(e.message, "[expect.toEqual] [object Object] " + +// "expected to be equal to [object Object]"); +// } +// }, + +// "should fail assertion by calling buster.assert.fail": function () { +// try { +// expect({ id: 42 }).toEqual({ bleh: "Nah" }); +// } catch (e) {} + +// assert.ok(referee.fail.calledOnce); +// }, + +// "should emit assertion pass event": function () { +// var listener = sinon.spy(); +// referee.on("pass", listener); + +// expect({ id: 42 }).toEqual({ id: 42 }); + +// assert.ok(listener.calledOnce); +// }, + +// "should emit assertion fail event": function () { +// var listener = sinon.spy(); +// referee.on("failure", listener); +// referee.throwOnFailure = false; + +// expect({ id: 42 }).toEqual({ id: 22 }); + +// assert.ok(listener.calledOnce); +// }, + +// "should expose refutation as expectation too": function () { +// try { +// expect({ id: 42 }).not.toEqual({ id: 42 }); +// throw new Error("Did not throw"); +// } catch (e) { +// assert.equal(e.message, "[expect.not.toEqual] [object Object] " + +// "expected not to be equal to [object Object]"); +// } +// }, + +// "should expose all assertions": function () { +// var obj = { id: 42 }; + +// expect(obj).toBe(obj); +// expect(obj).not.toBe({ id: 42 }); +// expect(obj).toEqual({ id: 42 }); +// expect(obj).not.toEqual({}); +// expect(obj).toBeObject(); +// expect(false).not.toBeObject(); +// expect(function () {}).toBeFunction(); +// expect({}).not.toBeFunction(); +// expect(null).toBeDefined(); +// expect(undefined).not.toBeDefined(); +// expect(null).toBeNull(); +// expect(42).not.toBeNull(); +// expect(obj).toMatch({ id: 42 }); +// expect(obj).not.toMatch({ id: 37 }); +// expect(function () { +// throw new TypeError("Oops"); +// }).toThrow("TypeError"); +// expect(function () {}).not.toThrow(); +// expect({ tagName: "li" }).toHaveTagName("li"); +// expect({ tagName: "ol" }).not.toHaveTagName("li"); +// expect({ className: "a b c" }).toHaveClassName("b"); +// expect({ className: "a b c" }).not.toHaveClassName("d"); +// expect(true).toBeTruthy(); +// expect(false).not.toBeTruthy(); +// expect(false).toBeFalsy(); +// expect(true).not.toBeFalsy(); +// expect(3).toBeCloseTo(3, 0); +// expect(2).not.toBeCloseTo(3, 0.5); +// expect(2).toBeGreaterThan(1); +// expect(1).not.toBeGreaterThan(2); +// expect(1).toBeLessThan(2); +// expect(2).not.toBeLessThan(1); +// expect([0, 1, 2]).toContain(1); +// expect([0, 1, 2]).not.toContain(3); +// } +// }); diff --git a/test/buster-assertions-test.js b/test/referee-test.js similarity index 87% rename from test/buster-assertions-test.js rename to test/referee-test.js index ccefb94f..f07af375 100644 --- a/test/buster-assertions-test.js +++ b/test/referee-test.js @@ -1,155 +1,148 @@ -/*jslint onevar: false, browser: true, eqeqeq: false, nomen: false, - plusplus: false, regexp: false*/ -/*global require, __dirname*/ -(function (B, sinon, assert, testHelper) { - var bu, ba; - - if (typeof require == "function" && typeof module == "object") { - sinon = require("sinon"); - assert = require("assert"); +/*jslint maxlen:160*/ +(function (referee, testHelper, buster) { + if (typeof require === "function" && typeof module === "object") { + referee = require("../lib/referee"); testHelper = require("./test-helper"); - bu = require("buster-util"); - ba = require("./../lib/buster-assertions"); - } else { - bu = buster.util; - ba = buster.assertions; + buster = require("buster"); } - bu.testCase("AssertTest", { + buster.testCase("assert", { setUp: testHelper.setUp, tearDown: testHelper.tearDown, "allows true": function () { - var okListener = sinon.spy(); - ba.on("pass", okListener); + var okListener = this.spy(); + referee.on("pass", okListener); - assert.doesNotThrow(function () { - ba.assert(true); + refute.exception(function () { + referee.assert(true); }); - assert.ok(okListener.calledOnce); - assert.ok(okListener.calledWith("assert")); + assert.calledOnce(okListener); + assert.calledWith(okListener, "assert"); }, "allows truthy values": function () { - assert.doesNotThrow(function () { - ba.assert({}); - ba.assert([]); - ba.assert("Truthy"); - ba.assert(1); - ba.assert(/a/); + refute.exception(function () { + referee.assert({}); + referee.assert([]); + referee.assert("Truthy"); + referee.assert(1); + referee.assert(/a/); }); }, "allows true with message": function () { - assert.doesNotThrow(function () { - ba.assert(true, "s'aright"); + refute.exception(function () { + referee.assert(true, "s'aright"); }); }, "does not allow false": function () { - var okListener = sinon.spy(); - ba.on("pass", okListener); + var okListener = this.spy(); + referee.on("pass", okListener); - assert.throws(function () { - ba.assert(false); + assert.exception(function () { + referee.assert(false); }); - assert.ok(!okListener.called); + refute.called(okListener); }, "does not allow falsy values": function () { - assert.throws(function () { - ba.assert(""); + assert.exception(function () { + referee.assert(""); }); - assert.throws(function () { - ba.assert(0); + assert.exception(function () { + referee.assert(0); }); - assert.throws(function () { - ba.assert(NaN); + assert.exception(function () { + referee.assert(NaN); }); - assert.throws(function () { - ba.assert(null); + assert.exception(function () { + referee.assert(null); }); - assert.throws(function () { - ba.assert(undefined); + assert.exception(function () { + referee.assert(undefined); }); }, "does not allow false with message": function () { - assert.throws(function () { - ba.assert(false, "Some message"); + assert.exception(function () { + referee.assert(false, "Some message"); }); }, "fails with generated message": function () { try { - ba.assert(false); + referee.assert(false); throw new Error("Didn't fail"); } catch (e) { - assert.equal("AssertionError", e.name); - assert.equal("[assert] Expected false to be truthy", e.message); + assert.equals(e.name, "AssertionError"); + assert.equals(e.message, "[assert] Expected false to be truthy"); } }, "fails with custom message": function () { try { - ba.assert(false, "False FTW"); + referee.assert(false, "False FTW"); throw new Error("Didn't fail"); } catch (e) { - assert.equal("AssertionError", e.name); - assert.equal("False FTW", e.message); + assert.equals(e.name, "AssertionError"); + assert.equals(e.message, "False FTW"); } }, "updates assertion count": function () { - ba.count = 0; + referee.count = 0; try { - ba.assert(true); - ba.assert(false); + referee.assert(true); + referee.assert(false); } catch (e) {} - assert.equal(2, ba.count); + assert.equals(referee.count, 2); }, "formats value with assert.format": function () { - ba.format = sinon.spy(); + referee.format = this.spy(); try { - ba.assert(false); + referee.assert(false); } catch (e) {} - assert.ok(ba.format.calledOnce); - assert.ok(ba.format.calledWith(false)); + assert.calledOnce(referee.format); + assert.calledWith(referee.format, false); }, "fails if not passed arguments": function () { try { - ba.assert(); + referee.assert(); throw new Error("Expected assert to fail"); } catch (e) { - assert.equal("[assert] Expected to receive at least 1 argument", - e.message); + assert.equals(e.message, "[assert] Expected to receive at least 1 argument"); } }, "does not throw if not configured to": - testHelper.assertionFailureEventTest(function () { - ba.assert(false); - }) + testHelper.assertionFailureEventTest(function () { + referee.assert(false); + }) }); + testHelper.assertionTests("assert", "isTrue", function (pass, fail, msg) { pass("for true", true); fail("for false", false); msg("represent expected value in message", "[assert.isTrue] Expected [object Object] to be true", {}); msg("include custom message", - "[assert.isTrue] Oh: Expected [object Object] to be true", {}, "Oh"); + "[assert.isTrue] Oh: Expected [object Object] to be true", + {}, + "Oh"); fail("for object", {}); fail("for array", []); fail("for string", "32"); @@ -208,9 +201,9 @@ fail("when comparing null to null", null, null); fail("when comparing undefined to undefined", undefined, undefined); msg("include objects in message", - "[refute.same] [object Object] expected not to be the same object as [object Object]", obj, obj); + "[refute.same] [object Object] expected not to be the same object as [object Object]", obj, obj); msg("include custom message", - "[refute.same] Sigh... [object Object] expected not to be the same object as [object Object]", + "[refute.same] Sigh... [object Object] expected not to be the same object as [object Object]", obj, obj, "Sigh..."); fail("when comparing NaN to NaN", NaN, NaN); pass("when comparing -0 to +0", -0, +0); @@ -235,16 +228,16 @@ pass("when comparing date objects with same date", date, sameDate); fail("when comparing date objects with different dates", date, anotherDate); fail("when comparing date objects to null", date, null); - pass("when comparing strings and numbers with coercion", "4", 4); - pass("when comparing numbers and strings with coercion", 4, "4"); - pass("when comparing number object with coercion", 32, new Number(32)); - pass("when comparing number object reverse with coercion", new Number(32), 32); - pass("when comparing falsy values with coercion", 0, ""); - pass("when comparing falsy values reverse with coercion", "", 0); - pass("when comparing string boxing with coercion", "4", new String("4")); - pass("when comparing string boxing reverse with coercion", new String("4"), "4"); + fail("when comparing strings and numbers with coercion", "4", 4); + fail("when comparing numbers and strings with coercion", 4, "4"); + fail("when comparing number object with coercion", 32, new Number(32)); + fail("when comparing number object reverse with coercion", new Number(32), 32); + fail("when comparing falsy values with coercion", 0, ""); + fail("when comparing falsy values reverse with coercion", "", 0); + fail("when comparing string boxing with coercion", "4", new String("4")); + fail("when comparing string boxing reverse with coercion", new String("4"), "4"); pass("when comparing NaN to NaN", NaN, NaN); - pass("when comparing -0 to +0", -0, +0); + fail("when comparing -0 to +0", -0, +0); fail("when comparing objects with different own properties", { id: 42 }, { id: 42, di: 24 }); fail("when comparing objects with different own properties #2", @@ -276,8 +269,6 @@ name: "Hey" }); - function func() {} - pass("when comparing arrays", [1, 2, "Hey there", func, { id: 42, prop: [2, 3] }], [1, 2, "Hey there", func, { id: 42, prop: [2, 3] }]); @@ -306,7 +297,7 @@ function gather() { return arguments; } var arrayLike = { length: 4, "0": 1, "1": 2, "2": {}, "3": [] }; - pass("when comparing arguments to array", [1,2,{},[]], gather(1, 2, {}, [])); + pass("when comparing arguments to array", [1, 2, {}, []], gather(1, 2, {}, [])); pass("when comparing array to arguments", gather(), []); pass("when comparing arguments to array like object", @@ -362,29 +353,28 @@ "Yo", "Hey"); }); - if (typeof document != "undefined") { - bu.testCase("AssertEqualsHostObjectTest", { - setUp: testHelper.setUp, - tearDown: testHelper.tearDown, + buster.testCase("assert.equals host objects", { + requiresSupportFor: { "DOM": typeof document !== "undefined" }, + setUp: testHelper.setUp, + tearDown: testHelper.tearDown, - "should pass when comparing DOM element to itself": function () { - var element = document.createElement("div"); + "should pass when comparing DOM element to itself": function () { + var element = document.createElement("div"); - assert.doesNotThrow(function () { - ba.assert.equals(element, element); - }); - }, + refute.exception(function () { + referee.assert.equals(element, element); + }); + }, - "should fail when comparing different DOM elements": function () { - var div = document.createElement("div"); - var span = document.createElement("span"); + "should fail when comparing different DOM elements": function () { + var div = document.createElement("div"); + var span = document.createElement("span"); - assert.throws(function () { - ba.assert.equals(div, span); - }); - } - }); - } + assert.exception(function () { + referee.assert.equals(div, span); + }); + } + }); testHelper.assertionTests("refute", "equals", function (pass, fail, msg) { fail("when comparing object to itself", obj, obj); @@ -406,9 +396,9 @@ fail("when comparing date objects with same date", date, sameDate); pass("when comparing date objects with different dates", date, anotherDate); pass("when comparing date objects to null", new Date(), null); - fail("when comparing string with number with coercion", "4", 4); - fail("when comparing number with string with coercion", 32, "32"); - fail("when comparing with coercion", 0, ""); + pass("when comparing string with number with coercion", "4", 4); + pass("when comparing number with string with coercion", 32, "32"); + pass("when comparing with coercion", 0, ""); pass("when comparing objects with different own properties", { id: 42 }, { id: 42, di: 24 }); pass("when comparing objects with different own properties #2", @@ -421,7 +411,7 @@ pass("when comparing objects with one property with different values", { id: 42 }, { id: 24 }); fail("when comparing NaN to NaN", NaN, NaN); - fail("when comparing -0 to +0", -0, +0); + pass("when comparing -0 to +0", -0, +0); var deepObject = { id: 42, @@ -473,7 +463,7 @@ function gather() { return arguments; } var arrayLike = { length: 4, "0": 1, "1": 2, "2": {}, "3": [] }; - fail("when comparing arguments to array", [1,2,{},[]], gather(1, 2, {}, [])); + fail("when comparing arguments to array", [1, 2, {}, []], gather(1, 2, {}, [])); fail("when comparing array to arguments", gather(), []); fail("when comparing arguments to array like object", arrayLike, gather(1, 2, {}, [])); @@ -490,32 +480,48 @@ pass("when greater than", 2, 1); fail("when equal", 1, 1); fail("when less than", 0, 1); - msg("fail with descriptive message", - "[assert.greater] Expected 1 to be greater than 2", 1, 2) + msg( + "fail with descriptive message", + "[assert.greater] Expected 1 to be greater than 2", + 1, + 2 + ); }); testHelper.assertionTests("refute", "greater", function (pass, fail, msg) { fail("when greater than", 2, 1); pass("when equal", 1, 1); pass("when less than", 0, 1); - msg("fail with descriptive message", - "[refute.greater] Expected 2 to be less than or equal to 1", 2, 1) + msg( + "fail with descriptive message", + "[refute.greater] Expected 2 to be less than or equal to 1", + 2, + 1 + ); }); testHelper.assertionTests("assert", "less", function (pass, fail, msg) { fail("when greater than", 2, 1); fail("when equal", 1, 1); pass("when less than", 0, 1); - msg("fail with descriptive message", - "[assert.less] Expected 2 to be less than 1", 2, 1) + msg( + "fail with descriptive message", + "[assert.less] Expected 2 to be less than 1", + 2, + 1 + ); }); testHelper.assertionTests("refute", "less", function (pass, fail, msg) { pass("when greater than", 2, 1); pass("when equal", 1, 1); fail("when less than", 0, 1); - msg("fail with descriptive message", - "[refute.less] Expected 1 to be greater than or equal to 2", 1, 2) + msg( + "fail with descriptive message", + "[refute.less] Expected 1 to be greater than or equal to 2", + 1, + 2 + ); }); testHelper.assertionTests("assert", "isString", function (pass, fail, msg) { @@ -627,7 +633,7 @@ pass("for function", function () {}); pass("for null", null); msg("fail with descriptive message", - "[refute.isNumber] Ho ho! Expected 42 to be NaN or another non-number value", + "[refute.isNumber] Ho ho! Expected 42 to be NaN or a non-number value", 42, "Ho ho!"); }); @@ -833,33 +839,27 @@ fail("if match object is false", "Assertions 123", false); fail("if matching a number against a string", "Assertions 123", 23); - pass("if matching a number against a similar string", "23", 23); + fail("if matching a number against a similar string", "23", 23); pass("if matching a number against itself", 23, 23); pass("if matcher is a function that returns true", - "Assertions 123", function (obj) { - return true; - }); + "Assertions 123", function (obj) { return true; }); fail("if matcher is a function that returns false", - "Assertions 123", function (obj) { - return false; - }); + "Assertions 123", function (obj) { return false; }); fail("if matcher is a function that returns falsy", "Assertions 123", function () {}); fail("if matcher does not return explicit true", - "Assertions 123", function () { - return "Hey"; - }); + "Assertions 123", function () { return "Hey"; }); this["should call matcher with assertion argument"] = function () { - var listener = sinon.stub().returns(true); + var listener = this.stub().returns(true); - ba.assert.match("Assertions 123", listener); + referee.assert.match("Assertions 123", listener); - assert.ok(listener.calledWith("Assertions 123")); + assert.calledWith(listener, "Assertions 123"); }; pass("if matcher is substring of matchee", "Diskord", "or"); @@ -915,7 +915,7 @@ owner: { someDude: "Yes", hello: function (value) { - return value == "ok"; + return value === "ok"; } } }); @@ -960,29 +960,23 @@ fail("if matching a number against a similar string", 23, "23"); fail("if matching a number against itself", 23, 23); fail("if matcher is a function that returns true", "Assertions 123", - function (obj) { - return true; - }); + function (obj) { return true; }); pass("if matcher is a function that returns false", - "Assertions 123", function (obj) { - return false; - }); + "Assertions 123", function (obj) { return false; }); pass("if matcher is a function that returns falsy", "Assertions 123", function () {}); pass("if matcher does not return explicit true", - "Assertions 123", function () { - return "Hey"; - }); + "Assertions 123", function () { return "Hey"; }); this["should call matcher with assertion argument"] = function () { - var listener = sinon.stub().returns(false); + var listener = this.stub().returns(false); - ba.refute.match("Assertions 123", listener); + referee.refute.match("Assertions 123", listener); - assert.ok(listener.calledWith("Assertions 123")); + assert.calledWith(listener, "Assertions 123"); }; fail("if matcher is substring of matchee", "Diskord", "or"); @@ -1035,7 +1029,7 @@ owner: { someDude: "Yes", hello: function (value) { - return value == "ok"; + return value === "ok"; } } }); @@ -1058,7 +1052,7 @@ owner: { someDude: "No", hello: function (value) { - return value == "ok"; + return value === "ok"; } } }); @@ -1202,7 +1196,7 @@ "[assert.tagName] Yikes! Expected [object Object] to have tagName property", {}, "li", "Yikes!"); - if (typeof document != "undefined") { + if (typeof document !== "undefined") { pass("for DOM elements", document.createElement("li"), "li"); } }); @@ -1241,7 +1235,7 @@ "[refute.tagName] Yes: Expected [object Object] to have tagName property", {}, "li", "Yes"); - if (typeof document != "undefined") { + if (typeof document !== "undefined") { pass("for DOM elements", document.createElement("li"), "p"); } }); @@ -1281,9 +1275,9 @@ pass("when element includes all class names in different order", { className: "a b c d e" }, "e a d"); - pass("with class names as array", { className: "a b c d e" }, ["e","a","d"]); + pass("with class names as array", { className: "a b c d e" }, ["e", "a", "d"]); - if (typeof document != "undefined") { + if (typeof document !== "undefined") { var li = document.createElement("li"); li.className = "some thing in here"; @@ -1324,10 +1318,10 @@ { className: "feed item post" }, "item post"); fail("when element includes all class names in different order", { className: "a b c d e" }, "e a d"); - fail("with class names as array", { className: "a b c d e" }, ["e","a","d"]); - pass("with class names as array", { className: "a b c d e" }, ["f","a","d"]); + fail("with class names as array", { className: "a b c d e" }, ["e", "a", "d"]); + pass("with class names as array", { className: "a b c d e" }, ["f", "a", "d"]); - if (typeof document != "undefined") { + if (typeof document !== "undefined") { var li = document.createElement("li"); li.className = "some thing in here"; @@ -1399,10 +1393,10 @@ }); testHelper.assertionTests("assert", "contains", function (pass, fail, msg) { - pass("when array contains value", [0,1,2], 1); - fail("when array does not contain value", [0,1,2], 3); + pass("when array contains value", [0, 1, 2], 1); + fail("when array does not contain value", [0, 1, 2], 3); msg("with descriptive message", - "[assert.contains] Expected [0,1,2] to contain 3", [0,1,2], 3); + "[assert.contains] Expected [0,1,2] to contain 3", [0, 1, 2], 3); var thing = {}; var otherThing = {}; pass("when array contains the actual object", [thing], thing); @@ -1411,10 +1405,10 @@ }); testHelper.assertionTests("refute", "contains", function (pass, fail, msg) { - fail("when array contains value", [0,1,2], 1); - pass("when array does not contain value", [0,1,2], 3); + fail("when array contains value", [0, 1, 2], 1); + pass("when array does not contain value", [0, 1, 2], 3); msg("with descriptive message", - "[refute.contains] Expected [0,1,2] not to contain 2", [0,1,2], 2); + "[refute.contains] Expected [0,1,2] not to contain 2", [0, 1, 2], 2); var thing = {}; var otherThing = {}; fail("when array contains the actual object", [thing], thing); @@ -1422,16 +1416,16 @@ [thing], otherThing); }); - bu.testCase("CustomAssertionsTest", { + buster.testCase("CustomAssertionsTest", { setUp: testHelper.setUp, tearDown: function () { testHelper.tearDown.call(this); - delete ba.assert.custom; - delete ba.refute.custom; + delete referee.assert.custom; + delete referee.refute.custom; }, "should expose properties on this as message values": function () { - ba.add("custom", { + referee.add("custom", { assert: function (actual, expected) { this.actual = actual + "?"; this.expected = expected + "!"; @@ -1441,15 +1435,15 @@ }); try { - ba.assert.custom(2, 3); + referee.assert.custom(2, 3); throw new Error("Didn't throw"); } catch (e) { - assert.equal(e.message, "[assert.custom] 2? 3!"); + assert.equals("[assert.custom] 2? 3!", e.message); } }, "should format interpolated property with format": function () { - ba.add("custom", { + referee.add("custom", { assert: function (actual, expected) { this.actual = actual + "?"; this.expected = expected + "!"; @@ -1459,15 +1453,15 @@ }); try { - ba.assert.custom(2, 3); + referee.assert.custom(2, 3); } catch (e) {} - assert.ok(ba.format.calledWith("2?")); - assert.ok(ba.format.calledWith("3!")); + assert.calledWith(referee.format, "2?"); + assert.calledWith(referee.format, "3!"); }, "should not expose fail property": function () { - ba.add("custom", { + referee.add("custom", { assert: function (actual, expected) { return false; }, @@ -1475,19 +1469,19 @@ }); try { - ba.assert.custom(2, 3); + referee.assert.custom(2, 3); throw new Error("Didn't throw"); } catch (e) { - assert.equal(e.message, "[assert.custom] ${fail}"); + assert.equals("[assert.custom] ${fail}", e.message); } }, "should not leak properties between calls": function () { var i = 0; - ba.add("custom", { + referee.add("custom", { assert: function (actual, expected) { - if (i == 0) { + if (i === 0) { this.actual = "A"; } else { this.expected = "B"; @@ -1500,19 +1494,19 @@ }); try { - ba.assert.custom(4, 5); + referee.assert.custom(4, 5); } catch (e) {} try { - ba.assert.custom(2, 3); + referee.assert.custom(2, 3); throw new Error("Didn't throw"); - } catch (e) { - assert.equal(e.message, "[assert.custom] ${actual} B"); + } catch (err) { + assert.equals("[assert.custom] ${actual} B", err.message); } }, "should interpolate same property multiple times": function () { - ba.add("custom", { + referee.add("custom", { assert: function (actual, expected) { this.actual = actual + "?"; return false; @@ -1521,15 +1515,15 @@ }); try { - ba.assert.custom(2, 3); + referee.assert.custom(2, 3); throw new Error("Didn't throw"); } catch (e) { - assert.equal(e.message, "[assert.custom] 2? 2?"); + assert.equals("[assert.custom] 2? 2?", e.message); } }, "should interpolate numeric placeholders multiple times": function () { - ba.add("custom", { + referee.add("custom", { assert: function (actual, expected) { this.actual = actual + "?"; return false; @@ -1538,11 +1532,26 @@ }); try { - ba.assert.custom(2, 3); + referee.assert.custom(2, 3); throw new Error("Didn't throw"); } catch (e) { - assert.equal(e.message, "[assert.custom] 2 2"); + assert.equals("[assert.custom] 2 2", e.message); } + }, + + "should add expectation if expect property is set": function () { + referee.add("custom", { + assert: function (actual) { + return actual === "foo"; + }, + assertMessage: "Expected ${1} to be foo!", + refuteMessage: "Expected not to be foo!", + expectation: "toBeFoo" + }); + + refute.exception(function () { + referee.expect("foo").toBeFoo(); + }); } }); -}(this.buster, this.sinon, this.assert, this.testHelper)); +}(this.referee, this.testHelper, this.buster)); diff --git a/test/test-helper.js b/test/test-helper.js index c30c741c..3aa38761 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -1,15 +1,8 @@ -if (typeof module === "object" && typeof require === "function") { - var assert = require("assert"); - var sinon = require("sinon"); - - var buster = { - assertions: require("./../lib/buster-assertions"), - util: require("buster-util") - }; -} - -var testHelper = (function () { - var ba = buster.assertions; +var testHelper = (function (referee, buster) { + if (typeof module === "object" && typeof require === "function") { + referee = require("../lib/referee"); + buster = require("buster"); + } function slice(args, index) { return Array.prototype.slice.call(args, index); @@ -18,7 +11,7 @@ var testHelper = (function () { function assertFailureEvent(callback) { var fails = this.failListener.callCount; var passes = this.okListener.callCount; - ba.throwOnFailure = false; + referee.throwOnFailure = false; try { callback(); @@ -26,11 +19,11 @@ var testHelper = (function () { assert.fail("Assertion threw when it should not: " + e.message); } - assert.equal(this.failListener.callCount, fails + 1, - "Fail listener was not called once: " + - this.failListener.callCount - fails); - assert.equal(this.okListener.callCount, passes, - "Pass listener was unexpectedly called"); + assert.equals(this.failListener.callCount, fails + 1, + "Fail listener was not called once: " + + this.failListener.callCount - fails); + assert.equals(this.okListener.callCount, passes, + "Pass listener was unexpectedly called"); } function assertionFailureEventTest(callback) { @@ -41,54 +34,60 @@ var testHelper = (function () { function passingAssertionTest(type, assertion, args) { return function () { - var initialCount = ba.count; + var initialCount = referee.count; var callStr = type + "." + assertion + "(" + args.join(", ") + ")"; try { - ba[type][assertion].apply(ba, args); + referee[type][assertion].apply(referee, args); } catch (e) { - if (typeof console != "undefined") { + if (typeof console !== "undefined") { console.log("Failed: " + callStr); } else { buster.util.puts("Failed: " + callStr); } } - assert.equal( - this.okListener.callCount, 1, - "Expected buster.assertions to emit the pass event once for " + callStr); - sinon.assert.calledWith(this.okListener, type + "." + assertion); - assert.equal(1, ba.count - initialCount); - sinon.assert.notCalled(ba.fail); - sinon.assert.notCalled(this.failListener); + assert.equals( + this.okListener.callCount, + 1, + "Expected referee to emit the pass event once for " + callStr + ); + assert.calledWith(this.okListener, type + "." + assertion); + assert.equals(referee.count - initialCount, 1); + refute.called(referee.fail); + refute.called(this.failListener); }; } function failingAssertionTest(type, assertion, args) { return function () { - var initialCount = ba.count; + var initialCount = referee.count; var callStr = type + "." + assertion + "(" + args.join(", ") + ")"; try { - ba[type][assertion].apply(ba, args); + referee[type][assertion].apply(referee, args); - if (typeof console != "undefined") { + if (typeof console !== "undefined") { console.log("Unexpectedly passed: " + callStr); } else { buster.util.puts("Unexpectedly passed: " + callStr); } } catch (e) {} - assert.equal(ba.fail.callCount, 1, - "Expected buster.assertions.fail to be called once for " + callStr + - ", was called " + ba.fail.callCount + " times"); + assert.equals( + referee.fail.callCount, + 1, + "Expected referee.fail to be called once for " + + callStr + ", was called " + referee.fail.callCount + + " times" + ); - assert.equal(1, ba.count - initialCount); - sinon.assert.notCalled(this.okListener); - sinon.assert.calledOnce(this.failListener); + assert.equals(referee.count - initialCount, 1); + refute.called(this.okListener); + assert.calledOnce(this.failListener); assertFailureEvent.call(this, function () { - ba[type][assertion].apply(ba, args); + referee[type][assertion].apply(referee, args); }); }; } @@ -98,37 +97,40 @@ var testHelper = (function () { var msg; try { - ba[type][assertion].apply(ba, args); + referee[type][assertion].apply(referee, args); throw new Error(type + "." + assertion + " expected to fail"); } catch (e) { - assert.equal(e.name, "AssertionError", e.name + ": " + e.message); - assert.equal(e.message, message, "Message was " + e.message + ", " + - "expected " + message); + assert.equals(e.name, "AssertionError", + e.name + ": " + e.message); + assert.equals( + e.message, + message, + "Message was " + e.message + ", " + "expected " + message + ); msg = e.message; } var expected = test.expectedFormats; - if (typeof expected != "number") { + if (typeof expected !== "number") { expected = args.length; - if (typeof args[args.length - 1] == "string") { + if (typeof args[args.length - 1] === "string") { expected -= 1; } } - assert.ok(ba.format.callCount >= expected); + assert(referee.format.callCount >= expected); - for (var i = 0, l = expected; i < l; ++i) { - if (isNaN(args[i]) && isNaN(ba.format.args[i][0])) { - continue; + var i, l; + for (i = 0, l = expected; i < l; ++i) { + if (!isNaN(args[i]) || !isNaN(referee.format.args[i][0])) { + assert.calledWith(referee.format, args[i]); } - - assert.ok(ba.format.calledWith(args[i])); } - assert.equal(this.failListener.args[0][0].name, "AssertionError"); - assert.equal(this.failListener.args[0][0].message, msg); + assert.equals(this.failListener.args[0][0].name, "AssertionError"); + assert.equals(this.failListener.args[0][0].message, msg); }; return test; @@ -144,7 +146,11 @@ var testHelper = (function () { function pass(name) { tests[prefix + "pass " + name] = passingAssertionTest( - type, assertion, slice(arguments, 1), name); + type, + assertion, + slice(arguments, 1), + name + ); } function fail(name) { @@ -153,44 +159,45 @@ var testHelper = (function () { } function msg(name, message) { - tests[prefix + name] = - assertionMessageTest(type, assertion, message, slice(arguments, 2)); + tests[prefix + name] = assertionMessageTest( + type, + assertion, + message, + slice(arguments, 2) + ); return tests[prefix + name]; } callback.call(tests, pass, fail, msg); - return buster.util.testCase(type + "." + assertion + "Test", tests); + return buster.testCase(type + "." + assertion, tests); } return { setUp: function () { - this.sandbox = sinon.sandbox.create(); - this.sandbox.spy(ba, "fail"); + this.spy(referee, "fail"); - ba.format = sinon.spy(function (object) { - return "" + object; + referee.format = this.spy(function (object) { + return String(object); }); - this.okListener = sinon.spy(); - ba.on("pass", this.okListener); - this.failListener = sinon.spy(); - ba.on("failure", this.failListener); + this.okListener = this.spy(); + referee.on("pass", this.okListener); + this.failListener = this.spy(); + referee.on("failure", this.failListener); }, tearDown: function () { - delete ba.listeners; - ba.count = 0; - this.sandbox.restore(); - - delete ba.throwOnFailure; + delete referee.listeners; + referee.count = 0; + delete referee.throwOnFailure; }, assertionFailureEventTest: assertionFailureEventTest, assertionTests: assertionTests }; -}()); +}(this.referee, this.buster)); -if (typeof module == "object") { +if (typeof module === "object") { module.exports = testHelper; } diff --git a/vendor/buster-core b/vendor/buster-core deleted file mode 120000 index cfa4e155..00000000 --- a/vendor/buster-core +++ /dev/null @@ -1 +0,0 @@ -/home/christian/projects/buster/buster-core \ No newline at end of file diff --git a/vendor/buster-util b/vendor/buster-util deleted file mode 120000 index 9c96d1d1..00000000 --- a/vendor/buster-util +++ /dev/null @@ -1 +0,0 @@ -/home/christian/projects/buster/buster-util \ No newline at end of file diff --git a/vendor/sinon b/vendor/sinon deleted file mode 120000 index f235f589..00000000 --- a/vendor/sinon +++ /dev/null @@ -1 +0,0 @@ -/home/christian/projects/sinon/sinon \ No newline at end of file