mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 15:40:22 +00:00
the flag must be in all src and test files so that we get the benefit of running in the strict mode even in jstd the following script was used to modify all files: for file in `find src test -name "*.js"`; do echo -e "'use strict';\n" > temp.txt cat $file >> temp.txt mv temp.txt $file done
328 lines
9.2 KiB
JavaScript
328 lines
9.2 KiB
JavaScript
'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
|
|
*/
|
|
_jQuery.event.special.change = undefined;
|
|
|
|
|
|
if (window.jstestdriver) {
|
|
window.jstd = jstestdriver;
|
|
window.dump = function(){
|
|
var args = [];
|
|
forEach(arguments, function(arg){
|
|
if (isElement(arg)) {
|
|
arg = sortedHtml(arg);
|
|
} else if (isObject(arg)) {
|
|
arg = toJson(arg, true);
|
|
}
|
|
args.push(arg);
|
|
});
|
|
jstd.console.log.apply(jstd.console, args);
|
|
};
|
|
}
|
|
|
|
beforeEach(function(){
|
|
// This is to reset parsers global cache of expressions.
|
|
compileCache = {};
|
|
// reset to jQuery or default to us.
|
|
bindJQuery();
|
|
jqLite(document.body).html('');
|
|
this.addMatchers({
|
|
toBeInvalid: function(){
|
|
var element = jqLite(this.actual);
|
|
var hasClass = element.hasClass('ng-validation-error');
|
|
var validationError = element.attr('ng-validation-error');
|
|
this.message = function(){
|
|
if (!hasClass)
|
|
return "Expected class 'ng-validation-error' not found.";
|
|
return "Expected an error message, but none was found.";
|
|
};
|
|
return hasClass && validationError;
|
|
},
|
|
|
|
toBeValid: function(){
|
|
var element = jqLite(this.actual);
|
|
var hasClass = element.hasClass('ng-validation-error');
|
|
this.message = function(){
|
|
return "Expected to not have class 'ng-validation-error' but found.";
|
|
};
|
|
return !hasClass;
|
|
},
|
|
|
|
toEqualData: function(expected) {
|
|
return equals(this.actual, expected);
|
|
},
|
|
|
|
toHaveClass: function(clazz) {
|
|
this.message = function(){
|
|
return "Expected '" + sortedHtml(this.actual) + "' to have class '" + clazz + "'.";
|
|
};
|
|
return this.actual.hasClass ?
|
|
this.actual.hasClass(clazz) :
|
|
jqLite(this.actual).hasClass(clazz);
|
|
},
|
|
|
|
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 = toJson(this.actual.message);
|
|
} else {
|
|
expected = toJson(this.actual);
|
|
}
|
|
return "Expected " + expected + " to match an Error with message " + toJson(messageRegexp);
|
|
};
|
|
return this.actual.name == 'Error' && messageRegexp.test(this.actual.message);
|
|
}
|
|
});
|
|
|
|
$logMock.log.logs = [];
|
|
$logMock.warn.logs = [];
|
|
$logMock.info.logs = [];
|
|
$logMock.error.logs = [];
|
|
});
|
|
|
|
afterEach(function() {
|
|
// check $log mock
|
|
forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
|
|
if ($logMock[logLevel].logs.length) {
|
|
forEach($logMock[logLevel].logs, function(log) {
|
|
forEach(log, function deleteStack(logItem) {
|
|
if (logItem instanceof Error) {
|
|
dump(logItem.stack);
|
|
delete logItem.stack;
|
|
delete logItem.arguments;
|
|
} else {
|
|
dump(logItem);
|
|
}
|
|
});
|
|
});
|
|
|
|
throw new Error("Exprected $log." + logLevel + ".logs array to be empty. " +
|
|
"Either a message was logged unexpectedly, or an expected log message was not checked " +
|
|
"and removed. Array contents: " + toJson($logMock[logLevel].logs));
|
|
}
|
|
});
|
|
|
|
clearJqCache();
|
|
});
|
|
|
|
function clearJqCache(){
|
|
var count = 0;
|
|
forEachSorted(jqCache, function(value, key){
|
|
count ++;
|
|
delete jqCache[key];
|
|
forEach(value, function(value, key){
|
|
if (value.$element)
|
|
dump(key, sortedHtml(value.$element));
|
|
else
|
|
dump(key, toJson(value));
|
|
});
|
|
});
|
|
if (count) {
|
|
fail('Found jqCache references that were not deallocated!');
|
|
}
|
|
}
|
|
|
|
function nakedExpect(obj) {
|
|
return expect(angular.fromJson(angular.toJson(obj)));
|
|
}
|
|
|
|
function childNode(element, index) {
|
|
return jqLite(element[0].childNodes[index]);
|
|
}
|
|
|
|
function dealoc(obj) {
|
|
if (obj) {
|
|
var element = obj.$element || obj || {};
|
|
if (element.nodeName) element = jqLite(element);
|
|
if (element.dealoc) element.dealoc();
|
|
}
|
|
}
|
|
|
|
extend(angular, {
|
|
'element': jqLite,
|
|
'compile': compile,
|
|
'scope': createScope,
|
|
'copy': copy,
|
|
'extend': extend,
|
|
'equals': equals,
|
|
'forEach': forEach,
|
|
'noop':noop,
|
|
'bind':bind,
|
|
'toJson': toJson,
|
|
'fromJson': fromJson,
|
|
'identity':identity,
|
|
'injector': createInjector,
|
|
'isUndefined': isUndefined,
|
|
'isDefined': isDefined,
|
|
'isString': isString,
|
|
'isFunction': isFunction,
|
|
'isObject': isObject,
|
|
'isNumber': isNumber,
|
|
'isArray': isArray
|
|
});
|
|
|
|
|
|
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, '<').
|
|
replace(/>/g, '>');
|
|
} 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; i<attributes.length; i++) {
|
|
if (i>0 && attributes[i] == attributes[i-1])
|
|
continue; //IE9 creates dupes. Ignore them!
|
|
|
|
var attr = attributes[i];
|
|
if(attr.name.match(/^ng:/) ||
|
|
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'))
|
|
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<children.length; j++) {
|
|
toString(children[j]);
|
|
}
|
|
html += '</' + node.nodeName.toLowerCase() + '>';
|
|
}
|
|
});
|
|
return html;
|
|
}
|
|
|
|
|
|
/**
|
|
* 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 display != 'none';
|
|
}
|
|
|
|
function assertHidden(node) {
|
|
assertFalse("Node should be hidden but vas visible: " + sortedHtml(node), isCssVisible(node));
|
|
}
|
|
|
|
function assertVisible(node) {
|
|
assertTrue("Node should be visible but vas hidden: " + sortedHtml(node), isCssVisible(node));
|
|
}
|
|
|
|
function assertJsonEquals(expected, actual) {
|
|
assertEquals(toJson(expected), toJson(actual));
|
|
}
|
|
|
|
function assertUndefined(value) {
|
|
assertEquals('undefined', typeof value);
|
|
}
|
|
|
|
function assertDefined(value) {
|
|
assertTrue(toJson(value), !!value);
|
|
}
|
|
|
|
function assertThrows(error, fn){
|
|
var exception = null;
|
|
try {
|
|
fn();
|
|
} catch(e) {
|
|
exception = e;
|
|
}
|
|
if (!exception) {
|
|
fail("Expecting exception, none thrown");
|
|
}
|
|
assertEquals(error, exception);
|
|
}
|
|
|
|
window.log = noop;
|
|
window.error = noop;
|
|
|
|
function rethrow(e) {
|
|
if(e) {
|
|
throw e;
|
|
}
|
|
}
|