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.
This commit is contained in:
Igor Minar 2013-04-18 12:50:49 -07:00
parent 695c54c17b
commit 5da6b125a7
4 changed files with 166 additions and 117 deletions

4
angularFiles.js vendored
View file

@ -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',

View file

@ -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.

View file

@ -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;
}
}
}());

View file

@ -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]));
}
}
}