Skip to content

Commit 5da6b12

Browse files
committed
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.
1 parent 695c54c commit 5da6b12

File tree

4 files changed

+166
-117
lines changed

4 files changed

+166
-117
lines changed

angularFiles.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ angularFiles = {
8080

8181
'angularScenario': [
8282
'src/ngScenario/Scenario.js',
83+
'src/ngScenario/browserTrigger.js',
8384
'src/ngScenario/Application.js',
8485
'src/ngScenario/Describe.js',
8586
'src/ngScenario/Future.js',
@@ -147,7 +148,6 @@ angularFiles = {
147148
'lib/jasmine/jasmine.js',
148149
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
149150
'build/angular.js',
150-
'build/angular-scenario.js',
151151
'src/ngMock/angular-mocks.js',
152152
'src/ngCookies/cookies.js',
153153
'src/ngResource/resource.js',
@@ -157,7 +157,9 @@ angularFiles = {
157157
'src/ngSanitize/sanitize.js',
158158
'src/ngSanitize/directive/ngBindHtml.js',
159159
'src/ngSanitize/filter/linky.js',
160+
'src/ngScenario/browserTrigger.js',
160161
'test/matchers.js',
162+
'test/testabilityPatch.js',
161163
'test/ngMock/*.js',
162164
'test/ngCookies/*.js',
163165
'test/ngResource/*.js',

src/ngScenario/Scenario.js

Lines changed: 0 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -223,102 +223,6 @@ function callerFile(offset) {
223223
};
224224
}
225225

226-
/**
227-
* Triggers a browser event. Attempts to choose the right event if one is
228-
* not specified.
229-
*
230-
* @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
231-
* @param {string} type Optional event type.
232-
* @param {Array.<string>=} keys Optional list of pressed keys
233-
* (valid values: 'alt', 'meta', 'shift', 'ctrl')
234-
* @param {number} x Optional x-coordinate for mouse/touch events.
235-
* @param {number} y Optional y-coordinate for mouse/touch events.
236-
*/
237-
function browserTrigger(element, type, keys, x, y) {
238-
if (element && !element.nodeName) element = element[0];
239-
if (!element) return;
240-
if (!type) {
241-
type = {
242-
'text': 'change',
243-
'textarea': 'change',
244-
'hidden': 'change',
245-
'password': 'change',
246-
'button': 'click',
247-
'submit': 'click',
248-
'reset': 'click',
249-
'image': 'click',
250-
'checkbox': 'click',
251-
'radio': 'click',
252-
'select-one': 'change',
253-
'select-multiple': 'change'
254-
}[lowercase(element.type)] || 'click';
255-
}
256-
if (lowercase(nodeName_(element)) == 'option') {
257-
element.parentNode.value = element.value;
258-
element = element.parentNode;
259-
type = 'change';
260-
}
261-
262-
keys = keys || [];
263-
function pressed(key) {
264-
return indexOf(keys, key) !== -1;
265-
}
266-
267-
if (msie < 9) {
268-
switch(element.type) {
269-
case 'radio':
270-
case 'checkbox':
271-
element.checked = !element.checked;
272-
break;
273-
}
274-
// WTF!!! Error: Unspecified error.
275-
// Don't know why, but some elements when detached seem to be in inconsistent state and
276-
// calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error)
277-
// forcing the browser to compute the element position (by reading its CSS)
278-
// puts the element in consistent state.
279-
element.style.posLeft;
280-
281-
// TODO(vojta): create event objects with pressed keys to get it working on IE<9
282-
var ret = element.fireEvent('on' + type);
283-
if (lowercase(element.type) == 'submit') {
284-
while(element) {
285-
if (lowercase(element.nodeName) == 'form') {
286-
element.fireEvent('onsubmit');
287-
break;
288-
}
289-
element = element.parentNode;
290-
}
291-
}
292-
return ret;
293-
} else {
294-
var evnt = document.createEvent('MouseEvents'),
295-
originalPreventDefault = evnt.preventDefault,
296-
iframe = _jQuery('#application iframe')[0],
297-
appWindow = iframe ? iframe.contentWindow : window,
298-
fakeProcessDefault = true,
299-
finalProcessDefault,
300-
angular = appWindow.angular || {};
301-
302-
// igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
303-
angular['ff-684208-preventDefault'] = false;
304-
evnt.preventDefault = function() {
305-
fakeProcessDefault = false;
306-
return originalPreventDefault.apply(evnt, arguments);
307-
};
308-
309-
x = x || 0;
310-
y = y || 0;
311-
evnt.initMouseEvent(type, true, true, window, 0, x, y, x, y, pressed('ctrl'), pressed('alt'),
312-
pressed('shift'), pressed('meta'), 0, element);
313-
314-
element.dispatchEvent(evnt);
315-
finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
316-
317-
delete angular['ff-684208-preventDefault'];
318-
319-
return finalProcessDefault;
320-
}
321-
}
322226

323227
/**
324228
* Don't use the jQuery trigger method since it works incorrectly.

src/ngScenario/browserTrigger.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
'use strict';
2+
3+
(function() {
4+
var msie = parseInt((/msie (\d+)/.exec(navigator.userAgent.toLowerCase()) || [])[1], 10);
5+
6+
function indexOf(array, obj) {
7+
if (array.indexOf) return array.indexOf(obj);
8+
9+
for ( var i = 0; i < array.length; i++) {
10+
if (obj === array[i]) return i;
11+
}
12+
return -1;
13+
}
14+
15+
16+
17+
/**
18+
* Triggers a browser event. Attempts to choose the right event if one is
19+
* not specified.
20+
*
21+
* @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
22+
* @param {string} eventType Optional event type.
23+
* @param {Array.<string>=} keys Optional list of pressed keys
24+
* (valid values: 'alt', 'meta', 'shift', 'ctrl')
25+
* @param {number} x Optional x-coordinate for mouse/touch events.
26+
* @param {number} y Optional y-coordinate for mouse/touch events.
27+
*/
28+
window.browserTrigger = function browserTrigger(element, eventType, keys, x, y) {
29+
if (element && !element.nodeName) element = element[0];
30+
if (!element) return;
31+
32+
var inputType = (element.type) ? element.type.toLowerCase() : null,
33+
nodeName = element.nodeName.toLowerCase();
34+
35+
if (!eventType) {
36+
eventType = {
37+
'text': 'change',
38+
'textarea': 'change',
39+
'hidden': 'change',
40+
'password': 'change',
41+
'button': 'click',
42+
'submit': 'click',
43+
'reset': 'click',
44+
'image': 'click',
45+
'checkbox': 'click',
46+
'radio': 'click',
47+
'select-one': 'change',
48+
'select-multiple': 'change',
49+
'_default_': 'click'
50+
}[inputType || '_default_'];
51+
}
52+
53+
if (nodeName == 'option') {
54+
element.parentNode.value = element.value;
55+
element = element.parentNode;
56+
eventType = 'change';
57+
}
58+
59+
keys = keys || [];
60+
function pressed(key) {
61+
return indexOf(keys, key) !== -1;
62+
}
63+
64+
if (msie < 9) {
65+
if (inputType == 'radio' || inputType == 'checkbox') {
66+
element.checked = !element.checked;
67+
}
68+
69+
// WTF!!! Error: Unspecified error.
70+
// Don't know why, but some elements when detached seem to be in inconsistent state and
71+
// calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error)
72+
// forcing the browser to compute the element position (by reading its CSS)
73+
// puts the element in consistent state.
74+
element.style.posLeft;
75+
76+
// TODO(vojta): create event objects with pressed keys to get it working on IE<9
77+
var ret = element.fireEvent('on' + eventType);
78+
if (inputType == 'submit') {
79+
while(element) {
80+
if (element.nodeName.toLowerCase() == 'form') {
81+
element.fireEvent('onsubmit');
82+
break;
83+
}
84+
element = element.parentNode;
85+
}
86+
}
87+
return ret;
88+
} else {
89+
var evnt = document.createEvent('MouseEvents'),
90+
originalPreventDefault = evnt.preventDefault,
91+
appWindow = element.ownerDocument.defaultView,
92+
fakeProcessDefault = true,
93+
finalProcessDefault,
94+
angular = appWindow.angular || {};
95+
96+
// igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
97+
angular['ff-684208-preventDefault'] = false;
98+
evnt.preventDefault = function() {
99+
fakeProcessDefault = false;
100+
return originalPreventDefault.apply(evnt, arguments);
101+
};
102+
103+
x = x || 0;
104+
y = y || 0;
105+
evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'), pressed('alt'),
106+
pressed('shift'), pressed('meta'), 0, element);
107+
108+
element.dispatchEvent(evnt);
109+
finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
110+
111+
delete angular['ff-684208-preventDefault'];
112+
113+
return finalProcessDefault;
114+
}
115+
}
116+
}());

