From 1d06a943857719ef533ca374c05aa5e02089a4d9 Mon Sep 17 00:00:00 2001
From: Igor Minar
Date: Fri, 23 Aug 2013 15:41:47 -0700
Subject: chore: reorganize test helper files under test/helpers
---
angularFiles.js | 7 +-
src/privateMocks.js | 28 ----
test/helpers/matchers.js | 266 +++++++++++++++++++++++++++++++++++
test/helpers/privateMocks.js | 28 ++++
test/helpers/privateMocksSpec.js | 36 +++++
test/helpers/testabilityPatch.js | 297 +++++++++++++++++++++++++++++++++++++++
test/matchers.js | 266 -----------------------------------
test/privateMocksSpec.js | 36 -----
test/testabilityPatch.js | 297 ---------------------------------------
9 files changed, 629 insertions(+), 632 deletions(-)
delete mode 100644 src/privateMocks.js
create mode 100644 test/helpers/matchers.js
create mode 100644 test/helpers/privateMocks.js
create mode 100644 test/helpers/privateMocksSpec.js
create mode 100644 test/helpers/testabilityPatch.js
delete mode 100644 test/matchers.js
delete mode 100644 test/privateMocksSpec.js
delete mode 100644 test/testabilityPatch.js
diff --git a/angularFiles.js b/angularFiles.js
index a20dc21a..cd23aca0 100755
--- a/angularFiles.js
+++ b/angularFiles.js
@@ -80,7 +80,6 @@ angularFiles = {
'src/ngTouch/directive/ngClick.js',
'src/ngTouch/directive/ngSwipe.js',
'docs/components/angular-bootstrap/bootstrap.js',
- 'src/privateMocks.js'
],
'angularScenario': [
@@ -101,8 +100,7 @@ angularFiles = {
],
'angularTest': [
- 'test/testabilityPatch.js',
- 'test/matchers.js',
+ 'test/helpers/*.js',
'test/ngScenario/*.js',
'test/ngScenario/output/*.js',
'test/*.js',
@@ -144,8 +142,7 @@ angularFiles = {
'build/angular.js',
'@angularSrcModules',
'src/ngScenario/browserTrigger.js',
- 'test/matchers.js',
- 'test/testabilityPatch.js',
+ 'test/helpers/*.js',
'test/ngMock/*.js',
'test/ngCookies/*.js',
'test/ngRoute/**/*.js',
diff --git a/src/privateMocks.js b/src/privateMocks.js
deleted file mode 100644
index 6d9fb34f..00000000
--- a/src/privateMocks.js
+++ /dev/null
@@ -1,28 +0,0 @@
-function createMockStyleSheet(doc, wind) {
- doc = doc ? doc[0] : document;
- wind = wind || window;
-
- var node = doc.createElement('style');
- var head = doc.getElementsByTagName('head')[0];
- head.appendChild(node);
-
- var ss = doc.styleSheets[doc.styleSheets.length - 1];
-
- return {
- addRule : function(selector, styles) {
- try {
- ss.insertRule(selector + '{ ' + styles + '}', 0);
- }
- catch(e) {
- try {
- ss.addRule(selector, styles);
- }
- catch(e) {}
- }
- },
-
- destroy : function() {
- head.removeChild(node);
- }
- };
-};
diff --git a/test/helpers/matchers.js b/test/helpers/matchers.js
new file mode 100644
index 00000000..57bf35c7
--- /dev/null
+++ b/test/helpers/matchers.js
@@ -0,0 +1,266 @@
+beforeEach(function() {
+
+ function cssMatcher(presentClasses, absentClasses) {
+ return function() {
+ var element = angular.element(this.actual);
+ var present = true;
+ var absent = false;
+
+ angular.forEach(presentClasses.split(' '), function(className){
+ present = present && element.hasClass(className);
+ });
+
+ angular.forEach(absentClasses.split(' '), function(className){
+ absent = absent || element.hasClass(className);
+ });
+
+ this.message = function() {
+ return "Expected to have " + presentClasses +
+ (absentClasses ? (" and not have " + absentClasses + "" ) : "") +
+ " but had " + element[0].className + ".";
+ };
+ return present && !absent;
+ };
+ }
+
+ function indexOf(array, obj) {
+ for ( var i = 0; i < array.length; i++) {
+ if (obj === array[i]) return i;
+ }
+ return -1;
+ }
+
+ function isNgElementHidden(element) {
+ return angular.element(element).hasClass('ng-hide');
+ };
+
+ this.addMatchers({
+ toBeInvalid: cssMatcher('ng-invalid', 'ng-valid'),
+ toBeValid: cssMatcher('ng-valid', 'ng-invalid'),
+ toBeDirty: cssMatcher('ng-dirty', 'ng-pristine'),
+ toBePristine: cssMatcher('ng-pristine', 'ng-dirty'),
+ toBeShown: function() {
+ this.message = valueFn(
+ "Expected element " + (this.isNot ? "": "not ") + "to have 'ng-hide' class");
+ return !isNgElementHidden(this.actual);
+ },
+ toBeHidden: function() {
+ this.message = valueFn(
+ "Expected element " + (this.isNot ? "not ": "") + "to have 'ng-hide' class");
+ return isNgElementHidden(this.actual);
+ },
+
+ toEqual: function(expected) {
+ if (this.actual && this.actual.$$log) {
+ this.actual = (typeof expected === 'string')
+ ? this.actual.toString()
+ : this.actual.toArray();
+ }
+ return jasmine.Matchers.prototype.toEqual.call(this, expected);
+ },
+
+ toEqualData: function(expected) {
+ return angular.equals(this.actual, expected);
+ },
+
+ toEqualError: function(message) {
+ this.message = function() {
+ var expected;
+ if (this.actual.message && this.actual.name == 'Error') {
+ expected = toJson(this.actual.message);
+ } else {
+ expected = toJson(this.actual);
+ }
+ return "Expected " + expected + " to be an Error with message " + toJson(message);
+ };
+ return this.actual.name == 'Error' && this.actual.message == message;
+ },
+
+ toMatchError: function(messageRegexp) {
+ this.message = function() {
+ var expected;
+ if (this.actual.message && this.actual.name == 'Error') {
+ expected = angular.toJson(this.actual.message);
+ } else {
+ expected = angular.toJson(this.actual);
+ }
+ return "Expected " + expected + " to match an Error with message " + angular.toJson(messageRegexp);
+ };
+ return this.actual.name == 'Error' && messageRegexp.test(this.actual.message);
+ },
+
+ toHaveBeenCalledOnce: function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalledOnce does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ var msg = 'Expected spy ' + this.actual.identity + ' to have been called once, but was ',
+ count = this.actual.callCount;
+ return [
+ count === 0 ? msg + 'never called.' :
+ msg + 'called ' + count + ' times.',
+ msg.replace('to have', 'not to have') + 'called once.'
+ ];
+ };
+
+ return this.actual.callCount == 1;
+ },
+
+
+ toHaveBeenCalledOnceWith: function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ if (this.actual.callCount != 1) {
+ if (this.actual.callCount == 0) {
+ return [
+ 'Expected spy ' + this.actual.identity + ' to have been called once with ' +
+ jasmine.pp(expectedArgs) + ' but it was never called.',
+ 'Expected spy ' + this.actual.identity + ' not to have been called with ' +
+ jasmine.pp(expectedArgs) + ' but it was.'
+ ];
+ }
+
+ return [
+ 'Expected spy ' + this.actual.identity + ' to have been called once with ' +
+ jasmine.pp(expectedArgs) + ' but it was called ' + this.actual.callCount + ' times.',
+ 'Expected spy ' + this.actual.identity + ' not to have been called once with ' +
+ jasmine.pp(expectedArgs) + ' but it was.'
+ ];
+ } else {
+ return [
+ 'Expected spy ' + this.actual.identity + ' to have been called once with ' +
+ jasmine.pp(expectedArgs) + ' but was called with ' + jasmine.pp(this.actual.argsForCall),
+ 'Expected spy ' + this.actual.identity + ' not to have been called once with ' +
+ jasmine.pp(expectedArgs) + ' but was called with ' + jasmine.pp(this.actual.argsForCall)
+ ];
+ }
+ };
+
+ return this.actual.callCount === 1 && this.env.contains_(this.actual.argsForCall, expectedArgs);
+ },
+
+
+ toBeOneOf: function() {
+ return indexOf(arguments, this.actual) !== -1;
+ },
+
+ toHaveClass: function(clazz) {
+ this.message = function() {
+ return "Expected '" + angular.mock.dump(this.actual) + "' to have class '" + clazz + "'.";
+ };
+ return this.actual.hasClass ?
+ this.actual.hasClass(clazz) :
+ angular.element(this.actual).hasClass(clazz);
+ },
+
+ toThrowMatching: function(expected) {
+ return jasmine.Matchers.prototype.toThrow.call(this, expected);
+ },
+
+ toThrowMinErr: function(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 = this.isNot ? "not " : "",
+ regex = jasmine.isA_("RegExp", content) ? content :
+ isDefined(content) ? new RegExp(escapeRegexp(content)) : undefined;
+
+ if(!isFunction(this.actual)) {
+ throw new Error('Actual is not a function');
+ }
+
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception) {
+ exceptionMessage = exception.message || exception;
+ }
+
+ this.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) {
+ return result;
+ }
+
+ if (isDefined(regex)) {
+ return regex.test(exceptionMessage);
+ }
+ return result;
+ }
+ });
+});
+
+
+// TODO(vojta): remove this once Jasmine in Karma gets updated
+// https://github.com/pivotal/jasmine/blob/c40b64a24c607596fa7488f2a0ddb98d063c872a/src/core/Matchers.js#L217-L246
+// This toThrow supports RegExps.
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception, exceptionMessage;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception) {
+ exceptionMessage = exception.message || exception;
+ result = (isUndefined(expected) || this.env.equals_(exceptionMessage, expected.message || expected) || (jasmine.isA_("RegExp", expected) && expected.test(exceptionMessage)));
+ }
+
+ var not = this.isNot ? "not " : "";
+ var regexMatch = jasmine.isA_("RegExp", expected) ? " an exception matching" : "";
+
+ this.message = function() {
+ if (exception) {
+ return ["Expected function " + not + "to throw" + regexMatch, expected ? expected.message || expected : "an exception", ", but it threw", exceptionMessage].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+
+/**
+ * Create jasmine.Spy on given method, but ignore calls without arguments
+ * This is helpful when need to spy only setter methods and ignore getters
+ */
+function spyOnlyCallsWithArgs(obj, method) {
+ var spy = spyOn(obj, method);
+ obj[method] = function() {
+ if (arguments.length) return spy.apply(this, arguments);
+ return spy.originalValue.apply(this);
+ };
+ return spy;
+}
diff --git a/test/helpers/privateMocks.js b/test/helpers/privateMocks.js
new file mode 100644
index 00000000..6d9fb34f
--- /dev/null
+++ b/test/helpers/privateMocks.js
@@ -0,0 +1,28 @@
+function createMockStyleSheet(doc, wind) {
+ doc = doc ? doc[0] : document;
+ wind = wind || window;
+
+ var node = doc.createElement('style');
+ var head = doc.getElementsByTagName('head')[0];
+ head.appendChild(node);
+
+ var ss = doc.styleSheets[doc.styleSheets.length - 1];
+
+ return {
+ addRule : function(selector, styles) {
+ try {
+ ss.insertRule(selector + '{ ' + styles + '}', 0);
+ }
+ catch(e) {
+ try {
+ ss.addRule(selector, styles);
+ }
+ catch(e) {}
+ }
+ },
+
+ destroy : function() {
+ head.removeChild(node);
+ }
+ };
+};
diff --git a/test/helpers/privateMocksSpec.js b/test/helpers/privateMocksSpec.js
new file mode 100644
index 00000000..e58a2b75
--- /dev/null
+++ b/test/helpers/privateMocksSpec.js
@@ -0,0 +1,36 @@
+describe('private mocks', function() {
+ describe('createMockStyleSheet', function() {
+
+ it('should allow custom styles to be created and removed when the stylesheet is destroyed',
+ inject(function($compile, $document, $window, $rootElement, $rootScope) {
+
+ var doc = $document[0];
+ var count = doc.styleSheets.length;
+ var stylesheet = createMockStyleSheet($document, $window);
+ expect(doc.styleSheets.length).toBe(count + 1);
+
+ jqLite(doc.body).append($rootElement);
+
+ var elm = $compile('
...
')($rootScope);
+ $rootElement.append(elm);
+
+ expect(getStyle(elm, 'paddingTop')).toBe('0px');
+
+ stylesheet.addRule('.padded', 'padding-top:2px');
+
+ expect(getStyle(elm, 'paddingTop')).toBe('2px');
+
+ stylesheet.destroy();
+
+ expect(getStyle(elm, 'paddingTop')).toBe('0px');
+
+ function getStyle(element, key) {
+ var node = element[0];
+ return node.currentStyle ?
+ node.currentStyle[key] :
+ $window.getComputedStyle(node)[key];
+ };
+ }));
+
+ });
+});
diff --git a/test/helpers/testabilityPatch.js b/test/helpers/testabilityPatch.js
new file mode 100644
index 00000000..514a5fdb
--- /dev/null
+++ b/test/helpers/testabilityPatch.js
@@ -0,0 +1,297 @@
+'use strict';
+
+/**
+ * Here is the problem: http://bugs.jquery.com/ticket/7292
+ * basically jQuery treats change event on some browsers (IE) as a
+ * special event and changes it form 'change' to 'click/keydown' and
+ * few others. This horrible hack removes the special treatment
+ */
+if (window._jQuery) _jQuery.event.special.change = undefined;
+
+if (window.bindJQuery) bindJQuery();
+
+beforeEach(function() {
+ // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
+ if (window.publishExternalAPI) {
+ publishExternalAPI(angular);
+
+ // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
+ // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
+ // correct this, but only if we are not running in jqLite mode
+ if (!_jqLiteMode && _jQuery !== jQuery) {
+ jQuery = _jQuery;
+ }
+
+ // This resets global id counter;
+ uid = ['0', '0', '0'];
+
+ // reset to jQuery or default to us.
+ bindJQuery();
+ }
+
+
+ angular.element(document.body).html('').removeData();
+});
+
+afterEach(function() {
+ if (this.$injector) {
+ var $rootScope = this.$injector.get('$rootScope');
+ var $rootElement = this.$injector.get('$rootElement');
+ var $log = this.$injector.get('$log');
+ // release the injector
+ dealoc($rootScope);
+ dealoc($rootElement);
+
+ // check $log mock
+ $log.assertEmpty && $log.assertEmpty();
+ }
+
+ // complain about uncleared jqCache references
+ var count = 0;
+
+ // This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775
+ //var cache = jqLite.cache;
+ var cache = angular.element.cache;
+
+ forEachSorted(cache, function(expando, key){
+ angular.forEach(expando.data, function(value, key){
+ count ++;
+ if (value && value.$element) {
+ dump('LEAK', key, value.$id, sortedHtml(value.$element));
+ } else {
+ dump('LEAK', key, angular.toJson(value));
+ }
+ });
+ });
+ if (count) {
+ throw new Error('Found jqCache references that were not deallocated! count: ' + count);
+ }
+
+
+ // copied from Angular.js
+ // we need these two methods here so that we can run module tests with wrapped angular.js
+ function sortedKeys(obj) {
+ var keys = [];
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ keys.push(key);
+ }
+ }
+ return keys.sort();
+ }
+
+ function forEachSorted(obj, iterator, context) {
+ var keys = sortedKeys(obj);
+ for ( var i = 0; i < keys.length; i++) {
+ iterator.call(context, obj[keys[i]], keys[i]);
+ }
+ return keys;
+ }
+});
+
+
+function dealoc(obj) {
+ var jqCache = angular.element.cache;
+ if (obj) {
+ if (angular.isElement(obj)) {
+ cleanup(angular.element(obj));
+ } else {
+ for(var key in jqCache) {
+ var value = jqCache[key];
+ if (value.data && value.data.$scope == obj) {
+ delete jqCache[key];
+ }
+ }
+ }
+ }
+
+ function cleanup(element) {
+ element.off().removeData();
+ // Note: We aren't using element.contents() here. Under jQuery, element.contents() can fail
+ // for IFRAME elements. jQuery explicitly uses (element.contentDocument ||
+ // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
+ // to a document.
+ var children = element[0].childNodes || [];
+ for ( var i = 0; i < children.length; i++) {
+ cleanup(angular.element(children[i]));
+ }
+ }
+}
+
+/**
+ * @param {DOMElement} element
+ * @param {boolean=} showNgClass
+ */
+function sortedHtml(element, showNgClass) {
+ var html = "";
+ forEach(jqLite(element), function toString(node) {
+
+ if (node.nodeName == "#text") {
+ html += node.nodeValue.
+ replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
+ replace(//g, '>');
+ } else if (node.nodeName == "#comment") {
+ html += '';
+ } else {
+ html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
+ var attributes = node.attributes || [];
+ var attrs = [];
+ var className = node.className || '';
+ if (!showNgClass) {
+ className = className.replace(/ng-[\w-]+\s*/g, '');
+ }
+ className = trim(className);
+ if (className) {
+ attrs.push(' class="' + className + '"');
+ }
+ for(var i=0; i0 && attributes[i] == attributes[i-1])
+ continue; //IE9 creates dupes. Ignore them!
+
+ var attr = attributes[i];
+ if(attr.name.match(/^ng[\:\-]/) ||
+ (attr.value || attr.value == '') &&
+ attr.value !='null' &&
+ attr.value !='auto' &&
+ attr.value !='false' &&
+ attr.value !='inherit' &&
+ (attr.value !='0' || attr.name =='value') &&
+ attr.name !='loop' &&
+ attr.name !='complete' &&
+ attr.name !='maxLength' &&
+ attr.name !='size' &&
+ attr.name !='class' &&
+ attr.name !='start' &&
+ attr.name !='tabIndex' &&
+ attr.name !='style' &&
+ attr.name.substr(0, 6) != 'jQuery') {
+ // in IE we need to check for all of these.
+ if (/ng-\d+/.exec(attr.name) ||
+ attr.name == 'getElementById' ||
+ // IE7 has `selected` in attributes
+ attr.name == 'selected' ||
+ // IE7 adds `value` attribute to all LI tags
+ (node.nodeName == 'LI' && attr.name == 'value') ||
+ // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
+ (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
+ (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
+ continue;
+ }
+
+ attrs.push(' ' + attr.name + '="' + attr.value + '"');
+ }
+ }
+ attrs.sort();
+ html += attrs.join('');
+ if (node.style) {
+ var style = [];
+ if (node.style.cssText) {
+ forEach(node.style.cssText.split(';'), function(value){
+ value = trim(value);
+ if (value) {
+ style.push(lowercase(value));
+ }
+ });
+ }
+ for(var css in node.style){
+ var value = node.style[css];
+ if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
+ var text = lowercase(css + ': ' + value);
+ if (value != 'false' && indexOf(style, text) == -1) {
+ style.push(text);
+ }
+ }
+ }
+ style.sort();
+ var tmp = style;
+ style = [];
+ forEach(tmp, function(value){
+ if (!value.match(/^max[^\-]/))
+ style.push(value);
+ });
+ if (style.length) {
+ html += ' style="' + style.join('; ') + ';"';
+ }
+ }
+ html += '>';
+ var children = node.childNodes;
+ for(var j=0; j';
+ }
+ });
+ return html;
+}
+
+
+// TODO(vojta): migrate these helpers into jasmine matchers
+/**a
+ * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
+ * actually test if an element is displayed by the browser. Be aware!!!
+ */
+function isCssVisible(node) {
+ var display = node.css('display');
+ return !node.hasClass('ng-hide') && display != 'none';
+}
+
+function assertHidden(node) {
+ if (isCssVisible(node)) {
+ throw new Error('Node should be hidden but was visible: ' + angular.module.ngMock.dump(node));
+ }
+}
+
+function assertVisible(node) {
+ if (!isCssVisible(node)) {
+ throw new Error('Node should be visible but was hidden: ' + angular.module.ngMock.dump(node));
+ }
+}
+
+function provideLog($provide) {
+ $provide.factory('log', function() {
+ var messages = [];
+
+ function log(msg) {
+ messages.push(msg);
+ return msg;
+ }
+
+ log.toString = function() {
+ return messages.join('; ');
+ }
+
+ log.toArray = function() {
+ return messages;
+ }
+
+ log.reset = function() {
+ messages = [];
+ }
+
+ log.fn = function(msg) {
+ return function() {
+ log(msg);
+ }
+ }
+
+ log.$$log = true;
+
+ return log;
+ });
+}
+
+function pending() {
+ dump('PENDING');
+};
+
+function trace(name) {
+ dump(new Error(name).stack);
+}
+
+var karmaDump = dump;
+window.dump = function () {
+ karmaDump.apply(undefined, map(arguments, function(arg) {
+ return angular.mock.dump(arg);
+ }));
+};
diff --git a/test/matchers.js b/test/matchers.js
deleted file mode 100644
index 57bf35c7..00000000
--- a/test/matchers.js
+++ /dev/null
@@ -1,266 +0,0 @@
-beforeEach(function() {
-
- function cssMatcher(presentClasses, absentClasses) {
- return function() {
- var element = angular.element(this.actual);
- var present = true;
- var absent = false;
-
- angular.forEach(presentClasses.split(' '), function(className){
- present = present && element.hasClass(className);
- });
-
- angular.forEach(absentClasses.split(' '), function(className){
- absent = absent || element.hasClass(className);
- });
-
- this.message = function() {
- return "Expected to have " + presentClasses +
- (absentClasses ? (" and not have " + absentClasses + "" ) : "") +
- " but had " + element[0].className + ".";
- };
- return present && !absent;
- };
- }
-
- function indexOf(array, obj) {
- for ( var i = 0; i < array.length; i++) {
- if (obj === array[i]) return i;
- }
- return -1;
- }
-
- function isNgElementHidden(element) {
- return angular.element(element).hasClass('ng-hide');
- };
-
- this.addMatchers({
- toBeInvalid: cssMatcher('ng-invalid', 'ng-valid'),
- toBeValid: cssMatcher('ng-valid', 'ng-invalid'),
- toBeDirty: cssMatcher('ng-dirty', 'ng-pristine'),
- toBePristine: cssMatcher('ng-pristine', 'ng-dirty'),
- toBeShown: function() {
- this.message = valueFn(
- "Expected element " + (this.isNot ? "": "not ") + "to have 'ng-hide' class");
- return !isNgElementHidden(this.actual);
- },
- toBeHidden: function() {
- this.message = valueFn(
- "Expected element " + (this.isNot ? "not ": "") + "to have 'ng-hide' class");
- return isNgElementHidden(this.actual);
- },
-
- toEqual: function(expected) {
- if (this.actual && this.actual.$$log) {
- this.actual = (typeof expected === 'string')
- ? this.actual.toString()
- : this.actual.toArray();
- }
- return jasmine.Matchers.prototype.toEqual.call(this, expected);
- },
-
- toEqualData: function(expected) {
- return angular.equals(this.actual, expected);
- },
-
- toEqualError: function(message) {
- this.message = function() {
- var expected;
- if (this.actual.message && this.actual.name == 'Error') {
- expected = toJson(this.actual.message);
- } else {
- expected = toJson(this.actual);
- }
- return "Expected " + expected + " to be an Error with message " + toJson(message);
- };
- return this.actual.name == 'Error' && this.actual.message == message;
- },
-
- toMatchError: function(messageRegexp) {
- this.message = function() {
- var expected;
- if (this.actual.message && this.actual.name == 'Error') {
- expected = angular.toJson(this.actual.message);
- } else {
- expected = angular.toJson(this.actual);
- }
- return "Expected " + expected + " to match an Error with message " + angular.toJson(messageRegexp);
- };
- return this.actual.name == 'Error' && messageRegexp.test(this.actual.message);
- },
-
- toHaveBeenCalledOnce: function() {
- if (arguments.length > 0) {
- throw new Error('toHaveBeenCalledOnce does not take arguments, use toHaveBeenCalledWith');
- }
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- var msg = 'Expected spy ' + this.actual.identity + ' to have been called once, but was ',
- count = this.actual.callCount;
- return [
- count === 0 ? msg + 'never called.' :
- msg + 'called ' + count + ' times.',
- msg.replace('to have', 'not to have') + 'called once.'
- ];
- };
-
- return this.actual.callCount == 1;
- },
-
-
- toHaveBeenCalledOnceWith: function() {
- var expectedArgs = jasmine.util.argsToArray(arguments);
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- if (this.actual.callCount != 1) {
- if (this.actual.callCount == 0) {
- return [
- 'Expected spy ' + this.actual.identity + ' to have been called once with ' +
- jasmine.pp(expectedArgs) + ' but it was never called.',
- 'Expected spy ' + this.actual.identity + ' not to have been called with ' +
- jasmine.pp(expectedArgs) + ' but it was.'
- ];
- }
-
- return [
- 'Expected spy ' + this.actual.identity + ' to have been called once with ' +
- jasmine.pp(expectedArgs) + ' but it was called ' + this.actual.callCount + ' times.',
- 'Expected spy ' + this.actual.identity + ' not to have been called once with ' +
- jasmine.pp(expectedArgs) + ' but it was.'
- ];
- } else {
- return [
- 'Expected spy ' + this.actual.identity + ' to have been called once with ' +
- jasmine.pp(expectedArgs) + ' but was called with ' + jasmine.pp(this.actual.argsForCall),
- 'Expected spy ' + this.actual.identity + ' not to have been called once with ' +
- jasmine.pp(expectedArgs) + ' but was called with ' + jasmine.pp(this.actual.argsForCall)
- ];
- }
- };
-
- return this.actual.callCount === 1 && this.env.contains_(this.actual.argsForCall, expectedArgs);
- },
-
-
- toBeOneOf: function() {
- return indexOf(arguments, this.actual) !== -1;
- },
-
- toHaveClass: function(clazz) {
- this.message = function() {
- return "Expected '" + angular.mock.dump(this.actual) + "' to have class '" + clazz + "'.";
- };
- return this.actual.hasClass ?
- this.actual.hasClass(clazz) :
- angular.element(this.actual).hasClass(clazz);
- },
-
- toThrowMatching: function(expected) {
- return jasmine.Matchers.prototype.toThrow.call(this, expected);
- },
-
- toThrowMinErr: function(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 = this.isNot ? "not " : "",
- regex = jasmine.isA_("RegExp", content) ? content :
- isDefined(content) ? new RegExp(escapeRegexp(content)) : undefined;
-
- if(!isFunction(this.actual)) {
- throw new Error('Actual is not a function');
- }
-
- try {
- this.actual();
- } catch (e) {
- exception = e;
- }
-
- if (exception) {
- exceptionMessage = exception.message || exception;
- }
-
- this.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) {
- return result;
- }
-
- if (isDefined(regex)) {
- return regex.test(exceptionMessage);
- }
- return result;
- }
- });
-});
-
-
-// TODO(vojta): remove this once Jasmine in Karma gets updated
-// https://github.com/pivotal/jasmine/blob/c40b64a24c607596fa7488f2a0ddb98d063c872a/src/core/Matchers.js#L217-L246
-// This toThrow supports RegExps.
-jasmine.Matchers.prototype.toThrow = function(expected) {
- var result = false;
- var exception, exceptionMessage;
- if (typeof this.actual != 'function') {
- throw new Error('Actual is not a function');
- }
- try {
- this.actual();
- } catch (e) {
- exception = e;
- }
-
- if (exception) {
- exceptionMessage = exception.message || exception;
- result = (isUndefined(expected) || this.env.equals_(exceptionMessage, expected.message || expected) || (jasmine.isA_("RegExp", expected) && expected.test(exceptionMessage)));
- }
-
- var not = this.isNot ? "not " : "";
- var regexMatch = jasmine.isA_("RegExp", expected) ? " an exception matching" : "";
-
- this.message = function() {
- if (exception) {
- return ["Expected function " + not + "to throw" + regexMatch, expected ? expected.message || expected : "an exception", ", but it threw", exceptionMessage].join(' ');
- } else {
- return "Expected function to throw an exception.";
- }
- };
-
- return result;
-};
-
-
-/**
- * Create jasmine.Spy on given method, but ignore calls without arguments
- * This is helpful when need to spy only setter methods and ignore getters
- */
-function spyOnlyCallsWithArgs(obj, method) {
- var spy = spyOn(obj, method);
- obj[method] = function() {
- if (arguments.length) return spy.apply(this, arguments);
- return spy.originalValue.apply(this);
- };
- return spy;
-}
diff --git a/test/privateMocksSpec.js b/test/privateMocksSpec.js
deleted file mode 100644
index e58a2b75..00000000
--- a/test/privateMocksSpec.js
+++ /dev/null
@@ -1,36 +0,0 @@
-describe('private mocks', function() {
- describe('createMockStyleSheet', function() {
-
- it('should allow custom styles to be created and removed when the stylesheet is destroyed',
- inject(function($compile, $document, $window, $rootElement, $rootScope) {
-
- var doc = $document[0];
- var count = doc.styleSheets.length;
- var stylesheet = createMockStyleSheet($document, $window);
- expect(doc.styleSheets.length).toBe(count + 1);
-
- jqLite(doc.body).append($rootElement);
-
- var elm = $compile('...
')($rootScope);
- $rootElement.append(elm);
-
- expect(getStyle(elm, 'paddingTop')).toBe('0px');
-
- stylesheet.addRule('.padded', 'padding-top:2px');
-
- expect(getStyle(elm, 'paddingTop')).toBe('2px');
-
- stylesheet.destroy();
-
- expect(getStyle(elm, 'paddingTop')).toBe('0px');
-
- function getStyle(element, key) {
- var node = element[0];
- return node.currentStyle ?
- node.currentStyle[key] :
- $window.getComputedStyle(node)[key];
- };
- }));
-
- });
-});
diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js
deleted file mode 100644
index 514a5fdb..00000000
--- a/test/testabilityPatch.js
+++ /dev/null
@@ -1,297 +0,0 @@
-'use strict';
-
-/**
- * Here is the problem: http://bugs.jquery.com/ticket/7292
- * basically jQuery treats change event on some browsers (IE) as a
- * special event and changes it form 'change' to 'click/keydown' and
- * few others. This horrible hack removes the special treatment
- */
-if (window._jQuery) _jQuery.event.special.change = undefined;
-
-if (window.bindJQuery) bindJQuery();
-
-beforeEach(function() {
- // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
- if (window.publishExternalAPI) {
- publishExternalAPI(angular);
-
- // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
- // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
- // correct this, but only if we are not running in jqLite mode
- if (!_jqLiteMode && _jQuery !== jQuery) {
- jQuery = _jQuery;
- }
-
- // This resets global id counter;
- uid = ['0', '0', '0'];
-
- // reset to jQuery or default to us.
- bindJQuery();
- }
-
-
- angular.element(document.body).html('').removeData();
-});
-
-afterEach(function() {
- if (this.$injector) {
- var $rootScope = this.$injector.get('$rootScope');
- var $rootElement = this.$injector.get('$rootElement');
- var $log = this.$injector.get('$log');
- // release the injector
- dealoc($rootScope);
- dealoc($rootElement);
-
- // check $log mock
- $log.assertEmpty && $log.assertEmpty();
- }
-
- // complain about uncleared jqCache references
- var count = 0;
-
- // This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775
- //var cache = jqLite.cache;
- var cache = angular.element.cache;
-
- forEachSorted(cache, function(expando, key){
- angular.forEach(expando.data, function(value, key){
- count ++;
- if (value && value.$element) {
- dump('LEAK', key, value.$id, sortedHtml(value.$element));
- } else {
- dump('LEAK', key, angular.toJson(value));
- }
- });
- });
- if (count) {
- throw new Error('Found jqCache references that were not deallocated! count: ' + count);
- }
-
-
- // copied from Angular.js
- // we need these two methods here so that we can run module tests with wrapped angular.js
- function sortedKeys(obj) {
- var keys = [];
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- keys.push(key);
- }
- }
- return keys.sort();
- }
-
- function forEachSorted(obj, iterator, context) {
- var keys = sortedKeys(obj);
- for ( var i = 0; i < keys.length; i++) {
- iterator.call(context, obj[keys[i]], keys[i]);
- }
- return keys;
- }
-});
-
-
-function dealoc(obj) {
- var jqCache = angular.element.cache;
- if (obj) {
- if (angular.isElement(obj)) {
- cleanup(angular.element(obj));
- } else {
- for(var key in jqCache) {
- var value = jqCache[key];
- if (value.data && value.data.$scope == obj) {
- delete jqCache[key];
- }
- }
- }
- }
-
- function cleanup(element) {
- element.off().removeData();
- // Note: We aren't using element.contents() here. Under jQuery, element.contents() can fail
- // for IFRAME elements. jQuery explicitly uses (element.contentDocument ||
- // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
- // to a document.
- var children = element[0].childNodes || [];
- for ( var i = 0; i < children.length; i++) {
- cleanup(angular.element(children[i]));
- }
- }
-}
-
-/**
- * @param {DOMElement} element
- * @param {boolean=} showNgClass
- */
-function sortedHtml(element, showNgClass) {
- var html = "";
- forEach(jqLite(element), function toString(node) {
-
- if (node.nodeName == "#text") {
- html += node.nodeValue.
- replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
- replace(//g, '>');
- } else if (node.nodeName == "#comment") {
- html += '';
- } else {
- html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
- var attributes = node.attributes || [];
- var attrs = [];
- var className = node.className || '';
- if (!showNgClass) {
- className = className.replace(/ng-[\w-]+\s*/g, '');
- }
- className = trim(className);
- if (className) {
- attrs.push(' class="' + className + '"');
- }
- for(var i=0; i0 && attributes[i] == attributes[i-1])
- continue; //IE9 creates dupes. Ignore them!
-
- var attr = attributes[i];
- if(attr.name.match(/^ng[\:\-]/) ||
- (attr.value || attr.value == '') &&
- attr.value !='null' &&
- attr.value !='auto' &&
- attr.value !='false' &&
- attr.value !='inherit' &&
- (attr.value !='0' || attr.name =='value') &&
- attr.name !='loop' &&
- attr.name !='complete' &&
- attr.name !='maxLength' &&
- attr.name !='size' &&
- attr.name !='class' &&
- attr.name !='start' &&
- attr.name !='tabIndex' &&
- attr.name !='style' &&
- attr.name.substr(0, 6) != 'jQuery') {
- // in IE we need to check for all of these.
- if (/ng-\d+/.exec(attr.name) ||
- attr.name == 'getElementById' ||
- // IE7 has `selected` in attributes
- attr.name == 'selected' ||
- // IE7 adds `value` attribute to all LI tags
- (node.nodeName == 'LI' && attr.name == 'value') ||
- // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
- (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
- (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
- continue;
- }
-
- attrs.push(' ' + attr.name + '="' + attr.value + '"');
- }
- }
- attrs.sort();
- html += attrs.join('');
- if (node.style) {
- var style = [];
- if (node.style.cssText) {
- forEach(node.style.cssText.split(';'), function(value){
- value = trim(value);
- if (value) {
- style.push(lowercase(value));
- }
- });
- }
- for(var css in node.style){
- var value = node.style[css];
- if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
- var text = lowercase(css + ': ' + value);
- if (value != 'false' && indexOf(style, text) == -1) {
- style.push(text);
- }
- }
- }
- style.sort();
- var tmp = style;
- style = [];
- forEach(tmp, function(value){
- if (!value.match(/^max[^\-]/))
- style.push(value);
- });
- if (style.length) {
- html += ' style="' + style.join('; ') + ';"';
- }
- }
- html += '>';
- var children = node.childNodes;
- for(var j=0; j';
- }
- });
- return html;
-}
-
-
-// TODO(vojta): migrate these helpers into jasmine matchers
-/**a
- * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
- * actually test if an element is displayed by the browser. Be aware!!!
- */
-function isCssVisible(node) {
- var display = node.css('display');
- return !node.hasClass('ng-hide') && display != 'none';
-}
-
-function assertHidden(node) {
- if (isCssVisible(node)) {
- throw new Error('Node should be hidden but was visible: ' + angular.module.ngMock.dump(node));
- }
-}
-
-function assertVisible(node) {
- if (!isCssVisible(node)) {
- throw new Error('Node should be visible but was hidden: ' + angular.module.ngMock.dump(node));
- }
-}
-
-function provideLog($provide) {
- $provide.factory('log', function() {
- var messages = [];
-
- function log(msg) {
- messages.push(msg);
- return msg;
- }
-
- log.toString = function() {
- return messages.join('; ');
- }
-
- log.toArray = function() {
- return messages;
- }
-
- log.reset = function() {
- messages = [];
- }
-
- log.fn = function(msg) {
- return function() {
- log(msg);
- }
- }
-
- log.$$log = true;
-
- return log;
- });
-}
-
-function pending() {
- dump('PENDING');
-};
-
-function trace(name) {
- dump(new Error(name).stack);
-}
-
-var karmaDump = dump;
-window.dump = function () {
- karmaDump.apply(undefined, map(arguments, function(arg) {
- return angular.mock.dump(arg);
- }));
-};
--
cgit v1.2.3