colonymech / docs / www / colonyscout / internal / jeditable / tests / testrunner.js @ f59acf11
History | View | Annotate | Download (10.3 KB)
1 |
/*
|
---|---|
2 |
* QUnit - jQuery unit testrunner
|
3 |
*
|
4 |
* http://docs.jquery.com/QUnit
|
5 |
*
|
6 |
* Copyright (c) 2008 John Resig, Jörn Zaefferer
|
7 |
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
8 |
* and GPL (GPL-LICENSE.txt) licenses.
|
9 |
*
|
10 |
* $Id: testrunner.js 5827 2008-08-13 17:14:48Z joern.zaefferer $
|
11 |
*/
|
12 |
|
13 |
var _config = {
|
14 |
fixture: null, |
15 |
Test: [],
|
16 |
stats: {
|
17 |
all: 0, |
18 |
bad: 0 |
19 |
}, |
20 |
queue: [],
|
21 |
blocking: true, |
22 |
timeout: null, |
23 |
expected: null, |
24 |
currentModule: null, |
25 |
asyncTimeout: 2 // seconds for async timeout |
26 |
}; |
27 |
|
28 |
_config.filters = location.search.length > 1 && //restrict modules/tests by get parameters |
29 |
jQuery.map( location.search.slice(1).split('&'), decodeURIComponent ); |
30 |
|
31 |
var isLocal = !!(window.location.protocol == 'file:'); |
32 |
|
33 |
jQuery(function() {
|
34 |
jQuery('#userAgent').html(navigator.userAgent);
|
35 |
runTest(); |
36 |
}); |
37 |
|
38 |
function synchronize(callback) { |
39 |
_config.queue[_config.queue.length] = callback; |
40 |
if(!_config.blocking) {
|
41 |
process(); |
42 |
} |
43 |
} |
44 |
|
45 |
function process() { |
46 |
while(_config.queue.length && !_config.blocking) {
|
47 |
var call = _config.queue[0]; |
48 |
_config.queue = _config.queue.slice(1);
|
49 |
call(); |
50 |
} |
51 |
} |
52 |
|
53 |
function stop(allowFailure) { |
54 |
_config.blocking = true;
|
55 |
var handler = allowFailure ? start : function() { |
56 |
ok( false, "Test timed out" ); |
57 |
start(); |
58 |
}; |
59 |
// Disabled, caused too many random errors
|
60 |
//_config.timeout = setTimeout(handler, _config.asyncTimeout * 1000);
|
61 |
} |
62 |
function start() { |
63 |
// A slight delay, to avoid any current callbacks
|
64 |
setTimeout(function(){
|
65 |
if(_config.timeout)
|
66 |
clearTimeout(_config.timeout); |
67 |
_config.blocking = false;
|
68 |
process(); |
69 |
}, 13);
|
70 |
} |
71 |
|
72 |
function validTest( name ) { |
73 |
var filters = _config.filters;
|
74 |
if( !filters )
|
75 |
return true; |
76 |
|
77 |
var i = filters.length,
|
78 |
run = false;
|
79 |
while( i-- ){
|
80 |
var filter = filters[i],
|
81 |
not = filter.charAt(0) == '!'; |
82 |
if( not )
|
83 |
filter = filter.slice(1);
|
84 |
if( name.indexOf(filter) != -1 ) |
85 |
return !not;
|
86 |
if( not )
|
87 |
run = true;
|
88 |
} |
89 |
return run;
|
90 |
} |
91 |
|
92 |
function runTest() { |
93 |
_config.blocking = false;
|
94 |
var started = +new Date; |
95 |
_config.fixture = document.getElementById('main').innerHTML;
|
96 |
_config.ajaxSettings = jQuery.ajaxSettings; |
97 |
synchronize(function() {
|
98 |
jQuery('<p id="testresult" class="result">').html(['Tests completed in ', |
99 |
+new Date - started, ' milliseconds.<br/>', |
100 |
'<span class="bad">', _config.stats.bad, '</span> tests of <span class="all">', _config.stats.all, '</span> failed.</p>'] |
101 |
.join(''))
|
102 |
.appendTo("body");
|
103 |
jQuery("#banner").addClass(_config.stats.bad ? "fail" : "pass"); |
104 |
}); |
105 |
} |
106 |
|
107 |
function test(name, callback, nowait) { |
108 |
if(_config.currentModule)
|
109 |
name = _config.currentModule + " module: " + name;
|
110 |
|
111 |
if ( !validTest(name) )
|
112 |
return;
|
113 |
|
114 |
synchronize(function() {
|
115 |
_config.Test = []; |
116 |
try {
|
117 |
callback(); |
118 |
} catch(e) {
|
119 |
if( typeof console != "undefined" && console.error && console.warn ) { |
120 |
console.error("Test " + name + " died, exception and test follows"); |
121 |
console.error(e); |
122 |
console.warn(callback.toString()); |
123 |
} |
124 |
_config.Test.push( [ false, "Died on test #" + (_config.Test.length+1) + ": " + e.message ] ); |
125 |
} |
126 |
}); |
127 |
synchronize(function() {
|
128 |
try {
|
129 |
reset(); |
130 |
} catch(e) {
|
131 |
if( typeof console != "undefined" && console.error && console.warn ) { |
132 |
console.error("reset() failed, following Test " + name + ", exception and reset fn follows"); |
133 |
console.error(e); |
134 |
console.warn(reset.toString()); |
135 |
} |
136 |
} |
137 |
|
138 |
// don't output pause tests
|
139 |
if(nowait) return; |
140 |
|
141 |
if(_config.expected && _config.expected != _config.Test.length) {
|
142 |
_config.Test.push( [ false, "Expected " + _config.expected + " assertions, but " + _config.Test.length + " were run" ] ); |
143 |
} |
144 |
_config.expected = null;
|
145 |
|
146 |
var good = 0, bad = 0; |
147 |
var ol = document.createElement("ol"); |
148 |
ol.style.display = "none";
|
149 |
var li = "", state = "pass"; |
150 |
for ( var i = 0; i < _config.Test.length; i++ ) { |
151 |
var li = document.createElement("li"); |
152 |
li.className = _config.Test[i][0] ? "pass" : "fail"; |
153 |
li.appendChild( document.createTextNode(_config.Test[i][1]) );
|
154 |
ol.appendChild( li ); |
155 |
|
156 |
_config.stats.all++; |
157 |
if ( !_config.Test[i][0] ) { |
158 |
state = "fail";
|
159 |
bad++; |
160 |
_config.stats.bad++; |
161 |
} else good++;
|
162 |
} |
163 |
|
164 |
var li = document.createElement("li"); |
165 |
li.className = state; |
166 |
|
167 |
var b = document.createElement("strong"); |
168 |
b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + _config.Test.length + ")</b>"; |
169 |
b.onclick = function(){ |
170 |
var n = this.nextSibling; |
171 |
if ( jQuery.css( n, "display" ) == "none" ) |
172 |
n.style.display = "block";
|
173 |
else
|
174 |
n.style.display = "none";
|
175 |
}; |
176 |
jQuery(b).dblclick(function(event) {
|
177 |
var target = jQuery(event.target).filter("strong").clone(); |
178 |
if ( target.length ) {
|
179 |
target.children().remove(); |
180 |
location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(jQuery.trim(target.text())); |
181 |
} |
182 |
}); |
183 |
li.appendChild( b ); |
184 |
li.appendChild( ol ); |
185 |
|
186 |
document.getElementById("tests").appendChild( li );
|
187 |
}); |
188 |
} |
189 |
|
190 |
// call on start of module test to prepend name to all tests
|
191 |
function module(moduleName) { |
192 |
_config.currentModule = moduleName; |
193 |
} |
194 |
|
195 |
/**
|
196 |
* Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
|
197 |
*/
|
198 |
function expect(asserts) { |
199 |
_config.expected = asserts; |
200 |
} |
201 |
|
202 |
/**
|
203 |
* Resets the test setup. Useful for tests that modify the DOM.
|
204 |
*/
|
205 |
function reset() { |
206 |
jQuery("#main").html( _config.fixture );
|
207 |
jQuery.event.global = {}; |
208 |
jQuery.ajaxSettings = jQuery.extend({}, _config.ajaxSettings); |
209 |
} |
210 |
|
211 |
/**
|
212 |
* Asserts true.
|
213 |
* @example ok( jQuery("a").size() > 5, "There must be at least 5 anchors" );
|
214 |
*/
|
215 |
function ok(a, msg) { |
216 |
_config.Test.push( [ !!a, msg ] ); |
217 |
} |
218 |
|
219 |
/**
|
220 |
* Asserts that two arrays are the same
|
221 |
*/
|
222 |
function isSet(a, b, msg) { |
223 |
var ret = true; |
224 |
if ( a && b && a.length != undefined && a.length == b.length ) { |
225 |
for ( var i = 0; i < a.length; i++ ) |
226 |
if ( a[i] != b[i] )
|
227 |
ret = false;
|
228 |
} else
|
229 |
ret = false;
|
230 |
if ( !ret )
|
231 |
_config.Test.push( [ ret, msg + " expected: " + serialArray(b) + " result: " + serialArray(a) ] ); |
232 |
else
|
233 |
_config.Test.push( [ ret, msg ] ); |
234 |
} |
235 |
|
236 |
/**
|
237 |
* Asserts that two objects are equivalent
|
238 |
*/
|
239 |
function isObj(a, b, msg) { |
240 |
var ret = true; |
241 |
|
242 |
if ( a && b ) {
|
243 |
for ( var i in a ) |
244 |
if ( a[i] != b[i] )
|
245 |
ret = false;
|
246 |
|
247 |
for ( i in b ) |
248 |
if ( a[i] != b[i] )
|
249 |
ret = false;
|
250 |
} else
|
251 |
ret = false;
|
252 |
|
253 |
_config.Test.push( [ ret, msg ] ); |
254 |
} |
255 |
|
256 |
function serialArray( a ) { |
257 |
var r = [];
|
258 |
|
259 |
if ( a && a.length )
|
260 |
for ( var i = 0; i < a.length; i++ ) { |
261 |
var str = a[i].nodeName;
|
262 |
if ( str ) {
|
263 |
str = str.toLowerCase(); |
264 |
if ( a[i].id )
|
265 |
str += "#" + a[i].id;
|
266 |
} else
|
267 |
str = a[i]; |
268 |
r.push( str ); |
269 |
} |
270 |
|
271 |
return "[ " + r.join(", ") + " ]"; |
272 |
} |
273 |
|
274 |
function flatMap(a, block) { |
275 |
var result = [];
|
276 |
$.each(a, function() { |
277 |
var x = block.apply(this, arguments); |
278 |
if (x !== false) |
279 |
result.push(x); |
280 |
}) |
281 |
return result;
|
282 |
} |
283 |
|
284 |
function serialObject( a ) { |
285 |
return "{ " + flatMap(a, function(key, value) { |
286 |
return key + ": " + value; |
287 |
}).join(", ") + " }"; |
288 |
} |
289 |
|
290 |
function compare(a, b, msg) { |
291 |
var ret = true; |
292 |
if ( a && b && a.length != undefined && a.length == b.length ) { |
293 |
for ( var i = 0; i < a.length; i++ ) |
294 |
for(var key in a[i]) { |
295 |
if (a[i][key].constructor == Array) {
|
296 |
for (var arrayKey in a[i][key]) { |
297 |
if (a[i][key][arrayKey] != b[i][key][arrayKey]) {
|
298 |
ret = false;
|
299 |
} |
300 |
} |
301 |
} else if (a[i][key] != b[i][key]) { |
302 |
ret = false
|
303 |
} |
304 |
} |
305 |
} else
|
306 |
ret = false;
|
307 |
ok( ret, msg + " expected: " + serialArray(b) + " result: " + serialArray(a) ); |
308 |
} |
309 |
|
310 |
function compare2(a, b, msg) { |
311 |
var ret = true; |
312 |
if ( a && b ) {
|
313 |
for(var key in a) { |
314 |
if (a[key].constructor == Array) {
|
315 |
for (var arrayKey in a[key]) { |
316 |
if (a[key][arrayKey] != b[key][arrayKey]) {
|
317 |
ret = false;
|
318 |
} |
319 |
} |
320 |
} else if (a[key] != b[key]) { |
321 |
ret = false
|
322 |
} |
323 |
} |
324 |
for(key in b) { |
325 |
if (b[key].constructor == Array) {
|
326 |
for (var arrayKey in b[key]) { |
327 |
if (a[key][arrayKey] != b[key][arrayKey]) {
|
328 |
ret = false;
|
329 |
} |
330 |
} |
331 |
} else if (a[key] != b[key]) { |
332 |
ret = false
|
333 |
} |
334 |
} |
335 |
} else
|
336 |
ret = false;
|
337 |
ok( ret, msg + " expected: " + serialObject(b) + " result: " + serialObject(a) ); |
338 |
} |
339 |
|
340 |
/**
|
341 |
* Returns an array of elements with the given IDs, eg.
|
342 |
* @example q("main", "foo", "bar")
|
343 |
* @result [<div id="main">, <span id="foo">, <input id="bar">]
|
344 |
*/
|
345 |
function q() { |
346 |
var r = [];
|
347 |
for ( var i = 0; i < arguments.length; i++ ) |
348 |
r.push( document.getElementById( arguments[i] ) );
|
349 |
return r;
|
350 |
} |
351 |
|
352 |
/**
|
353 |
* Asserts that a select matches the given IDs
|
354 |
* @example t("Check for something", "//[a]", ["foo", "baar"]);
|
355 |
* @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
|
356 |
*/
|
357 |
function t(a,b,c) { |
358 |
var f = jQuery(b);
|
359 |
var s = ""; |
360 |
for ( var i = 0; i < f.length; i++ ) |
361 |
s += (s && ",") + '"' + f[i].id + '"'; |
362 |
isSet(f, q.apply(q,c), a + " (" + b + ")"); |
363 |
} |
364 |
|
365 |
/**
|
366 |
* Add random number to url to stop IE from caching
|
367 |
*
|
368 |
* @example url("data/test.html")
|
369 |
* @result "data/test.html?10538358428943"
|
370 |
*
|
371 |
* @example url("data/test.php?foo=bar")
|
372 |
* @result "data/test.php?foo=bar&10538358345554"
|
373 |
*/
|
374 |
function url(value) { |
375 |
return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); |
376 |
} |
377 |
|
378 |
/**
|
379 |
* Checks that the first two arguments are equal, with an optional message.
|
380 |
* Prints out both actual and expected values.
|
381 |
*
|
382 |
* Prefered to ok( actual == expected, message )
|
383 |
*
|
384 |
* @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." );
|
385 |
*
|
386 |
* @param Object actual
|
387 |
* @param Object expected
|
388 |
* @param String message (optional)
|
389 |
*/
|
390 |
function equals(actual, expected, message) { |
391 |
var result = expected == actual;
|
392 |
message = message || (result ? "okay" : "failed"); |
393 |
_config.Test.push( [ result, result ? message + ": " + expected : message + " expected: " + expected + " actual: " + actual ] ); |
394 |
} |
395 |
|
396 |
/**
|
397 |
* Trigger an event on an element.
|
398 |
*
|
399 |
* @example triggerEvent( document.body, "click" );
|
400 |
*
|
401 |
* @param DOMElement elem
|
402 |
* @param String type
|
403 |
*/
|
404 |
function triggerEvent( elem, type, event ) { |
405 |
if ( jQuery.browser.mozilla || jQuery.browser.opera ) {
|
406 |
event = document.createEvent("MouseEvents");
|
407 |
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, |
408 |
0, 0, 0, 0, 0, false, false, false, false, 0, null); |
409 |
elem.dispatchEvent( event ); |
410 |
} else if ( jQuery.browser.msie ) { |
411 |
elem.fireEvent("on"+type);
|
412 |
} |
413 |
} |