test/testabilityPatch.js

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,31 @@
66
* special event and changes it form 'change' to 'click/keydown' and
77
* few others. This horrible hack removes the special treatment
88
*/
9-
_jQuery.event.special.change = undefined;
9+
if (window._jQuery) _jQuery.event.special.change = undefined;
10+
11+
if (window.bindJQuery) bindJQuery();
1012

11-
bindJQuery();
1213
beforeEach(function() {
13-
publishExternalAPI(angular);
14+
// all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
15+
if (window.publishExternalAPI) {
16+
publishExternalAPI(angular);
17+
18+
// workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
19+
// IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
20+
// correct this, but only if we are not running in jqLite mode
21+
if (!_jqLiteMode && _jQuery !== jQuery) {
22+
jQuery = _jQuery;
23+
}
1424

15-
// workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
16-
// IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
17-
// correct this, but only if we are not running in jqLite mode
18-
if (!_jqLiteMode && _jQuery !== jQuery) {
19-
jQuery = _jQuery;
25+
// This resets global id counter;
26+
uid = ['0', '0', '0'];
27+
28+
// reset to jQuery or default to us.
29+
bindJQuery();
2030
}
2131

22-
// This resets global id counter;
23-
uid = ['0', '0', '0'];
2432

25-
// reset to jQuery or default to us.
26-
bindJQuery();
27-
jqLite(document.body).html('').removeData();
33+
angular.element(document.body).html('').removeData();
2834
});
2935

3036
afterEach(function() {
@@ -45,29 +51,50 @@ afterEach(function() {
4551

4652
// This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775
4753
//var cache = jqLite.cache;
48-
var cache = JQLite.cache;
54+
var cache = angular.element.cache;
4955

5056
forEachSorted(cache, function(expando, key){
51-
forEach(expando.data, function(value, key){
57+
angular.forEach(expando.data, function(value, key){
5258
count ++;
5359
if (value.$element) {
5460
dump('LEAK', key, value.$id, sortedHtml(value.$element));
5561
} else {
56-
dump('LEAK', key, toJson(value));
62+
dump('LEAK', key, angular.toJson(value));
5763
}
5864
});
5965
});
6066
if (count) {
6167
throw new Error('Found jqCache references that were not deallocated! count: ' + count);
6268
}
69+
70+
71+
// copied from Angular.js
72+
// we need these two methods here so that we can run module tests with wrapped angular.js
73+
function sortedKeys(obj) {
74+
var keys = [];
75+
for (var key in obj) {
76+
if (obj.hasOwnProperty(key)) {
77+
keys.push(key);
78+
}
79+
}
80+
return keys.sort();
81+
}
82+
83+
function forEachSorted(obj, iterator, context) {
84+
var keys = sortedKeys(obj);
85+
for ( var i = 0; i < keys.length; i++) {
86+
iterator.call(context, obj[keys[i]], keys[i]);
87+
}
88+
return keys;
89+
}
6390
});
6491

6592

6693
function dealoc(obj) {
67-
var jqCache = jqLite.cache;
94+
var jqCache = angular.element.cache;
6895
if (obj) {
69-
if (isElement(obj)) {
70-
cleanup(jqLite(obj));
96+
if (angular.isElement(obj)) {
97+
cleanup(angular.element(obj));
7198
} else {
7299
for(var key in jqCache) {
73100
var value = jqCache[key];
@@ -81,7 +108,7 @@ function dealoc(obj) {
81108
function cleanup(element) {
82109
element.unbind().removeData();
83110
for ( var i = 0, children = element.contents() || []; i < children.length; i++) {
84-
cleanup(jqLite(children[i]));
111+
cleanup(angular.element(children[i]));
85112
}
86113
}
87114
}

0 commit comments

Comments
 (0)