From 1b3545c82a8d2502da6ff6877776e3068860abd1 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 12 Nov 2009 12:47:44 -0500 Subject: [PATCH 01/12] Remove 'actual' param from matchers test and message functions. Use this.actual instead. This way, the signature of the test function matches how the matcher is called from a spec. Spy matchers now throw an exception when called with non-spies, rather than returning false. This makes the message function simpler, and will work better with future dot-not support. Added better specs for error conditions on spy matchers. --- spec/suites/MatchersSpec.js | 71 ++++++------- src/Matchers.js | 201 ++++++++++++++++-------------------- src/base.js | 10 ++ 3 files changed, 134 insertions(+), 148 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index 156bc3b..a9420bf 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -463,7 +463,7 @@ describe("jasmine.Matchers", function() { } catch (e) { exception = e; } - ; + expect(exception).toBeDefined(); expect(exception.message).toEqual('Actual is not a function'); @@ -476,21 +476,44 @@ describe("jasmine.Matchers", function() { }); - describe("wasCalled, wasNotCalled, wasCalledWith", function() { + describe("spy matchers (wasCalled, wasNotCalled, wasCalledWith)", 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."); + it("should throw an exception when wasCalled and wasNotCalled are invoked with the wrong number of arguments", function() { + expect(function() { + match(TestClass.someFunction).wasCalled("unwanted argument"); + }).toThrow('wasCalled does not take arguments, use wasCalledWith'); + + expect(function() { + match(TestClass.someFunction).wasNotCalled("unwanted argument"); + }).toThrow('wasNotCalled does not take arguments'); + }); + + describe('with non-spies', function() { + it('should always show an error', function () { + expect(function() { + match(TestClass.someFunction).wasCalled(); + }).toThrow('Expected a spy, but got Function.'); + + expect(function() { + match(TestClass.someFunction).wasNotCalled(); + }).toThrow('Expected a spy, but got Function.'); + + expect(function() { + match(TestClass.someFunction).wasCalledWith(); + }).toThrow('Expected a spy, but got Function.'); + + expect(function() { + match(undefined).wasCalled(); + }).toThrow('Expected a spy, but got undefined.'); + + expect(function() { + match({some:'object'}).wasCalled(); + }).toThrow('Expected a spy, but got { some : \'object\' }.'); }); }); @@ -538,7 +561,6 @@ describe("jasmine.Matchers", function() { }); }); - describe("wasCalledWith to build an ExpectationResult", function () { var TestClass; beforeEach(function() { @@ -552,30 +574,6 @@ describe("jasmine.Matchers", function() { 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); @@ -590,5 +588,4 @@ describe("jasmine.Matchers", function() { expect(result.expected).toEqual(['a','b']); }); }); -}) - ; +}); diff --git a/src/Matchers.js b/src/Matchers.js index 889b98d..c58eb58 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -28,11 +28,10 @@ jasmine.Matchers.matcherFn_ = function(matcherName, options) { return function () { jasmine.util.extend(this, options); var matcherArgs = jasmine.util.argsToArray(arguments); - var args = [this.actual].concat(matcherArgs); - var result = options.test.apply(this, args); + var result = options.test.apply(this, arguments); var message; if (!result) { - message = options.message.apply(this, args); + message = options.message.apply(this, arguments); } var expectationResult = new jasmine.ExpectationResult({ matcherName: matcherName, @@ -55,11 +54,11 @@ jasmine.Matchers.matcherFn_ = function(matcherName, options) { */ jasmine.Matchers.prototype.toBe = jasmine.Matchers.matcherFn_('toBe', { - test: function (actual, expected) { - return actual === expected; + test: function(expected) { + return this.actual === expected; }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to be " + jasmine.pp(expected); + message: function(expected) { + return "Expected " + jasmine.pp(this.actual) + " to be " + jasmine.pp(expected); } }); @@ -68,11 +67,11 @@ jasmine.Matchers.prototype.toBe = jasmine.Matchers.matcherFn_('toBe', { * @param expected */ jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { - test: function (actual, expected) { - return actual !== expected; + test: function(expected) { + return this.actual !== expected; }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to not be " + jasmine.pp(expected); + message: function(expected) { + return "Expected " + jasmine.pp(this.actual) + " to not be " + jasmine.pp(expected); } }); @@ -83,11 +82,11 @@ jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { */ jasmine.Matchers.prototype.toEqual = jasmine.Matchers.matcherFn_('toEqual', { - test: function (actual, expected) { - return this.env.equals_(actual, expected); + test: function(expected) { + return this.env.equals_(this.actual, expected); }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to equal " + jasmine.pp(expected); + message: function(expected) { + return "Expected " + jasmine.pp(this.actual) + " to equal " + jasmine.pp(expected); } }); @@ -96,11 +95,11 @@ jasmine.Matchers.prototype.toEqual = jasmine.Matchers.matcherFn_('toEqual', { * @param expected */ jasmine.Matchers.prototype.toNotEqual = jasmine.Matchers.matcherFn_('toNotEqual', { - test: function (actual, expected) { - return !this.env.equals_(actual, expected); + test: function(expected) { + return !this.env.equals_(this.actual, expected); }, - message: function(actual, expected) { - return "Expected " + jasmine.pp(actual) + " to not equal " + jasmine.pp(expected); + message: function(expected) { + return "Expected " + jasmine.pp(this.actual) + " to not equal " + jasmine.pp(expected); } }); @@ -111,11 +110,11 @@ 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); + test: function(expected) { + return new RegExp(expected).test(this.actual); }, - message: function(actual, expected) { - return jasmine.pp(actual) + " does not match the regular expression " + new RegExp(expected).toString(); + message: function(expected) { + return jasmine.pp(this.actual) + " does not match the regular expression " + new RegExp(expected).toString(); } }); @@ -125,21 +124,21 @@ jasmine.Matchers.prototype.toMatch = jasmine.Matchers.matcherFn_('toMatch', { */ jasmine.Matchers.prototype.toNotMatch = jasmine.Matchers.matcherFn_('toNotMatch', { - test: function(actual, expected) { - return !(new RegExp(expected).test(actual)); + test: function(expected) { + return !(new RegExp(expected).test(this.actual)); }, - message: function(actual, expected) { - return jasmine.pp(actual) + " should not match " + new RegExp(expected).toString(); + message: function(expected) { + return jasmine.pp(this.actual) + " should not match " + new RegExp(expected).toString(); } }); /** - * 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); + test: function() { + return (this.actual !== undefined); }, message: function() { return 'Expected actual to not be undefined.'; @@ -147,15 +146,15 @@ jasmine.Matchers.prototype.toBeDefined = jasmine.Matchers.matcherFn_('toBeDefine }); /** - * 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); + test: function() { + return (this.actual === undefined); }, - message: function(actual) { - return 'Expected ' + jasmine.pp(actual) + ' to be undefined.'; + message: function() { + return 'Expected ' + jasmine.pp(this.actual) + ' to be undefined.'; } }); @@ -164,11 +163,11 @@ jasmine.Matchers.prototype.toBeUndefined = jasmine.Matchers.matcherFn_('toBeUnde * */ jasmine.Matchers.prototype.toBeNull = jasmine.Matchers.matcherFn_('toBeNull', { - test: function(actual) { - return (actual === null); + test: function() { + return (this.actual === null); }, - message: function(actual) { - return 'Expected ' + jasmine.pp(actual) + ' to be null.'; + message: function() { + return 'Expected ' + jasmine.pp(this.actual) + ' to be null.'; } }); @@ -176,8 +175,8 @@ jasmine.Matchers.prototype.toBeNull = jasmine.Matchers.matcherFn_('toBeNull', { * Matcher that boolean not-nots the actual. */ jasmine.Matchers.prototype.toBeTruthy = jasmine.Matchers.matcherFn_('toBeTruthy', { - test: function(actual) { - return !!actual; + test: function() { + return !!this.actual; }, message: function() { return 'Expected actual to be truthy'; @@ -189,90 +188,70 @@ jasmine.Matchers.prototype.toBeTruthy = jasmine.Matchers.matcherFn_('toBeTruthy' * Matcher that boolean nots the actual. */ jasmine.Matchers.prototype.toBeFalsy = jasmine.Matchers.matcherFn_('toBeFalsy', { - test: function(actual) { - return !actual; + test: function() { + return !this.actual; }, - message: function(actual) { - return 'Expected ' + jasmine.pp(actual) + ' to be falsy'; + message: function() { + return 'Expected ' + jasmine.pp(this.actual) + ' to be falsy'; } }); /** - * 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; + if (arguments.length > 0) { + throw new Error('wasCalled does not take arguments, use wasCalledWith'); } - return actual.wasCalled; + + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); + } + + return this.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."; + return "Expected spy " + this.actual.identity + " to have been called."; } }); /** - * 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; + if (arguments.length > 0) { + throw new Error('wasNotCalled does not take arguments'); } - return !actual.wasCalled; + + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); + } + + return !this.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."; + return "Expected spy " + this.actual.identity + " to not have been called."; } }); 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; + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); } - return this.env.contains_(actual.argsForCall, args); + + return this.env.contains_(this.actual.argsForCall, arguments); }, 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; + return "Expected spy to have been called with " + jasmine.pp(arguments) + " but was called with " + this.actual.argsForCall; } }); /** - * 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 * @@ -285,11 +264,11 @@ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.matcherFn_('wasCalle */ jasmine.Matchers.prototype.toContain = jasmine.Matchers.matcherFn_('toContain', { - test: function(actual, expected) { - return this.env.contains_(actual, expected); + test: function(expected) { + return this.env.contains_(this.actual, expected); }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to contain ' + jasmine.pp(expected); + message: function(expected) { + return 'Expected ' + jasmine.pp(this.actual) + ' to contain ' + jasmine.pp(expected); } }); @@ -299,29 +278,29 @@ jasmine.Matchers.prototype.toContain = jasmine.Matchers.matcherFn_('toContain', * @param {Object} item */ jasmine.Matchers.prototype.toNotContain = jasmine.Matchers.matcherFn_('toNotContain', { - test: function(actual, expected) { - return !this.env.contains_(actual, expected); + test: function(expected) { + return !this.env.contains_(this.actual, expected); }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to not contain ' + jasmine.pp(expected); + message: function(expected) { + return 'Expected ' + jasmine.pp(this.actual) + ' to not contain ' + jasmine.pp(expected); } }); jasmine.Matchers.prototype.toBeLessThan = jasmine.Matchers.matcherFn_('toBeLessThan', { - test: function(actual, expected) { - return actual < expected; + test: function(expected) { + return this.actual < expected; }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to be less than ' + jasmine.pp(expected); + message: function(expected) { + return 'Expected ' + jasmine.pp(this.actual) + ' to be less than ' + jasmine.pp(expected); } }); jasmine.Matchers.prototype.toBeGreaterThan = jasmine.Matchers.matcherFn_('toBeGreaterThan', { - test: function(actual, expected) { - return actual > expected; + test: function(expected) { + return this.actual > expected; }, - message: function(actual, expected) { - return 'Expected ' + jasmine.pp(actual) + ' to be greater than ' + jasmine.pp(expected); + message: function(expected) { + return 'Expected ' + jasmine.pp(this.actual) + ' to be greater than ' + jasmine.pp(expected); } }); @@ -343,16 +322,16 @@ jasmine.Matchers.prototype.toThrow = jasmine.Matchers.matcherFn_('toThrow', { } return exception; }, - test: function(actual, expected) { + test: function(expected) { var result = false; - var exception = this.getException_(actual, expected); + var exception = this.getException_(this.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); + message: function(expected) { + var exception = this.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 { diff --git a/src/base.js b/src/base.js index 2f2e8e3..a516af7 100755 --- a/src/base.js +++ b/src/base.js @@ -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. From 3b92b9bb79be7847ce8eb9e5c3bef024964e9424 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 12 Nov 2009 14:36:58 -0500 Subject: [PATCH 02/12] Remove message function from matchers where a formulaic message is good enough. --- spec/suites/MatchersSpec.js | 4 +-- src/Matchers.js | 57 +++++++++---------------------------- src/base.js | 2 +- 3 files changed, 16 insertions(+), 47 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index a9420bf..06a2d5b 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -213,7 +213,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 +297,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); }); diff --git a/src/Matchers.js b/src/Matchers.js index c58eb58..b4486b7 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -31,7 +31,19 @@ jasmine.Matchers.matcherFn_ = function(matcherName, options) { var result = options.test.apply(this, arguments); var message; if (!result) { - message = options.message.apply(this, arguments); + if (options.message) { + message = options.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, @@ -56,9 +68,6 @@ jasmine.Matchers.matcherFn_ = function(matcherName, options) { jasmine.Matchers.prototype.toBe = jasmine.Matchers.matcherFn_('toBe', { test: function(expected) { return this.actual === expected; - }, - message: function(expected) { - return "Expected " + jasmine.pp(this.actual) + " to be " + jasmine.pp(expected); } }); @@ -69,9 +78,6 @@ jasmine.Matchers.prototype.toBe = jasmine.Matchers.matcherFn_('toBe', { jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { test: function(expected) { return this.actual !== expected; - }, - message: function(expected) { - return "Expected " + jasmine.pp(this.actual) + " to not be " + jasmine.pp(expected); } }); @@ -84,9 +90,6 @@ jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { jasmine.Matchers.prototype.toEqual = jasmine.Matchers.matcherFn_('toEqual', { test: function(expected) { return this.env.equals_(this.actual, expected); - }, - message: function(expected) { - return "Expected " + jasmine.pp(this.actual) + " to equal " + jasmine.pp(expected); } }); @@ -97,9 +100,6 @@ jasmine.Matchers.prototype.toEqual = jasmine.Matchers.matcherFn_('toEqual', { jasmine.Matchers.prototype.toNotEqual = jasmine.Matchers.matcherFn_('toNotEqual', { test: function(expected) { return !this.env.equals_(this.actual, expected); - }, - message: function(expected) { - return "Expected " + jasmine.pp(this.actual) + " to not equal " + jasmine.pp(expected); } }); @@ -122,7 +122,6 @@ jasmine.Matchers.prototype.toMatch = jasmine.Matchers.matcherFn_('toMatch', { * 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(expected) { return !(new RegExp(expected).test(this.actual)); @@ -135,39 +134,27 @@ jasmine.Matchers.prototype.toNotMatch = jasmine.Matchers.matcherFn_('toNotMatch' /** * Matcher that compares the actual to undefined. */ - jasmine.Matchers.prototype.toBeDefined = jasmine.Matchers.matcherFn_('toBeDefined', { test: function() { return (this.actual !== undefined); - }, - message: function() { - return 'Expected actual to not be undefined.'; } }); /** * Matcher that compares the actual to undefined. */ - jasmine.Matchers.prototype.toBeUndefined = jasmine.Matchers.matcherFn_('toBeUndefined', { test: function() { return (this.actual === undefined); - }, - message: function() { - return 'Expected ' + jasmine.pp(this.actual) + ' to be undefined.'; } }); /** * Matcher that compares the actual to null. - * */ jasmine.Matchers.prototype.toBeNull = jasmine.Matchers.matcherFn_('toBeNull', { test: function() { return (this.actual === null); - }, - message: function() { - return 'Expected ' + jasmine.pp(this.actual) + ' to be null.'; } }); @@ -177,9 +164,6 @@ jasmine.Matchers.prototype.toBeNull = jasmine.Matchers.matcherFn_('toBeNull', { jasmine.Matchers.prototype.toBeTruthy = jasmine.Matchers.matcherFn_('toBeTruthy', { test: function() { return !!this.actual; - }, - message: function() { - return 'Expected actual to be truthy'; } }); @@ -190,9 +174,6 @@ jasmine.Matchers.prototype.toBeTruthy = jasmine.Matchers.matcherFn_('toBeTruthy' jasmine.Matchers.prototype.toBeFalsy = jasmine.Matchers.matcherFn_('toBeFalsy', { test: function() { return !this.actual; - }, - message: function() { - return 'Expected ' + jasmine.pp(this.actual) + ' to be falsy'; } }); @@ -266,9 +247,6 @@ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.matcherFn_('wasCalle jasmine.Matchers.prototype.toContain = jasmine.Matchers.matcherFn_('toContain', { test: function(expected) { return this.env.contains_(this.actual, expected); - }, - message: function(expected) { - return 'Expected ' + jasmine.pp(this.actual) + ' to contain ' + jasmine.pp(expected); } }); @@ -280,27 +258,18 @@ jasmine.Matchers.prototype.toContain = jasmine.Matchers.matcherFn_('toContain', jasmine.Matchers.prototype.toNotContain = jasmine.Matchers.matcherFn_('toNotContain', { test: function(expected) { return !this.env.contains_(this.actual, expected); - }, - message: function(expected) { - return 'Expected ' + jasmine.pp(this.actual) + ' to not contain ' + jasmine.pp(expected); } }); jasmine.Matchers.prototype.toBeLessThan = jasmine.Matchers.matcherFn_('toBeLessThan', { test: function(expected) { return this.actual < expected; - }, - message: function(expected) { - return 'Expected ' + jasmine.pp(this.actual) + ' to be less than ' + jasmine.pp(expected); } }); jasmine.Matchers.prototype.toBeGreaterThan = jasmine.Matchers.matcherFn_('toBeGreaterThan', { test: function(expected) { return this.actual > expected; - }, - message: function(expected) { - return 'Expected ' + jasmine.pp(this.actual) + ' to be greater than ' + jasmine.pp(expected); } }); diff --git a/src/base.js b/src/base.js index a516af7..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 From 98e86817bfc0c83fe0804ed59486dd18560afe96 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 12 Nov 2009 15:03:55 -0500 Subject: [PATCH 03/12] Fix wasCalledWith matcher. --- spec/suites/MatchersSpec.js | 42 +++++++++++++++++++------------------ src/Matchers.js | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index 06a2d5b..9bc40fe 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -535,28 +535,30 @@ describe("jasmine.Matchers", function() { 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); - }); + describe("wasCalledWith", function() { + it('wasCalledWith 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 return false if it was not called with the expected args', function() { - TestClass.someFunction('a', 'b', 'c'); - var expected = match(TestClass.someFunction); - expect(expected.wasCalledWith('c', 'b', 'a')).toEqual(false); - var result = mockSpec.addMatcherResult.mostRecentCall.args[0]; - expect(result.passed()).toEqual(false); - expect(result.expected).toEqual(['c', 'b', 'a']); - expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); - }); + it('should return false if it was not called with the expected args', function() { + TestClass.someFunction('a', 'b', 'c'); + var expected = match(TestClass.someFunction); + expect(expected.wasCalledWith('c', 'b', 'a')).toEqual(false); + var result = mockSpec.addMatcherResult.mostRecentCall.args[0]; + expect(result.passed()).toEqual(false); + expect(result.expected).toEqual(['c', 'b', 'a']); + expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); + }); - it('should allow matches across multiple calls', function() { - var expected = match(TestClass.someFunction); - TestClass.someFunction('a', 'b', 'c'); - TestClass.someFunction('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 allow matches across multiple calls', function() { + var expected = match(TestClass.someFunction); + TestClass.someFunction('a', 'b', 'c'); + TestClass.someFunction('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); + }); }); }); }); diff --git a/src/Matchers.js b/src/Matchers.js index b4486b7..b31f4f6 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -224,7 +224,7 @@ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.matcherFn_('wasCalle throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); } - return this.env.contains_(this.actual.argsForCall, arguments); + return this.env.contains_(this.actual.argsForCall, jasmine.util.argsToArray(arguments)); }, message: function() { return "Expected spy to have been called with " + jasmine.pp(arguments) + " but was called with " + this.actual.argsForCall; From 7be8247b2f3c5c8e61e80fa8c36b9f0cc8d5d408 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 12 Nov 2009 15:37:52 -0500 Subject: [PATCH 04/12] Fix pretty printing of RegExp objects. --- spec/suites/PrettyPrintSpec.js | 4 ++++ src/PrettyPrinter.js | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/suites/PrettyPrintSpec.js b/spec/suites/PrettyPrintSpec.js index 48b1c7d..71f27c4 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; diff --git a/src/PrettyPrinter.js b/src/PrettyPrinter.js index d044753..fb63428 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!'); } @@ -35,6 +33,8 @@ jasmine.PrettyPrinter.prototype.format = function(value) { 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') { From 5a8a050c4605b9382e21d40f46fca271874e77f1 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 12 Nov 2009 15:43:49 -0500 Subject: [PATCH 05/12] Removed toMatch and toNotMatch's message functions, now sufficiently handled by the default message builder. --- spec/suites/MatchersSpec.js | 11 +++-------- src/Matchers.js | 6 ------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index 9bc40fe..ec00dea 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -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); }); diff --git a/src/Matchers.js b/src/Matchers.js index b31f4f6..49c165c 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -112,9 +112,6 @@ jasmine.Matchers.prototype.toNotEqual = jasmine.Matchers.matcherFn_('toNotEqual' jasmine.Matchers.prototype.toMatch = jasmine.Matchers.matcherFn_('toMatch', { test: function(expected) { return new RegExp(expected).test(this.actual); - }, - message: function(expected) { - return jasmine.pp(this.actual) + " does not match the regular expression " + new RegExp(expected).toString(); } }); @@ -125,9 +122,6 @@ jasmine.Matchers.prototype.toMatch = jasmine.Matchers.matcherFn_('toMatch', { jasmine.Matchers.prototype.toNotMatch = jasmine.Matchers.matcherFn_('toNotMatch', { test: function(expected) { return !(new RegExp(expected).test(this.actual)); - }, - message: function(expected) { - return jasmine.pp(this.actual) + " should not match " + new RegExp(expected).toString(); } }); From ee5905d2377efa91633aa2a5dd39afa7a218898d Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 12 Nov 2009 16:13:44 -0500 Subject: [PATCH 06/12] Fix html escaping of matcher failure messages. --- lib/TrivialReporter.js | 4 +--- spec/suites/TrivialReporterSpec.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) 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/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"); + }); }); }); From b0ae4611399192203a1d714540122678dffdb48b Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 12 Nov 2009 16:49:48 -0500 Subject: [PATCH 07/12] Nicer pretty printing of spy objects. --- spec/suites/PrettyPrintSpec.js | 16 ++++++++++++++++ src/PrettyPrinter.js | 2 ++ 2 files changed, 18 insertions(+) diff --git a/spec/suites/PrettyPrintSpec.js b/spec/suites/PrettyPrintSpec.js index 71f27c4..cf5f95a 100644 --- a/spec/suites/PrettyPrintSpec.js +++ b/spec/suites/PrettyPrintSpec.js @@ -73,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/src/PrettyPrinter.js b/src/PrettyPrinter.js index fb63428..16021b6 100644 --- a/src/PrettyPrinter.js +++ b/src/PrettyPrinter.js @@ -27,6 +27,8 @@ 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') { From 752b91f118d09e514e5a8c320a844df6fa99f808 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Fri, 13 Nov 2009 12:21:34 -0500 Subject: [PATCH 08/12] Reorganizing spy matcher specs. --- spec/suites/MatchersSpec.js | 56 ++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index ec00dea..c8784db 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -474,32 +474,35 @@ describe("jasmine.Matchers", function() { describe("spy matchers (wasCalled, wasNotCalled, wasCalledWith)", function() { var TestClass; beforeEach(function() { - TestClass = { someFunction: function() { - } }; + TestClass = { + normalFunction: function() { + }, + spyFunction: jasmine.createSpy("My spy") + }; }); it("should throw an exception when wasCalled and wasNotCalled are invoked with the wrong number of arguments", function() { expect(function() { - match(TestClass.someFunction).wasCalled("unwanted argument"); + match(TestClass.normalFunction).wasCalled("unwanted argument"); }).toThrow('wasCalled does not take arguments, use wasCalledWith'); expect(function() { - match(TestClass.someFunction).wasNotCalled("unwanted argument"); + match(TestClass.normalFunction).wasNotCalled("unwanted argument"); }).toThrow('wasNotCalled does not take arguments'); }); describe('with non-spies', function() { it('should always show an error', function () { expect(function() { - match(TestClass.someFunction).wasCalled(); + match(TestClass.normalFunction).wasCalled(); }).toThrow('Expected a spy, but got Function.'); expect(function() { - match(TestClass.someFunction).wasNotCalled(); + match(TestClass.normalFunction).wasNotCalled(); }).toThrow('Expected a spy, but got Function.'); expect(function() { - match(TestClass.someFunction).wasCalledWith(); + match(TestClass.normalFunction).wasCalledWith(); }).toThrow('Expected a spy, but got Function.'); expect(function() { @@ -513,32 +516,35 @@ describe("jasmine.Matchers", function() { }); describe('with spies', function () { + 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); + }); - beforeEach(function () { - TestClass.someFunction = jasmine.createSpy("My spy"); }); - it("should track if it was called", function() { - expect(match(TestClass.someFunction).wasCalled()).toEqual(false); - expect(match(TestClass.someFunction).wasNotCalled()).toEqual(true); + 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); + }); - TestClass.someFunction(); - expect(match(TestClass.someFunction).wasCalled()).toEqual(true); - expect(function () { - match(TestClass.someFunction).wasCalled('some arg'); - }).toThrow('wasCalled does not take arguments, use wasCalledWith'); - expect(match(TestClass.someFunction).wasNotCalled()).toEqual(false); }); describe("wasCalledWith", function() { it('wasCalledWith 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); + 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); @@ -547,9 +553,9 @@ 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); From b0326d3078c910f8aa302c676e27217ea09bd490 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Fri, 13 Nov 2009 12:30:22 -0500 Subject: [PATCH 09/12] Reorganizing spy matcher specs. --- spec/suites/MatchersSpec.js | 163 ++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 82 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index c8784db..8480982 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -471,7 +471,7 @@ describe("jasmine.Matchers", function() { }); - describe("spy matchers (wasCalled, wasNotCalled, wasCalledWith)", function() { + describe("spy matchers È", function() { var TestClass; beforeEach(function() { TestClass = { @@ -481,30 +481,25 @@ describe("jasmine.Matchers", function() { }; }); - it("should throw an exception when wasCalled and wasNotCalled are invoked with the wrong number of arguments", function() { - expect(function() { - match(TestClass.normalFunction).wasCalled("unwanted argument"); - }).toThrow('wasCalled does not take arguments, use wasCalledWith'); + describe("wasCalled", function() { + it("should pass iff the spy was called", function() { + expect(match(TestClass.spyFunction).wasCalled()).toEqual(false); - expect(function() { - match(TestClass.normalFunction).wasNotCalled("unwanted argument"); - }).toThrow('wasNotCalled does not take arguments'); - }); + TestClass.spyFunction(); + expect(match(TestClass.spyFunction).wasCalled()).toEqual(true); + }); - describe('with non-spies', function() { - it('should always show an error', function () { + 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'); + }); + + it('should throw an exception when invoked on a non-spy', function () { expect(function() { match(TestClass.normalFunction).wasCalled(); }).toThrow('Expected a spy, but got Function.'); - expect(function() { - match(TestClass.normalFunction).wasNotCalled(); - }).toThrow('Expected a spy, but got Function.'); - - expect(function() { - match(TestClass.normalFunction).wasCalledWith(); - }).toThrow('Expected a spy, but got Function.'); - expect(function() { match(undefined).wasCalled(); }).toThrow('Expected a spy, but got undefined.'); @@ -515,80 +510,84 @@ describe("jasmine.Matchers", function() { }); }); - describe('with spies', function () { - 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); - }); + 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); }); - 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'); }); - 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 throw an exception when invoked on a non-spy', function () { + expect(function() { + match(TestClass.normalFunction).wasNotCalled(); + }).toThrow('Expected a spy, but got Function.'); + }); + }); + + 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.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); + expect(result.expected).toEqual(['c', 'b', 'a']); + expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); + }); + + it('should allow matches across multiple calls', function() { + 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', function () { + expect(function() { + match(TestClass.normalFunction).wasCalledWith(); + }).toThrow('Expected a spy, but got Function.'); + }); + + 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 return false if it was not called with the expected args', function() { - TestClass.spyFunction('a', 'b', 'c'); - var expected = match(TestClass.spyFunction); - expect(expected.wasCalledWith('c', 'b', 'a')).toEqual(false); + 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.expected).toEqual(['c', 'b', 'a']); - expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); - }); - - it('should allow matches across multiple calls', function() { - 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); + 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 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']); - }); - }); }); From 60ea562560f0156cc76a441bc358e102c48a6cdd Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Fri, 13 Nov 2009 12:40:04 -0500 Subject: [PATCH 10/12] Reuse an 'it' block. --- spec/suites/MatchersSpec.js | 44 +++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index 8480982..b716994 100644 --- a/spec/suites/MatchersSpec.js +++ b/spec/suites/MatchersSpec.js @@ -471,7 +471,7 @@ describe("jasmine.Matchers", function() { }); - describe("spy matchers È", function() { + describe("spy matchers >>", function() { var TestClass; beforeEach(function() { TestClass = { @@ -481,6 +481,22 @@ describe("jasmine.Matchers", function() { }; }); + function shouldThrowAnExceptionWhenInvokedOnANonSpy(methodName) { + return function() { + expect(function() { + match(TestClass.normalFunction)[methodName](); + }).toThrow('Expected a spy, but got Function.'); + + 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); @@ -495,19 +511,7 @@ describe("jasmine.Matchers", function() { }).toThrow('wasCalled does not take arguments, use wasCalledWith'); }); - it('should throw an exception when invoked on a non-spy', function () { - expect(function() { - match(TestClass.normalFunction).wasCalled(); - }).toThrow('Expected a spy, but got Function.'); - - expect(function() { - match(undefined).wasCalled(); - }).toThrow('Expected a spy, but got undefined.'); - - expect(function() { - match({some:'object'}).wasCalled(); - }).toThrow('Expected a spy, but got { some : \'object\' }.'); - }); + it('should throw an exception when invoked on a non-spy', shouldThrowAnExceptionWhenInvokedOnANonSpy('wasCalled')); }); describe("wasNotCalled", function() { @@ -524,11 +528,7 @@ describe("jasmine.Matchers", function() { }).toThrow('wasNotCalled does not take arguments'); }); - it('should throw an exception when invoked on a non-spy', function () { - expect(function() { - match(TestClass.normalFunction).wasNotCalled(); - }).toThrow('Expected a spy, but got Function.'); - }); + it('should throw an exception when invoked on a non-spy', shouldThrowAnExceptionWhenInvokedOnANonSpy('wasNotCalled')); }); describe("wasCalledWith", function() { @@ -556,11 +556,7 @@ describe("jasmine.Matchers", function() { expect(expected.wasCalledWith('x', 'y', 'z')).toEqual(false); }); - it('should throw an exception when invoked on a non-spy', function () { - expect(function() { - match(TestClass.normalFunction).wasCalledWith(); - }).toThrow('Expected a spy, but got Function.'); - }); + it('should throw an exception when invoked on a non-spy', shouldThrowAnExceptionWhenInvokedOnANonSpy('wasCalledWith')); describe("to build an ExpectationResult", function () { beforeEach(function() { From 2fc78a0fe21e55a169d256d991d90bb3f47649ac Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Fri, 13 Nov 2009 13:28:38 -0500 Subject: [PATCH 11/12] Moved last message formatting functions to be set up by matcher test function. --- src/Matchers.js | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Matchers.js b/src/Matchers.js index 49c165c..123b91c 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -31,8 +31,8 @@ jasmine.Matchers.matcherFn_ = function(matcherName, options) { var result = options.test.apply(this, arguments); var message; if (!result) { - if (options.message) { - message = options.message.apply(this, arguments); + 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; @@ -185,10 +185,11 @@ jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.matcherFn_('wasCalled', 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; - }, - message: function() { - return "Expected spy " + this.actual.identity + " to have been called."; } }); @@ -205,10 +206,11 @@ jasmine.Matchers.prototype.wasNotCalled = jasmine.Matchers.matcherFn_('wasNotCal 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; - }, - message: function() { - return "Expected spy " + this.actual.identity + " to not have been called."; } }); @@ -218,10 +220,11 @@ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.matcherFn_('wasCalle 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)); - }, - message: function() { - return "Expected spy to have been called with " + jasmine.pp(arguments) + " but was called with " + this.actual.argsForCall; } }); @@ -291,15 +294,17 @@ jasmine.Matchers.prototype.toThrow = jasmine.Matchers.matcherFn_('toThrow', { if (exception) { result = (expected === undefined || this.env.equals_(exception.message || exception, expected.message || expected)); } + + this.message = function(expected) { + var exception = this.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; - }, - message: function(expected) { - var exception = this.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."; - } } }); From 1a53838d978d9bd78dff2c35fe6dd6f8b73aab05 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Fri, 13 Nov 2009 14:32:08 -0500 Subject: [PATCH 12/12] Wrap base matchers from jasmine.Matcher prototype automatically at env instantiation time rather than manually. --- spec/suites/MatchersSpec.js | 6 +- src/Env.js | 13 +- src/Matchers.js | 251 +++++++++++++++--------------------- src/Spec.js | 4 +- 4 files changed, 121 insertions(+), 153 deletions(-) diff --git a/spec/suites/MatchersSpec.js b/spec/suites/MatchersSpec.js index b716994..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() { @@ -435,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); 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 123b91c..74a63ec 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -24,11 +24,10 @@ 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 result = options.test.apply(this, arguments); + var result = matcherFunction.apply(this, arguments); var message; if (!result) { if (this.message) { @@ -65,21 +64,17 @@ jasmine.Matchers.matcherFn_ = function(matcherName, options) { * @param expected */ -jasmine.Matchers.prototype.toBe = jasmine.Matchers.matcherFn_('toBe', { - test: function(expected) { - return this.actual === 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(expected) { - return this.actual !== 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. @@ -87,21 +82,17 @@ jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { * @param expected */ -jasmine.Matchers.prototype.toEqual = jasmine.Matchers.matcherFn_('toEqual', { - test: function(expected) { - return this.env.equals_(this.actual, 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(expected) { - return !this.env.equals_(this.actual, 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 @@ -109,124 +100,91 @@ jasmine.Matchers.prototype.toNotEqual = jasmine.Matchers.matcherFn_('toNotEqual' * * @param reg_exp */ -jasmine.Matchers.prototype.toMatch = jasmine.Matchers.matcherFn_('toMatch', { - test: function(expected) { - return new RegExp(expected).test(this.actual); - } -}); +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(expected) { - return !(new RegExp(expected).test(this.actual)); - } -}); +jasmine.Matchers.prototype.toNotMatch = function(expected) { + return !(new RegExp(expected).test(this.actual)); +}; /** * Matcher that compares the actual to undefined. */ -jasmine.Matchers.prototype.toBeDefined = jasmine.Matchers.matcherFn_('toBeDefined', { - test: function() { - return (this.actual !== undefined); - } -}); +jasmine.Matchers.prototype.toBeDefined = function() { + return (this.actual !== undefined); +}; /** * Matcher that compares the actual to undefined. */ -jasmine.Matchers.prototype.toBeUndefined = jasmine.Matchers.matcherFn_('toBeUndefined', { - test: function() { - return (this.actual === 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() { - return (this.actual === 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() { - return !!this.actual; - } -}); +jasmine.Matchers.prototype.toBeTruthy = function() { + return !!this.actual; +}; /** * Matcher that boolean nots the actual. */ -jasmine.Matchers.prototype.toBeFalsy = jasmine.Matchers.matcherFn_('toBeFalsy', { - test: function() { - return !this.actual; - } -}); +jasmine.Matchers.prototype.toBeFalsy = function() { + return !this.actual; +}; /** * Matcher that checks to see if the actual, a Jasmine spy, was called. */ - -jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.matcherFn_('wasCalled', { - test: 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; +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 actual, a Jasmine spy, was not called. */ -jasmine.Matchers.prototype.wasNotCalled = jasmine.Matchers.matcherFn_('wasNotCalled', { - test: function() { - if (arguments.length > 0) { - throw new Error('wasNotCalled does not take arguments'); - } - - 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; +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() { - 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)); + 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 actual, a Jasmine spy, was called with a set of parameters. @@ -234,49 +192,51 @@ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.matcherFn_('wasCalle * @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(expected) { - return this.env.contains_(this.actual, 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(expected) { - return !this.env.contains_(this.actual, expected); - } -}); +jasmine.Matchers.prototype.toNotContain = function(expected) { + return !this.env.contains_(this.actual, expected); +}; -jasmine.Matchers.prototype.toBeLessThan = jasmine.Matchers.matcherFn_('toBeLessThan', { - test: function(expected) { - return this.actual < expected; - } -}); +jasmine.Matchers.prototype.toBeLessThan = function(expected) { + return this.actual < expected; +}; -jasmine.Matchers.prototype.toBeGreaterThan = jasmine.Matchers.matcherFn_('toBeGreaterThan', { - test: function(expected) { - return this.actual > 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'); @@ -287,26 +247,25 @@ jasmine.Matchers.prototype.toThrow = jasmine.Matchers.matcherFn_('toThrow', { exception = e; } return exception; - }, - test: function(expected) { - var result = false; - var exception = this.getException_(this.actual, expected); - if (exception) { - result = (expected === undefined || this.env.equals_(exception.message || exception, expected.message || expected)); - } - - this.message = function(expected) { - var exception = this.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; } -}); + + 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/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) {