From 1e586a011320916f1761c689e5ad31befde29613 Mon Sep 17 00:00:00 2001 From: Christian Johansen Date: Fri, 20 Jul 2012 01:14:49 +0200 Subject: [PATCH] Big ass rename: buster-assertions -> referee - Switch out test framework (use Buster) --- .gitignore | 1 - .gitmodules | 9 - .npmignore | 1 - LICENSE | 2 +- Readme.md | 16 - Readme.rst | 24 + autolint.js | 21 + buster.js | 18 + jsTestDriver.conf | 22 - jsl.conf | 4 - lib/buster-assertions.js | 797 ------------------ lib/buster-assertions/expect.js | 63 -- lib/expect.js | 65 ++ lib/referee.js | 647 ++++++++++++++ package.json | 16 +- run-tests | 4 +- test/buster-assertions-util-test.js | 70 -- test/buster-assertions/expect-test.js | 112 --- test/expect-test.js | 110 +++ ...ter-assertions-test.js => referee-test.js} | 371 ++++---- test/test-helper.js | 149 ++-- vendor/buster-core | 1 - vendor/buster-util | 1 - vendor/sinon | 1 - 24 files changed, 1165 insertions(+), 1360 deletions(-) delete mode 100644 .gitmodules delete mode 100644 Readme.md create mode 100644 Readme.rst create mode 100644 autolint.js create mode 100644 buster.js delete mode 100644 jsTestDriver.conf delete mode 100644 jsl.conf delete mode 100644 lib/buster-assertions.js delete mode 100644 lib/buster-assertions/expect.js create mode 100644 lib/expect.js create mode 100644 lib/referee.js delete mode 100644 test/buster-assertions-util-test.js delete mode 100644 test/buster-assertions/expect-test.js create mode 100644 test/expect-test.js rename test/{buster-assertions-test.js => referee-test.js} (87%) delete mode 120000 vendor/buster-core delete mode 120000 vendor/buster-util delete mode 120000 vendor/sinon 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