diff --git a/lib/TrivialReporter.js b/lib/TrivialReporter.js index e0e1589..8219d4a 100644 --- a/lib/TrivialReporter.js +++ b/lib/TrivialReporter.js @@ -89,9 +89,7 @@ jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { for (var i = 0; i < resultItems.length; i++) { var result = resultItems[i]; if (result.passed && !result.passed()) { - var resultMessageDiv = this.createDom('div', {className: 'resultMessage fail'}); - resultMessageDiv.innerHTML = result.message; // todo: lame; mend - specDiv.appendChild(resultMessageDiv); + specDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); specDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); } } diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index 156bc3b..4944727 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -8,7 +8,7 @@ describe("jasmine.Matchers", function() { }); function match(value) { - return new jasmine.Matchers(env, value, mockSpec); + return new env.matchersClass(env, value, mockSpec); } it("toEqual with primitives, objects, dates, html nodes, etc.", function() { @@ -161,8 +161,7 @@ describe("jasmine.Matchers", function() { expect(result.matcherName).toEqual("toMatch"); expect(result.passed()).toEqual(false); - expect(result.message).toMatch(jasmine.pp(actual)); - expect(result.message).toMatch(new RegExp(expected).toString()); + expect(result.message).toEqual("Expected 'a' to match 'b'."); expect(result.expected).toEqual(expected); expect(result.actual).toEqual(actual); }); @@ -177,9 +176,7 @@ describe("jasmine.Matchers", function() { expect(result.matcherName).toEqual("toNotMatch"); expect(result.passed()).toEqual(false); - expect(result.message).toMatch(expected.toString()); - expect(result.message).toMatch(jasmine.pp(actual)); - expect(result.message).toMatch("not"); + expect(result.message).toEqual("Expected 'a' to not match /a/."); expect(result.expected).toEqual(expected); expect(result.actual).toEqual(actual); }); @@ -193,9 +190,7 @@ describe("jasmine.Matchers", function() { expect(result.matcherName).toEqual("toNotMatch"); expect(result.passed()).toEqual(false); - expect(result.message).toMatch(jasmine.pp(str)); - expect(result.message).toMatch(new RegExp(str).toString()); - expect(result.message).toMatch("not"); + expect(result.message).toEqual("Expected 'a' to not match 'a'."); expect(result.expected).toEqual(str); expect(result.actual).toEqual(str); }); @@ -213,7 +208,7 @@ describe("jasmine.Matchers", function() { expect(result.matcherName).toEqual("toBeDefined"); expect(result.passed()).toEqual(false); - expect(result.message).toEqual('Expected actual to not be undefined.'); + expect(result.message).toEqual('Expected undefined to be defined.'); expect(result.actual).toEqual(undefined); }); @@ -297,7 +292,7 @@ describe("jasmine.Matchers", function() { expect(result.matcherName).toEqual("toBeTruthy"); expect(result.passed()).toEqual(false); - expect(result.message).toEqual("Expected actual to be truthy"); + expect(result.message).toEqual("Expected false to be truthy."); expect(result.actual).toEqual(false); }); @@ -440,9 +435,9 @@ describe("jasmine.Matchers", function() { }); it("toThrow", function() { - var expected = new jasmine.Matchers(env, function() { + var expected = match(function() { throw new Error("Fake Error"); - }, mockSpec); + }); expect(expected.toThrow()).toEqual(true); expect(expected.toThrow("Fake Error")).toEqual(true); expect(expected.toThrow(new Error("Fake Error"))).toEqual(true); @@ -463,7 +458,7 @@ describe("jasmine.Matchers", function() { } catch (e) { exception = e; } - ; + expect(exception).toBeDefined(); expect(exception.message).toEqual('Actual is not a function'); @@ -476,50 +471,75 @@ describe("jasmine.Matchers", function() { }); - describe("wasCalled, wasNotCalled, wasCalledWith", function() { + describe("spy matchers >>", function() { var TestClass; beforeEach(function() { - TestClass = { someFunction: function() { - } }; - }); - describe('without spies', function() { - it('should always show an error', function () { - expect(match(TestClass.someFunction).wasCalled()).toEqual(false); - var result = mockSpec.addMatcherResult.mostRecentCall.args[0]; - expect(result.message).toEqual("Actual is not a spy."); - - expect(match(TestClass.someFunction).wasNotCalled()).toEqual(false); - result = mockSpec.addMatcherResult.mostRecentCall.args[0]; - expect(result.message).toEqual("Actual is not a spy."); - }); + TestClass = { + normalFunction: function() { + }, + spyFunction: jasmine.createSpy("My spy") + }; }); - describe('with spies', function () { + function shouldThrowAnExceptionWhenInvokedOnANonSpy(methodName) { + return function() { + expect(function() { + match(TestClass.normalFunction)[methodName](); + }).toThrow('Expected a spy, but got Function.'); - beforeEach(function () { - TestClass.someFunction = jasmine.createSpy("My spy"); + expect(function() { + match(undefined)[methodName](); + }).toThrow('Expected a spy, but got undefined.'); + + expect(function() { + match({some:'object'})[methodName](); + }).toThrow('Expected a spy, but got { some : \'object\' }.'); + }; + } + + describe("wasCalled", function() { + it("should pass iff the spy was called", function() { + expect(match(TestClass.spyFunction).wasCalled()).toEqual(false); + + TestClass.spyFunction(); + expect(match(TestClass.spyFunction).wasCalled()).toEqual(true); }); - it("should track if it was called", function() { - expect(match(TestClass.someFunction).wasCalled()).toEqual(false); - expect(match(TestClass.someFunction).wasNotCalled()).toEqual(true); - - TestClass.someFunction(); - expect(match(TestClass.someFunction).wasCalled()).toEqual(true); - expect(function () { - match(TestClass.someFunction).wasCalled('some arg'); + it("should throw an exception when invoked with any arguments", function() { + expect(function() { + match(TestClass.normalFunction).wasCalled("unwanted argument"); }).toThrow('wasCalled does not take arguments, use wasCalledWith'); - expect(match(TestClass.someFunction).wasNotCalled()).toEqual(false); }); - it('should return true if it was called with the expected args', function() { - TestClass.someFunction('a', 'b', 'c'); - expect(match(TestClass.someFunction).wasCalledWith('a', 'b', 'c')).toEqual(true); + it('should throw an exception when invoked on a non-spy', shouldThrowAnExceptionWhenInvokedOnANonSpy('wasCalled')); + }); + + describe("wasNotCalled", function() { + it("should pass iff the spy was not called", function() { + expect(match(TestClass.spyFunction).wasNotCalled()).toEqual(true); + + TestClass.spyFunction(); + expect(match(TestClass.spyFunction).wasNotCalled()).toEqual(false); + }); + + it("should throw an exception when invoked with any arguments", function() { + expect(function() { + match(TestClass.normalFunction).wasNotCalled("unwanted argument"); + }).toThrow('wasNotCalled does not take arguments'); + }); + + it('should throw an exception when invoked on a non-spy', shouldThrowAnExceptionWhenInvokedOnANonSpy('wasNotCalled')); + }); + + describe("wasCalledWith", function() { + it('wasCalledWith should return true if it was called with the expected args', function() { + TestClass.spyFunction('a', 'b', 'c'); + expect(match(TestClass.spyFunction).wasCalledWith('a', 'b', 'c')).toEqual(true); }); it('should return false if it was not called with the expected args', function() { - TestClass.someFunction('a', 'b', 'c'); - var expected = match(TestClass.someFunction); + TestClass.spyFunction('a', 'b', 'c'); + var expected = match(TestClass.spyFunction); expect(expected.wasCalledWith('c', 'b', 'a')).toEqual(false); var result = mockSpec.addMatcherResult.mostRecentCall.args[0]; expect(result.passed()).toEqual(false); @@ -528,67 +548,42 @@ describe("jasmine.Matchers", function() { }); it('should allow matches across multiple calls', function() { - var expected = match(TestClass.someFunction); - TestClass.someFunction('a', 'b', 'c'); - TestClass.someFunction('d', 'e', 'f'); + var expected = match(TestClass.spyFunction); + TestClass.spyFunction('a', 'b', 'c'); + TestClass.spyFunction('d', 'e', 'f'); expect(expected.wasCalledWith('a', 'b', 'c')).toEqual(true); expect(expected.wasCalledWith('d', 'e', 'f')).toEqual(true); expect(expected.wasCalledWith('x', 'y', 'z')).toEqual(false); }); + + it('should throw an exception when invoked on a non-spy', shouldThrowAnExceptionWhenInvokedOnANonSpy('wasCalledWith')); + + describe("to build an ExpectationResult", function () { + beforeEach(function() { + var currentSuite; + var spec; + currentSuite = env.describe('default current suite', function() { + spec = env.it(); + }, spec); + TestClass = { someFunction: function(a, b) { + } }; + spec.spyOn(TestClass, 'someFunction'); + }); + + it("should should handle the case of a spy", function() { + TestClass.someFunction('a', 'c'); + var matcher = match(TestClass.someFunction); + matcher.wasCalledWith('a', 'b'); + + var result = mockSpec.addMatcherResult.mostRecentCall.args[0]; + expect(result.matcherName).toEqual("wasCalledWith"); + expect(result.passed()).toEqual(false); + expect(result.message).toMatch("['a', 'b']"); + expect(result.message).toMatch("['a', 'c']"); + expect(result.actual).toEqual(TestClass.someFunction); + expect(result.expected).toEqual(['a','b']); + }); + }); }); }); - - - describe("wasCalledWith to build an ExpectationResult", function () { - var TestClass; - beforeEach(function() { - var currentSuite; - var spec; - currentSuite = env.describe('default current suite', function() { - spec = env.it(); - }, spec); - TestClass = { someFunction: function(a, b) { - } }; - spec.spyOn(TestClass, 'someFunction'); - }); - - it("should handle case of actual not being a spy", function() { - var matcher = match(); - matcher.wasCalledWith('a', 'b'); - - var result = mockSpec.addMatcherResult.mostRecentCall.args[0]; - - expect(result.matcherName).toEqual("wasCalledWith"); - expect(result.passed()).toEqual(false); - expect(result.message).toEqual("Actual is not a spy"); - expect(result.actual).toEqual(undefined); - expect(result.expected).toEqual(['a','b']); - - matcher = match('foo'); - matcher.wasCalledWith('a', 'b'); - - result = mockSpec.addMatcherResult.mostRecentCall.args[0]; - - expect(result.matcherName).toEqual("wasCalledWith"); - expect(result.passed()).toEqual(false); - expect(result.message).toEqual("Actual is not a spy"); - expect(result.actual).toEqual('foo'); - expect(result.expected).toEqual(['a','b']); - }); - - it("should should handle the case of a spy", function() { - TestClass.someFunction('a', 'c'); - var matcher = match(TestClass.someFunction); - matcher.wasCalledWith('a', 'b'); - - var result = mockSpec.addMatcherResult.mostRecentCall.args[0]; - expect(result.matcherName).toEqual("wasCalledWith"); - expect(result.passed()).toEqual(false); - expect(result.message).toMatch("['a', 'b']"); - expect(result.message).toMatch("['a', 'c']"); - expect(result.actual).toEqual(TestClass.someFunction); - expect(result.expected).toEqual(['a','b']); - }); - }); -}) - ; +}); diff --git a/spec/suites/PrettyPrintSpec.js b/spec/suites/PrettyPrintSpec.js index 48b1c7d..cf5f95a 100644 --- a/spec/suites/PrettyPrintSpec.js +++ b/spec/suites/PrettyPrintSpec.js @@ -32,6 +32,10 @@ describe("jasmine.pp", function () { }, bar: [1, 2, 3]})).toEqual("{ foo : Function, bar : [ 1, 2, 3 ] }"); }); + it("should stringify RegExp objects properly", function() { + expect(jasmine.pp(/x|y|z/)).toEqual("/x|y|z/"); + }); + it("should indicate circular object references", function() { var sampleValue = {foo: 'hello'}; sampleValue.nested = sampleValue; @@ -69,5 +73,21 @@ describe("jasmine.pp", function () { expect(jasmine.pp(window)).toEqual(""); }); + it("should stringify Date objects properly", function() { + var now = new Date(); + expect(jasmine.pp(now)).toEqual("Date(" + now.toString() + ")"); + }); + + it("should stringify spy objects properly", function() { + var TestObject = { + someFunction: function() { + } + }; + spyOn(TestObject, 'someFunction'); + expect(jasmine.pp(TestObject.someFunction)).toEqual("spy on someFunction"); + + expect(jasmine.pp(jasmine.createSpy("something"))).toEqual("spy on something"); + }); + }); diff --git a/spec/suites/TrivialReporterSpec.js b/spec/suites/TrivialReporterSpec.js index 1660c51..2fcc2ca 100644 --- a/spec/suites/TrivialReporterSpec.js +++ b/spec/suites/TrivialReporterSpec.js @@ -122,6 +122,19 @@ describe("TrivialReporter", function() { var divs = body.getElementsByTagName("div"); expect(divs[3].innerHTML).toEqual("Expected 'a' to be null, but it was not"); }); + + it("should add the failure message to the DOM (non-toEquals matchers)", function() { + expectationResult = new jasmine.ExpectationResult({ + matcherName: "toBeNull", passed: false, message: "Expected '1 < 2' to e null, & it was not" + }); + + spyOn(results, 'getItems').andReturn([expectationResult]); + + trivialReporter.reportSpecResults(spec); + + var divs = body.getElementsByTagName("div"); + expect(divs[3].innerHTML).toEqual("Expected '1 < 2' to <b>e null, & it was not"); + }); }); }); diff --git a/src/Env.js b/src/Env.js index aecacde..dac30f1 100644 --- a/src/Env.js +++ b/src/Env.js @@ -10,7 +10,7 @@ jasmine.Env = function() { this.reporter = new jasmine.MultiReporter(); - this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL + this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; this.lastUpdate = 0; this.specFilter = function() { return true; @@ -19,6 +19,17 @@ jasmine.Env = function() { this.nextSpecId_ = 0; this.nextSuiteId_ = 0; this.equalityTesters_ = []; + + // wrap matchers + this.matchersClass = function() { + jasmine.Matchers.apply(this, arguments); + }; + jasmine.util.inherit(this.matchersClass, jasmine.Matchers); + + for (var methodName in jasmine.Matchers.prototype) { + var orig = jasmine.Matchers.prototype[methodName]; + this.matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); + } }; diff --git a/src/Matchers.js b/src/Matchers.js index 889b98d..74a63ec 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -24,15 +24,25 @@ jasmine.Matchers.prototype.report = function(result, failing_message, details) { return result; }; -jasmine.Matchers.matcherFn_ = function(matcherName, options) { - return function () { - jasmine.util.extend(this, options); +jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { + return function() { var matcherArgs = jasmine.util.argsToArray(arguments); - var args = [this.actual].concat(matcherArgs); - var result = options.test.apply(this, args); + var result = matcherFunction.apply(this, arguments); var message; if (!result) { - message = options.message.apply(this, args); + if (this.message) { + message = this.message.apply(this, arguments); + } else { + var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); + message = "Expected " + jasmine.pp(this.actual) + " " + englishyPredicate; + if (matcherArgs.length > 0) { + for (var i = 0; i < matcherArgs.length; i++) { + if (i > 0) message += ","; + message += " " + jasmine.pp(matcherArgs[i]); + } + } + message += "."; + } } var expectationResult = new jasmine.ExpectationResult({ matcherName: matcherName, @@ -54,27 +64,17 @@ jasmine.Matchers.matcherFn_ = function(matcherName, options) { * @param expected */ -jasmine.Matchers.prototype.toBe = jasmine.Matchers.matcherFn_('toBe', { - test: function (actual, expected) { - return actual === expected; - }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to be " + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toBe = function(expected) { + return this.actual === expected; +}; /** * toNotBe: compares the actual to the expected using !== * @param expected */ -jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { - test: function (actual, expected) { - return actual !== expected; - }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to not be " + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toNotBe = function(expected) { + return this.actual !== expected; +}; /** * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. @@ -82,27 +82,17 @@ jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { * @param expected */ -jasmine.Matchers.prototype.toEqual = jasmine.Matchers.matcherFn_('toEqual', { - test: function (actual, expected) { - return this.env.equals_(actual, expected); - }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to equal " + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toEqual = function(expected) { + return this.env.equals_(this.actual, expected); +}; /** * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual * @param expected */ -jasmine.Matchers.prototype.toNotEqual = jasmine.Matchers.matcherFn_('toNotEqual', { - test: function (actual, expected) { - return !this.env.equals_(actual, expected); - }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to not equal " + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toNotEqual = function(expected) { + return !this.env.equals_(this.actual, expected); +}; /** * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes @@ -110,228 +100,143 @@ jasmine.Matchers.prototype.toNotEqual = jasmine.Matchers.matcherFn_('toNotEqual' * * @param reg_exp */ -jasmine.Matchers.prototype.toMatch = jasmine.Matchers.matcherFn_('toMatch', { - test: function(actual, expected) { - return new RegExp(expected).test(actual); - }, - message: function(actual, expected) { - return jasmine.pp(actual) + " does not match the regular expression " + new RegExp(expected).toString(); - } -}); +jasmine.Matchers.prototype.toMatch = function(expected) { + return new RegExp(expected).test(this.actual); +}; /** * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch * @param reg_exp */ - -jasmine.Matchers.prototype.toNotMatch = jasmine.Matchers.matcherFn_('toNotMatch', { - test: function(actual, expected) { - return !(new RegExp(expected).test(actual)); - }, - message: function(actual, expected) { - return jasmine.pp(actual) + " should not match " + new RegExp(expected).toString(); - } -}); +jasmine.Matchers.prototype.toNotMatch = function(expected) { + return !(new RegExp(expected).test(this.actual)); +}; /** - * Matcher that compares the acutal to undefined. + * Matcher that compares the actual to undefined. */ - -jasmine.Matchers.prototype.toBeDefined = jasmine.Matchers.matcherFn_('toBeDefined', { - test: function(actual) { - return (actual !== undefined); - }, - message: function() { - return 'Expected actual to not be undefined.'; - } -}); +jasmine.Matchers.prototype.toBeDefined = function() { + return (this.actual !== undefined); +}; /** - * Matcher that compares the acutal to undefined. + * Matcher that compares the actual to undefined. */ - -jasmine.Matchers.prototype.toBeUndefined = jasmine.Matchers.matcherFn_('toBeUndefined', { - test: function(actual) { - return (actual === undefined); - }, - message: function(actual) { - return 'Expected ' + jasmine.pp(actual) + ' to be undefined.'; - } -}); +jasmine.Matchers.prototype.toBeUndefined = function() { + return (this.actual === undefined); +}; /** * Matcher that compares the actual to null. - * */ -jasmine.Matchers.prototype.toBeNull = jasmine.Matchers.matcherFn_('toBeNull', { - test: function(actual) { - return (actual === null); - }, - message: function(actual) { - return 'Expected ' + jasmine.pp(actual) + ' to be null.'; - } -}); +jasmine.Matchers.prototype.toBeNull = function() { + return (this.actual === null); +}; /** * Matcher that boolean not-nots the actual. */ -jasmine.Matchers.prototype.toBeTruthy = jasmine.Matchers.matcherFn_('toBeTruthy', { - test: function(actual) { - return !!actual; - }, - message: function() { - return 'Expected actual to be truthy'; - } -}); +jasmine.Matchers.prototype.toBeTruthy = function() { + return !!this.actual; +}; /** * Matcher that boolean nots the actual. */ -jasmine.Matchers.prototype.toBeFalsy = jasmine.Matchers.matcherFn_('toBeFalsy', { - test: function(actual) { - return !actual; - }, - message: function(actual) { - return 'Expected ' + jasmine.pp(actual) + ' to be falsy'; - } -}); +jasmine.Matchers.prototype.toBeFalsy = function() { + return !this.actual; +}; /** - * Matcher that checks to see if the acutal, a Jasmine spy, was called. + * Matcher that checks to see if the actual, a Jasmine spy, was called. */ - -jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.matcherFn_('wasCalled', { - getActual_: function() { - var args = jasmine.util.argsToArray(arguments); - if (args.length > 1) { - throw(new Error('wasCalled does not take arguments, use wasCalledWith')); - } - return args.splice(0, 1)[0]; - }, - test: function() { - var actual = this.getActual_.apply(this, arguments); - if (!actual || !actual.isSpy) { - return false; - } - return actual.wasCalled; - }, - message: function() { - var actual = this.getActual_.apply(this, arguments); - if (!actual || !actual.isSpy) { - return 'Actual is not a spy.'; - } - return "Expected spy " + actual.identity + " to have been called."; +jasmine.Matchers.prototype.wasCalled = function() { + if (arguments.length > 0) { + throw new Error('wasCalled does not take arguments, use wasCalledWith'); } -}); + + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); + } + + this.message = function() { + return "Expected spy " + this.actual.identity + " to have been called."; + }; + + return this.actual.wasCalled; +}; /** - * Matcher that checks to see if the acutal, a Jasmine spy, was not called. + * Matcher that checks to see if the actual, a Jasmine spy, was not called. */ -jasmine.Matchers.prototype.wasNotCalled = jasmine.Matchers.matcherFn_('wasNotCalled', { - getActual_: function() { - var args = jasmine.util.argsToArray(arguments); - return args.splice(0, 1)[0]; - }, - test: function() { - var actual = this.getActual_.apply(this, arguments); - if (!actual || !actual.isSpy) { - return false; - } - return !actual.wasCalled; - }, - message: function() { - var actual = this.getActual_.apply(this, arguments); - if (!actual || !actual.isSpy) { - return 'Actual is not a spy.'; - } - return "Expected spy " + actual.identity + " to not have been called."; +jasmine.Matchers.prototype.wasNotCalled = function() { + if (arguments.length > 0) { + throw new Error('wasNotCalled does not take arguments'); } -}); -jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.matcherFn_('wasCalledWith', { - test: function() { - var args = jasmine.util.argsToArray(arguments); - var actual = args.splice(0, 1)[0]; - if (!actual || !actual.isSpy) { - return false; - } - return this.env.contains_(actual.argsForCall, args); - }, - message: function() { - var args = jasmine.util.argsToArray(arguments); - var actual = args.splice(0, 1)[0]; - var message; - if (!actual || !actual.isSpy) { - message = 'Actual is not a spy'; - } else { - message = "Expected spy to have been called with " + jasmine.pp(args) + " but was called with " + actual.argsForCall; - } - return message; + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); } -}); + + this.message = function() { + return "Expected spy " + this.actual.identity + " to not have been called."; + }; + + return !this.actual.wasCalled; +}; /** - * Matcher that checks to see if the acutal, a Jasmine spy, was called with a set of parameters. + * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. * * @example * */ +jasmine.Matchers.prototype.wasCalledWith = function() { + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); + } + + this.message = function() { + return "Expected spy to have been called with " + jasmine.pp(arguments) + " but was called with " + jasmine.pp(this.actual.argsForCall); + }; + + return this.env.contains_(this.actual.argsForCall, jasmine.util.argsToArray(arguments)); +}; /** * Matcher that checks that the expected item is an element in the actual Array. * * @param {Object} item */ - -jasmine.Matchers.prototype.toContain = jasmine.Matchers.matcherFn_('toContain', { - test: function(actual, expected) { - return this.env.contains_(actual, expected); - }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to contain ' + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toContain = function(expected) { + return this.env.contains_(this.actual, expected); +}; /** * Matcher that checks that the expected item is NOT an element in the actual Array. * * @param {Object} item */ -jasmine.Matchers.prototype.toNotContain = jasmine.Matchers.matcherFn_('toNotContain', { - test: function(actual, expected) { - return !this.env.contains_(actual, expected); - }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to not contain ' + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toNotContain = function(expected) { + return !this.env.contains_(this.actual, expected); +}; -jasmine.Matchers.prototype.toBeLessThan = jasmine.Matchers.matcherFn_('toBeLessThan', { - test: function(actual, expected) { - return actual < expected; - }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to be less than ' + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toBeLessThan = function(expected) { + return this.actual < expected; +}; -jasmine.Matchers.prototype.toBeGreaterThan = jasmine.Matchers.matcherFn_('toBeGreaterThan', { - test: function(actual, expected) { - return actual > expected; - }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to be greater than ' + jasmine.pp(expected); - } -}); +jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { + return this.actual > expected; +}; /** * Matcher that checks that the expected exception was thrown by the actual. * * @param {String} expectedException */ -jasmine.Matchers.prototype.toThrow = jasmine.Matchers.matcherFn_('toThrow', { - getException_: function(actual, expected) { +jasmine.Matchers.prototype.toThrow = function(expected) { + function getException_(actual, expected) { var exception; if (typeof actual != 'function') { throw new Error('Actual is not a function'); @@ -342,24 +247,25 @@ jasmine.Matchers.prototype.toThrow = jasmine.Matchers.matcherFn_('toThrow', { exception = e; } return exception; - }, - test: function(actual, expected) { - var result = false; - var exception = this.getException_(actual, expected); - if (exception) { - result = (expected === undefined || this.env.equals_(exception.message || exception, expected.message || expected)); - } - return result; - }, - message: function(actual, expected) { - var exception = this.getException_(actual, expected); + } + + var result = false; + var exception = getException_(this.actual, expected); + if (exception) { + result = (expected === undefined || this.env.equals_(exception.message || exception, expected.message || expected)); + } + + this.message = function(expected) { + var exception = getException_(this.actual, expected); if (exception && (expected === undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { return ["Expected function to throw", expected.message || expected, ", but it threw", exception.message || exception ].join(' '); } else { return "Expected function to throw an exception."; } - } -}); + }; + + return result; +}; jasmine.Matchers.Any = function(expectedClass) { this.expectedClass = expectedClass; diff --git a/src/PrettyPrinter.js b/src/PrettyPrinter.js index d044753..16021b6 100644 --- a/src/PrettyPrinter.js +++ b/src/PrettyPrinter.js @@ -9,11 +9,9 @@ jasmine.PrettyPrinter = function() { * Formats a value in a nice, human-readable string. * * @param value - * @returns {String} */ jasmine.PrettyPrinter.prototype.format = function(value) { if (this.ppNestLevel_ > 40) { - // return '(jasmine.pp nested too deeply!)'; throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); } @@ -29,12 +27,16 @@ jasmine.PrettyPrinter.prototype.format = function(value) { this.emitScalar(value.toString()); } else if (typeof value === 'string') { this.emitString(value); + } else if (jasmine.isSpy(value)) { + this.emitScalar("spy on " + value.identity); } else if (typeof value === 'function') { this.emitScalar('Function'); } else if (typeof value.nodeType === 'number') { this.emitScalar('HTMLNode'); } else if (value instanceof Date) { this.emitScalar('Date(' + value + ')'); + } else if (value instanceof RegExp) { + this.emitScalar(value.toString()); } else if (value.__Jasmine_been_here_before__) { this.emitScalar(''); } else if (jasmine.isArray_(value) || typeof value == 'object') { diff --git a/src/Spec.js b/src/Spec.js index a0a7453..4931432 100644 --- a/src/Spec.js +++ b/src/Spec.js @@ -10,11 +10,9 @@ jasmine.Spec = function(env, suite, description) { if (!env) { throw new Error('jasmine.Env() required'); } - ; if (!suite) { throw new Error('jasmine.Suite() required'); } - ; var spec = this; spec.id = env.nextSpecId ? env.nextSpecId() : null; spec.env = env; @@ -91,7 +89,7 @@ jasmine.Spec.prototype.fail = function (e) { }; jasmine.Spec.prototype.getMatchersClass_ = function() { - return this.matchersClass || jasmine.Matchers; + return this.matchersClass || this.env.matchersClass; }; jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { diff --git a/src/base.js b/src/base.js index 2f2e8e3..58b2394 100755 --- a/src/base.js +++ b/src/base.js @@ -19,7 +19,7 @@ jasmine.unimplementedMethod_ = function() { jasmine.DEFAULT_UPDATE_INTERVAL = 250; /** - * Allows for bound functions to be comapred. Internal use only. + * Allows for bound functions to be compared. Internal use only. * * @ignore * @private @@ -324,6 +324,16 @@ jasmine.createSpy = function(name) { return spyObj; }; +/** + * Determines whether an object is a spy. + * + * @param {jasmine.Spy|Object} putativeSpy + * @returns {Boolean} + */ +jasmine.isSpy = function(putativeSpy) { + return putativeSpy && putativeSpy.isSpy; +}; + /** * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something * large in one call.