PluginProbe
RSVP and Event Management / 1.3.0
RSVP and Event Management v1.3.0
trunk 0.5.0 0.6.0 0.7.0 0.8.0 0.9.0 0.9.5 1.0.0 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.5.0 1.6.0 1.6.1 1.6.2 1.6.5 1.7.0 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 All 136 releases
rsvp / jquery-ui-1.7.2.custom / development-bundle / external / qunit / testrunner.js

testrunner.js in RSVP and Event Management 1.3.0, at jquery-ui-1.7.2.custom/development-bundle/external/qunit/testrunner.js

781 lines 21.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 6173 2009-02-02 20:09:32Z jeresig $
11 */
12
13 (function($) {
14
15 // Tests for equality any JavaScript type and structure without unexpected results.
16 // Discussions and reference: http://philrathe.com/articles/equiv
17 // Test suites: http://philrathe.com/tests/equiv
18 // Author: Philippe Rathé <[email protected]>
19 var equiv = function () {
20
21 var innerEquiv; // the real equiv function
22 var callers = []; // stack to decide between skip/abort functions
23
24 // Determine what is o.
25 function hoozit(o) {
26 if (typeof o === "string") {
27 return "string";
28
29 } else if (typeof o === "boolean") {
30 return "boolean";
31
32 } else if (typeof o === "number") {
33
34 if (isNaN(o)) {
35 return "nan";
36 } else {
37 return "number";
38 }
39
40 } else if (typeof o === "undefined") {
41 return "undefined";
42
43 // consider: typeof null === object
44 } else if (o === null) {
45 return "null";
46
47 // consider: typeof [] === object
48 } else if (o instanceof Array) {
49 return "array";
50
51 // consider: typeof new Date() === object
52 } else if (o instanceof Date) {
53 return "date";
54
55 // consider: /./ instanceof Object;
56 // /./ instanceof RegExp;
57 // typeof /./ === "function"; // => false in IE and Opera,
58 // true in FF and Safari
59 } else if (o instanceof RegExp) {
60 return "regexp";
61
62 } else if (typeof o === "object") {
63 return "object";
64
65 } else if (o instanceof Function) {
66 return "function";
67 }
68 }
69
70 // Call the o related callback with the given arguments.
71 function bindCallbacks(o, callbacks, args) {
72 var prop = hoozit(o);
73 if (prop) {
74 if (hoozit(callbacks[prop]) === "function") {
75 return callbacks[prop].apply(callbacks, args);
76 } else {
77 return callbacks[prop]; // or undefined
78 }
79 }
80 }
81
82 var callbacks = function () {
83
84 // for string, boolean, number and null
85 function useStrictEquality(b, a) {
86 return a === b;
87 }
88
89 return {
90 "string": useStrictEquality,
91 "boolean": useStrictEquality,
92 "number": useStrictEquality,
93 "null": useStrictEquality,
94 "undefined": useStrictEquality,
95
96 "nan": function (b) {
97 return isNaN(b);
98 },
99
100 "date": function (b, a) {
101 return hoozit(b) === "date" && a.valueOf() === b.valueOf();
102 },
103
104 "regexp": function (b, a) {
105 return hoozit(b) === "regexp" &&
106 a.source === b.source && // the regex itself
107 a.global === b.global && // and its modifers (gmi) ...
108 a.ignoreCase === b.ignoreCase &&
109 a.multiline === b.multiline;
110 },
111
112 // - skip when the property is a method of an instance (OOP)
113 // - abort otherwise,
114 // initial === would have catch identical references anyway
115 "function": function () {
116 var caller = callers[callers.length - 1];
117 return caller !== Object &&
118 typeof caller !== "undefined";
119 },
120
121 "array": function (b, a) {
122 var i;
123 var len;
124
125 // b could be an object literal here
126 if ( ! (hoozit(b) === "array")) {
127 return false;
128 }
129
130 len = a.length;
131 if (len !== b.length) { // safe and faster
132 return false;
133 }
134 for (i = 0; i < len; i++) {
135 if( ! innerEquiv(a[i], b[i])) {
136 return false;
137 }
138 }
139 return true;
140 },
141
142 "object": function (b, a) {
143 var i;
144 var eq = true; // unless we can proove it
145 var aProperties = [], bProperties = []; // collection of strings
146
147 // comparing constructors is more strict than using instanceof
148 if ( a.constructor !== b.constructor) {
149 return false;
150 }
151
152 // stack constructor before traversing properties
153 callers.push(a.constructor);
154
155 for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
156
157 aProperties.push(i); // collect a's properties
158
159 if ( ! innerEquiv(a[i], b[i])) {
160 eq = false;
161 }
162 }
163
164 callers.pop(); // unstack, we are done
165
166 for (i in b) {
167 bProperties.push(i); // collect b's properties
168 }
169
170 // Ensures identical properties name
171 return eq && innerEquiv(aProperties.sort(), bProperties.sort());
172 }
173 };
174 }();
175
176 innerEquiv = function () { // can take multiple arguments
177 var args = Array.prototype.slice.apply(arguments);
178 if (args.length < 2) {
179 return true; // end transition
180 }
181
182 return (function (a, b) {
183 if (a === b) {
184 return true; // catch the most you can
185
186 } else if (typeof a !== typeof b || a === null || b === null || typeof a === "undefined" || typeof b === "undefined") {
187 return false; // don't lose time with error prone cases
188
189 } else {
190 return bindCallbacks(a, callbacks, [b, a]);
191 }
192
193 // apply transition with (1..n) arguments
194 })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
195 };
196
197 return innerEquiv;
198 }(); // equiv
199
200 var GETParams = $.map( location.search.slice(1).split('&'), decodeURIComponent ),
201 ngindex = $.inArray("noglobals", GETParams),
202 noglobals = ngindex !== -1;
203
204 if( noglobals )
205 GETParams.splice( ngindex, 1 );
206
207 var config = {
208 stats: {
209 all: 0,
210 bad: 0
211 },
212 queue: [],
213 // block until document ready
214 blocking: true,
215 //restrict modules/tests by get parameters
216 filters: GETParams,
217 isLocal: !!(window.location.protocol == 'file:')
218 };
219
220 // public API as global methods
221 $.extend(window, {
222 test: test,
223 module: module,
224 expect: expect,
225 ok: ok,
226 equals: equals,
227 start: start,
228 stop: stop,
229 reset: reset,
230 isLocal: config.isLocal,
231 same: function(a, b, message) {
232 push(equiv(a, b), a, b, message);
233 },
234 QUnit: {
235 equiv: equiv,
236 ok: ok,
237 done: function(failures, total){},
238 log: function(result, message){}
239 },
240 // legacy methods below
241 isSet: isSet,
242 isObj: isObj,
243 compare: function() {
244 throw "compare is deprecated - use same() instead";
245 },
246 compare2: function() {
247 throw "compare2 is deprecated - use same() instead";
248 },
249 serialArray: function() {
250 throw "serialArray is deprecated - use jsDump.parse() instead";
251 },
252 q: q,
253 t: t,
254 url: url,
255 triggerEvent: triggerEvent
256 });
257
258 $(window).load(function() {
259 $('#userAgent').html(navigator.userAgent);
260 var head = $('<div class="testrunner-toolbar"><label for="filter-pass">Hide passed tests</label></div>').insertAfter("#userAgent");
261 $('<input type="checkbox" id="filter-pass" />').attr("disabled", true).prependTo(head).click(function() {
262 $('li.pass')[this.checked ? 'hide' : 'show']();
263 });
264 $('<input type="checkbox" id="filter-missing">').attr("disabled", true).appendTo(head).click(function() {
265 $("li.fail:contains('missing test - untested code is broken code')").parent('ol').parent('li.fail')[this.checked ? 'hide' : 'show']();
266 });
267 $("#filter-missing").after('<label for="filter-missing">Hide missing tests (untested code is broken code)</label>');
268 runTest();
269 });
270
271 function synchronize(callback) {
272 config.queue.push(callback);
273 if(!config.blocking) {
274 process();
275 }
276 }
277
278 function process() {
279 while(config.queue.length && !config.blocking) {
280 config.queue.shift()();
281 }
282 }
283
284 function stop(timeout) {
285 config.blocking = true;
286 if (timeout)
287 config.timeout = setTimeout(function() {
288 QUnit.ok( false, "Test timed out" );
289 start();
290 }, timeout);
291 }
292 function start() {
293 // A slight delay, to avoid any current callbacks
294 setTimeout(function() {
295 if(config.timeout)
296 clearTimeout(config.timeout);
297 config.blocking = false;
298 process();
299 }, 13);
300 }
301
302 function validTest( name ) {
303 var i = config.filters.length,
304 run = false;
305
306 if( !i )
307 return true;
308
309 while( i-- ){
310 var filter = config.filters[i],
311 not = filter.charAt(0) == '!';
312 if( not )
313 filter = filter.slice(1);
314 if( name.indexOf(filter) != -1 )
315 return !not;
316 if( not )
317 run = true;
318 }
319 return run;
320 }
321
322 function runTest() {
323 config.blocking = false;
324 var started = +new Date;
325 config.fixture = document.getElementById('main').innerHTML;
326 config.ajaxSettings = $.ajaxSettings;
327 synchronize(function() {
328 $('<p id="testresult" class="result"/>').html(['Tests completed in ',
329 +new Date - started, ' milliseconds.<br/>',
330 '<span class="bad">', config.stats.bad, '</span> tests of <span class="all">', config.stats.all, '</span> failed.']
331 .join(''))
332 .appendTo("body");
333 $("#banner").addClass(config.stats.bad ? "fail" : "pass");
334 QUnit.done( config.stats.bad, config.stats.all );
335 });
336 }
337
338 var pollution;
339
340 function saveGlobal(){
341 pollution = [ ];
342
343 if( noglobals )
344 for( var key in window )
345 pollution.push(key);
346 }
347 function checkPollution( name ){
348 var old = pollution;
349 saveGlobal();
350
351 if( pollution.length > old.length ){
352 ok( false, "Introduced global variable(s): " + diff(old, pollution).join(", ") );
353 config.expected++;
354 }
355 }
356
357 function diff( clean, dirty ){
358 return $.grep( dirty, function(name){
359 return $.inArray( name, clean ) == -1;
360 });
361 }
362
363 function test(name, callback) {
364 if(config.currentModule)
365 name = config.currentModule + " module: " + name;
366 var lifecycle = $.extend({
367 setup: function() {},
368 teardown: function() {}
369 }, config.moduleLifecycle);
370
371 if ( !validTest(name) )
372 return;
373
374 synchronize(function() {
375 config.assertions = [];
376 config.expected = null;
377 try {
378 if( !pollution )
379 saveGlobal();
380 lifecycle.setup();
381 } catch(e) {
382 QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
383 }
384 })
385 synchronize(function() {
386 try {
387 callback();
388 } catch(e) {
389 if( typeof console != "undefined" && console.error && console.warn ) {
390 console.error("Test " + name + " died, exception and test follows");
391 console.error(e);
392 console.warn(callback.toString());
393 }
394 QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
395 // else next test will carry the responsibility
396 saveGlobal();
397 }
398 });
399 synchronize(function() {
400 try {
401 checkPollution();
402 lifecycle.teardown();
403 } catch(e) {
404 QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
405 }
406 })
407 synchronize(function() {
408 try {
409 reset();
410 } catch(e) {
411 if( typeof console != "undefined" && console.error && console.warn ) {
412 console.error("reset() failed, following Test " + name + ", exception and reset fn follows");
413 console.error(e);
414 console.warn(reset.toString());
415 }
416 }
417
418 if(config.expected && config.expected != config.assertions.length) {
419 QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
420 }
421
422 var good = 0, bad = 0;
423 var ol = $("<ol/>").hide();
424 config.stats.all += config.assertions.length;
425 for ( var i = 0; i < config.assertions.length; i++ ) {
426 var assertion = config.assertions[i];
427 $("<li/>").addClass(assertion.result ? "pass" : "fail").text(assertion.message || "(no message)").appendTo(ol);
428 assertion.result ? good++ : bad++;
429 }
430 config.stats.bad += bad;
431
432 var b = $("<strong/>").html(name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>")
433 .click(function(){
434 $(this).next().toggle();
435 })
436 .dblclick(function(event) {
437 var target = $(event.target).filter("strong").clone();
438 if ( target.length ) {
439 target.children().remove();
440 location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target.text()));
441 }
442 });
443
444 $("<li/>").addClass(bad ? "fail" : "pass").append(b).append(ol).appendTo("#tests");
445
446 if(bad) {
447 $("#filter-pass").attr("disabled", null);
448 $("#filter-missing").attr("disabled", null);
449 }
450 });
451 }
452
453 // call on start of module test to prepend name to all tests
454 function module(name, lifecycle) {
455 config.currentModule = name;
456 config.moduleLifecycle = lifecycle;
457 }
458
459 /**
460 * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
461 */
462 function expect(asserts) {
463 config.expected = asserts;
464 }
465
466 /**
467 * Resets the test setup. Useful for tests that modify the DOM.
468 */
469 function reset() {
470 $("#main").html( config.fixture );
471 $.event.global = {};
472 $.ajaxSettings = $.extend({}, config.ajaxSettings);
473 }
474
475 /**
476 * Asserts true.
477 * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
478 */
479 function ok(a, msg) {
480 QUnit.log(a, msg);
481
482 config.assertions.push({
483 result: !!a,
484 message: msg
485 });
486 }
487
488 /**
489 * Asserts that two arrays are the same
490 */
491 function isSet(a, b, msg) {
492 function serialArray( a ) {
493 var r = [];
494
495 if ( a && a.length )
496 for ( var i = 0; i < a.length; i++ ) {
497 var str = a[i].nodeName;
498 if ( str ) {
499 str = str.toLowerCase();
500 if ( a[i].id )
501 str += "#" + a[i].id;
502 } else
503 str = a[i];
504 r.push( str );
505 }
506
507 return "[ " + r.join(", ") + " ]";
508 }
509 var ret = true;
510 if ( a && b && a.length != undefined && a.length == b.length ) {
511 for ( var i = 0; i < a.length; i++ )
512 if ( a[i] != b[i] )
513 ret = false;
514 } else
515 ret = false;
516 QUnit.ok( ret, !ret ? (msg + " expected: " + serialArray(b) + " result: " + serialArray(a)) : msg );
517 }
518
519 /**
520 * Asserts that two objects are equivalent
521 */
522 function isObj(a, b, msg) {
523 var ret = true;
524
525 if ( a && b ) {
526 for ( var i in a )
527 if ( a[i] != b[i] )
528 ret = false;
529
530 for ( i in b )
531 if ( a[i] != b[i] )
532 ret = false;
533 } else
534 ret = false;
535
536 QUnit.ok( ret, msg );
537 }
538
539 /**
540 * Returns an array of elements with the given IDs, eg.
541 * @example q("main", "foo", "bar")
542 * @result [<div id="main">, <span id="foo">, <input id="bar">]
543 */
544 function q() {
545 var r = [];
546 for ( var i = 0; i < arguments.length; i++ )
547 r.push( document.getElementById( arguments[i] ) );
548 return r;
549 }
550
551 /**
552 * Asserts that a select matches the given IDs
553 * @example t("Check for something", "//[a]", ["foo", "baar"]);
554 * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
555 */
556 function t(a,b,c) {
557 var f = $(b);
558 var s = "";
559 for ( var i = 0; i < f.length; i++ )
560 s += (s && ",") + '"' + f[i].id + '"';
561 isSet(f, q.apply(q,c), a + " (" + b + ")");
562 }
563
564 /**
565 * Add random number to url to stop IE from caching
566 *
567 * @example url("data/test.html")
568 * @result "data/test.html?10538358428943"
569 *
570 * @example url("data/test.php?foo=bar")
571 * @result "data/test.php?foo=bar&10538358345554"
572 */
573 function url(value) {
574 return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000);
575 }
576
577 /**
578 * Checks that the first two arguments are equal, with an optional message.
579 * Prints out both actual and expected values.
580 *
581 * Prefered to ok( actual == expected, message )
582 *
583 * @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." );
584 *
585 * @param Object actual
586 * @param Object expected
587 * @param String message (optional)
588 */
589 function equals(actual, expected, message) {
590 push(expected == actual, actual, expected, message);
591 }
592
593 function push(result, actual, expected, message) {
594 message = message || (result ? "okay" : "failed");
595 QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + jsDump.parse(expected) + " result: " + jsDump.parse(actual) );
596 }
597
598 /**
599 * Trigger an event on an element.
600 *
601 * @example triggerEvent( document.body, "click" );
602 *
603 * @param DOMElement elem
604 * @param String type
605 */
606 function triggerEvent( elem, type, event ) {
607 if ( $.browser.mozilla || $.browser.opera ) {
608 event = document.createEvent("MouseEvents");
609 event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
610 0, 0, 0, 0, 0, false, false, false, false, 0, null);
611 elem.dispatchEvent( event );
612 } else if ( $.browser.msie ) {
613 elem.fireEvent("on"+type);
614 }
615 }
616
617 })(jQuery);
618
619 /**
620 * jsDump
621 * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
622 * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
623 * Date: 5/15/2008
624 * @projectDescription Advanced and extensible data dumping for Javascript.
625 * @version 1.0.0
626 * @author Ariel Flesler
627 * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
628 */
629 (function(){
630 function quote( str ){
631 return '"' + str.toString().replace(/"/g, '\\"') + '"';
632 };
633 function literal( o ){
634 return o + '';
635 };
636 function join( pre, arr, post ){
637 var s = jsDump.separator(),
638 base = jsDump.indent();
639 inner = jsDump.indent(1);
640 if( arr.join )
641 arr = arr.join( ',' + s + inner );
642 if( !arr )
643 return pre + post;
644 return [ pre, inner + arr, base + post ].join(s);
645 };
646 function array( arr ){
647 var i = arr.length, ret = Array(i);
648 this.up();
649 while( i-- )
650 ret[i] = this.parse( arr[i] );
651 this.down();
652 return join( '[', ret, ']' );
653 };
654
655 var reName = /^function (\w+)/;
656
657 var jsDump = window.jsDump = {
658 parse:function( obj, type ){//type is used mostly internally, you can fix a (custom)type in advance
659 var parser = this.parsers[ type || this.typeOf(obj) ];
660 type = typeof parser;
661
662 return type == 'function' ? parser.call( this, obj ) :
663 type == 'string' ? parser :
664 this.parsers.error;
665 },
666 typeOf:function( obj ){
667 var type = typeof obj,
668 f = 'function';//we'll use it 3 times, save it
669 return type != 'object' && type != f ? type :
670 !obj ? 'null' :
671 obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions
672 obj.getHours ? 'date' :
673 obj.scrollBy ? 'window' :
674 obj.nodeName == '#document' ? 'document' :
675 obj.nodeName ? 'node' :
676 obj.item ? 'nodelist' : // Safari reports nodelists as functions
677 obj.callee ? 'arguments' :
678 obj.call || obj.constructor != Array && //an array would also fall on this hack
679 (obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects
680 'length' in obj ? 'array' :
681 type;
682 },
683 separator:function(){
684 return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
685 },
686 indent:function( extra ){// extra can be a number, shortcut for increasing-calling-decreasing
687 if( !this.multiline )
688 return '';
689 var chr = this.indentChar;
690 if( this.HTML )
691 chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
692 return Array( this._depth_ + (extra||0) ).join(chr);
693 },
694 up:function( a ){
695 this._depth_ += a || 1;
696 },
697 down:function( a ){
698 this._depth_ -= a || 1;
699 },
700 setParser:function( name, parser ){
701 this.parsers[name] = parser;
702 },
703 // The next 3 are exposed so you can use them
704 quote:quote,
705 literal:literal,
706 join:join,
707 //
708 _depth_: 1,
709 // This is the list of parsers, to modify them, use jsDump.setParser
710 parsers:{
711 window: '[Window]',
712 document: '[Document]',
713 error:'[ERROR]', //when no parser is found, shouldn't happen
714 unknown: '[Unknown]',
715 'null':'null',
716 undefined:'undefined',
717 'function':function( fn ){
718 var ret = 'function',
719 name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
720 if( name )
721 ret += ' ' + name;
722 ret += '(';
723
724 ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
725 return join( ret, this.parse(fn,'functionCode'), '}' );
726 },
727 array: array,
728 nodelist: array,
729 arguments: array,
730 object:function( map ){
731 var ret = [ ];
732 this.up();
733 for( var key in map )
734 ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
735 this.down();
736 return join( '{', ret, '}' );
737 },
738 node:function( node ){
739 var open = this.HTML ? '&lt;' : '<',
740 close = this.HTML ? '&gt;' : '>';
741
742 var tag = node.nodeName.toLowerCase(),
743 ret = open + tag;
744
745 for( var a in this.DOMAttrs ){
746 var val = node[this.DOMAttrs[a]];
747 if( val )
748 ret += ' ' + a + '=' + this.parse( val, 'attribute' );
749 }
750 return ret + close + open + '/' + tag + close;
751 },
752 functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function
753 var l = fn.length;
754 if( !l ) return '';
755
756 var args = Array(l);
757 while( l-- )
758 args[l] = String.fromCharCode(97+l);//97 is 'a'
759 return ' ' + args.join(', ') + ' ';
760 },
761 key:quote, //object calls it internally, the key part of an item in a map
762 functionCode:'[code]', //function calls it internally, it's the content of the function
763 attribute:quote, //node calls it internally, it's an html attribute value
764 string:quote,
765 date:quote,
766 regexp:literal, //regex
767 number:literal,
768 'boolean':literal
769 },
770 DOMAttrs:{//attributes to dump from nodes, name=>realName
771 id:'id',
772 name:'name',
773 'class':'className'
774 },
775 HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
776 indentChar:' ',//indentation unit
777 multiline:true //if true, items in a collection, are separated by a \n, else just a space.
778 };
779
780 })();
781