From 9f247eb278fe1e6ef2194f2da23e35e01a625386 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Thu, 24 Dec 2009 12:15:18 -0500 Subject: [PATCH] Custom matchers may now work like regular matchers -- just return a boolean, don't call this.report(). The old style still works but is deprecated. --- spec/suites/CustomMatchersSpec.js | 75 ++++++++++++++++++++++++++++++- src/Env.js | 5 +-- src/Matchers.js | 15 +++++++ src/Spec.js | 4 +- 4 files changed, 90 insertions(+), 9 deletions(-) diff --git a/spec/suites/CustomMatchersSpec.js b/spec/suites/CustomMatchersSpec.js index 51af930..a1d2496 100644 --- a/spec/suites/CustomMatchersSpec.js +++ b/spec/suites/CustomMatchersSpec.js @@ -9,7 +9,6 @@ describe("Custom Matchers", function() { it("should be easy to add more matchers local to a spec, suite, etc.", function() { var spec1, spec2, spec1Matcher, spec2Matcher; - var suite = env.describe('some suite', function() { env.beforeEach(function() { this.addMatchers({ matcherForSuite: function(expected) { @@ -37,5 +36,77 @@ describe("Custom Matchers", function() { expect(spec2Matcher.matcherForSuite("expected")).toEqual("matcherForSuite: actual: yyy; expected: expected"); expect(spec2Matcher.matcherForSpec).toBe(jasmine.undefined); }); - + + it("should generate messages with the same rules as for regular matchers when this.report() is not called", function() { + var spec; + var suite = env.describe('some suite', function() { + spec = env.it('spec with an expectation').runs(function () { + this.addMatchers({ + toBeTrue: function() { + return this.actual === true; + } + }); + this.expect(true).toBeTrue(); + this.expect(false).toBeTrue(); + }); + }); + + suite.execute(); + var passResult = new jasmine.ExpectationResult({passed: true, matcherName: 'toBeTrue', + actual: true, expected: jasmine.undefined, message: "Passed." }); + var failResult = new jasmine.ExpectationResult({passed: false, matcherName: 'toBeTrue', + actual: false, expected: jasmine.undefined, message: "Expected false to be true." }); + failResult.trace = jasmine.any(Object); + expect(spec.results().getItems()).toEqual([passResult, failResult]); + }); + + it("should pass args", function() { + var matcherCallArgs = []; + var spec; + var suite = env.describe('some suite', function() { + spec = env.it('spec with an expectation').runs(function () { + this.addMatchers({ + toBeTrue: function() { + matcherCallArgs.push(jasmine.util.argsToArray(arguments)); + return this.actual === true; + } + }); + this.expect(true).toBeTrue(); + this.expect(false).toBeTrue('arg'); + this.expect(true).toBeTrue('arg1', 'arg2'); + }); + }); + + suite.execute(); + var results = spec.results().getItems(); + expect(results[0].expected).toEqual(jasmine.undefined); + expect(results[1].expected).toEqual('arg'); + expect(results[2].expected).toEqual(['arg1', 'arg2']); + + expect(matcherCallArgs).toEqual([[], ['arg'], ['arg1', 'arg2']]); + }); + + describe("in the old style", function() { + it("should report deprecation a warning", function() { + var spec; + var suite = env.describe('some suite', function() { + spec = env.it('spec with an expectation').runs(function () { + this.addMatchers({ + toBeTrue: function() { + this.report(this.actual === true, this.actual + " was not true.", "details"); + } + }); + this.expect(true).toBeTrue(); + this.expect(false).toBeTrue(); + }); + }); + + suite.execute(); + var passResult = new jasmine.ExpectationResult({passed: true, message: "Passed.", details: "details"}); + var failResult = new jasmine.ExpectationResult({passed: false, message: "false was not true.", details: "details"}); + failResult.trace = jasmine.any(Object); + expect(spec.results().getItems()).toEqual([passResult, failResult]); + }); + }); + }); \ No newline at end of file diff --git a/src/Env.js b/src/Env.js index 142ddfb..5d288b3 100644 --- a/src/Env.js +++ b/src/Env.js @@ -26,10 +26,7 @@ jasmine.Env = function() { }; 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); - } + jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); }; diff --git a/src/Matchers.js b/src/Matchers.js index 79f5d53..e4ee8c8 100644 --- a/src/Matchers.js +++ b/src/Matchers.js @@ -8,13 +8,18 @@ jasmine.Matchers = function(env, actual, spec) { this.env = env; this.actual = actual; this.spec = spec; + this.reportWasCalled_ = false; }; jasmine.Matchers.pp = function(str) { return jasmine.util.htmlEscape(jasmine.pp(str)); }; +/** @deprecated */ jasmine.Matchers.prototype.report = function(result, failing_message, details) { +// todo first: report deprecation warning [xw] +// todo later: throw new Error("As of jasmine 0.xx, custom matchers must be implemented differently -- please see jasmine docs"); + this.reportWasCalled_ = true; var expectationResult = new jasmine.ExpectationResult({ passed: result, message: failing_message, @@ -24,10 +29,20 @@ jasmine.Matchers.prototype.report = function(result, failing_message, details) { return result; }; +jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { + for (var methodName in prototype) { + if (methodName == 'report') continue; + var orig = prototype[methodName]; + matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); + } +}; + jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { return function() { var matcherArgs = jasmine.util.argsToArray(arguments); var result = matcherFunction.apply(this, arguments); + if (this.reportWasCalled_) return result; + var message; if (!result) { if (this.message) { diff --git a/src/Spec.js b/src/Spec.js index fa6ddd4..14179c4 100644 --- a/src/Spec.js +++ b/src/Spec.js @@ -98,9 +98,7 @@ jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { parent.apply(this, arguments); }; jasmine.util.inherit(newMatchersClass, parent); - for (var method in matchersPrototype) { - newMatchersClass.prototype[method] = matchersPrototype[method]; - } + jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); this.matchersClass = newMatchersClass; };