diff --git a/spec/core/matchers/toThrowErrorSpec.js b/spec/core/matchers/toThrowErrorSpec.js index 8dc88dbd..1c0faee1 100644 --- a/spec/core/matchers/toThrowErrorSpec.js +++ b/spec/core/matchers/toThrowErrorSpec.js @@ -155,7 +155,7 @@ describe("toThrowError", function() { result = matcher.compare(fn, Error); expect(result.pass).toBe(true); - expect(result.message).toEqual("Expected function not to throw Error."); + expect(result.message()).toEqual("Expected function not to throw Error."); }); it("passes if thrown is a custom error that takes arguments and the expected is the same error", function() { @@ -175,7 +175,7 @@ describe("toThrowError", function() { result = matcher.compare(fn, CustomError); expect(result.pass).toBe(true); - expect(result.message).toEqual("Expected function not to throw CustomError."); + expect(result.message()).toEqual("Expected function not to throw CustomError."); }); it("fails if thrown is an Error and the expected is a different Error", function() { @@ -191,7 +191,7 @@ describe("toThrowError", function() { result = matcher.compare(fn, TypeError); expect(result.pass).toBe(false); - expect(result.message).toEqual("Expected function to throw TypeError, but it threw Error."); + expect(result.message()).toEqual("Expected function to throw TypeError, but it threw Error."); }); it("passes if thrown is a type of Error and it is equal to the expected Error and message", function() { @@ -259,7 +259,7 @@ describe("toThrowError", function() { result = matcher.compare(fn, TypeError, /foo/); expect(result.pass).toBe(true); - expect(result.message()).toEqual("Expected function not to throw TypeError with message matching /foo/."); + expect(result.message()).toEqual("Expected function not to throw TypeError with a message matching /foo/."); }); it("fails if thrown is a type of Error and the expected is a different Error", function() { @@ -275,6 +275,6 @@ describe("toThrowError", function() { result = matcher.compare(fn, TypeError, /bar/); expect(result.pass).toBe(false); - expect(result.message()).toEqual("Expected function to throw TypeError with message matching /bar/, but it threw TypeError with message 'foo'."); + expect(result.message()).toEqual("Expected function to throw TypeError with a message matching /bar/, but it threw TypeError with message 'foo'."); }); }); diff --git a/src/core/matchers/toThrowError.js b/src/core/matchers/toThrowError.js index e8f220d2..29519142 100644 --- a/src/core/matchers/toThrowError.js +++ b/src/core/matchers/toThrowError.js @@ -5,18 +5,13 @@ getJasmineRequireObj().toThrowError = function(j$) { var threw = false, pass = {pass: true}, fail = {pass: false}, - thrown, - errorType, - message, - regexp, - name, - constructorName; + thrown; if (typeof actual != 'function') { throw new Error('Actual is not a Function'); } - extractExpectedParams.apply(null, arguments); + var errorMatcher = getMatcher.apply(null, arguments); try { actual(); @@ -35,121 +30,108 @@ getJasmineRequireObj().toThrowError = function(j$) { return fail; } - if (arguments.length == 1) { + if (errorMatcher.hasNoSpecifics()) { pass.message = 'Expected function not to throw an Error, but it threw ' + fnNameFor(thrown) + '.'; return pass; } - if (errorType) { - name = fnNameFor(errorType); - constructorName = fnNameFor(thrown.constructor); - } - - if (errorType && message) { - if (thrown.constructor == errorType && util.equals(thrown.message, message)) { - pass.message = function() { return 'Expected function not to throw ' + name + ' with message ' + j$.pp(message) + '.'; }; - return pass; - } else { - fail.message = function() { return 'Expected function to throw ' + name + ' with message ' + j$.pp(message) + - ', but it threw ' + constructorName + ' with message ' + j$.pp(thrown.message) + '.'; }; - return fail; - } - } - - if (errorType && regexp) { - if (thrown.constructor == errorType && regexp.test(thrown.message)) { - pass.message = function() { return 'Expected function not to throw ' + name + ' with message matching ' + j$.pp(regexp) + '.'; }; - return pass; - } else { - fail.message = function() { return 'Expected function to throw ' + name + ' with message matching ' + j$.pp(regexp) + - ', but it threw ' + constructorName + ' with message ' + j$.pp(thrown.message) + '.'; }; - return fail; - } - } - - if (errorType) { - if (thrown.constructor == errorType) { - pass.message = 'Expected function not to throw ' + name + '.'; - return pass; - } else { - fail.message = 'Expected function to throw ' + name + ', but it threw ' + constructorName + '.'; - return fail; - } - } - - if (message) { - if (thrown.message == message) { - pass.message = function() { return 'Expected function not to throw an exception with message ' + j$.pp(message) + '.'; }; - return pass; - } else { - fail.message = function() { return 'Expected function to throw an exception with message ' + j$.pp(message) + - ', but it threw an exception with message ' + j$.pp(thrown.message) + '.'; }; - return fail; - } - } - - if (regexp) { - if (regexp.test(thrown.message)) { - pass.message = function() { return 'Expected function not to throw an exception with a message matching ' + j$.pp(regexp) + '.'; }; - return pass; - } else { - fail.message = function() { return 'Expected function to throw an exception with a message matching ' + j$.pp(regexp) + - ', but it threw an exception with message ' + j$.pp(thrown.message) + '.'; }; - return fail; - } - } - - function fnNameFor(func) { - return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1]; - } - - function extractExpectedParams() { - if (arguments.length == 1) { - return; - } - - if (arguments.length == 2) { - var expected = arguments[1]; - - if (expected instanceof RegExp) { - regexp = expected; - } else if (typeof expected == 'string') { - message = expected; - } else if (checkForAnErrorType(expected)) { - errorType = expected; - } - - if (!(errorType || message || regexp)) { - throw new Error('Expected is not an Error, string, or RegExp.'); - } - } else { - if (checkForAnErrorType(arguments[1])) { - errorType = arguments[1]; - } else { - throw new Error('Expected error type is not an Error.'); - } - - if (arguments[2] instanceof RegExp) { - regexp = arguments[2]; - } else if (typeof arguments[2] == 'string') { - message = arguments[2]; - } else { - throw new Error('Expected error message is not a string or RegExp.'); - } - } - } - - function checkForAnErrorType(type) { - if (typeof type !== 'function') { - return false; - } - - var Surrogate = function() {}; - Surrogate.prototype = type.prototype; - return (new Surrogate()) instanceof Error; + if (errorMatcher.matches(thrown)) { + pass.message = function() { + return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.'; + }; + return pass; + } else { + fail.message = function() { + return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + + ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.'; + }; + return fail; } } }; + + function getMatcher() { + var expected = null, + errorType = null; + + if (arguments.length == 2) { + expected = arguments[1]; + if (isAnErrorType(expected)) { + errorType = expected; + expected = null; + } + } else if (arguments.length > 2) { + errorType = arguments[1]; + expected = arguments[2]; + if (!isAnErrorType(errorType)) { + throw new Error('Expected error type is not an Error.'); + } + } + + if (expected && !isStringOrRegExp(expected)) { + if (errorType) { + throw new Error('Expected error message is not a string or RegExp.'); + } else { + throw new Error('Expected is not an Error, string, or RegExp.'); + } + } + + function messageMatch(message) { + if (typeof expected == 'string') { + return expected == message; + } else { + return expected.test(message); + } + } + + return { + errorTypeDescription: errorType ? fnNameFor(errorType) : 'an exception', + thrownDescription: function(thrown) { + var thrownName = errorType ? fnNameFor(thrown.constructor) : 'an exception', + thrownMessage = ''; + + if (expected) { + thrownMessage = ' with message ' + j$.pp(thrown.message); + } + + return thrownName + thrownMessage; + }, + messageDescription: function() { + if (expected === null) { + return ''; + } else if (expected instanceof RegExp) { + return ' with a message matching ' + j$.pp(expected); + } else { + return ' with message ' + j$.pp(expected); + } + }, + hasNoSpecifics: function() { + return expected === null && errorType === null; + }, + matches: function(error) { + return (errorType === null || error.constructor === errorType) && + (expected === null || messageMatch(error.message)); + } + }; + } + + function fnNameFor(func) { + return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1]; + } + + function isStringOrRegExp(potential) { + return potential instanceof RegExp || (typeof potential == 'string'); + } + + function isAnErrorType(type) { + if (typeof type !== 'function') { + return false; + } + + var Surrogate = function() {}; + Surrogate.prototype = type.prototype; + return (new Surrogate()) instanceof Error; + } } return toThrowError;