diff options
| author | Igor Minar | 2013-04-18 12:50:49 -0700 |
|---|---|---|
| committer | Igor Minar | 2013-04-18 14:34:53 -0700 |
| commit | 5da6b125a7447b4bbabb88b2d82b5634b55c3aea (patch) | |
| tree | d67bb5ce97dbed432b15ed9481f5055416437604 | |
| parent | 695c54c17b3299cd6170c45878b41cb46a577cd2 (diff) | |
| download | angular.js-5da6b125a7447b4bbabb88b2d82b5634b55c3aea.tar.bz2 | |
test(modules): fix module tests which got disabled by ngMobile
When ngMobile was merged in, we accidentaly included angular-scenario.js
in the test file set for modules. Loading this file overrode jasmine's
`it` and `describe` global functions which essentially disabled all of
~200 unit tests for wrapped modules.
This change refactors the code to run the wrapped module tests.
I had to extract browserTrigger from scenario runner in order to achieve
this without code duplication.
| -rw-r--r-- | angularFiles.js | 4 | ||||
| -rw-r--r-- | src/ngScenario/Scenario.js | 96 | ||||
| -rw-r--r-- | src/ngScenario/browserTrigger.js | 116 | ||||
| -rw-r--r-- | test/testabilityPatch.js | 67 |
4 files changed, 166 insertions, 117 deletions
diff --git a/angularFiles.js b/angularFiles.js index b2c23a8f..30c65df1 100644 --- a/angularFiles.js +++ b/angularFiles.js @@ -80,6 +80,7 @@ angularFiles = { 'angularScenario': [ 'src/ngScenario/Scenario.js', + 'src/ngScenario/browserTrigger.js', 'src/ngScenario/Application.js', 'src/ngScenario/Describe.js', 'src/ngScenario/Future.js', @@ -147,7 +148,6 @@ angularFiles = { 'lib/jasmine/jasmine.js', 'lib/jasmine-jstd-adapter/JasmineAdapter.js', 'build/angular.js', - 'build/angular-scenario.js', 'src/ngMock/angular-mocks.js', 'src/ngCookies/cookies.js', 'src/ngResource/resource.js', @@ -157,7 +157,9 @@ angularFiles = { 'src/ngSanitize/sanitize.js', 'src/ngSanitize/directive/ngBindHtml.js', 'src/ngSanitize/filter/linky.js', + 'src/ngScenario/browserTrigger.js', 'test/matchers.js', + 'test/testabilityPatch.js', 'test/ngMock/*.js', 'test/ngCookies/*.js', 'test/ngResource/*.js', diff --git a/src/ngScenario/Scenario.js b/src/ngScenario/Scenario.js index 1ed9d119..f78e3931 100644 --- a/src/ngScenario/Scenario.js +++ b/src/ngScenario/Scenario.js @@ -223,102 +223,6 @@ function callerFile(offset) { }; } -/** - * Triggers a browser event. Attempts to choose the right event if one is - * not specified. - * - * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement - * @param {string} type Optional event type. - * @param {Array.<string>=} keys Optional list of pressed keys - * (valid values: 'alt', 'meta', 'shift', 'ctrl') - * @param {number} x Optional x-coordinate for mouse/touch events. - * @param {number} y Optional y-coordinate for mouse/touch events. - */ -function browserTrigger(element, type, keys, x, y) { - if (element && !element.nodeName) element = element[0]; - if (!element) return; - if (!type) { - type = { - 'text': 'change', - 'textarea': 'change', - 'hidden': 'change', - 'password': 'change', - 'button': 'click', - 'submit': 'click', - 'reset': 'click', - 'image': 'click', - 'checkbox': 'click', - 'radio': 'click', - 'select-one': 'change', - 'select-multiple': 'change' - }[lowercase(element.type)] || 'click'; - } - if (lowercase(nodeName_(element)) == 'option') { - element.parentNode.value = element.value; - element = element.parentNode; - type = 'change'; - } - - keys = keys || []; - function pressed(key) { - return indexOf(keys, key) !== -1; - } - - if (msie < 9) { - switch(element.type) { - case 'radio': - case 'checkbox': - element.checked = !element.checked; - break; - } - // WTF!!! Error: Unspecified error. - // Don't know why, but some elements when detached seem to be in inconsistent state and - // calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error) - // forcing the browser to compute the element position (by reading its CSS) - // puts the element in consistent state. - element.style.posLeft; - - // TODO(vojta): create event objects with pressed keys to get it working on IE<9 - var ret = element.fireEvent('on' + type); - if (lowercase(element.type) == 'submit') { - while(element) { - if (lowercase(element.nodeName) == 'form') { - element.fireEvent('onsubmit'); - break; - } - element = element.parentNode; - } - } - return ret; - } else { - var evnt = document.createEvent('MouseEvents'), - originalPreventDefault = evnt.preventDefault, - iframe = _jQuery('#application iframe')[0], - appWindow = iframe ? iframe.contentWindow : window, - fakeProcessDefault = true, - finalProcessDefault, - angular = appWindow.angular || {}; - - // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208 - angular['ff-684208-preventDefault'] = false; - evnt.preventDefault = function() { - fakeProcessDefault = false; - return originalPreventDefault.apply(evnt, arguments); - }; - - x = x || 0; - y = y || 0; - evnt.initMouseEvent(type, true, true, window, 0, x, y, x, y, pressed('ctrl'), pressed('alt'), - pressed('shift'), pressed('meta'), 0, element); - - element.dispatchEvent(evnt); - finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault); - - delete angular['ff-684208-preventDefault']; - - return finalProcessDefault; - } -} /** * Don't use the jQuery trigger method since it works incorrectly. diff --git a/src/ngScenario/browserTrigger.js b/src/ngScenario/browserTrigger.js new file mode 100644 index 00000000..dc7a9916 --- /dev/null +++ b/src/ngScenario/browserTrigger.js @@ -0,0 +1,116 @@ +'use strict'; + +(function() { + var msie = parseInt((/msie (\d+)/.exec(navigator.userAgent.toLowerCase()) || [])[1], 10); + + function indexOf(array, obj) { + if (array.indexOf) return array.indexOf(obj); + + for ( var i = 0; i < array.length; i++) { + if (obj === array[i]) return i; + } + return -1; + } + + + + /** + * Triggers a browser event. Attempts to choose the right event if one is + * not specified. + * + * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement + * @param {string} eventType Optional event type. + * @param {Array.<string>=} keys Optional list of pressed keys + * (valid values: 'alt', 'meta', 'shift', 'ctrl') + * @param {number} x Optional x-coordinate for mouse/touch events. + * @param {number} y Optional y-coordinate for mouse/touch events. + */ + window.browserTrigger = function browserTrigger(element, eventType, keys, x, y) { + if (element && !element.nodeName) element = element[0]; + if (!element) return; + + var inputType = (element.type) ? element.type.toLowerCase() : null, + nodeName = element.nodeName.toLowerCase(); + + if (!eventType) { + eventType = { + 'text': 'change', + 'textarea': 'change', + 'hidden': 'change', + 'password': 'change', + 'button': 'click', + 'submit': 'click', + 'reset': 'click', + 'image': 'click', + 'checkbox': 'click', + 'radio': 'click', + 'select-one': 'change', + 'select-multiple': 'change', + '_default_': 'click' + }[inputType || '_default_']; + } + + if (nodeName == 'option') { + element.parentNode.value = element.value; + element = element.parentNode; + eventType = 'change'; + } + + keys = keys || []; + function pressed(key) { + return indexOf(keys, key) !== -1; + } + + if (msie < 9) { + if (inputType == 'radio' || inputType == 'checkbox') { + element.checked = !element.checked; + } + + // WTF!!! Error: Unspecified error. + // Don't know why, but some elements when detached seem to be in inconsistent state and + // calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error) + // forcing the browser to compute the element position (by reading its CSS) + // puts the element in consistent state. + element.style.posLeft; + + // TODO(vojta): create event objects with pressed keys to get it working on IE<9 + var ret = element.fireEvent('on' + eventType); + if (inputType == 'submit') { + while(element) { + if (element.nodeName.toLowerCase() == 'form') { + element.fireEvent('onsubmit'); + break; + } + element = element.parentNode; + } + } + return ret; + } else { + var evnt = document.createEvent('MouseEvents'), + originalPreventDefault = evnt.preventDefault, + appWindow = element.ownerDocument.defaultView, + fakeProcessDefault = true, + finalProcessDefault, + angular = appWindow.angular || {}; + + // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208 + angular['ff-684208-preventDefault'] = false; + evnt.preventDefault = function() { + fakeProcessDefault = false; + return originalPreventDefault.apply(evnt, arguments); + }; + + x = x || 0; + y = y || 0; + evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'), pressed('alt'), + pressed('shift'), pressed('meta'), 0, element); + + element.dispatchEvent(evnt); + finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault); + + delete angular['ff-684208-preventDefault']; + + return finalProcessDefault; + } + } +}()); diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js index a4d4b46f..679294ee 100644 --- a/test/testabilityPatch.js +++ b/test/testabilityPatch.js @@ -6,25 +6,31 @@ * special event and changes it form 'change' to 'click/keydown' and * few others. This horrible hack removes the special treatment */ -_jQuery.event.special.change = undefined; +if (window._jQuery) _jQuery.event.special.change = undefined; + +if (window.bindJQuery) bindJQuery(); -bindJQuery(); beforeEach(function() { - publishExternalAPI(angular); + // 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; + } - // 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(); } - // This resets global id counter; - uid = ['0', '0', '0']; - // reset to jQuery or default to us. - bindJQuery(); - jqLite(document.body).html('').removeData(); + angular.element(document.body).html('').removeData(); }); afterEach(function() { @@ -45,29 +51,50 @@ afterEach(function() { // This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775 //var cache = jqLite.cache; - var cache = JQLite.cache; + var cache = angular.element.cache; forEachSorted(cache, function(expando, key){ - forEach(expando.data, function(value, key){ + angular.forEach(expando.data, function(value, key){ count ++; if (value.$element) { dump('LEAK', key, value.$id, sortedHtml(value.$element)); } else { - dump('LEAK', key, toJson(value)); + 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 = jqLite.cache; + var jqCache = angular.element.cache; if (obj) { - if (isElement(obj)) { - cleanup(jqLite(obj)); + if (angular.isElement(obj)) { + cleanup(angular.element(obj)); } else { for(var key in jqCache) { var value = jqCache[key]; @@ -81,7 +108,7 @@ function dealoc(obj) { function cleanup(element) { element.unbind().removeData(); for ( var i = 0, children = element.contents() || []; i < children.length; i++) { - cleanup(jqLite(children[i])); + cleanup(angular.element(children[i])); } } } |
