2391 lines
83 KiB
JavaScript
2391 lines
83 KiB
JavaScript
|
/**
|
||
|
* TestCase - JavaScript testing framework, version 2.0.2
|
||
|
* Copyright (C) 2007-2008 Nikolay V. Nemshilov aka St. <nemshilov-gmail-com>
|
||
|
*
|
||
|
* The library is freely distributable under the terms of an MIT-style license
|
||
|
* For details, see the TestCase web site: http://testcase.rubyforge.net
|
||
|
*/
|
||
|
|
||
|
|
||
|
var TestCaseUtil = {
|
||
|
create_class: function() {
|
||
|
var superklass = null, params = this.to_a(arguments);
|
||
|
if (typeof params[0] == 'function')
|
||
|
superklass = params.shift();
|
||
|
var klass = function() {
|
||
|
return this.initialize ? this.initialize.apply(this, arguments) : this;
|
||
|
}
|
||
|
if (superklass) {
|
||
|
var subclass = function() { };
|
||
|
subclass.prototype = superklass.prototype;
|
||
|
klass.prototype = new subclass;
|
||
|
klass.superclass = superklass;
|
||
|
}
|
||
|
klass.prototype.constructor = klass;
|
||
|
if (params[0])
|
||
|
this.extend(klass.prototype, params[0]);
|
||
|
return klass;
|
||
|
},
|
||
|
extend: function(object, properties, dont_overwrite) {
|
||
|
for (key in properties)
|
||
|
if (!(dont_overwrite && typeof object[key] != 'undefined'))
|
||
|
object[key] = properties[key];
|
||
|
return object;
|
||
|
},
|
||
|
extend_with_camelized_aliases: function(object, mixin) {
|
||
|
var camelized_mixin = {};
|
||
|
for (key in mixin) {
|
||
|
var parts = key.split('_'), camelized = parts[0];
|
||
|
for (var i=1; i < parts.length; i++)
|
||
|
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
|
||
|
camelized_mixin[camelized] = mixin[key];
|
||
|
}
|
||
|
return TestCaseUtil.extend(object, camelized_mixin);
|
||
|
},
|
||
|
extend_fully_object_and_prototype: function(object, mixin) {
|
||
|
TestCaseUtil.extend(object, mixin);
|
||
|
TestCaseUtil.extend(object.prototype, mixin);
|
||
|
TestCaseUtil.extend_with_camelized_aliases(object, mixin);
|
||
|
return TestCaseUtil.extend_with_camelized_aliases(object.prototype, mixin);
|
||
|
},
|
||
|
equal: function(obj1, obj2) {
|
||
|
return TestCaseUtil.to_s(obj1) == TestCaseUtil.to_s(obj2);
|
||
|
},
|
||
|
to_a: function(it) {
|
||
|
var a = [];
|
||
|
for (var i=0; i < it.length; i++)
|
||
|
a.push(it[i]);
|
||
|
return a;
|
||
|
},
|
||
|
to_s: function(object, one_level) {
|
||
|
var value = this._try_to_s(object);
|
||
|
if (value !== object) return value;
|
||
|
var entries = this._get_object_stringified_entries(
|
||
|
one_level ? this._one_level_to_s : this.to_s, object
|
||
|
);
|
||
|
return object instanceof Array ? '['+ entries.join(', ')+ ']' : '{' + entries.join(', ') + '}';
|
||
|
},
|
||
|
debug: function(object) {
|
||
|
return this.to_s(object, true);
|
||
|
},
|
||
|
MAX_OBJECT_STRING_LENGTH: 80,
|
||
|
to_pretty_s: function(object, offset) {
|
||
|
if (object == null) { return 'null'; }
|
||
|
else if (typeof object != 'object') {
|
||
|
return this.to_s(object);
|
||
|
} else {
|
||
|
var offset = offset || 0;
|
||
|
var object_s = this.to_s(object);
|
||
|
if (object_s.length > this.MAX_OBJECT_STRING_LENGTH) {
|
||
|
if (object instanceof Array) {
|
||
|
var len = object.length;
|
||
|
} else {
|
||
|
var len = 0;
|
||
|
for (var key in object) {
|
||
|
len++;
|
||
|
}
|
||
|
}
|
||
|
if (len > 1) {
|
||
|
var entries = this._get_object_stringified_entries(
|
||
|
this.to_pretty_s, object, offset + 1
|
||
|
);
|
||
|
var offset_s = '';
|
||
|
for (var i=0; i < offset; i++) {
|
||
|
offset_s += ' ';
|
||
|
}
|
||
|
object_s = object instanceof Array ?
|
||
|
"[" + entries.join(",\n "+ offset_s) + "\n"+offset_s+"]" :
|
||
|
"{" + entries.join(",\n "+ offset_s) + "\n"+offset_s+"}" ;
|
||
|
}
|
||
|
}
|
||
|
return object_s;
|
||
|
}
|
||
|
},
|
||
|
_get_object_stringified_entries: function(method, object, param) {
|
||
|
var entries = [];
|
||
|
if (object instanceof Array) {
|
||
|
for (var i=0; i < object.length; i++) {
|
||
|
entries.push(method.apply(this, [object[i], param]));
|
||
|
}
|
||
|
} else {
|
||
|
for (var property in object) {
|
||
|
entries.push(this.to_s(property) + ': ' + method.apply(this, [object[property], param]));
|
||
|
}
|
||
|
}
|
||
|
return entries;
|
||
|
},
|
||
|
_one_level_to_s: function(object) {
|
||
|
var value = this._try_to_s(object);
|
||
|
if (value !== object) {
|
||
|
return value;
|
||
|
} else if (object instanceof Array) {
|
||
|
return '[...]';
|
||
|
} else {
|
||
|
return '{...}';
|
||
|
}
|
||
|
},
|
||
|
_try_to_s: function(object) {
|
||
|
switch (typeof object) {
|
||
|
case 'undefined':
|
||
|
case 'unknown': return 'undefined';
|
||
|
case 'string': return '"'+object+'"';
|
||
|
case 'number': return ''+object;
|
||
|
case 'function':
|
||
|
case 'boolean': return object.toString();
|
||
|
}
|
||
|
if (object === null) return 'null';
|
||
|
if (object.nodeType == 1)
|
||
|
return '<'+object.tagName+
|
||
|
(object.id ? ' id="'+object.id+'"':'')+
|
||
|
(object.className ? ' class="'+object.className+'"':'')+
|
||
|
(object.title ? ' title="'+object.title+'"':'')+
|
||
|
(object.type ? ' type="'+object.type+'"':'')+
|
||
|
'>'+object.innerHTML+'</'+object.tagName+'>';
|
||
|
return object;
|
||
|
},
|
||
|
get_object_class_name: function(object) {
|
||
|
if (object === null) { return 'Null'; }
|
||
|
switch (typeof object) {
|
||
|
case 'string': return 'String';
|
||
|
case 'boolean': return 'Boolean';
|
||
|
case 'number': return 'Number';
|
||
|
case 'function': return 'Function';
|
||
|
case 'object':
|
||
|
if (typeof object.constructor != 'undefined') {
|
||
|
var match = object.constructor.toString().match(/function\s*(\w+)/);
|
||
|
if (match && match.length == 2) {
|
||
|
return match[1];
|
||
|
}
|
||
|
for (var key in self) {
|
||
|
try {
|
||
|
if (object instanceof self[key])
|
||
|
return key;
|
||
|
} catch (e) {}
|
||
|
}
|
||
|
if (object instanceof Array) {
|
||
|
return 'Array';
|
||
|
} else {
|
||
|
return 'Object';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 'Unknown';
|
||
|
},
|
||
|
get_class_name: function(klass) {
|
||
|
if (klass === null) { return 'Null'; }
|
||
|
switch (klass) {
|
||
|
case String: return 'String';
|
||
|
case Boolean: return 'Boolean';
|
||
|
case Number: return 'Number';
|
||
|
case Function: return 'Function';
|
||
|
case Array: return 'Array';
|
||
|
case Object: return 'Object';
|
||
|
default:
|
||
|
for (var key in self) {
|
||
|
if (klass == self[key])
|
||
|
return key;
|
||
|
}
|
||
|
}
|
||
|
return 'Unknown';
|
||
|
},
|
||
|
Browser: {
|
||
|
IE: !!(window.attachEvent && !window.opera),
|
||
|
Opera: !!window.opera,
|
||
|
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
|
||
|
Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
|
||
|
MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/),
|
||
|
Konqueror: navigator.userAgent.indexOf('Konqueror') != -1
|
||
|
},
|
||
|
$: function(element) {
|
||
|
return typeof element == 'string' ? document.getElementById(element) : element;
|
||
|
},
|
||
|
$$: function(css_rule) {
|
||
|
return this.Element.select(document, css_rule);
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.Array = {
|
||
|
include: function(list, item) {
|
||
|
for (var i=0; i < list.length; i++)
|
||
|
if (list[i] == item)
|
||
|
return true;
|
||
|
return false;
|
||
|
},
|
||
|
merge: function(list1, list2) {
|
||
|
for (var i=0; i < list2.length; i++) {
|
||
|
if (!this.include(list1, list2[i]))
|
||
|
list1.push(list2[i]);
|
||
|
}
|
||
|
return list1;
|
||
|
},
|
||
|
without: function(list, item) {
|
||
|
var new_list = [];
|
||
|
for (var i=0; i < list.length; i++)
|
||
|
if (list[i] != item)
|
||
|
new_list.push(list[i]);
|
||
|
return new_list;
|
||
|
},
|
||
|
uniq: function(list) {
|
||
|
var new_list = [];
|
||
|
for (var i=0; i < list.length; i++)
|
||
|
if (!this.include(new_list, list[i]))
|
||
|
new_list.push(list[i]);
|
||
|
return new_list;
|
||
|
},
|
||
|
find: function(list, callback) {
|
||
|
for (var i=0; i < list.length; i++)
|
||
|
if (callback(list[i]))
|
||
|
return list[i];
|
||
|
return null;
|
||
|
},
|
||
|
each: function(list, callback) {
|
||
|
for (var i=0; i < list.length; i++)
|
||
|
callback(list[i]);
|
||
|
return list;
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.Event = {
|
||
|
KEY_UP: 38,
|
||
|
observe: function(element, name, callback) {
|
||
|
var element = TestCaseUtil.$(element);
|
||
|
if (element.addEventListener) {
|
||
|
element.addEventListener(name, callback, false);
|
||
|
} else {
|
||
|
element.attachEvent("on" + name, callback);
|
||
|
}
|
||
|
return element;
|
||
|
},
|
||
|
stop: function(event) {
|
||
|
if (event.stopPropagation) {
|
||
|
event.stopPropagation();
|
||
|
event.preventDefault();
|
||
|
} else {
|
||
|
event.cancelBubble = true;
|
||
|
event.returnValue = false;
|
||
|
}
|
||
|
},
|
||
|
element: function(event) {
|
||
|
var target = event.srcElement ? event.srcElement : event.target;
|
||
|
return (!target || target.nodeType == 1) ? target : target.parentNode;
|
||
|
},
|
||
|
pointerX: function(event) {
|
||
|
return this.pointer(event).x;
|
||
|
},
|
||
|
pointerY: function(event) {
|
||
|
return this.pointer(event).y;
|
||
|
},
|
||
|
pointer: function(event) {
|
||
|
return {
|
||
|
x: event.pageX || (event.clientX +
|
||
|
(document.documentElement.scrollLeft || document.body.scrollLeft)),
|
||
|
y: event.pageY || (event.clientY +
|
||
|
(document.documentElement.scrollTop || document.body.scrollTop))
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.Element = {
|
||
|
visible: function(element) {
|
||
|
return TestCaseUtil.$(element).style.display != 'none';
|
||
|
},
|
||
|
show: function(element) {
|
||
|
TestCaseUtil.$(element).style.display = '';
|
||
|
},
|
||
|
hide: function(element) {
|
||
|
TestCaseUtil.$(element).style.display = 'none';
|
||
|
},
|
||
|
toggle: function(element) {
|
||
|
if (this.visible(element))
|
||
|
this.hide(element);
|
||
|
else
|
||
|
this.show(element);
|
||
|
},
|
||
|
up: function(element, css_rule) {
|
||
|
return this.Selector.match_atom(element, css_rule) ? element :
|
||
|
(element.parentNode ? this.up(element.parentNode, css_rule) : null);
|
||
|
},
|
||
|
down: function(element, css_rule) {
|
||
|
return this.Selector.find_first(element, css_rule);
|
||
|
},
|
||
|
select: function(element, css_rule) {
|
||
|
return this.Selector.find_all(element, css_rule);
|
||
|
},
|
||
|
has_class_names: function(element, class_names) {
|
||
|
for (var i=0; i < class_names.length; i++)
|
||
|
if (!this.has_class_name(element, class_names[i]))
|
||
|
return false;
|
||
|
return true;
|
||
|
},
|
||
|
has_class_name: function(element, class_name) {
|
||
|
var elementClassName = element.className;
|
||
|
return (elementClassName && elementClassName.length > 0 && (elementClassName == class_name ||
|
||
|
new RegExp("(^|\\s)" + class_name + "(\\s|$)").test(elementClassName)));
|
||
|
},
|
||
|
add_class_name: function(element, class_name) {
|
||
|
if (!this.has_class_name(element, class_name))
|
||
|
element.className += (element.className ? ' ' : '') + class_name;
|
||
|
return element;
|
||
|
},
|
||
|
remove_class_name: function(element, class_name) {
|
||
|
element.className = element.className.replace(
|
||
|
new RegExp("(^|\\s+)" + class_name + "(\\s+|$)"), ' ').replace(/^\s+|\s+$/g, '');
|
||
|
return element;
|
||
|
},
|
||
|
has_attributes: function(element, attrs) {
|
||
|
for (key in attrs)
|
||
|
if (attrs[key] != null && element[key] != attrs[key])
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.Element.Selector = {
|
||
|
find_first: function(element, css_rule) {
|
||
|
var founds = this.find_all(element, css_rule);
|
||
|
return founds.length ? founds[0] : null;
|
||
|
},
|
||
|
find_all: function(element, css_rule) {
|
||
|
var founds = [], element = TestCaseUtil.$(element);
|
||
|
if (typeof css_rule == 'string')
|
||
|
css_rule = this._parse_rule(css_rule);
|
||
|
if (css_rule[0] instanceof Array) {
|
||
|
for (var i=0; i < css_rule.length; i++)
|
||
|
TestCaseUtil.Array.merge(founds, this.find_all(element, css_rule[i]));
|
||
|
} else {
|
||
|
var css_atom = css_rule.shift();
|
||
|
switch (css_atom.rel) {
|
||
|
case '>': founds = this._find_immidiate_descendants(element, css_atom); break;
|
||
|
case '+': founds = this._find_next_sibling(element, css_atom); break;
|
||
|
case '~': founds = this._find_late_siblings(element, css_atom); break;
|
||
|
default: founds = this._find_descendants(element, css_atom);
|
||
|
}
|
||
|
if (css_rule.length > 0) {
|
||
|
var sub_founds = [];
|
||
|
for (var i=0; i < founds.length; i++) {
|
||
|
var css_rule_clone = [];
|
||
|
for (var j=0; j < css_rule.length; j++)
|
||
|
css_rule_clone.push(TestCaseUtil.extend({}, css_rule[j]));
|
||
|
TestCaseUtil.Array.merge(sub_founds, this.find_all(founds[i], css_rule_clone));
|
||
|
}
|
||
|
founds = sub_founds;
|
||
|
}
|
||
|
}
|
||
|
return founds;
|
||
|
},
|
||
|
_find_descendants: function(element, css_atom, immidiates_only) {
|
||
|
var founds = [], child = element.firstChild;
|
||
|
while (child) {
|
||
|
if (child.nodeType == 1) {
|
||
|
if (this._fully_match_atom(child, css_atom, element) &&
|
||
|
!TestCaseUtil.Array.include(founds, child)) {
|
||
|
founds.push(child);
|
||
|
}
|
||
|
if (!immidiates_only)
|
||
|
TestCaseUtil.Array.merge(founds, this._find_descendants(child, css_atom));
|
||
|
}
|
||
|
child = child.nextSibling;
|
||
|
}
|
||
|
return founds;
|
||
|
},
|
||
|
_find_immidiate_descendants: function(element, css_atom) {
|
||
|
return this._find_descendants(element, css_atom, true);
|
||
|
},
|
||
|
_find_next_sibling: function(element, css_atom) {
|
||
|
var founds = [], node = element.nextSibling;
|
||
|
while (node) {
|
||
|
if (node.nodeType == 1) {
|
||
|
if (this._fully_match_atom(node, css_atom, element) &&
|
||
|
!TestCaseUtil.Array.include(founds, node))
|
||
|
founds.push(node);
|
||
|
break;
|
||
|
}
|
||
|
node = node.nextSibling;
|
||
|
}
|
||
|
return founds;
|
||
|
},
|
||
|
_find_late_siblings: function(element, css_atom) {
|
||
|
var founds = [], node = element.nextSibling;
|
||
|
while (node) {
|
||
|
if (node.nodeType == 1) {
|
||
|
if (this._fully_match_atom(node, css_atom, element) &&
|
||
|
!TestCaseUtil.Array.include(founds, node))
|
||
|
founds.push(node);
|
||
|
}
|
||
|
node = node.nextSibling;
|
||
|
}
|
||
|
return founds;
|
||
|
},
|
||
|
_fully_match_atom: function(element, css_atom, parent_node) {
|
||
|
return this.match_atom(element, css_atom) &&
|
||
|
this._match_pseudo(parent_node, element, css_atom.pseudo);
|
||
|
},
|
||
|
_match_pseudo: function(element, child, pseudo) {
|
||
|
switch (pseudo) {
|
||
|
case 'first-child': return this._is_first_child(element, child);
|
||
|
case 'last-child': return this._is_last_child(element, child);
|
||
|
case 'only-child': return this._is_only_child(element, child);
|
||
|
default: return true;
|
||
|
}
|
||
|
},
|
||
|
_is_first_child: function(element, child) {
|
||
|
var node = element.firstChild;
|
||
|
while (node) {
|
||
|
if (node.nodeType == 1)
|
||
|
return node == child;
|
||
|
node = node.nextSibling;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
_is_last_child: function(element, child) {
|
||
|
var node = element.lastChild;
|
||
|
while (node) {
|
||
|
if (node.nodeType == 1)
|
||
|
return node == child;
|
||
|
node = node.previousSibling;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
_is_only_child: function(element, child) {
|
||
|
var found = null, node = element.firstChild;
|
||
|
while (node) {
|
||
|
if (node.nodeType == 1) {
|
||
|
if (found)
|
||
|
return false;
|
||
|
else
|
||
|
found = node;
|
||
|
}
|
||
|
node = node.nextSibling;
|
||
|
}
|
||
|
return found == child;
|
||
|
},
|
||
|
match_atom: function(element, css_atom) {
|
||
|
if (typeof css_atom == 'string')
|
||
|
css_atom = TestCaseUtil.Element.Selector._parse_atom(css_atom);
|
||
|
return (css_atom.tag_name == '*' || element.tagName == css_atom.tag_name)
|
||
|
&& TestCaseUtil.Element.has_class_names(element, css_atom.class_names)
|
||
|
&& TestCaseUtil.Element.Selector._match_css_attributes(element, css_atom.attrs)
|
||
|
&& (!css_atom.id || element.id == css_atom.id);
|
||
|
},
|
||
|
_match_css_attributes: function(element, attrs_def) {
|
||
|
for (var i=0; i < attrs_def.length; i++) {
|
||
|
var match = false;
|
||
|
switch (attrs_def[i].type) {
|
||
|
case '|=':
|
||
|
match = (typeof element[attrs_def[i].name] == 'string') && (
|
||
|
element[attrs_def[i].name] == attrs_def[i].value ||
|
||
|
new RegExp("(^|\-)" + attrs_def[i].value + "(\-|$)").test(element[attrs_def[i].name])
|
||
|
);
|
||
|
break;
|
||
|
case '~=':
|
||
|
match = (typeof element[attrs_def[i].name] == 'string') && (
|
||
|
element[attrs_def[i].name] == attrs_def[i].value ||
|
||
|
new RegExp("(^|\\s)" + attrs_def[i].value + "(\\s|$)").test(element[attrs_def[i].name])
|
||
|
);
|
||
|
break;
|
||
|
default:
|
||
|
match = element[attrs_def[i].name] == attrs_def[i].value;
|
||
|
}
|
||
|
if (!match) return false;
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
_parse_rule: function(css_rule) {
|
||
|
var rules = css_rule.split(',');
|
||
|
var recognized_rules = [];
|
||
|
for (var i=0; i < rules.length; i++) {
|
||
|
var rule = rules[i].replace(/^\s+|\s+$/g, '');
|
||
|
var match, separator_pos, recognized_rule = [];
|
||
|
var relation = null;
|
||
|
while ((match = rule.match(/(\s*([~>+ ])\s*)[^=]/))) {
|
||
|
separator_pos = rule.indexOf(match[0]);
|
||
|
recognized_rule.push({
|
||
|
rule: rule.substring(0, separator_pos).replace(/^\s+|\s+$/g, ''),
|
||
|
rel: relation
|
||
|
});
|
||
|
relation = match[2];
|
||
|
rule = rule.substr(separator_pos+(match[1].length==1 ? 1 : match[1].length-1)).replace(/^\s+|\s+$/g, '');
|
||
|
}
|
||
|
recognized_rule.push({ rule: rule, rel: relation });
|
||
|
for (var j=0; j < recognized_rule.length; j++)
|
||
|
TestCaseUtil.extend(recognized_rule[j], this._parse_atom(recognized_rule[j].rule));
|
||
|
recognized_rules.push(recognized_rule);
|
||
|
}
|
||
|
return recognized_rules;
|
||
|
},
|
||
|
_id_re: /#[^\[\.]*/,
|
||
|
_attrs_re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/,
|
||
|
_parse_atom: function(rule) {
|
||
|
var atom = {
|
||
|
tag_name: '*',
|
||
|
id: null,
|
||
|
class_names: [],
|
||
|
pseudo: null,
|
||
|
attrs: []
|
||
|
};
|
||
|
var els = rule.split(':');
|
||
|
if (els.length > 1) {
|
||
|
atom.pseudo = els[1].toLowerCase();
|
||
|
rule = els[0];
|
||
|
}
|
||
|
while ((attr_match = rule.match(this._attrs_re))) {
|
||
|
atom.attrs.push({
|
||
|
name: attr_match[1],
|
||
|
type: attr_match[2],
|
||
|
value: attr_match[5]
|
||
|
});
|
||
|
rule = rule.replace(attr_match[0], '');
|
||
|
}
|
||
|
if ((id_match = rule.match(this._id_re))) {
|
||
|
atom.id = id_match[0].substr(1);
|
||
|
rule = rule.replace(id_match[0], '');
|
||
|
}
|
||
|
atom.class_names = rule.split('.');
|
||
|
atom.tag_name = atom.class_names.shift().toUpperCase();
|
||
|
if (atom.tag_name == '')
|
||
|
atom.tag_name = '*';
|
||
|
return atom;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.Diff = {
|
||
|
calc: function(obj1, obj2) {
|
||
|
if (TestCaseUtil.get_object_class_name(obj1) != TestCaseUtil.get_object_class_name(obj2))
|
||
|
throw "The given objects are instances of different classes";
|
||
|
if (obj1 == null || obj2 == null) throw "One of the objects is null";
|
||
|
if (obj1 == obj2) return [];
|
||
|
switch (typeof obj1) {
|
||
|
case 'string': return TestCaseUtil.Diff._string_diff.apply(TestCaseUtil.Diff, [obj1, obj2]);
|
||
|
case 'function': return TestCaseUtil.Diff._string_diff.apply(TestCaseUtil.Diff, [obj1.toString(), obj2.toString()]);
|
||
|
case 'boolean':
|
||
|
case 'number': return obj1 == obj2 ? [] : [{del: obj1}, {ins: obj2}];
|
||
|
default: return TestCaseUtil.Diff[obj1 instanceof Array ? '_array_diff' : '_object_diff'].apply(TestCaseUtil.Diff, [obj1, obj2]);
|
||
|
}
|
||
|
},
|
||
|
_string_diff: function(str1, str2) {
|
||
|
return this.__compact(
|
||
|
this.__calc_diff(str1.split("\n"), str2.split("\n")),
|
||
|
function (group, entry) { return group +"\n"+ entry; }
|
||
|
);
|
||
|
},
|
||
|
_array_diff: function(list1, list2) {
|
||
|
var diff = this.__calc_diff(list1, list2);
|
||
|
for (var i=0; i < diff.length; i++) {
|
||
|
var key = 'eql';
|
||
|
if (typeof diff[i]['del'] != 'undefined') {
|
||
|
key = 'del';
|
||
|
} else if (typeof diff[i]['ins'] != 'undefined') {
|
||
|
key = 'ins';
|
||
|
}
|
||
|
}
|
||
|
return diff;
|
||
|
},
|
||
|
_object_diff: function(obj1, obj2) {
|
||
|
var lists = [[], []], objects = [obj1, obj2];
|
||
|
for (var i=0; i < 2; i++) {
|
||
|
for (var key in objects[i]) {
|
||
|
lists[i].push( key+"{:_key-sep_:}"+TestCaseUtil.to_s(objects[i][key]) );
|
||
|
}
|
||
|
}
|
||
|
var diff = this.__calc_diff(lists[0], lists[1]);
|
||
|
var collect = { eql: {}, ins: {}, del: {} };
|
||
|
for (var i=0; i < diff.length; i++) {
|
||
|
var key = 'eql';
|
||
|
if (diff[i]['ins']) {
|
||
|
key = 'ins';
|
||
|
} else if (diff[i]['del']) {
|
||
|
key = 'del';
|
||
|
}
|
||
|
var a_key = diff[i][key].split("{:_key-sep_:}")[0];
|
||
|
collect[key][a_key] = (diff[i]['ins'] ? obj2 : obj1)[a_key];
|
||
|
}
|
||
|
var diff = [], keys = ['del', 'ins', 'eql'];
|
||
|
for (var i=0; i < keys.length; i++) {
|
||
|
if (!TestCaseUtil.equal(collect[keys[i]], {})) {
|
||
|
var el = {}; el[keys[i]] = collect[keys[i]];
|
||
|
diff.push(el);
|
||
|
}
|
||
|
}
|
||
|
return diff;
|
||
|
},
|
||
|
__calc_diff: function(first, second) {
|
||
|
var diff = [], start_k = 0;
|
||
|
for (var i=0; i < first.length; i++) {
|
||
|
var eql_found = false;
|
||
|
var inses = [];
|
||
|
for (var k=start_k; k < second.length; k++) {
|
||
|
if (TestCaseUtil.equal(first[i], second[k])) {
|
||
|
eql_found = second[k];
|
||
|
start_k = k+1;
|
||
|
break;
|
||
|
} else {
|
||
|
inses.push(second[k]);
|
||
|
}
|
||
|
}
|
||
|
if (eql_found) {
|
||
|
for (var j=0; j < inses.length; j++) {
|
||
|
diff.push({ins: inses[j]});
|
||
|
}
|
||
|
diff.push({eql: eql_found});
|
||
|
} else {
|
||
|
diff.push({del: first[i]});
|
||
|
}
|
||
|
}
|
||
|
for (var k=start_k; k < second.length; k++) {
|
||
|
diff.push({ins: second[k]});
|
||
|
}
|
||
|
var only_eqls = true;
|
||
|
for (var i=0; i < diff.length; i++) {
|
||
|
if (diff[i]['del'] || diff[i]['ins']) {
|
||
|
only_eqls = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return only_eqls ? [] : diff;
|
||
|
},
|
||
|
__compact: function(diff, compactor) {
|
||
|
if (diff.length == 0) { return diff; }
|
||
|
var c_diff = [];
|
||
|
var last_o = diff[0];
|
||
|
for (var i=1; i < diff.length; i++) {
|
||
|
var key = 'eql';
|
||
|
if (typeof diff[i]['ins'] != 'undefined') {
|
||
|
key = 'ins';
|
||
|
} else if (typeof diff[i]['del'] != 'undefined') {
|
||
|
key = 'del';
|
||
|
}
|
||
|
if (typeof last_o[key] != 'undefined') {
|
||
|
last_o[key] = compactor(last_o[key], diff[i][key]);
|
||
|
} else {
|
||
|
c_diff.push(last_o);
|
||
|
last_o = diff[i];
|
||
|
}
|
||
|
}
|
||
|
c_diff.push(last_o);
|
||
|
return c_diff;
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.Cookie = {
|
||
|
enabled: function() {
|
||
|
document.cookie = "test_cookie=test";
|
||
|
return document.cookie.indexOf("test_cookie=test")!=-1;
|
||
|
},
|
||
|
set: function(key, value, keep_days) {
|
||
|
if (keep_days) {
|
||
|
var date = new Date();date.setTime(date.getTime()+(100*24*60*60*1000));
|
||
|
}
|
||
|
document.cookie = key+"="+escape(value)+(keep_days ? "; expires="+date.toGMTString() : "");
|
||
|
},
|
||
|
get: function(key) {
|
||
|
var value = '', pairs = document.cookie.split(";");
|
||
|
for (var i=0; i < pairs.length; i++) {
|
||
|
var pair = pairs[i].split('=');
|
||
|
if (pair.length == 2 && pair[0].replace(/^\s+|\s+$/g, '') == key)
|
||
|
value = pair[1].replace(/^\s+|\s+$/g, '');
|
||
|
}
|
||
|
return unescape(value);
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
var TestCase = TestCaseUtil.create_class();
|
||
|
TestCaseUtil.extend(TestCase, {
|
||
|
version: "2.0.2",
|
||
|
create: function(defs) {
|
||
|
var Test = TestCaseUtil.create_class();
|
||
|
TestCaseUtil.extend(Test, TestCase);
|
||
|
Test.prototype = new TestCase();
|
||
|
Test.extend = function(entries) {
|
||
|
TestCaseUtil.extend(this.prototype, entries);
|
||
|
this.wire_custom_assertions(entries);
|
||
|
};
|
||
|
Test.extend(defs || {});
|
||
|
return Test;
|
||
|
}
|
||
|
});
|
||
|
TestCaseUtil.extend(TestCase.prototype, {
|
||
|
name: null,
|
||
|
title: null,
|
||
|
size: 0,
|
||
|
failed: 0,
|
||
|
passed: 0,
|
||
|
assertions: 0,
|
||
|
initialize: function(title) {
|
||
|
this.title = (this.name || "Unnamed Test") + (title ? ": "+title : "");
|
||
|
this.size = 0;
|
||
|
this.passed = 0;
|
||
|
this.assertations = 0;
|
||
|
for (key in this) {
|
||
|
if (key.substring(0, 4) == "test") {
|
||
|
this.size ++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Starter = {
|
||
|
run: function(title) {
|
||
|
var test = this._get_test_instance();
|
||
|
this._register_test(test);
|
||
|
test.passed = 0;
|
||
|
test.failed = 0;
|
||
|
test.assertions = 0;
|
||
|
if (this.reporter && this.reporter.ui_builder &&
|
||
|
this.reporter.ui_builder.test_is_skipped(test)) {
|
||
|
test.skipped = true;
|
||
|
this.reporter.ui_builder.create_summary_report(this.reporter.current_test_block, test);
|
||
|
return test;
|
||
|
}
|
||
|
this._call_before_all(test);
|
||
|
try {
|
||
|
var test_names = this._get_test_methods(test);
|
||
|
for (var i=0; i < test_names.length; i++) {
|
||
|
var name = test_names[i];
|
||
|
this._report_test_started(name);
|
||
|
this._call_setup(test);
|
||
|
test.manual_failure = null;
|
||
|
var test_start_assertion_num = test.assertions;
|
||
|
try {
|
||
|
test[name]();
|
||
|
if (test.manual_failure)
|
||
|
throw new TestCase.Exception(test.manual_failure);
|
||
|
test.passed++;
|
||
|
this._report_test_passed(name);
|
||
|
} catch (e) {
|
||
|
if (e instanceof TestCase.Exception) {
|
||
|
test.failed++;
|
||
|
this._report_failed(name, e, test.assertions - test_start_assertion_num + 1);
|
||
|
} else {
|
||
|
throw e;
|
||
|
}
|
||
|
} finally {
|
||
|
this._call_teardown(test);
|
||
|
}
|
||
|
}
|
||
|
} finally {
|
||
|
this._call_after_all(test);
|
||
|
}
|
||
|
return test;
|
||
|
},
|
||
|
run_on_load: function() {
|
||
|
var $this = this;
|
||
|
TestCaseUtil.Event.observe(window, 'load', function() {
|
||
|
$this.run();
|
||
|
});
|
||
|
},
|
||
|
_get_test_instance: function(title) {
|
||
|
if (typeof this == 'object') {
|
||
|
var test = this;
|
||
|
} else {
|
||
|
var Test = this;
|
||
|
var test = new Test(title);
|
||
|
}
|
||
|
return test;
|
||
|
},
|
||
|
_get_test_methods: function(test) {
|
||
|
var test_method_names = [];
|
||
|
for (key in test)
|
||
|
if (key.substring(0, 4) == "test" && typeof test[key] == 'function')
|
||
|
test_method_names.push(key);
|
||
|
if (navigator.userAgent.indexOf("MSIE") != -1) { test_method_names.reverse(true); }
|
||
|
return test_method_names;
|
||
|
},
|
||
|
_call_setup: function(test) {
|
||
|
if (test['setup']) test.setup.apply(test);
|
||
|
else if (test['setUp']) test.setUp.apply(test);
|
||
|
},
|
||
|
_call_teardown: function(test) {
|
||
|
if (test['teardown']) test.teardown.apply(test);
|
||
|
else if (test['tearDown']) test.tearDown.apply(test);
|
||
|
},
|
||
|
_call_before_all: function(test) {
|
||
|
if (test['before_all']) test.before_all.apply(test);
|
||
|
else if (test['beforeAll']) test.beforeAll.apply(test);
|
||
|
},
|
||
|
_call_after_all: function(test) {
|
||
|
if (test['after_all']) test.after_all.apply(test);
|
||
|
else if (test['afterAll']) test.afterAll.apply(test);
|
||
|
},
|
||
|
_register_test: function(test) {
|
||
|
if (this.reporter) { this.reporter.register(test); }
|
||
|
},
|
||
|
_report_test_started: function(test_name) {
|
||
|
if (this.reporter) { this.reporter.test_started(test_name); }
|
||
|
},
|
||
|
_report_test_passed: function(test_name) {
|
||
|
if (this.reporter) { this.reporter.test_passed(test_name); }
|
||
|
},
|
||
|
_report_failed: function(test_name, error, assertion_num) {
|
||
|
if (this.reporter) {
|
||
|
this.reporter.test_failed(test_name, error, assertion_num);
|
||
|
} else {
|
||
|
throw error;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Mocking = {
|
||
|
mock: function(object, name, mock) {
|
||
|
if (!object[name]) throw "The object have no method '"+name+"' to mock it up";
|
||
|
var o_mocks = TestCase.Mocking._get_mocks_of(object);
|
||
|
o_mocks[name] = o_mocks[name] || object[name];
|
||
|
return object[name] = mock;
|
||
|
},
|
||
|
undo_mock: function(object, name) {
|
||
|
if (this._has_mock_for(object, name)) {
|
||
|
var o_mocks = TestCase.Mocking._get_mocks_of(object);
|
||
|
if (o_mocks[name]) {
|
||
|
object[name] = o_mocks[name];
|
||
|
o_mocks[name] = null;
|
||
|
}
|
||
|
}
|
||
|
return object[name];
|
||
|
},
|
||
|
with_mock: function(object, name, mock, func, scope) {
|
||
|
this.mock(object, name, mock);
|
||
|
try {
|
||
|
func.apply(scope);
|
||
|
} finally {
|
||
|
this.undo_mock(object, name);
|
||
|
}
|
||
|
},
|
||
|
mock_effects: function() {
|
||
|
this._run_if_mockable('mock_effects');
|
||
|
},
|
||
|
undo_effects_mock: function() {
|
||
|
this._run_if_mockable('undo_effects_mock');
|
||
|
},
|
||
|
with_effects_mock: function(func, scope) {
|
||
|
this.mock_effects();
|
||
|
try {
|
||
|
func.apply(scope);
|
||
|
} finally {
|
||
|
this.undo_effects_mock();
|
||
|
}
|
||
|
},
|
||
|
mock_ajax: function(options) {
|
||
|
this._run_if_mockable('mock_ajax', options);
|
||
|
},
|
||
|
undo_ajax_mock: function() {
|
||
|
this._run_if_mockable('undo_ajax_mock');
|
||
|
},
|
||
|
with_ajax_mock: function(options, func, scope) {
|
||
|
this.mock_ajax();
|
||
|
try {
|
||
|
func.apply(scope);
|
||
|
} finally {
|
||
|
this.undo_ajax_mock();
|
||
|
}
|
||
|
},
|
||
|
__mock_ups: [],
|
||
|
_get_mocks_of: function(object) {
|
||
|
var o_mocks = null;
|
||
|
var mockups = TestCase.Mocking.__mock_ups;
|
||
|
for (var i=0; i < mockups.length; i++) {
|
||
|
if (mockups[i]['object'] == object) {
|
||
|
o_mocks = mockups[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!o_mocks) {
|
||
|
o_mocks = {
|
||
|
'object': object, 'mocks': {}
|
||
|
};
|
||
|
TestCase.Mocking.__mock_ups.push(o_mocks);
|
||
|
}
|
||
|
return o_mocks['mocks'];
|
||
|
},
|
||
|
_has_mock_for: function(object, name) {
|
||
|
var mockups = TestCase.Mocking.__mock_ups;
|
||
|
for (var i=0; i < mockups.length; i++) {
|
||
|
if (mockups[i]['object'] == object) {
|
||
|
return typeof mockups[i]['mocks'][name] != 'undefined' && mockups[i]['mocks'][name] != null;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
_mockable_libs: ['Prototype', 'MooTools', 'jQuery'],
|
||
|
_run_if_mockable: function() {
|
||
|
var args = TestCaseUtil.to_a(arguments);
|
||
|
var method_name = args.shift();
|
||
|
if (method_name == 'mock_ajax') {
|
||
|
this._raw_mockup_ajax.apply(this, args);
|
||
|
} else if (method_name == 'undo_ajax_mock') {
|
||
|
this._raw_undo_ajax_mockup();
|
||
|
}
|
||
|
for (var i=0; i < this._mockable_libs.length; i++) {
|
||
|
if (self[this._mockable_libs[i]]) {
|
||
|
return this[this._mockable_libs[i]][method_name].apply(this[this._mockable_libs[i]], args);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
_raw_mockup_ajax: function(params) {
|
||
|
if (TestCaseUtil.Browser.IE) {
|
||
|
this.__ms_raw_ajax_mock(params);
|
||
|
} else {
|
||
|
this.__w3c_raw_ajax_mock(params);
|
||
|
}
|
||
|
},
|
||
|
__w3c_raw_ajax_mock: function(params) {
|
||
|
if (!(new XMLHttpRequest instanceof TestCase.Mocking.FakeXMLHttpRequest)) {
|
||
|
this.mock(self, 'XMLHttpRequest', function() {
|
||
|
return new TestCase.Mocking.FakeXMLHttpRequest(params);
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
__ms_raw_ajax_mock: function(params) {
|
||
|
if (!(new ActiveXObject('Msxml2.XMLHTTP') instanceof TestCase.Mocking.FakeXMLHttpRequest)) {
|
||
|
var _ = ActiveXObject;
|
||
|
this.mock(self, 'ActiveXObject', function(param) {
|
||
|
if (param.indexOf('XMLHTTP') != -1) {
|
||
|
return new TestCase.Mocking.FakeXMLHttpRequest(params);
|
||
|
} else {
|
||
|
return new _(param);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
_raw_undo_ajax_mockup: function() {
|
||
|
if (TestCaseUtil.Browser.IE) {
|
||
|
this.undo_mock(self, 'ActiveXObject');
|
||
|
} else {
|
||
|
this.undo_mock(self, 'XMLHttpRequest');
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Mocking.FakeXMLHttpRequest = TestCaseUtil.create_class({
|
||
|
onreadystatechange: null,
|
||
|
readyState: null,
|
||
|
status: null,
|
||
|
statusText: null,
|
||
|
responseText: null,
|
||
|
responseXML: null,
|
||
|
fakeData: null,
|
||
|
initialize: function(options) {
|
||
|
this.fakeData = TestCaseUtil.extend({
|
||
|
status: 200,
|
||
|
xml: null,
|
||
|
text: '',
|
||
|
headers: {}
|
||
|
}, options || {});
|
||
|
this.onreadystatechange = function() {};
|
||
|
this.readyState = 0;
|
||
|
},
|
||
|
__onSend: function() {
|
||
|
this.readyState = 2;
|
||
|
this.status = this.fakeData.status;
|
||
|
this.onreadystatechange();
|
||
|
this.readyState = 3;
|
||
|
this.responseText = '';
|
||
|
this.onreadystatechange();
|
||
|
this.readyState = 4;
|
||
|
this.responseText = this.fakeData.text;
|
||
|
this.responseXML = this.fakeData.xml;
|
||
|
this.onreadystatechange();
|
||
|
},
|
||
|
open: function(method, url, async, user, password) {
|
||
|
this.readyState = 1;
|
||
|
},
|
||
|
send: function(body) {
|
||
|
this.__onSend();
|
||
|
},
|
||
|
setRequestHeader: function(name, value) {
|
||
|
},
|
||
|
getResponseHeader: function(name) {
|
||
|
for (var key in this.fakeData.headers) {
|
||
|
if (key.toLowerCase() == name.toLowerCase())
|
||
|
return this.fakeData.headers[key];
|
||
|
}
|
||
|
return null;
|
||
|
},
|
||
|
getAllResponseHeaders: function() {
|
||
|
var headers = [];
|
||
|
for (var key in this.fakeData.headers) {
|
||
|
headers.push(key+": "+this.fakeData.headers[key]);
|
||
|
}
|
||
|
return headers.join("\n\n");
|
||
|
},
|
||
|
overrideMimeType: function(mimetype) {},
|
||
|
addEventListener: function(type, listener, useCapture) {},
|
||
|
removeEventListener: function(type, listener, useCapture) {},
|
||
|
dispatchEvent: function(event) {},
|
||
|
dispatchException: function(e) {
|
||
|
throw e;
|
||
|
},
|
||
|
abort: function() {}
|
||
|
});
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Mocking.Prototype = {
|
||
|
hide_effects: ['Fade', 'SlideUp', 'BlindUp', 'SwitchOff'],
|
||
|
show_effects: ['Appear', 'SlideDown', 'BlindDown', 'Grow'],
|
||
|
mock_effects: function() {
|
||
|
if (!self['Effect']) return false;
|
||
|
for (var i=0; i < this.hide_effects.length; i++) {
|
||
|
TestCase.mock(Effect, this.hide_effects[i], function(element, options) {
|
||
|
Element.hide(element);
|
||
|
if (options.afterFinish) options.afterFinish();
|
||
|
return element;
|
||
|
});
|
||
|
TestCase.mock(Effect, this.show_effects[i], function(element, options) {
|
||
|
Element.show(element);
|
||
|
if (options.afterFinish) options.afterFinish();
|
||
|
return element;
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
undo_effects_mock: function() {
|
||
|
if (!self['Effect']) return false;
|
||
|
for (var i=0; i < this.hide_effects.length; i++) {
|
||
|
TestCase.undo_mock(Effect, this.hide_effects[i]);
|
||
|
TestCase.undo_mock(Effect, this.show_effects[i]);
|
||
|
}
|
||
|
},
|
||
|
mock_ajax: function(options) {
|
||
|
if (!self['Ajax']) { return false; }
|
||
|
TestCase.mock(Ajax, 'getTransport', function() {
|
||
|
return new TestCase.Mocking.FakeXMLHttpRequest(options);
|
||
|
});
|
||
|
},
|
||
|
undo_ajax_mock: function() {
|
||
|
if (!self['Ajax']) { return false; }
|
||
|
TestCase.undo_mock(Ajax, 'getTransport');
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Mocking.MooTools = {
|
||
|
mock_effects: function() {
|
||
|
if (!self['Fx']) { return false; }
|
||
|
if (Fx['Tween']) {
|
||
|
TestCase.mock(Fx.Tween.prototype, 'start', function(property, from, to) {
|
||
|
this.onStart();
|
||
|
this.set(property, from);
|
||
|
if (to) {
|
||
|
this.set(property, to);
|
||
|
}
|
||
|
this.onComplete();
|
||
|
});
|
||
|
}
|
||
|
if (Fx['Morph']) {
|
||
|
TestCase.mock(Fx.Morph.prototype, 'start', function(properties) {
|
||
|
this.onStart();
|
||
|
var from = {}, to = {};
|
||
|
for (var key in properties) {
|
||
|
if (properties[key] instanceof Array) {
|
||
|
from[key] = properties[key][0];
|
||
|
to[key] = properties[key][1];
|
||
|
} else {
|
||
|
from[key] = properties[key];
|
||
|
}
|
||
|
}
|
||
|
this.set(from);
|
||
|
if (!TestCaseUtil.equal(to, {})) {
|
||
|
this.set(to);
|
||
|
}
|
||
|
this.onComplete();
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
undo_effects_mock: function() {
|
||
|
if (!self['Fx']) { return false; }
|
||
|
if (Fx['Tween']) TestCase.undo_mock(Fx.Tween.prototype, 'start');
|
||
|
if (Fx['Morph']) TestCase.undo_mock(Fx.Morph.prototype, 'start');
|
||
|
},
|
||
|
mock_ajax: function(options) {
|
||
|
if (!self['Request']) { return false; }
|
||
|
var old_initialize = Request.prototype.initialize;
|
||
|
TestCase.mock(Request.prototype, 'initialize', function() {
|
||
|
old_initialize.apply(this, arguments);
|
||
|
this.xhr = new TestCase.Mocking.FakeXMLHttpRequest(options);
|
||
|
});
|
||
|
},
|
||
|
undo_ajax_mock: function() {
|
||
|
if (!self['Request']) { return false; }
|
||
|
TestCase.undo_mock(Request.prototype, 'initialize');
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Mocking.jQuery = {
|
||
|
mock_effects: function() {
|
||
|
},
|
||
|
undo_effects_mock: function() {
|
||
|
},
|
||
|
mock_ajax: function(options) {
|
||
|
},
|
||
|
undo_ajax_mock: function() {
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Fires = {
|
||
|
FIRES_DEFAULT_MOUSE_EVENT_OPTIONS: {
|
||
|
pointerX: 0,
|
||
|
pointerY: 0,
|
||
|
button: 0,
|
||
|
bubbles: true,
|
||
|
cancelable: true,
|
||
|
altKey: false,
|
||
|
ctrlKey: false,
|
||
|
shiftKey: false,
|
||
|
metaKey: false
|
||
|
},
|
||
|
FIRES_DEFAULT_KEYBOARD_EVENT_OPTIONS: {
|
||
|
keyCode: 0,
|
||
|
charCode: 0,
|
||
|
bubbles: true,
|
||
|
cancelable: true,
|
||
|
altKey: false,
|
||
|
ctrlKey: false,
|
||
|
shiftKey: false,
|
||
|
metaKey: false
|
||
|
},
|
||
|
fire_mouse_event: function(element, eventName, options) {
|
||
|
return this._fire_event(this._$(element),
|
||
|
this._create_mouse_event(this._$(element), eventName, options)
|
||
|
);
|
||
|
},
|
||
|
fire_key_event: function(element, eventName, keyCode, options) {
|
||
|
return this._fire_event(this._$(element),
|
||
|
this._create_key_event(this._$(element), eventName,
|
||
|
TestCaseUtil.extend((options || {}), {keyCode: keyCode, charCode: keyCode})
|
||
|
)
|
||
|
);
|
||
|
},
|
||
|
fire_click: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'click', options);
|
||
|
},
|
||
|
fire_middle_click: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'middleclick', TestCaseUtil.extend({button: 1}, options || {}));
|
||
|
},
|
||
|
fire_right_click: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'rightclick', TestCaseUtil.extend({button: 2}, options || {}));
|
||
|
},
|
||
|
fire_double_click: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'dblclick', options);
|
||
|
},
|
||
|
fire_mouse_down: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'mousedown', options);
|
||
|
},
|
||
|
fire_mouse_up: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'mouseup', options);
|
||
|
},
|
||
|
fire_mouse_over: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'mouseover', options);
|
||
|
},
|
||
|
fire_mouse_out: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'mouseout', options);
|
||
|
},
|
||
|
fire_mouse_move: function(element, options) {
|
||
|
return this.fire_mouse_event(element, 'mousemove', options);
|
||
|
},
|
||
|
fire_key_press: function(element, key, options) {
|
||
|
return this.fire_key_event(element, 'keypress', key, options);
|
||
|
},
|
||
|
fire_key_down: function(element, key, options) {
|
||
|
return this.fire_key_event(element, 'keydown', key, options);
|
||
|
},
|
||
|
fire_key_up: function(element, key, options) {
|
||
|
return this.fire_key_event(element, 'keyup', key, options);
|
||
|
},
|
||
|
_$: function(element) {
|
||
|
element = TestCaseUtil.$(element);
|
||
|
if (element == document && document.createEvent && !element.dispatchEvent)
|
||
|
element = document.documentElement;
|
||
|
return element;
|
||
|
},
|
||
|
_fire_event: function(element, event) {
|
||
|
if (document.createEvent) {
|
||
|
element.dispatchEvent(event);
|
||
|
} else {
|
||
|
if (TestCaseUtil.Element.up(element, 'body')) {
|
||
|
if (event.eventType != 'onmiddleclick')
|
||
|
element.fireEvent(event.eventType, event);
|
||
|
} else {
|
||
|
this.fail("Please put your element on the page to fire an event on it in IE");
|
||
|
}
|
||
|
}
|
||
|
return event;
|
||
|
},
|
||
|
_create_mouse_event: function(element, eventName, options) {
|
||
|
return (document.createEvent ? this._create_w3c_mouse_event : this._create_ie_mouse_event).apply(
|
||
|
this, [element, eventName, TestCaseUtil.extend(this.FIRES_DEFAULT_MOUSE_EVENT_OPTIONS, options || {})]);
|
||
|
},
|
||
|
_create_w3c_mouse_event: function(element, eventName, options) {
|
||
|
var event = document.createEvent("MouseEvents");
|
||
|
event.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
|
||
|
eventName == 'dblclick' ? 2 : 1, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
|
||
|
options.ctrlKey, options.altKey, options.shiftKey, options.metakey, options.button, element
|
||
|
);
|
||
|
event.eventName = eventName;
|
||
|
return event;
|
||
|
},
|
||
|
_create_ie_mouse_event: function(element, eventName, options) {
|
||
|
var event = this._create_ie_event(eventName, options);
|
||
|
event.clientX = options.pointerX;
|
||
|
event.clientY = options.pointerY;
|
||
|
event.button = options.button == 1 ? 4 : options.button;
|
||
|
return event;
|
||
|
},
|
||
|
_create_key_event: function(element, eventName, options) {
|
||
|
return (document.createEvent ? this._create_w3c_keyboard_event : this._create_ie_keyboard_event).apply(
|
||
|
this, [eventName, TestCaseUtil.extend(this.FIRES_DEFAULT_KEYBOARD_EVENT_OPTIONS, options || {})]);
|
||
|
},
|
||
|
_create_w3c_keyboard_event: function(eventName, options) {
|
||
|
return (TestCaseUtil.Browser.Gecko ? this._create_gecko_keyboard_event : (
|
||
|
TestCaseUtil.Browser.WebKit ? this._create_webkit_keyboard_event : this._create_dom2_ui_event
|
||
|
)).apply(this, [eventName, options]);
|
||
|
},
|
||
|
_create_gecko_keyboard_event: function(eventName, options) {
|
||
|
var event = document.createEvent("KeyboardEvent");
|
||
|
event.initKeyEvent(eventName,
|
||
|
options.bubbles, options.cancelable, document.defaultView,
|
||
|
options.ctrlKey, options.altKey, options.shiftKey, options.metakey,
|
||
|
options.keyCode, options.charCode
|
||
|
);
|
||
|
event.eventName = eventName;
|
||
|
return event;
|
||
|
},
|
||
|
_create_webkit_keyboard_event: function(eventName, options) {
|
||
|
var event = document.createEvent("KeyboardEvent");
|
||
|
event.initKeyboardEvent(eventName,
|
||
|
options.bubbles, options.cancelable, document.defaultView,
|
||
|
null, 0,
|
||
|
options.ctrlKey, options.altKey, options.shiftKey, options.metakey
|
||
|
);
|
||
|
event.eventName = eventName;
|
||
|
return event;
|
||
|
},
|
||
|
_create_dom2_ui_event: function(eventName, options) {
|
||
|
var event = document.createEvent("UIEvent");
|
||
|
event.initUIEvent(eventName, options.bubbles, options.cancelable, document.defaultView, 1);
|
||
|
event.keyCode = options.keyCode;
|
||
|
event.charCode = options.charCode;
|
||
|
event.altKey = options.altKey;
|
||
|
event.metaKey = options.metaKey;
|
||
|
event.ctrlKey = options.ctrlKey;
|
||
|
event.shiftKey = options.shiftKey;
|
||
|
event.eventName = eventName;
|
||
|
return event;
|
||
|
},
|
||
|
_create_ie_keyboard_event: function(eventName, options) {
|
||
|
var event = this._create_ie_event(eventName, options);
|
||
|
event.keyCode = options.keyCode;
|
||
|
return event;
|
||
|
},
|
||
|
_create_ie_event: function(eventName, options) {
|
||
|
var event = document.createEventObject();
|
||
|
event.eventName = eventName == 'rightclick' ? 'contextmenu' : eventName;
|
||
|
event.type = event.eventType = "on" + event.eventName;
|
||
|
event.altKey = options.altKey;
|
||
|
event.ctrlKey = options.ctrlKey;
|
||
|
event.shiftKey = options.shiftKey;
|
||
|
return event;
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Exception = TestCaseUtil.create_class(Error, {
|
||
|
test: null,
|
||
|
assertion: null,
|
||
|
message: null,
|
||
|
initialize: function(test, assertion, message) {
|
||
|
this.test = test;
|
||
|
this.assertion = assertion;
|
||
|
this.message = message;
|
||
|
},
|
||
|
toString: function() {
|
||
|
return "TestCase.Exception: "+this.message;
|
||
|
}
|
||
|
});
|
||
|
TestCase.ProblemException = TestCaseUtil.create_class(TestCase.Exception, {
|
||
|
problem: null,
|
||
|
initialize: function(test, assertion, problem, message) {
|
||
|
this.test = test;
|
||
|
this.assertion = assertion;
|
||
|
this.problem = problem;
|
||
|
this.message = message;
|
||
|
},
|
||
|
toString: function() {
|
||
|
return "TestCase.ProblemException: "+this.problem+(this.message ? " ("+this.message+")" : "");
|
||
|
}
|
||
|
});
|
||
|
TestCase.WrongValueException = TestCaseUtil.create_class(TestCase.Exception, {
|
||
|
expected: null,
|
||
|
received: null,
|
||
|
format: false,
|
||
|
initialize: function(test, assertion, expected, received, message, format) {
|
||
|
this.test = test;
|
||
|
this.assertion = assertion;
|
||
|
this.expected = expected;
|
||
|
this.received = received;
|
||
|
this.message = message;
|
||
|
this.format = format;
|
||
|
},
|
||
|
toString: function() {
|
||
|
return "TestCase.WrongValueException: "+this.expected+" -> "+this.received;
|
||
|
}
|
||
|
});
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Messaging = {
|
||
|
fail: function(message) {
|
||
|
this.manual_failure = message;
|
||
|
throw new TestCase.Exception(this, this._last_assertion(), message);
|
||
|
},
|
||
|
debug: function(variable) {
|
||
|
alert(TestCaseUtil.debug(variable));
|
||
|
},
|
||
|
throw_problem: function(error, message) {
|
||
|
throw new TestCase.ProblemException(this, this._last_assertion(), error, message);
|
||
|
},
|
||
|
throw_unexp: function(expected, received, message, format) {
|
||
|
throw new TestCase.WrongValueException(this, this._last_assertion(), expected, received, message, format);
|
||
|
},
|
||
|
_last_assertion: function() {
|
||
|
return this['assert_'+this.last_assert_name];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.Assertions = {
|
||
|
assert_true: function(value, message) {
|
||
|
if (!value)
|
||
|
this.throw_unexp(true, value, message);
|
||
|
},
|
||
|
assert_false: function(value, message) {
|
||
|
if (value)
|
||
|
this.throw_unexp(false, value, message);
|
||
|
},
|
||
|
assert_null: function(value, message) {
|
||
|
if (value != null)
|
||
|
this.throw_unexp(null, value, message);
|
||
|
},
|
||
|
assert_not_null: function(value, message) {
|
||
|
if (value == null)
|
||
|
this.throw_problem("The value is null", message);
|
||
|
},
|
||
|
assert_type_of: function(type, value, message) {
|
||
|
if (typeof(value) != type)
|
||
|
this.throw_unexp(type.toLowerCase(), typeof(value), message);
|
||
|
},
|
||
|
assert_instance_of: function(type, value, message) {
|
||
|
if (!(value instanceof type))
|
||
|
this.throw_unexp(TestCaseUtil.get_class_name(type), TestCaseUtil.get_object_class_name(value), message);
|
||
|
},
|
||
|
assert_equal: function(expected, testing, message) {
|
||
|
if (!TestCaseUtil.equal(expected, testing))
|
||
|
this.throw_unexp(expected, testing, message, true);
|
||
|
},
|
||
|
assert_not_equal: function(expected, testing, message) {
|
||
|
if (TestCaseUtil.equal(expected, testing))
|
||
|
this.throw_problem("Received values are equal", message);
|
||
|
},
|
||
|
assert_same: function(expected, testing, message) {
|
||
|
if (expected != testing)
|
||
|
this.throw_problem("Values do not point to the same object", message);
|
||
|
},
|
||
|
assert_not_same: function(expected, testing, message) {
|
||
|
if (expected == testing)
|
||
|
this.throw_problem("Values point to the same object", message);
|
||
|
},
|
||
|
assert_match: function(pattern, string, message) {
|
||
|
if( !string.match(pattern) )
|
||
|
this.throw_problem("'"+string+"' doesn't match '"+pattern+"'", message);
|
||
|
},
|
||
|
assert_not_match: function(pattern, string, message) {
|
||
|
if( string.match(pattern) )
|
||
|
this.throw_problem("'"+string+"' match '"+pattern+"'", message);
|
||
|
},
|
||
|
assert_throws: function() {
|
||
|
var params = this._assert_throw_params.apply(this, arguments);
|
||
|
var catched = true;
|
||
|
try { params.callback.apply(params.scope_element);
|
||
|
catched = false;
|
||
|
} catch (e) { catched = e; }
|
||
|
if (!catched)
|
||
|
this.throw_problem('No exception raised during the call', params.message);
|
||
|
else if (params.exception_type) {
|
||
|
if (!this._type_of(catched, params.exception_type))
|
||
|
this.throw_unexp("Exception with type of: "+params.exception_type, catched, params.message);
|
||
|
}
|
||
|
},
|
||
|
assert_nothing_thrown: function() {
|
||
|
var params = this._assert_throw_params.apply(this, arguments);
|
||
|
try { params.callback.apply(params.scope_element);
|
||
|
} catch (e) {
|
||
|
if (params.exception_type) {
|
||
|
if (this._type_of(e, params.exception_type))
|
||
|
this.throw_problem("Unexpected exception with type '"+params.exception_type+
|
||
|
"' has been raised: \""+e.toString()+"\"", params.message);
|
||
|
} else {
|
||
|
this.throw_problem('Unexpected exception has been raised: "'+e.toString()+'"', params.message);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
_assert_throw_params: function() {
|
||
|
var params = typeof arguments[1] == 'function' ?
|
||
|
{ exception_type: arguments[0], callback: arguments[1]} :
|
||
|
{ callback: arguments[0]};
|
||
|
params.message = null;
|
||
|
for (var i=0; i < arguments.length; i++)
|
||
|
if (arguments[i].scope)
|
||
|
params.scope_element = arguments[i].scope;
|
||
|
if (arguments.length > 1) {
|
||
|
for (var i=arguments.length-1; i > 0; i--) {
|
||
|
if (arguments[i] == params.callback) {
|
||
|
break;
|
||
|
} else if (typeof arguments[i] == 'string') {
|
||
|
params.message = arguments[i];
|
||
|
} else if (typeof params.scope_element == 'undefined') {
|
||
|
params.scope_element = arguments[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return params;
|
||
|
},
|
||
|
_type_of: function(object, _type) {
|
||
|
switch(_type) {
|
||
|
case 'number':
|
||
|
case Number: return typeof object == 'number';
|
||
|
case 'string':
|
||
|
case String: return typeof object == 'string';
|
||
|
default: return object instanceof _type;
|
||
|
}
|
||
|
},
|
||
|
assert_called: function() {
|
||
|
var problems = [];
|
||
|
this._execute_wrapped_call(arguments, problems,
|
||
|
function(flag, call) {
|
||
|
if (!flag) problems.push("Attribute '"+call[1]+"' was not called");
|
||
|
}
|
||
|
);
|
||
|
},
|
||
|
assert_not_called: function() {
|
||
|
var problems = [];
|
||
|
this._execute_wrapped_call( arguments, problems,
|
||
|
function(flag, call) {
|
||
|
if (flag) problems.push("Attribute '"+call[1]+"' was unexpetedly called");
|
||
|
}
|
||
|
);
|
||
|
},
|
||
|
_execute_wrapped_call: function(args, problems, callback) {
|
||
|
var params = this._assert_called_params.apply(this, args);
|
||
|
try {
|
||
|
var flags = [];
|
||
|
for (var i=0; i < params.calls.length; i++) {
|
||
|
flags[i] = false;
|
||
|
this.mock(params.calls[i][0], params.calls[i][1], (function(flags, i, object, name) {
|
||
|
var method = object[name];
|
||
|
return function() {
|
||
|
flags[i] = true;
|
||
|
return method.apply(object, arguments);
|
||
|
};
|
||
|
})(flags, i, params.calls[i][0], params.calls[i][1]));
|
||
|
}
|
||
|
params.callback.apply(params['scope_element']);
|
||
|
for (var i=0; i < flags.length; i++) {
|
||
|
if (params.calls[i])
|
||
|
callback.apply(this, [flags[i], params.calls[i]]);
|
||
|
}
|
||
|
} finally {
|
||
|
for (var i=0; i < params.calls.length; i++) {
|
||
|
this.undo_mock(params.calls[i][0], params.calls[i][1]);
|
||
|
}
|
||
|
}
|
||
|
if (problems.length) {
|
||
|
this.throw_problem(problems.join("\n"), params.message);
|
||
|
}
|
||
|
},
|
||
|
_assert_called_params: function() {
|
||
|
var params = { calls: [], callback: null, message: null };
|
||
|
if (typeof arguments[1] == 'string') {
|
||
|
params.calls = [[arguments[0], arguments[1]]];
|
||
|
params.callback = arguments[2];
|
||
|
} else if (arguments[0] instanceof Array) {
|
||
|
if (arguments[0].length == 2 && typeof(arguments[0][1]) == 'string') {
|
||
|
params.calls = [arguments[0]];
|
||
|
} else {
|
||
|
params.calls = arguments[0];
|
||
|
}
|
||
|
params.callback = arguments[1];
|
||
|
}
|
||
|
for (var i=0; i < arguments.length; i++)
|
||
|
if (arguments[i].scope)
|
||
|
params.scope_element = arguments[i].scope;
|
||
|
if (arguments.length > 2) {
|
||
|
for (var i=arguments.length-1; i > 0; i--) {
|
||
|
if (arguments[i] == params.callback) {
|
||
|
break;
|
||
|
} else if (typeof arguments[i] == 'string') {
|
||
|
params.message = arguments[i];
|
||
|
} else if (typeof params.scope_element == 'undefined') {
|
||
|
params.scope_element = arguments[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return params;
|
||
|
},
|
||
|
assert_exists: function(css_rule, message) {
|
||
|
if (TestCaseUtil.$$(css_rule).length == 0)
|
||
|
this.throw_problem("Cannot find any element like '"+css_rule+"'", message);
|
||
|
},
|
||
|
assert_not_exists: function(css_rule, message) {
|
||
|
if (TestCaseUtil.$$(css_rule).length)
|
||
|
this.throw_problem("Element '"+css_rule+"' presents on the page", message);
|
||
|
},
|
||
|
assert_has_child: function(element, css_rule, message) {
|
||
|
if (!TestCaseUtil.Element.down(element, css_rule))
|
||
|
this.throw_problem("Element has no child element like '"+css_rule+"'", message);
|
||
|
},
|
||
|
assert_has_no_child: function(element, css_rule, message) {
|
||
|
if (TestCaseUtil.Element.down(element, css_rule))
|
||
|
this.throw_problem("Element has child element '"+css_rule+"'", message);
|
||
|
},
|
||
|
assert_has_parent: function(element, css_rule, message) {
|
||
|
if (!TestCaseUtil.Element.up(element, css_rule))
|
||
|
this.throw_problem("Element has no parent element like '"+css_rule+"'", message);
|
||
|
},
|
||
|
assert_has_no_parent: function(element, css_rule, message) {
|
||
|
if (TestCaseUtil.Element.up(element, css_rule))
|
||
|
this.throw_problem("Element has parent element '"+css_rule+"'", message);
|
||
|
},
|
||
|
assert_visible: function(element_or_css_rule, message) {
|
||
|
var elements = typeof element_or_css_rule == 'string' ? TestCaseUtil.$$(element_or_css_rule) : [element_or_css_rule];
|
||
|
if (!elements.length || !elements[0])
|
||
|
this.throw_unexp("Element is visible", "Element is not found", message);
|
||
|
else {
|
||
|
for (var i=0; i < elements.length; i++) {
|
||
|
var element_style = this.__get_element_style(elements[i]);
|
||
|
var element_display = elements[i].style.display || element_style['display'];
|
||
|
var element_visibility = elements[i].style.visibility || element_style['visibility'];
|
||
|
if (element_display == 'none' || element_visibility == 'hidden')
|
||
|
this.throw_problem("Element is not visible", message);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
assert_hidden: function(element_or_css_rule, message) {
|
||
|
var elements = typeof element_or_css_rule == 'string' ? TestCaseUtil.$$(element_or_css_rule) : [element_or_css_rule];
|
||
|
if (!elements.length || !elements[0])
|
||
|
this.throw_unexp("Element is hidden", "Element is not found", message);
|
||
|
else {
|
||
|
for (var i=0; i < elements.length; i++) {
|
||
|
var element_style = this.__get_element_style(elements[i]);
|
||
|
var element_display = elements[i].style.display || element_style['display'];
|
||
|
var element_visibility = elements[i].style.visibility || element_style['visibility'];
|
||
|
if (element_display != 'none' && element_visibility != 'hidden')
|
||
|
this.throw_problem("Element is visible", message);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
assert_has_class_name: function(element, class_name, message) {
|
||
|
if (!TestCaseUtil.Element.has_class_name(element, class_name))
|
||
|
this.throw_problem("Element has no class-name '"+class_name+"'", message);
|
||
|
},
|
||
|
assert_has_no_class_name: function(element, class_name, message) {
|
||
|
if (TestCaseUtil.Element.has_class_name(element, class_name))
|
||
|
this.throw_problem("Element have class-name '"+class_name+"'", message);
|
||
|
},
|
||
|
assert_has_attribute: function(element, name, message) {
|
||
|
if (element.getAttribute(name) == null)
|
||
|
this.throw_problem("Element has no attribute '"+name+"'", message);
|
||
|
},
|
||
|
assert_has_no_attribute: function(element, name, message) {
|
||
|
if (element.getAttribute(name) != null)
|
||
|
this.throw_problem("Element has attribute '"+name+"'", message);
|
||
|
},
|
||
|
assert_style: function(element, style, message) {
|
||
|
var element_computed_style = this.__get_element_style(element);
|
||
|
var element_style = {};
|
||
|
for (var key in style) {
|
||
|
if (key.toLowerCase().substring(key.length-5) == 'color') {
|
||
|
var t = document.createElement('span');
|
||
|
t.style[key] = style[key];
|
||
|
style[key] = t.style[key];
|
||
|
}
|
||
|
if (element.style && element.style[key]) {
|
||
|
element_style[key] = element.style[key];
|
||
|
} else if (element_computed_style[key]) {
|
||
|
element_style[key] = element_computed_style[key];
|
||
|
} else {
|
||
|
element_style[key] = null;
|
||
|
}
|
||
|
};
|
||
|
if (!TestCaseUtil.equal(style, element_style))
|
||
|
this.throw_unexp("Element has style:\n "+TestCaseUtil.to_s(style),
|
||
|
TestCaseUtil.to_s(element_style), message);
|
||
|
},
|
||
|
__get_element_style: function(element) {
|
||
|
var style = document.defaultView ? document.defaultView.getComputedStyle(element, null) : element.currentStyle;
|
||
|
return style ? style : {};
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCase.AssertionsExtender = {
|
||
|
add_assertion: function(name, func) {
|
||
|
var name = name.substr(0, 7) == 'assert_' ? name.substr(7, name.length) : name;
|
||
|
var assert = {}; assert['assert_'+name] = function() {
|
||
|
this._count_assert(name);
|
||
|
func.apply(this, arguments);
|
||
|
};
|
||
|
TestCaseUtil.extend(this.prototype ? this.prototype : this, assert);
|
||
|
TestCaseUtil.extend_with_camelized_aliases(this.prototype ? this.prototype : this, assert);
|
||
|
},
|
||
|
add_assertions: function(module) {
|
||
|
TestCaseUtil.extend(this.prototype ? this.prototype : this, module);
|
||
|
TestCaseUtil.extend_with_camelized_aliases(this.prototype ? this.prototype : this, module);
|
||
|
for (var key in module) {
|
||
|
if (key.substr(0, 7) == 'assert_')
|
||
|
this.add_assertion(key, module[key]);
|
||
|
}
|
||
|
},
|
||
|
wire_custom_assertions: function(test_def) {
|
||
|
for (var name in test_def) {
|
||
|
if (name.substr(0, 6) == 'assert' && typeof(test_def[name]) == 'function') {
|
||
|
this.add_assertion(name.replace(/([a-z]+)([A-Z])/g, '$1_$2').toLowerCase(), this.prototype[name]);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
_count_assert: function(name) {
|
||
|
this.assertions++;
|
||
|
this.last_assert_name = name;
|
||
|
}
|
||
|
};
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.extend_fully_object_and_prototype(TestCase, TestCase.Starter);
|
||
|
TestCaseUtil.extend_fully_object_and_prototype(TestCase, TestCase.Fires);
|
||
|
TestCaseUtil.extend_fully_object_and_prototype(TestCase, TestCase.Mocking);
|
||
|
var __mock_aliaces = {
|
||
|
mockUp: TestCase.mock,
|
||
|
mockup: TestCase.mock,
|
||
|
undo_mockup: TestCase.undo_mock,
|
||
|
undoMockup: TestCase.undo_mock,
|
||
|
undoMockUp: TestCase.undo_mock,
|
||
|
with_mocked: TestCase.with_mock,
|
||
|
withMocked: TestCase.with_mock,
|
||
|
mockupEffects: TestCase.mock_effects,
|
||
|
mockUpEffects: TestCase.mock_effects,
|
||
|
mockup_effects: TestCase.mock_effects,
|
||
|
undo_effects_mockup: TestCase.undo_effects_mock,
|
||
|
undoEffectsMockup: TestCase.undo_effects_mock,
|
||
|
undoMockUpEffects: TestCase.undo_effects_mock,
|
||
|
undoMockupEffects: TestCase.undo_effects_mock,
|
||
|
undo_mockup_effects: TestCase.undo_effects_mock,
|
||
|
mockUpAjax: TestCase.mock_ajax,
|
||
|
mockupAjax: TestCase.mock_ajax,
|
||
|
mockup_ajax: TestCase.mock_ajax,
|
||
|
undoMockupAjax: TestCase.undo_ajax_mock,
|
||
|
undoMockUpAjax: TestCase.undo_ajax_mock,
|
||
|
undo_mockup_ajax: TestCase.undo_ajax_mock,
|
||
|
undo_ajax_mockup: TestCase.undo_ajax_mock,
|
||
|
undoAjaxMockup: TestCase.undo_ajax_mock,
|
||
|
undoAjaxMockUp: TestCase.undo_ajax_mock,
|
||
|
with_ajax_mockup: TestCase.with_ajax_mock
|
||
|
};
|
||
|
TestCaseUtil.extend(TestCase, __mock_aliaces);
|
||
|
TestCaseUtil.extend(TestCase.prototype, __mock_aliaces);
|
||
|
TestCaseUtil.extend(TestCase.prototype, TestCase.Messaging);
|
||
|
TestCaseUtil.extend_fully_object_and_prototype(TestCase, TestCase.AssertionsExtender);
|
||
|
TestCase.add_assertions(TestCase.Assertions);
|
||
|
TestCaseUtil.extend(TestCase.prototype, {
|
||
|
flunk: TestCase.prototype.fail,
|
||
|
assert: TestCase.prototype.assert_true,
|
||
|
assert_nil: TestCase.prototype.assert_null,
|
||
|
assert_not_nil: TestCase.prototype.assert_not_null,
|
||
|
assert_kind_of: TestCase.prototype.assert_type_of,
|
||
|
assert_no_match: TestCase.prototype.assert_not_match,
|
||
|
assertEquals: TestCase.prototype.assert_equal,
|
||
|
assertNotEquals: TestCase.prototype.assert_not_equal,
|
||
|
assertNoMatch: TestCase.prototype.assert_not_match
|
||
|
});
|
||
|
TestCase.prototype.util = TestCaseUtil;
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
var TestSuite = TestCaseUtil.create_class({
|
||
|
title: null,
|
||
|
reporter: null,
|
||
|
test_cases: [],
|
||
|
initialize: function() {
|
||
|
this.test_cases = [];
|
||
|
this.add.apply(this, arguments);
|
||
|
},
|
||
|
add: function() {
|
||
|
for (var i=0; arguments.length > i; i++) {
|
||
|
this.test_cases.push(arguments[i]);
|
||
|
}
|
||
|
this.test_cases = TestCaseUtil.Array.uniq(this.test_cases);
|
||
|
return this;
|
||
|
},
|
||
|
remove: function() {
|
||
|
for (var i=0; i < arguments.length; i++)
|
||
|
this.test_cases = TestCaseUtil.Array.without(this.test_cases, arguments[i]);
|
||
|
return this;
|
||
|
},
|
||
|
run: function(title) {
|
||
|
for (var i=0; i < this.test_cases.length; i++)
|
||
|
this.test_cases[i].run();
|
||
|
return this;
|
||
|
},
|
||
|
run_on_load: function() {
|
||
|
var $this = this;
|
||
|
TestCaseUtil.Event.observe(window, 'load', function() {
|
||
|
$this.run();
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
TestSuite.prototype.runOnLoad = TestSuite.prototype.run_on_load
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
var TestReporter = TestCaseUtil.create_class({
|
||
|
ui_builder: null,
|
||
|
report_container: null,
|
||
|
current_test: null,
|
||
|
current_test_block: null,
|
||
|
current_test_done_bar: null,
|
||
|
seen_tests: null,
|
||
|
initialize: function(ui_builder){
|
||
|
this.ui_builder = ui_builder || new TestReporter.UIBuilder();
|
||
|
this.report_container = this.ui_builder.create_report_container();
|
||
|
this._is_prepared = false;
|
||
|
this.seen_tests = [];
|
||
|
},
|
||
|
register: function(test) {
|
||
|
this._check_prepare();
|
||
|
this.seen_tests.push(test);
|
||
|
this.current_test = test;
|
||
|
this.current_test_block = this.ui_builder.create_test_block(test, this.report_container);
|
||
|
this.current_test_done_bar = this.ui_builder.create_done_bar(this.current_test_block);
|
||
|
this.current_test.__start_time = new Date().getTime();
|
||
|
},
|
||
|
test_started: function(test_name) {},
|
||
|
test_passed: function(test_name) {
|
||
|
this.current_test_done_bar.style.width = ((this.current_test.passed / this.current_test.size) * 100)+'%';
|
||
|
this.check_for_test_summary_report();
|
||
|
},
|
||
|
test_failed: function(test_name, e, assertion_num) {
|
||
|
this.ui_builder.create_error_report(
|
||
|
this.current_test_block, test_name, e, assertion_num, this.current_test[test_name].toString()
|
||
|
);
|
||
|
this.check_for_test_summary_report();
|
||
|
},
|
||
|
check_for_test_summary_report: function() {
|
||
|
if (this.current_test.size == (this.current_test.passed + this.current_test.failed))
|
||
|
this.ui_builder.create_summary_report(this.current_test_block, this.current_test);
|
||
|
this.ui_builder.update_overall_summary(this.report_container, this.seen_tests);
|
||
|
},
|
||
|
prepare: function() {},
|
||
|
_check_prepare: function() {
|
||
|
if(!this._is_prepared){
|
||
|
this.prepare();
|
||
|
this._is_prepared = true;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestReporter.UIBuilder = TestCaseUtil.create_class({
|
||
|
DEFAULT_VIEW_NAME: 'summary-and-failed',
|
||
|
initialize: function() {},
|
||
|
create_report_container: function() {
|
||
|
var block = document.createElement("DIV");
|
||
|
block.innerHTML = ''+
|
||
|
'<div id="testcase-report-block">'+
|
||
|
' <h1>Test Report</h1>'+
|
||
|
' <select id="testcase-view-switcher">'+
|
||
|
' <option value="summary-only">Display: Summary only</option>'+
|
||
|
' <option value="summary-and-failed">Display: Summary and Failed Cases</option>'+
|
||
|
' <option value="summary-and-active">Display: Summary and Active Cases</option>'+
|
||
|
' <option value="summary-and-skipped">Display: Summary and Skipped Cases</option>'+
|
||
|
' <option value="summary-and-all">Display: Summary and All Cases</option>'+
|
||
|
' <option value="cases-only">Display: Test Cases Only</option>'+
|
||
|
' <option value="active-cases-only">Display: Active Cases Only</option>'+
|
||
|
' <option value="skipped-cases-only">Display: Skipped Cases Only</option>'+
|
||
|
' </select>'+
|
||
|
' <ul id="test-cases-list">'+
|
||
|
' <li id="testcase-summary-block">'+
|
||
|
' <input type="checkbox" id="testcase-toggle-all-cases" title="Skip/Activate all TestCases" />'+
|
||
|
' <div class="test-name">Summary</div>'+
|
||
|
' <div class="progress-bar">'+
|
||
|
' <div class="done-bar"></div>'+
|
||
|
' </div>'+
|
||
|
' <div class="error-report-summary">'+
|
||
|
' Total Cases: 0 / Tests: 0 / Passed: 0 / Failed : 0 / Assertions : 0'+
|
||
|
' </div>'+
|
||
|
' </li>'+
|
||
|
' </ul>'+
|
||
|
'</div>';
|
||
|
this.init_view_switcher(block);
|
||
|
this.init_toggle_all_cases(block);
|
||
|
return block;
|
||
|
},
|
||
|
create_test_block: function(test, report_container) {
|
||
|
var block = document.createElement("LI");
|
||
|
var skipper = document.createElement("INPUT");
|
||
|
skipper.type = "checkbox";
|
||
|
skipper.title = "Skip/Activate Test";
|
||
|
var $this = this;
|
||
|
skipper.onclick = function(event) {
|
||
|
$this.set_skip_test.apply($this, [event, test, skipper, block]);
|
||
|
};
|
||
|
block.appendChild(skipper);
|
||
|
skipper.checked = !this.test_is_skipped(test);
|
||
|
skipper.disabled = !TestCaseUtil.Cookie.enabled();
|
||
|
if (!skipper.checked) TestCaseUtil.Element.add_class_name(block, 'skipped');
|
||
|
var test_name = document.createElement("DIV");
|
||
|
test_name.className = "test-name";
|
||
|
test_name.innerHTML = test.title;
|
||
|
block.appendChild(test_name);
|
||
|
TestCaseUtil.Array.find(
|
||
|
TestCaseUtil.Element.select(report_container, '*'),
|
||
|
function(element){ return element.id == 'test-cases-list';}
|
||
|
).appendChild(block);
|
||
|
return block;
|
||
|
},
|
||
|
create_done_bar: function(block) {
|
||
|
var progress_bar = document.createElement("DIV");
|
||
|
progress_bar.className = "progress-bar";
|
||
|
var done_bar = document.createElement("DIV");
|
||
|
done_bar.className = "done-bar";
|
||
|
progress_bar.appendChild(done_bar);
|
||
|
block.appendChild(progress_bar);
|
||
|
return done_bar;
|
||
|
},
|
||
|
create_error_report: function(test_block, test_name, e, assertion_num, failed_test_code) {
|
||
|
var block = document.createElement("DIV");
|
||
|
block.className = 'error-report-case';
|
||
|
block.innerHTML = '<div class="error-report-case-title">Test error in <span class="test-name" title="Show code">'+ test_name +'</span> '+
|
||
|
'<span class="assertion-name">('+this.get_assertion_name(e, assertion_num)+')</span>:</div>'+this.create_error_text(e);
|
||
|
this.create_error_code_snippet(block, e, assertion_num, failed_test_code);
|
||
|
test_block.appendChild(block);
|
||
|
test_block.className = 'failed-case';
|
||
|
return block;
|
||
|
},
|
||
|
create_error_text: function(e) {
|
||
|
if (e instanceof TestCase.WrongValueException) {
|
||
|
var e_value = this._htmlized(e.format ? this._formatted_value(e.expected) : e.expected);
|
||
|
var r_value = this._htmlized(e.format ? this._formatted_value(e.received) : e.received);
|
||
|
return ''+
|
||
|
'<label>Expected:</label> <span class="report-text">'+ e_value +'</span> '+
|
||
|
'<label>but had:</label> <span class="report-text">'+ r_value +'</span> '+
|
||
|
this._create_diff_block(e) +
|
||
|
this._create_message_block(e);
|
||
|
} else if (e instanceof TestCase.ProblemException)
|
||
|
return '<label>Problem:</label> <span class="report-text">'+this._htmlized(e.problem)+'</span> ' + this._create_message_block(e);
|
||
|
else return e.message;
|
||
|
},
|
||
|
_htmlized: function(value) {
|
||
|
return typeof(value) == 'string' ? value.replace(/\n/g, "<br/>") : value;
|
||
|
},
|
||
|
MAX_UNFOLDED_VALUE_LENGTH: 200,
|
||
|
_formatted_value: function(value) {
|
||
|
var value_s = TestCaseUtil.to_pretty_s(value);
|
||
|
if (value_s.length > this.MAX_UNFOLDED_VALUE_LENGTH) {
|
||
|
return "<span class='formatted-value short-version'>"+
|
||
|
value_s.substr(0, this.MAX_UNFOLDED_VALUE_LENGTH).replace(/</g, '<').replace(/ /g, ' ') +
|
||
|
"</span>" +
|
||
|
"<span class='formatted-value full-version'>"+
|
||
|
value_s.replace(/</g, '<').replace(/ /g, ' ') +
|
||
|
"</span>" +
|
||
|
'<a href="" class="folding-toggler" title="Toggle the value" onclick="'+
|
||
|
"var short_version = TestCaseUtil.Element.down(TestCaseUtil.Element.up(this, 'span.report-text'), 'span.short-version');"+
|
||
|
"var full_version = TestCaseUtil.Element.down(TestCaseUtil.Element.up(this, 'span.report-text'), 'span.full-version');"+
|
||
|
"if (short_version.style.display != 'none') {"+
|
||
|
"short_version.style.display = 'none';"+
|
||
|
"full_version.style.display = 'block';"+
|
||
|
"this.innerHTML = 'Hide the full version';"+
|
||
|
"} else {"+
|
||
|
"short_version.style.display = 'block';"+
|
||
|
"full_version.style.display = 'none';"+
|
||
|
"this.innerHTML = 'Full version';"+
|
||
|
"}"+
|
||
|
'return false;">Full version</a>';
|
||
|
}
|
||
|
return "<span class='formatted-value'>"+ value_s.replace(/</g, '<').replace(/ /g, ' ') +"</span>";
|
||
|
},
|
||
|
_create_diff_block: function (e) {
|
||
|
if (e.format) {
|
||
|
try {
|
||
|
var is_array = e.expected instanceof Array;
|
||
|
var diff = TestCaseUtil.Diff.calc(e.expected, e.received);
|
||
|
if (diff.length > 0) {
|
||
|
var diff_entries = [];
|
||
|
for (var i=0; i < diff.length; i++) {
|
||
|
for (var key in diff[i]) {}
|
||
|
var value = diff[i][key];
|
||
|
if (typeof e.expected != 'string') {
|
||
|
if (typeof e.expected == 'object' && !is_array) {
|
||
|
var entries = [];
|
||
|
for (var name in value) {
|
||
|
entries.push('"'+ name +'": '+TestCaseUtil._one_level_to_s(value[name]));
|
||
|
}
|
||
|
value = "{"+ entries.join(",\n ") +"\n}";
|
||
|
} else if (typeof e.expected != 'function') {
|
||
|
value = TestCaseUtil.debug(value);
|
||
|
}
|
||
|
}
|
||
|
diff_entries.push('<span class="'+key+'">'+ value.replace(/</g, '<').replace(/\n/g, '<br/>').replace(/ /g, ' ') +'</span>');
|
||
|
}
|
||
|
return '<label>Diff:</label><span class="report-text">'+
|
||
|
'<span class="diff-block">'+
|
||
|
(is_array ? '[' : '')+
|
||
|
diff_entries.join(is_array ? ',<br/> ' : '<br/>') +
|
||
|
(is_array ? "<br/>]" : '') +
|
||
|
'</span>'+
|
||
|
'<a href="" class="diff-toggler" title="Toggle the diff" onclick="'+
|
||
|
"var block = TestCaseUtil.Element.down(TestCaseUtil.Element.up(this, 'span.report-text'), 'span.diff-block');"+
|
||
|
"if (block.style.display != 'block') {"+
|
||
|
"block.style.display = 'block';"+
|
||
|
"this.innerHTML = 'Hide';"+
|
||
|
"} else {"+
|
||
|
"block.style.display = 'none';"+
|
||
|
"this.innerHTML = 'Show';"+
|
||
|
"}"+
|
||
|
'return false;">Show</a>'+
|
||
|
'</span>';
|
||
|
}
|
||
|
} catch (e) { }
|
||
|
}
|
||
|
return '';
|
||
|
},
|
||
|
_create_message_block: function(e) {
|
||
|
return e.message ? '<label>Message:</label> <span class="report-text">'+e.message+'</span>' : '';
|
||
|
},
|
||
|
create_error_code_snippet: function(error_block, e, assertion_num, failed_test_code) {
|
||
|
var failed_test_code = this._paint_source_code(failed_test_code, e, assertion_num);
|
||
|
var failed_test_source_popup = document.createElement("DIV");
|
||
|
failed_test_source_popup.className = 'failed-code-snippet';
|
||
|
failed_test_source_popup.innerHTML = '<code>'+failed_test_code+'</code>';
|
||
|
failed_test_source_popup.style.display = 'none';
|
||
|
var test_name_pointer = TestCaseUtil.Element.select(error_block, 'span.test-name')[0];
|
||
|
test_name_pointer.parentNode.insertBefore(failed_test_source_popup, test_name_pointer);
|
||
|
TestCaseUtil.Event.observe(failed_test_source_popup, 'click', function(event) { TestCaseUtil.Event.stop(event); });
|
||
|
TestCaseUtil.Event.observe(test_name_pointer, 'click', function(event) {
|
||
|
TestCaseUtil.Event.stop(event);
|
||
|
TestCaseUtil.Element.toggle(failed_test_source_popup);
|
||
|
});
|
||
|
TestCaseUtil.Event.observe(document, 'click', function() {
|
||
|
TestCaseUtil.Element.hide(failed_test_source_popup);
|
||
|
});
|
||
|
return failed_test_source_popup;
|
||
|
},
|
||
|
_paint_source_code: function(failed_test_code, e, assertion_num) {
|
||
|
if (TestCaseUtil.Browser.IE) failed_test_code = failed_test_code.replace(/\n/mg, "<br/>\n").replace(/ /mg, " ");
|
||
|
var assertion_num = assertion_num - 1;
|
||
|
var asserts_counter = 0;
|
||
|
var assertion_matches = failed_test_code.match(/this\.assert.+(\n|;)/ig);
|
||
|
if (assertion_matches) {
|
||
|
for (var i=0; i < assertion_matches.length; i++) {
|
||
|
match = assertion_matches[i];
|
||
|
asserts_counter ++;
|
||
|
if (asserts_counter == assertion_num)
|
||
|
failed_test_code = failed_test_code.replace(match, '<span class="problematic-code">'+match+'</span>');
|
||
|
}
|
||
|
failed_test_code = failed_test_code.replace(/(this)(\.)(assert[^\(]*)(\s*\()/img, '$1$2<span class="assertion-method">$3</span>$4');
|
||
|
}
|
||
|
return failed_test_code;
|
||
|
},
|
||
|
create_summary_report: function(test_block, test) {
|
||
|
test.__taken_seconds = (test.__start_time && !test.skipped) ? (new Date().getTime() - test.__start_time)/1000 : 0;
|
||
|
var block = document.createElement("DIV");
|
||
|
block.className = 'error-report-summary';
|
||
|
block.innerHTML = "Total tests: "+ test.size +
|
||
|
" / Passed: "+ test.passed +
|
||
|
" / Failed: "+ test.failed +
|
||
|
" / Assertions: "+ test.assertions +
|
||
|
" / Seconds: "+test.__taken_seconds;
|
||
|
test_block.appendChild(block);
|
||
|
return block;
|
||
|
},
|
||
|
update_overall_summary: function(block, cases_list) {
|
||
|
var cases = 0, tests = 0, passed = 0, failed = 0, assertions = 0, seconds = 0;
|
||
|
for (var i=0; i < cases_list.length; i++) {
|
||
|
var testcase = cases_list[i];
|
||
|
if (!testcase.skipped) {
|
||
|
cases++;
|
||
|
tests += testcase.size;
|
||
|
passed += testcase.passed;
|
||
|
failed += testcase.failed;
|
||
|
assertions += testcase.assertions;
|
||
|
seconds += testcase.__taken_seconds;
|
||
|
}
|
||
|
}
|
||
|
var list_block = TestCaseUtil.Element.select(block, 'li#testcase-summary-block')[0];
|
||
|
if (list_block) {
|
||
|
var done_bar_element = TestCaseUtil.Element.select(list_block, 'div.done-bar')[0];
|
||
|
if (done_bar_element)
|
||
|
done_bar_element.style.width = ((tests > 0 ? (passed / tests) : 0) * 100)+'%';
|
||
|
var summary_element = TestCaseUtil.Element.select(list_block, 'div.error-report-summary')[0];
|
||
|
if (summary_element)
|
||
|
summary_element.innerHTML = "Total Cases: "+cases+
|
||
|
" / Tests: "+tests+
|
||
|
" / Passed: "+passed+
|
||
|
" / Failed : "+failed+
|
||
|
" / Assertions : "+assertions+
|
||
|
" / Seconds: "+seconds.toString().substr(0,5);
|
||
|
}
|
||
|
if (cases > 0) {
|
||
|
var switcher = TestCaseUtil.Element.select(block, 'input#testcase-toggle-all-cases')[0];
|
||
|
if (switcher)
|
||
|
switcher.checked = true;
|
||
|
}
|
||
|
},
|
||
|
test_is_skipped: function(test) {
|
||
|
return TestCaseUtil.Array.include(this.get_skipped_cases(), escape(test.title));
|
||
|
},
|
||
|
get_assertion_name: function(e, assertion_num) {
|
||
|
if (e.test && e.assertion) {
|
||
|
for (key in e.test)
|
||
|
if (e.test[key] == e.assertion)
|
||
|
return key;
|
||
|
} else {
|
||
|
return "assertion #"+assertion_num;
|
||
|
}
|
||
|
},
|
||
|
init_view_switcher: function(block) {
|
||
|
var descendants = TestCaseUtil.Element.select(block, '*');
|
||
|
var switcher = TestCaseUtil.Array.find(descendants, function(el) { return el.id == 'testcase-view-switcher' });
|
||
|
var list_element = TestCaseUtil.Array.find(descendants, function(el) { return el.id == 'test-cases-list' });
|
||
|
if (switcher && list_element) {
|
||
|
TestCaseUtil.Event.observe(switcher, 'change', function() {
|
||
|
list_element.className = switcher.value;
|
||
|
TestCaseUtil.Cookie.set("testcase_view", switcher.value, 100);
|
||
|
});
|
||
|
switcher.value = this.get_current_view_name();
|
||
|
list_element.className = switcher.value;
|
||
|
}
|
||
|
},
|
||
|
get_current_view_name: function() {
|
||
|
var view_name = TestCaseUtil.Cookie.get('testcase_view');
|
||
|
return view_name == '' ? this.DEFAULT_VIEW_NAME : view_name;
|
||
|
},
|
||
|
init_toggle_all_cases: function(block) {
|
||
|
var checkbox = TestCaseUtil.Array.find(TestCaseUtil.Element.select(block, '*'), function(el) { return el.id == 'testcase-toggle-all-cases' });
|
||
|
if (checkbox) {
|
||
|
var $this = this;
|
||
|
TestCaseUtil.Event.observe(checkbox, 'click', function(event) {
|
||
|
$this.toggle_all_cases.apply($this, [this, block, checkbox]);
|
||
|
});
|
||
|
checkbox.checked = false;
|
||
|
checkbox.disabled = TestCaseUtil.Cookie.enabled() ? false : true;
|
||
|
}
|
||
|
},
|
||
|
toggle_all_cases: function(event, block, checkbox) {
|
||
|
var elements = TestCaseUtil.Element.select(block, 'ul li input[type="checkbox"]');
|
||
|
for (var i=0; i < elements.length; i++) {
|
||
|
elements[i].checked = checkbox.checked;
|
||
|
if (elements[i].onclick)
|
||
|
elements[i].onclick();
|
||
|
}
|
||
|
},
|
||
|
set_skip_test: function(event, test, checkbox, block) {
|
||
|
TestCaseUtil.Element[checkbox.checked ? 'remove_class_name' : 'add_class_name'](block, 'skipped');
|
||
|
var skipped_cases = this.get_skipped_cases();
|
||
|
if (checkbox.checked)
|
||
|
skipped_cases = TestCaseUtil.Array.without(skipped_cases, escape(test.title));
|
||
|
else
|
||
|
skipped_cases.push(escape(test.title));
|
||
|
TestCaseUtil.Cookie.set("testcase_skipped_cases", skipped_cases.join("|"));
|
||
|
},
|
||
|
get_skipped_cases: function() {
|
||
|
return TestCaseUtil.Cookie.get('testcase_skipped_cases').split("|");
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestReporter.InlineReporter = TestCaseUtil.create_class(TestReporter, {
|
||
|
prepare: function() {
|
||
|
var source = ''+
|
||
|
'<div id="testcase-inline-report-block">'+
|
||
|
' <div class="title">'+
|
||
|
' <div class="closer" title="Close" onclick="TestCaseUtil.Element.hide(\'testcase-inline-report-block\');">x</div>'+
|
||
|
' </div>'+
|
||
|
' <div class="body"></div>'+
|
||
|
'</div>'+
|
||
|
'';
|
||
|
if (document.body) {
|
||
|
var block = document.createElement("DIV");
|
||
|
block.innerHTML = source;
|
||
|
document.body.appendChild(block);
|
||
|
} else {
|
||
|
document.write(source);
|
||
|
}
|
||
|
TestCaseUtil.Element.down('testcase-inline-report-block', 'div.body').appendChild(this.report_container);
|
||
|
}
|
||
|
});
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
TestCaseUtil.extend(TestCase, {
|
||
|
reporter: new TestReporter.InlineReporter()
|
||
|
});
|
||
|
|
||
|
|
||
|
/* ---------------- THE STYLES COLLECTION DUMPING ------------------- */
|
||
|
document.write('<style type="text/css">'+''+
|
||
|
'#testcase-report-block{'+
|
||
|
' font-family: Verdana;'+
|
||
|
' font-size: 9pt;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block h1{'+
|
||
|
' font-family: Arial;'+
|
||
|
' font-size: 12pt;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block div.progress-bar{'+
|
||
|
' display:block;'+
|
||
|
' height: 14px;'+
|
||
|
' width: 100%;'+
|
||
|
' background: red;'+
|
||
|
' padding: 0;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block div.progress-bar div.done-bar{'+
|
||
|
' display:block;'+
|
||
|
' position: relative;'+
|
||
|
' float: left;'+
|
||
|
' height: 14px;'+
|
||
|
' margin: 0;'+
|
||
|
' background: green;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block #testcase-view-switcher {'+
|
||
|
' position: relative;'+
|
||
|
' float: right;'+
|
||
|
' margin-top: -20pt;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul#test-cases-list{'+
|
||
|
' padding-left: 20pt;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li{'+
|
||
|
' margin-bottom: 8pt;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li#testcase-summary-block {'+
|
||
|
' padding-bottom: 4pt;'+
|
||
|
''+
|
||
|
' margin-bottom: 4pt;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.test-name{'+
|
||
|
' font-weight: bold;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case{'+
|
||
|
' padding: 4pt 0;'+
|
||
|
' border-bottom: 1px dotted gray;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case div.error-report-case-title{'+
|
||
|
' font-weight: bold;'+
|
||
|
' color: brown;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case div.error-report-case-title .test-name{'+
|
||
|
' text-decoration: underline;'+
|
||
|
' color: red;'+
|
||
|
' cursor: pointer;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case div.error-report-case-title .assertion-name{'+
|
||
|
' font-weight: normal;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case label{'+
|
||
|
' display: block;'+
|
||
|
' font-weight: bold;'+
|
||
|
' color: #888;'+
|
||
|
' margin-top: 4pt;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .report-text{'+
|
||
|
' display: block;'+
|
||
|
' padding-left: 4pt;'+
|
||
|
' border-left: 8pt solid #FEE;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .formatted-value {'+
|
||
|
' white-space: pre;'+
|
||
|
' font-family: monospace;'+
|
||
|
' display: block;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .formatted-value.short-version {'+
|
||
|
' color: gray;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .formatted-value.short-version:after {'+
|
||
|
' content: "...";'+
|
||
|
' font-size: 120%;'+
|
||
|
' font-weight: bold;'+
|
||
|
' margin-left: 4pt;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .formatted-value.full-version {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .folding-toggler {'+
|
||
|
' color: red;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .diff-block {'+
|
||
|
' white-space: pre;'+
|
||
|
' font-family: monospace;'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .diff-block .del {'+
|
||
|
' background: #FDD;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .diff-block .ins {'+
|
||
|
' background: #DFD;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li div.error-report-case .diff-toggler {'+
|
||
|
' color: red;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul#test-cases-list {'+
|
||
|
' list-style: none;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li {'+
|
||
|
(TestCaseUtil.Browser.IE?'margin-bottom: 0 !important; ':'')+
|
||
|
(TestCaseUtil.Browser.IE?'padding-bottom: 0 !important; ':'')+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li input {'+
|
||
|
' position: relative;'+
|
||
|
' float: left;'+
|
||
|
' margin-left: -16pt;'+
|
||
|
(TestCaseUtil.Browser.IE?'margin-left: -20pt;':'')+
|
||
|
(TestCaseUtil.Browser.IE?'margin-top: 10pt;':'')+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li.skipped {'+
|
||
|
' color: gray;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul#test-cases-list li.skipped div.progress-bar,'+
|
||
|
'#testcase-report-block ul#test-cases-list li.skipped div.progress-bar div.done-bar {'+
|
||
|
' background: gray;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.summary-only li {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul.summary-only li#testcase-summary-block {'+
|
||
|
' display: list-item;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.summary-and-failed li {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul.summary-and-failed li#testcase-summary-block,'+
|
||
|
'#testcase-report-block ul.summary-and-failed li.failed-case {'+
|
||
|
' display: list-item;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.summary-and-all li {'+
|
||
|
' display: list-item;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.cases-only li#testcase-summary-block {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.summary-and-active li.skipped {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.summary-and-skipped li {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul.summary-and-skipped li#testcase-summary-block,'+
|
||
|
'#testcase-report-block ul.summary-and-skipped li.failed-case,'+
|
||
|
'#testcase-report-block ul.summary-and-skipped li.skipped {'+
|
||
|
' display: list-item;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.active-cases-only li {'+
|
||
|
' display: list-item;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul.active-cases-only li#testcase-summary-block,'+
|
||
|
'#testcase-report-block ul.active-cases-only li.skipped {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block ul.skipped-cases-only li {'+
|
||
|
' display: none;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block ul.skipped-cases-only li.skipped {'+
|
||
|
' display: list-item;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-report-block div.failed-code-snippet {'+
|
||
|
' position: absolute;'+
|
||
|
' border: 1px solid brown;'+
|
||
|
' padding: 4pt;'+
|
||
|
' color: black;'+
|
||
|
' font-weight: normal;'+
|
||
|
' background: #FFE;'+
|
||
|
' cursor: default;'+
|
||
|
' border-left: 4pt solid brown;'+
|
||
|
' padding-left: 8pt;'+
|
||
|
' z-index: 999;'+
|
||
|
(TestCaseUtil.Browser.IE?'margin-top: 1em;':'')+
|
||
|
(TestCaseUtil.Browser.IE?'margin-left: -6em;':'')+
|
||
|
'}'+
|
||
|
'#testcase-report-block div.failed-code-snippet code {'+
|
||
|
' text-decoration: none !important;'+
|
||
|
' white-space: pre;'+
|
||
|
' margin: 0;'+
|
||
|
' padding: 0;'+
|
||
|
' display: block;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block div.failed-code-snippet code .problematic-code {'+
|
||
|
' border-bottom: 1px solid red;'+
|
||
|
'}'+
|
||
|
'#testcase-report-block div.failed-code-snippet code .assertion-method {'+
|
||
|
' color: #090;'+
|
||
|
'}'+
|
||
|
''+
|
||
|
'#testcase-inline-report-block{'+
|
||
|
' position: absolute;'+
|
||
|
' left: 20%;'+
|
||
|
' top: 10pt;'+
|
||
|
' background: white;'+
|
||
|
' z-index: 99999999;'+
|
||
|
' border: 1px solid gray;'+
|
||
|
' width: 500pt;'+
|
||
|
' font-size: 9pt;'+
|
||
|
' font-family: Verdana;'+
|
||
|
'}'+
|
||
|
'#testcase-inline-report-block div.title{'+
|
||
|
' display: block;'+
|
||
|
' height: 14pt;'+
|
||
|
' background: #EEE;'+
|
||
|
' padding: 0 4pt;'+
|
||
|
' border-bottom: 1px solid gray;'+
|
||
|
'}'+
|
||
|
'#testcase-inline-report-block div.title div.closer{'+
|
||
|
' border: 1px solid gray;'+
|
||
|
' float: right;'+
|
||
|
' position: relative;'+
|
||
|
' display: block;'+
|
||
|
' width: 8pt;'+
|
||
|
' height: 8pt;'+
|
||
|
' line-height: 8pt;'+
|
||
|
' text-align: center;'+
|
||
|
' padding: 1pt;'+
|
||
|
' margin-top: 1pt;'+
|
||
|
' cursor: pointer;'+
|
||
|
' background: #EBB;'+
|
||
|
'}'+
|
||
|
'#testcase-inline-report-block div.title div.closer:hover{'+
|
||
|
' background: #F88'+
|
||
|
'}'+
|
||
|
'#testcase-inline-report-block div.body{'+
|
||
|
' margin: .5em;'+
|
||
|
'}'+
|
||
|
'</style>');
|