/**
* QUnit - A JavaScript Unit Testing Framework
- *
+ *
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2011 John Resig, Jörn Zaefferer
// allow utility functions to access the current test environment
// TODO why??
QUnit.current_testEnvironment = this.testEnvironment;
-
+
try {
if ( !config.pollution ) {
saveGlobal();
},
teardown: function() {
try {
- checkPollution();
this.testEnvironment.teardown.call(this.testEnvironment);
+ checkPollution();
} catch(e) {
QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
}
if ( this.expected && this.expected != this.assertions.length ) {
QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
}
-
+
var good = 0, bad = 0,
tests = id("qunit-tests");
var b = document.createElement("strong");
b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
-
+
var a = document.createElement("a");
a.innerHTML = "Rerun";
a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
-
+
addEvent(b, "click", function() {
var next = b.nextSibling.nextSibling,
display = next.style.display;
next.style.display = display === "none" ? "block" : "none";
});
-
+
addEvent(b, "dblclick", function(e) {
var target = e && e.target ? e.target : window.event.srcElement;
if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
total: this.assertions.length
} );
},
-
+
queue: function() {
var test = this;
synchronize(function() {
synchronize(run);
};
}
-
+
};
var QUnit = {
QUnit.test(testName, expected, callback, true);
},
-
+
test: function(testName, expected, callback, async) {
var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
if ( !validTest(config.currentModule + ": " + testName) ) {
return;
}
-
+
var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
test.module = config.currentModule;
test.moduleTestEnvironment = config.currentModuleTestEnviroment;
test.queue();
},
-
+
/**
* Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
*/
notEqual: function(actual, expected, message) {
QUnit.push(expected != actual, actual, expected, message);
},
-
+
deepEqual: function(actual, expected, message) {
QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
},
raises: function(block, expected, message) {
var actual, ok = false;
-
+
if (typeof expected === 'string') {
message = expected;
expected = null;
}
-
+
try {
block();
} catch (e) {
actual = e;
}
-
+
if (actual) {
// we don't want to validate thrown error
if (!expected) {
ok = true;
- // expected is a regexp
+ // expected is a regexp
} else if (QUnit.objectType(expected) === "regexp") {
ok = expected.test(actual);
- // expected is a constructor
+ // expected is a constructor
} else if (actual instanceof expected) {
ok = true;
- // expected is a validation function which returns true is validation passed
+ // expected is a validation function which returns true is validation passed
} else if (expected.call({}, actual) === true) {
ok = true;
}
}
-
+
QUnit.ok(ok, message);
},
process();
}
},
-
+
stop: function(timeout) {
config.semaphore++;
config.blocking = true;
// block until document ready
blocking: true,
-
+
// by default, run previously failed tests first
// very useful in combination with "Hide passed tests" checked
reorder: true,
if ( result ) {
result.parentNode.removeChild( result );
}
-
+
if ( tests ) {
result = document.createElement( "p" );
result.id = "qunit-testresult";
result.innerHTML = 'Running...<br/> ';
}
},
-
+
/**
* Resets the test setup. Useful for tests that modify the DOM.
- *
+ *
* If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
*/
reset: function() {
}
}
},
-
+
/**
* Trigger an event on an element.
*
elem.fireEvent("on"+type);
}
},
-
+
// Safe object type checking
is: function( type, obj ) {
return QUnit.objectType( obj ) == type;
},
-
+
objectType: function( obj ) {
if (typeof obj === "undefined") {
return "undefined";
}
return undefined;
},
-
+
push: function(result, actual, expected, message) {
var details = {
result: result,
actual: actual,
expected: expected
};
-
+
message = escapeHtml(message) || (result ? "okay" : "failed");
message = '<span class="test-message">' + message + "</span>";
expected = escapeHtml(QUnit.jsDump.parse(expected));
}
}
output += "</table>";
-
+
QUnit.log(details);
-
+
config.current.assertions.push({
result: !!result,
message: output
});
},
-
+
url: function( params ) {
params = extend( extend( {}, QUnit.urlParams ), params );
var querystring = "?",
}
return window.location.pathname + querystring.slice( 0, -1 );
},
-
+
// Logging callbacks; all receive a single argument with the listed properties
// run test/logs.html for any related changes
begin: function() {},
addEvent(window, "load", function() {
QUnit.begin({});
-
+
// Initialize the config, saving the execution queue
var oldconfig = extend({}, config);
QUnit.init();
window.location = QUnit.url( params );
});
}
-
+
var toolbar = id("qunit-testrunner-toolbar");
if ( toolbar ) {
var filter = document.createElement("input");
banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
}
- if ( tests ) {
+ if ( tests ) {
id( "qunit-testresult" ).innerHTML = html;
}
if ( typeof document !== "undefined" && document.title ) {
- // TODO what are the unicode codes for these? as-is fails if qunit.js isn't served with the right mimetype/charset
- document.title = (config.stats.bad ? "✖" : "✔") + " " + document.title;
+ // show ✖ for good, ✔ for bad suite result in title
+ // use escape sequences in case file gets loaded with non-utf-8-charset
+ document.title = (config.stats.bad ? "\u2716" : "\u2714") + " " + document.title;
}
QUnit.done( {
failed: config.stats.bad,
- passed: passed,
+ passed: passed,
total: config.stats.all,
runtime: runtime
} );
return true;
}
- not = filter.charAt( 0 ) === "!";
+ var not = filter.charAt( 0 ) === "!";
if ( not ) {
filter = filter.slice( 1 );
}
function saveGlobal() {
config.pollution = [];
-
+
if ( config.noglobals ) {
for ( var key in window ) {
config.pollution.push( key );
function checkPollution( name ) {
var old = config.pollution;
saveGlobal();
-
+
var newGlobals = diff( config.pollution, old );
if ( newGlobals.length > 0 ) {
ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
}
}
}
-
+
var callbacks = function () {
// for string, boolean, number and null
// b could be an object literal here
if ( ! (QUnit.objectType(b) === "array")) {
return false;
- }
-
+ }
+
len = a.length;
if (len !== b.length) { // safe and faster
return false;
}
-
+
//track reference to avoid circular references
parents.push(a);
for (i = 0; i < len; i++) {
callers.push(a.constructor);
//track reference to avoid circular references
parents.push(a);
-
+
for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
loop = false;
for(j=0;j<parents.length;j++){
return '"' + str.toString().replace(/"/g, '\\"') + '"';
};
function literal( o ) {
- return o + '';
+ return o + '';
};
function join( pre, arr, post ) {
var s = jsDump.separator(),
return [ pre, inner + arr, base + post ].join(s);
};
function array( arr ) {
- var i = arr.length, ret = Array(i);
+ var i = arr.length, ret = Array(i);
this.up();
while ( i-- )
- ret[i] = this.parse( arr[i] );
+ ret[i] = this.parse( arr[i] );
this.down();
return join( '[', ret, ']' );
};
-
+
var reName = /^function (\w+)/;
-
+
var jsDump = {
parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
var parser = this.parsers[ type || this.typeOf(obj) ];
- type = typeof parser;
-
+ type = typeof parser;
+
return type == 'function' ? parser.call( this, obj ) :
type == 'string' ? parser :
this.parsers.error;
this.parsers[name] = parser;
},
// The next 3 are exposed so you can use them
- quote:quote,
+ quote:quote,
literal:literal,
join:join,
//
if ( name )
ret += ' ' + name;
ret += '(';
-
+
ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
},
node:function( node ) {
var open = QUnit.jsDump.HTML ? '<' : '<',
close = QUnit.jsDump.HTML ? '>' : '>';
-
+
var tag = node.nodeName.toLowerCase(),
ret = open + tag;
-
+
for ( var a in QUnit.jsDump.DOMAttrs ) {
var val = node[QUnit.jsDump.DOMAttrs[a]];
if ( val )
},
functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
var l = fn.length;
- if ( !l ) return '';
-
+ if ( !l ) return '';
+
var args = Array(l);
while ( l-- )
args[l] = String.fromCharCode(97+l);//97 is 'a'
*
* More Info:
* http://ejohn.org/projects/javascript-diff-algorithm/
- *
+ *
* Usage: QUnit.diff(expected, actual)
- *
+ *
* QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
*/
QUnit.diff = (function() {
function diff(o, n){
var ns = new Object();
var os = new Object();
-
+
for (var i = 0; i < n.length; i++) {
- if (ns[n[i]] == null)
+ if (ns[n[i]] == null)
ns[n[i]] = {
rows: new Array(),
o: null
};
ns[n[i]].rows.push(i);
}
-
+
for (var i = 0; i < o.length; i++) {
- if (os[o[i]] == null)
+ if (os[o[i]] == null)
os[o[i]] = {
rows: new Array(),
n: null
};
os[o[i]].rows.push(i);
}
-
+
for (var i in ns) {
if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
n[ns[i].rows[0]] = {
};
}
}
-
+
for (var i = 0; i < n.length - 1; i++) {
if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
n[i + 1] == o[n[i].row + 1]) {
};
}
}
-
+
for (var i = n.length - 1; i > 0; i--) {
if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
n[i - 1] == o[n[i].row - 1]) {
};
}
}
-
+
return {
o: o,
n: n
};
}
-
+
return function(o, n){
o = o.replace(/\s+$/, '');
n = n.replace(/\s+$/, '');
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
var str = "";
-
+
var oSpace = o.match(/\s+/g);
if (oSpace == null) {
oSpace = [" "];
else {
nSpace.push(" ");
}
-
+
if (out.n.length == 0) {
for (var i = 0; i < out.o.length; i++) {
str += '<del>' + out.o[i] + oSpace[i] + "</del>";
str += '<del>' + out.o[n] + oSpace[n] + "</del>";
}
}
-
+
for (var i = 0; i < out.n.length; i++) {
if (out.n[i].text == null) {
str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
}
else {
var pre = "";
-
+
for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
}
}
}
}
-
+
return str;
};
})();