diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 6fa00567139a..4e16d15550a6 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -1636,8 +1636,8 @@ describe('angular', function() { expect(function() { angularInit(appElement, angular.bootstrap); - }).toThrowError( - new RegExp('\\[\\$injector:modulerr] Failed to instantiate module doesntexist due to:\\n' + + }).toThrowMinErr('$injector', 'modulerr', + new RegExp('Failed to instantiate module doesntexist due to:\\n' + '.*\\[\\$injector:nomod] Module \'doesntexist\' is not available! You either ' + 'misspelled the module name or forgot to load it\\.') ); @@ -1650,9 +1650,8 @@ describe('angular', function() { expect(function() { angular.bootstrap(element); - }).toThrowError( - /\[ng:btstrpd\] App Already Bootstrapped with this Element '<div class="?ng\-scope"?( ng[0-9]+="?[0-9]+"?)?>'/i - ); + }).toThrowMinErr('ng', 'btstrpd', + /App Already Bootstrapped with this Element '<div class="?ng-scope"?( ng\d+="?\d+"?)?>'/i); dealoc(element); }); @@ -1662,9 +1661,7 @@ describe('angular', function() { angular.bootstrap(document.getElementsByTagName('html')[0]); expect(function() { angular.bootstrap(document); - }).toThrowError( - /\[ng:btstrpd\] App Already Bootstrapped with this Element 'document'/i - ); + }).toThrowMinErr('ng', 'btstrpd', /App Already Bootstrapped with this Element 'document'/i); dealoc(document); }); @@ -1863,8 +1860,8 @@ describe('angular', function() { expect(function() { angular.bootstrap(element, ['doesntexist']); - }).toThrowError( - new RegExp('\\[\\$injector:modulerr\\] Failed to instantiate module doesntexist due to:\\n' + + }).toThrowMinErr('$injector', 'modulerr', + new RegExp('Failed to instantiate module doesntexist due to:\\n' + '.*\\[\\$injector:nomod\\] Module \'doesntexist\' is not available! You either ' + 'misspelled the module name or forgot to load it\\.')); diff --git a/test/auto/injectorSpec.js b/test/auto/injectorSpec.js index 2e93498bb819..807a47847293 100644 --- a/test/auto/injectorSpec.js +++ b/test/auto/injectorSpec.js @@ -1062,7 +1062,7 @@ describe('injector', function() { createInjector([function($provide) { $provide.value('name', 'angular'); }, instanceLookupInModule]); - }).toThrowError(/\[\$injector:unpr] Unknown provider: name/); + }).toThrowMinErr('$injector', 'modulerr', '[$injector:unpr] Unknown provider: name'); }); }); }); diff --git a/test/helpers/matchers.js b/test/helpers/matchers.js index 9161e612c0ee..5a21ec52756d 100644 --- a/test/helpers/matchers.js +++ b/test/helpers/matchers.js @@ -49,6 +49,41 @@ beforeEach(function() { return hidden; } + function MinErrMatcher(isNot, namespace, code, content, wording) { + var codeRegex = new RegExp('^' + escapeRegexp('[' + namespace + ':' + code + ']')); + var contentRegex = angular.isUndefined(content) || jasmine.isA_('RegExp', content) ? + content : new RegExp(escapeRegexp(content)); + + this.test = test; + + function escapeRegexp(str) { + // This function escapes all special regex characters. + // We use it to create matching regex from arbitrary strings. + // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); + } + + function test(exception) { + var exceptionMessage = (exception && exception.message) || exception || ''; + + var codeMatches = codeRegex.test(exceptionMessage); + var contentMatches = angular.isUndefined(contentRegex) || contentRegex.test(exceptionMessage); + var matches = codeMatches && contentMatches; + + return { + pass: isNot ? !matches : matches, + message: message + }; + + function message() { + return 'Expected ' + wording.inputType + (isNot ? ' not' : '') + ' to ' + + wording.expectedAction + ' ' + namespace + 'MinErr(\'' + code + '\')' + + (contentRegex ? ' matching ' + contentRegex.toString() : '') + + (!exception ? '.' : ', but it ' + wording.actualAction + ': ' + exceptionMessage); + } + } + } + jasmine.addMatchers({ toBeEmpty: cssMatcher('ng-empty', 'ng-not-empty'), toBeNotEmpty: cssMatcher('ng-not-empty', 'ng-empty'), @@ -58,6 +93,7 @@ beforeEach(function() { toBePristine: cssMatcher('ng-pristine', 'ng-dirty'), toBeUntouched: cssMatcher('ng-untouched', 'ng-touched'), toBeTouched: cssMatcher('ng-touched', 'ng-untouched'), + toBeAPromise: function() { return { compare: generateCompare(false), @@ -71,6 +107,7 @@ beforeEach(function() { }; } }, + toBeShown: function() { return { compare: generateCompare(false), @@ -87,6 +124,7 @@ beforeEach(function() { }; } }, + toBeHidden: function() { return { compare: generateCompare(false), @@ -267,26 +305,34 @@ beforeEach(function() { } }, + toEqualMinErr: function() { + return { + compare: generateCompare(false), + negativeCompare: generateCompare(true) + }; + + function generateCompare(isNot) { + return function(actual, namespace, code, content) { + var matcher = new MinErrMatcher(isNot, namespace, code, content, { + inputType: 'error', + expectedAction: 'equal', + actualAction: 'was' + }); + + return matcher.test(actual); + }; + } + }, + toThrowMinErr: function() { return { compare: generateCompare(false), negativeCompare: generateCompare(true) }; + function generateCompare(isNot) { return function(actual, namespace, code, content) { - var result, - exception, - exceptionMessage = '', - escapeRegexp = function(str) { - // This function escapes all special regex characters. - // We use it to create matching regex from arbitrary strings. - // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); - }, - codeRegex = new RegExp('^\\[' + escapeRegexp(namespace) + ':' + escapeRegexp(code) + '\\]'), - not = isNot ? 'not ' : '', - regex = jasmine.isA_('RegExp', content) ? content : - angular.isDefined(content) ? new RegExp(escapeRegexp(content)) : undefined; + var exception; if (!angular.isFunction(actual)) { throw new Error('Actual is not a function'); @@ -298,41 +344,17 @@ beforeEach(function() { exception = e; } - if (exception) { - exceptionMessage = exception.message || exception; - } - - var message = function() { - return 'Expected function ' + not + 'to throw ' + - namespace + 'MinErr(\'' + code + '\')' + - (regex ? ' matching ' + regex.toString() : '') + - (exception ? ', but it threw ' + exceptionMessage : '.'); - }; - - result = codeRegex.test(exceptionMessage); - if (!result) { - if (isNot) { - return { pass: !result, message: message }; - } else { - return { pass: result, message: message }; - } - } + var matcher = new MinErrMatcher(isNot, namespace, code, content, { + inputType: 'function', + expectedAction: 'throw', + actualAction: 'threw' + }); - if (angular.isDefined(regex)) { - if (isNot) { - return { pass: !regex.test(exceptionMessage), message: message }; - } else { - return { pass: regex.test(exceptionMessage), message: message }; - } - } - if (isNot) { - return { pass: !result, message: message }; - } else { - return { pass: result, message: message }; - } + return matcher.test(exception); }; } }, + toBeMarkedAsSelected: function() { // Selected is special because the element property and attribute reflect each other's state. // IE9 will wrongly report hasAttribute('selected') === true when the property is diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index b00703c9bc04..502cfe67c5fa 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1712,7 +1712,7 @@ describe('jqLite', function() { aElem.on('click', noop); expect(function() { aElem.off('click', noop, '.test'); - }).toThrowError(/\[jqLite:offargs\]/); + }).toThrowMinErr('jqLite', 'offargs'); }); }); diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 45a7147b4e77..1786d3cd603b 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -1862,8 +1862,8 @@ describe('$compile', function() { $httpBackend.flush(); expect(sortedHtml(element)).toBe('