smparkes-envjs 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,136 @@
1
+ test("module without setup/teardown (default)", function() {
2
+ expect(1);
3
+ ok(true);
4
+ });
5
+
6
+ test("expect in test", 3, function() {
7
+ ok(true);
8
+ ok(true);
9
+ ok(true);
10
+ });
11
+
12
+ test("expect in test", 1, function() {
13
+ ok(true);
14
+ });
15
+
16
+ module("setup test", {
17
+ setup: function() {
18
+ ok(true);
19
+ }
20
+ });
21
+
22
+ test("module with setup", function() {
23
+ expect(2);
24
+ ok(true);
25
+ });
26
+
27
+ var state;
28
+
29
+ module("setup/teardown test", {
30
+ setup: function() {
31
+ state = true;
32
+ ok(true);
33
+ },
34
+ teardown: function() {
35
+ ok(true);
36
+ }
37
+ });
38
+
39
+ test("module with setup/teardown", function() {
40
+ expect(3);
41
+ ok(true);
42
+ });
43
+
44
+ module("setup/teardown test 2");
45
+
46
+ test("module without setup/teardown", function() {
47
+ expect(1);
48
+ ok(true);
49
+ });
50
+
51
+ if (typeof setTimeout !== 'undefined') {
52
+ state = 'fail';
53
+
54
+ module("teardown and stop", {
55
+ teardown: function() {
56
+ equals(state, "done", "Test teardown.");
57
+ }
58
+ });
59
+
60
+ test("teardown must be called after test ended", function() {
61
+ expect(1);
62
+ stop();
63
+ setTimeout(function() {
64
+ state = "done";
65
+ start();
66
+ }, 13);
67
+ });
68
+ } // end setTimeout tests
69
+
70
+ if (typeof asyncTest !== 'undefined') {
71
+ module("asyncTest");
72
+
73
+ asyncTest("asyncTest", function() {
74
+ expect(2);
75
+ ok(true);
76
+ setTimeout(function() {
77
+ state = "done";
78
+ ok(true);
79
+ start();
80
+ }, 13);
81
+ });
82
+
83
+ asyncTest("asyncTest", 2, function() {
84
+ ok(true);
85
+ setTimeout(function() {
86
+ state = "done";
87
+ ok(true);
88
+ start();
89
+ }, 13);
90
+ });
91
+ } // end asyncTest tests
92
+
93
+ module("save scope", {
94
+ setup: function() {
95
+ this.foo = "bar";
96
+ },
97
+ teardown: function() {
98
+ same(this.foo, "bar");
99
+ }
100
+ });
101
+ test("scope check", function() {
102
+ expect(2);
103
+ same(this.foo, "bar");
104
+ });
105
+
106
+ module("simple testEnvironment setup", {
107
+ foo: "bar",
108
+ bugid: "#5311" // example of meta-data
109
+ });
110
+ test("scope check", function() {
111
+ same(this.foo, "bar");
112
+ });
113
+ test("modify testEnvironment",function() {
114
+ this.foo="hamster";
115
+ });
116
+ test("testEnvironment reset for next test",function() {
117
+ same(this.foo, "bar");
118
+ });
119
+
120
+ module("testEnvironment with object", {
121
+ options:{
122
+ recipe:"soup",
123
+ ingredients:["hamster","onions"]
124
+ }
125
+ });
126
+ test("scope check", function() {
127
+ same(this.options, {recipe:"soup",ingredients:["hamster","onions"]}) ;
128
+ });
129
+ test("modify testEnvironment",function() {
130
+ // since we do a shallow copy, the testEnvironment can be modified
131
+ this.options.ingredients.push("carrots");
132
+ });
133
+ test("testEnvironment reset for next test",function() {
134
+ same(this.options, {recipe:"soup",ingredients:["hamster","onions","carrots"]}, "Is this a bug or a feature? Could do a deep copy") ;
135
+ });
136
+
@@ -0,0 +1,1002 @@
1
+ /*
2
+ * QUnit - A JavaScript Unit Testing Framework
3
+ *
4
+ * http://docs.jquery.com/QUnit
5
+ *
6
+ * Copyright (c) 2009 John Resig, Jörn Zaefferer
7
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
8
+ * and GPL (GPL-LICENSE.txt) licenses.
9
+ */
10
+
11
+ print(this);
12
+
13
+ (function(window) {
14
+
15
+ print(this);
16
+ print(window);
17
+
18
+ var QUnit = {
19
+
20
+ // Initialize the configuration options
21
+ init: function init() {
22
+ config = {
23
+ stats: { all: 0, bad: 0 },
24
+ moduleStats: { all: 0, bad: 0 },
25
+ started: +new Date,
26
+ blocking: false,
27
+ autorun: false,
28
+ assertions: [],
29
+ filters: [],
30
+ queue: []
31
+ };
32
+
33
+ var tests = id("qunit-tests"),
34
+ banner = id("qunit-banner"),
35
+ result = id("qunit-testresult");
36
+
37
+ if ( tests ) {
38
+ tests.innerHTML = "";
39
+ }
40
+
41
+ if ( banner ) {
42
+ banner.className = "";
43
+ }
44
+
45
+ if ( result ) {
46
+ result.parentNode.removeChild( result );
47
+ }
48
+ },
49
+
50
+ // call on start of module test to prepend name to all tests
51
+ module: function module(name, testEnvironment) {
52
+
53
+ synchronize(function() {
54
+ if ( config.currentModule ) {
55
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
56
+ }
57
+
58
+ config.currentModule = name;
59
+ config.moduleTestEnvironment = testEnvironment;
60
+ config.moduleStats = { all: 0, bad: 0 };
61
+
62
+ QUnit.moduleStart( name, testEnvironment );
63
+ });
64
+ },
65
+
66
+ asyncTest: function asyncTest(testName, expected, callback) {
67
+ if ( arguments.length === 2 ) {
68
+ callback = expected;
69
+ expected = 0;
70
+ }
71
+
72
+ QUnit.test(testName, expected, callback, true);
73
+ },
74
+
75
+ test: function test(testName, expected, callback, async) {
76
+ var name = testName, testEnvironment = {};
77
+
78
+ if ( arguments.length === 2 ) {
79
+ callback = expected;
80
+ expected = null;
81
+ }
82
+
83
+ if ( config.currentModule ) {
84
+ name = config.currentModule + " module: " + name;
85
+ }
86
+
87
+ if ( !validTest(name) ) {
88
+ return;
89
+ }
90
+
91
+ synchronize(function() {
92
+ QUnit.testStart( testName );
93
+
94
+ testEnvironment = extend({
95
+ setup: function() {},
96
+ teardown: function() {}
97
+ }, config.moduleTestEnvironment);
98
+
99
+ config.assertions = [];
100
+ config.expected = null;
101
+
102
+ if ( arguments.length >= 3 ) {
103
+ config.expected = callback;
104
+ callback = arguments[2];
105
+ }
106
+
107
+ try {
108
+ if ( !config.pollution ) {
109
+ saveGlobal();
110
+ }
111
+
112
+ testEnvironment.setup.call(testEnvironment);
113
+ } catch(e) {
114
+ QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
115
+ }
116
+
117
+ if ( async ) {
118
+ QUnit.stop();
119
+ }
120
+
121
+ try {
122
+ callback.call(testEnvironment);
123
+ } catch(e) {
124
+ fail("Test " + name + " died, exception and test follows", e, callback);
125
+ QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
126
+ // else next test will carry the responsibility
127
+ saveGlobal();
128
+
129
+ // Restart the tests if they're blocking
130
+ if ( config.blocking ) {
131
+ start();
132
+ }
133
+ }
134
+ });
135
+
136
+ synchronize(function() {
137
+ try {
138
+ checkPollution();
139
+ testEnvironment.teardown.call(testEnvironment);
140
+ } catch(e) {
141
+ QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
142
+ }
143
+
144
+ try {
145
+ QUnit.reset();
146
+ } catch(e) {
147
+ fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
148
+ }
149
+
150
+ if ( config.expected && config.expected != config.assertions.length ) {
151
+ QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
152
+ }
153
+
154
+ var good = 0, bad = 0,
155
+ tests = id("qunit-tests");
156
+
157
+ config.stats.all += config.assertions.length;
158
+ config.moduleStats.all += config.assertions.length;
159
+
160
+ if ( tests ) {
161
+ var ol = document.createElement("ol");
162
+ ol.style.display = "none";
163
+
164
+ for ( var i = 0; i < config.assertions.length; i++ ) {
165
+ var assertion = config.assertions[i];
166
+
167
+ var li = document.createElement("li");
168
+ li.className = assertion.result ? "pass" : "fail";
169
+ li.innerHTML = assertion.message || "(no message)";
170
+ ol.appendChild( li );
171
+
172
+ if ( assertion.result ) {
173
+ good++;
174
+ } else {
175
+ bad++;
176
+ config.stats.bad++;
177
+ config.moduleStats.bad++;
178
+ }
179
+ }
180
+
181
+ var b = document.createElement("strong");
182
+ b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
183
+
184
+ addEvent(b, "click", function() {
185
+ var next = b.nextSibling, display = next.style.display;
186
+ next.style.display = display === "none" ? "block" : "none";
187
+ });
188
+
189
+ addEvent(b, "dblclick", function(e) {
190
+ var target = (e || window.event).target;
191
+ if ( target.nodeName.toLowerCase() === "strong" ) {
192
+ var text = "", node = target.firstChild;
193
+
194
+ while ( node.nodeType === 3 ) {
195
+ text += node.nodeValue;
196
+ node = node.nextSibling;
197
+ }
198
+
199
+ text = text.replace(/(^\s*|\s*$)/g, "");
200
+
201
+ if ( window.location ) {
202
+ window.location.href = window.location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(text);
203
+ }
204
+ }
205
+ });
206
+
207
+ var li = document.createElement("li");
208
+ li.className = bad ? "fail" : "pass";
209
+ li.appendChild( b );
210
+ li.appendChild( ol );
211
+ tests.appendChild( li );
212
+
213
+ if ( bad ) {
214
+ var toolbar = id("qunit-testrunner-toolbar");
215
+ if ( toolbar ) {
216
+ toolbar.style.display = "block";
217
+ id("qunit-filter-pass").disabled = null;
218
+ id("qunit-filter-missing").disabled = null;
219
+ }
220
+ }
221
+
222
+ } else {
223
+ for ( var i = 0; i < config.assertions.length; i++ ) {
224
+ if ( !config.assertions[i].result ) {
225
+ bad++;
226
+ config.stats.bad++;
227
+ config.moduleStats.bad++;
228
+ }
229
+ }
230
+ }
231
+
232
+ QUnit.testDone( testName, bad, config.assertions.length );
233
+
234
+ if ( !window.setTimeout && !config.queue.length ) {
235
+ done();
236
+ }
237
+ });
238
+
239
+ if ( window.setTimeout && !config.doneTimer ) {
240
+ config.doneTimer = window.setTimeout(function(){
241
+ if ( !config.queue.length ) {
242
+ done();
243
+ } else {
244
+ synchronize( done );
245
+ }
246
+ }, 13);
247
+ }
248
+ },
249
+
250
+ /**
251
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
252
+ */
253
+ expect: function expect(asserts) {
254
+ config.expected = asserts;
255
+ },
256
+
257
+ /**
258
+ * Asserts true.
259
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
260
+ */
261
+ ok: function ok(a, msg) {
262
+ QUnit.log(a, msg);
263
+
264
+ config.assertions.push({
265
+ result: !!a,
266
+ message: msg
267
+ });
268
+ },
269
+
270
+ /**
271
+ * Checks that the first two arguments are equal, with an optional message.
272
+ * Prints out both actual and expected values.
273
+ *
274
+ * Prefered to ok( actual == expected, message )
275
+ *
276
+ * @example equals( format("Received {0} bytes.", 2), "Received 2 bytes." );
277
+ *
278
+ * @param Object actual
279
+ * @param Object expected
280
+ * @param String message (optional)
281
+ */
282
+ equals: function equals(actual, expected, message) {
283
+ push(expected == actual, actual, expected, message);
284
+ },
285
+
286
+ same: function(a, b, message) {
287
+ push(QUnit.equiv(a, b), a, b, message);
288
+ },
289
+
290
+ start: function start() {
291
+ // A slight delay, to avoid any current callbacks
292
+ if ( window.setTimeout ) {
293
+ window.setTimeout(function() {
294
+ if ( config.timeout ) {
295
+ clearTimeout(config.timeout);
296
+ }
297
+
298
+ config.blocking = false;
299
+ process();
300
+ }, 13);
301
+ } else {
302
+ config.blocking = false;
303
+ process();
304
+ }
305
+ },
306
+
307
+ stop: function stop(timeout) {
308
+ config.blocking = true;
309
+
310
+ if ( timeout && window.setTimeout ) {
311
+ config.timeout = window.setTimeout(function() {
312
+ QUnit.ok( false, "Test timed out" );
313
+ QUnit.start();
314
+ }, timeout);
315
+ }
316
+ },
317
+
318
+ /**
319
+ * Resets the test setup. Useful for tests that modify the DOM.
320
+ */
321
+ reset: function reset() {
322
+ if ( window.jQuery ) {
323
+ jQuery("#main").html( config.fixture );
324
+ jQuery.event.global = {};
325
+ jQuery.ajaxSettings = extend({}, config.ajaxSettings);
326
+ }
327
+ },
328
+
329
+ /**
330
+ * Trigger an event on an element.
331
+ *
332
+ * @example triggerEvent( document.body, "click" );
333
+ *
334
+ * @param DOMElement elem
335
+ * @param String type
336
+ */
337
+ triggerEvent: function triggerEvent( elem, type, event ) {
338
+ if ( document.createEvent ) {
339
+ event = document.createEvent("MouseEvents");
340
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
341
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
342
+ elem.dispatchEvent( event );
343
+
344
+ } else if ( elem.fireEvent ) {
345
+ elem.fireEvent("on"+type);
346
+ }
347
+ },
348
+
349
+ // Logging callbacks
350
+ done: function done(failures, total) {},
351
+ log: function log(result, message) {},
352
+ testStart: function testStart(name) {},
353
+ testDone: function testDone(name, failures, total) {},
354
+ moduleStart: function moduleStart(name, testEnvironment) {},
355
+ moduleDone: function moduleDone(name, failures, total) {}
356
+ };
357
+
358
+ // Maintain internal state
359
+ var config = {
360
+ // The queue of tests to run
361
+ queue: [],
362
+
363
+ // block until document ready
364
+ blocking: true
365
+ };
366
+
367
+ // Load paramaters
368
+ (function() {
369
+ var location = window.location || { search: "", protocol: "file:" },
370
+ GETParams = location.search.slice(1).split('&');
371
+
372
+ for ( var i = 0; i < GETParams.length; i++ ) {
373
+ GETParams[i] = decodeURIComponent( GETParams[i] );
374
+ if ( GETParams[i] === "noglobals" ) {
375
+ GETParams.splice( i, 1 );
376
+ i--;
377
+ config.noglobals = true;
378
+ }
379
+ }
380
+
381
+ // restrict modules/tests by get parameters
382
+ config.filters = GETParams;
383
+
384
+ // Figure out if we're running the tests from a server or not
385
+ QUnit.isLocal = !!(location.protocol === 'file:');
386
+ })();
387
+
388
+ // Expose the API as global variables, unless an 'exports'
389
+ // object exists, in that case we assume we're in CommonJS
390
+ if ( typeof exports === "undefined" || typeof require === "undefined" ) {
391
+ extend(window, QUnit);
392
+ window.QUnit = QUnit;
393
+ } else {
394
+ extend(exports, QUnit);
395
+ exports.QUnit = QUnit;
396
+ }
397
+
398
+ if ( typeof document === "undefined" || document.readyState === "complete" ) {
399
+ config.autorun = true;
400
+ }
401
+
402
+ addEvent(window, "load", function() {
403
+ // Initialize the config, saving the execution queue
404
+ var oldconfig = extend({}, config);
405
+ QUnit.init();
406
+ extend(config, oldconfig);
407
+
408
+ config.blocking = false;
409
+
410
+ var userAgent = id("qunit-userAgent");
411
+ if ( userAgent ) {
412
+ userAgent.innerHTML = navigator.userAgent;
413
+ }
414
+
415
+ var toolbar = id("qunit-testrunner-toolbar");
416
+ if ( toolbar ) {
417
+ toolbar.style.display = "none";
418
+
419
+ var filter = document.createElement("input");
420
+ filter.type = "checkbox";
421
+ filter.id = "qunit-filter-pass";
422
+ filter.disabled = true;
423
+ addEvent( filter, "click", function() {
424
+ var li = document.getElementsByTagName("li");
425
+ for ( var i = 0; i < li.length; i++ ) {
426
+ if ( li[i].className.indexOf("pass") > -1 ) {
427
+ li[i].style.display = filter.checked ? "none" : "block";
428
+ }
429
+ }
430
+ });
431
+ toolbar.appendChild( filter );
432
+
433
+ var label = document.createElement("label");
434
+ label.setAttribute("for", "filter-pass");
435
+ label.innerHTML = "Hide passed tests";
436
+ toolbar.appendChild( label );
437
+
438
+ var missing = document.createElement("input");
439
+ missing.type = "checkbox";
440
+ missing.id = "qunit-filter-missing";
441
+ missing.disabled = true;
442
+ addEvent( missing, "click", function() {
443
+ var li = document.getElementsByTagName("li");
444
+ for ( var i = 0; i < li.length; i++ ) {
445
+ if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
446
+ li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
447
+ }
448
+ }
449
+ });
450
+ toolbar.appendChild( missing );
451
+
452
+ label = document.createElement("label");
453
+ label.setAttribute("for", "filter-missing");
454
+ label.innerHTML = "Hide missing tests (untested code is broken code)";
455
+ toolbar.appendChild( label );
456
+ }
457
+
458
+ var main = id('main');
459
+ if ( main ) {
460
+ config.fixture = main.innerHTML;
461
+ }
462
+
463
+ if ( window.jQuery ) {
464
+ config.ajaxSettings = window.jQuery.ajaxSettings;
465
+ }
466
+
467
+ QUnit.start();
468
+ });
469
+
470
+ function done() {
471
+ if ( config.doneTimer && window.clearTimeout ) {
472
+ window.clearTimeout( config.doneTimer );
473
+ config.doneTimer = null;
474
+ }
475
+
476
+ if ( config.queue.length ) {
477
+ config.doneTimer = window.setTimeout(function(){
478
+ if ( !config.queue.length ) {
479
+ done();
480
+ } else {
481
+ synchronize( done );
482
+ }
483
+ }, 13);
484
+
485
+ return;
486
+ }
487
+
488
+ config.autorun = true;
489
+
490
+ // Log the last module results
491
+ if ( config.currentModule ) {
492
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
493
+ }
494
+
495
+ var banner = id("qunit-banner"),
496
+ tests = id("qunit-tests"),
497
+ html = ['Tests completed in ',
498
+ +new Date - config.started, ' milliseconds.<br/>',
499
+ '<span class="bad">', config.stats.all - config.stats.bad, '</span> tests of <span class="all">', config.stats.all, '</span> passed, ', config.stats.bad,' failed.'].join('');
500
+
501
+ if ( banner ) {
502
+ banner.className += " " + (config.stats.bad ? "fail" : "pass");
503
+ }
504
+
505
+ if ( tests ) {
506
+ var result = id("qunit-testresult");
507
+
508
+ if ( !result ) {
509
+ result = document.createElement("p");
510
+ result.id = "qunit-testresult";
511
+ result.className = "result";
512
+ tests.parentNode.insertBefore( result, tests.nextSibling );
513
+ }
514
+
515
+ result.innerHTML = html;
516
+ }
517
+
518
+ QUnit.done( config.stats.bad, config.stats.all );
519
+ }
520
+
521
+ function validTest( name ) {
522
+ var i = config.filters.length,
523
+ run = false;
524
+
525
+ if ( !i ) {
526
+ return true;
527
+ }
528
+
529
+ while ( i-- ) {
530
+ var filter = config.filters[i],
531
+ not = filter.charAt(0) == '!';
532
+
533
+ if ( not ) {
534
+ filter = filter.slice(1);
535
+ }
536
+
537
+ if ( name.indexOf(filter) !== -1 ) {
538
+ return !not;
539
+ }
540
+
541
+ if ( not ) {
542
+ run = true;
543
+ }
544
+ }
545
+
546
+ return run;
547
+ }
548
+
549
+ function push(result, actual, expected, message) {
550
+ message = message || (result ? "okay" : "failed");
551
+ QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + QUnit.jsDump.parse(expected) + " result: " + QUnit.jsDump.parse(actual) );
552
+ }
553
+
554
+ function synchronize( callback ) {
555
+ config.queue.push( callback );
556
+
557
+ if ( config.autorun && !config.blocking ) {
558
+ process();
559
+ }
560
+ }
561
+
562
+ function process() {
563
+ while ( config.queue.length && !config.blocking ) {
564
+ config.queue.shift()();
565
+ }
566
+ }
567
+
568
+ function saveGlobal() {
569
+ config.pollution = [];
570
+
571
+ if ( config.noglobals ) {
572
+ for ( var key in window ) {
573
+ config.pollution.push( key );
574
+ }
575
+ }
576
+ }
577
+
578
+ function checkPollution( name ) {
579
+ var old = config.pollution;
580
+ saveGlobal();
581
+
582
+ var newGlobals = diff( old, config.pollution );
583
+ if ( newGlobals.length > 0 ) {
584
+ ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
585
+ config.expected++;
586
+ }
587
+
588
+ var deletedGlobals = diff( config.pollution, old );
589
+ if ( deletedGlobals.length > 0 ) {
590
+ ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
591
+ config.expected++;
592
+ }
593
+ }
594
+
595
+ // returns a new Array with the elements that are in a but not in b
596
+ function diff( a, b ) {
597
+ var result = a.slice();
598
+ for ( var i = 0; i < result.length; i++ ) {
599
+ for ( var j = 0; j < b.length; j++ ) {
600
+ if ( result[i] === b[j] ) {
601
+ result.splice(i, 1);
602
+ i--;
603
+ break;
604
+ }
605
+ }
606
+ }
607
+ return result;
608
+ }
609
+
610
+ function fail(message, exception, callback) {
611
+ if ( typeof console !== "undefined" && console.error && console.warn ) {
612
+ console.error(message);
613
+ console.error(exception);
614
+ console.warn(callback.toString());
615
+
616
+ } else if ( window.opera && opera.postError ) {
617
+ opera.postError(message, exception, callback.toString);
618
+ }
619
+ }
620
+
621
+ function extend(a, b) {
622
+ for ( var prop in b ) {
623
+ a[prop] = b[prop];
624
+ }
625
+
626
+ return a;
627
+ }
628
+
629
+ function addEvent(elem, type, fn) {
630
+ if ( elem.addEventListener ) {
631
+ elem.addEventListener( type, fn, false );
632
+ } else if ( elem.attachEvent ) {
633
+ elem.attachEvent( "on" + type, fn );
634
+ } else {
635
+ fn();
636
+ }
637
+ }
638
+
639
+ function id(name) {
640
+ return !!(typeof document !== "undefined" && document && document.getElementById) &&
641
+ document.getElementById( name );
642
+ }
643
+
644
+ // Test for equality any JavaScript type.
645
+ // Discussions and reference: http://philrathe.com/articles/equiv
646
+ // Test suites: http://philrathe.com/tests/equiv
647
+ // Author: Philippe Rathé <prathe@gmail.com>
648
+ QUnit.equiv = function () {
649
+
650
+ var innerEquiv; // the real equiv function
651
+ var callers = []; // stack to decide between skip/abort functions
652
+
653
+
654
+ // Determine what is o.
655
+ function hoozit(o) {
656
+ if (o.constructor === String) {
657
+ return "string";
658
+
659
+ } else if (o.constructor === Boolean) {
660
+ return "boolean";
661
+
662
+ } else if (o.constructor === Number) {
663
+
664
+ if (isNaN(o)) {
665
+ return "nan";
666
+ } else {
667
+ return "number";
668
+ }
669
+
670
+ } else if (typeof o === "undefined") {
671
+ return "undefined";
672
+
673
+ // consider: typeof null === object
674
+ } else if (o === null) {
675
+ return "null";
676
+
677
+ // consider: typeof [] === object
678
+ } else if (o instanceof Array) {
679
+ return "array";
680
+
681
+ // consider: typeof new Date() === object
682
+ } else if (o instanceof Date) {
683
+ return "date";
684
+
685
+ // consider: /./ instanceof Object;
686
+ // /./ instanceof RegExp;
687
+ // typeof /./ === "function"; // => false in IE and Opera,
688
+ // true in FF and Safari
689
+ } else if (o instanceof RegExp) {
690
+ return "regexp";
691
+
692
+ } else if (typeof o === "object") {
693
+ return "object";
694
+
695
+ } else if (o instanceof Function) {
696
+ return "function";
697
+ } else {
698
+ return undefined;
699
+ }
700
+ }
701
+
702
+ // Call the o related callback with the given arguments.
703
+ function bindCallbacks(o, callbacks, args) {
704
+ var prop = hoozit(o);
705
+ if (prop) {
706
+ if (hoozit(callbacks[prop]) === "function") {
707
+ return callbacks[prop].apply(callbacks, args);
708
+ } else {
709
+ return callbacks[prop]; // or undefined
710
+ }
711
+ }
712
+ }
713
+
714
+ var callbacks = function () {
715
+
716
+ // for string, boolean, number and null
717
+ function useStrictEquality(b, a) {
718
+ if (b instanceof a.constructor || a instanceof b.constructor) {
719
+ // to catch short annotaion VS 'new' annotation of a declaration
720
+ // e.g. var i = 1;
721
+ // var j = new Number(1);
722
+ return a == b;
723
+ } else {
724
+ return a === b;
725
+ }
726
+ }
727
+
728
+ return {
729
+ "string": useStrictEquality,
730
+ "boolean": useStrictEquality,
731
+ "number": useStrictEquality,
732
+ "null": useStrictEquality,
733
+ "undefined": useStrictEquality,
734
+
735
+ "nan": function (b) {
736
+ return isNaN(b);
737
+ },
738
+
739
+ "date": function (b, a) {
740
+ return hoozit(b) === "date" && a.valueOf() === b.valueOf();
741
+ },
742
+
743
+ "regexp": function (b, a) {
744
+ return hoozit(b) === "regexp" &&
745
+ a.source === b.source && // the regex itself
746
+ a.global === b.global && // and its modifers (gmi) ...
747
+ a.ignoreCase === b.ignoreCase &&
748
+ a.multiline === b.multiline;
749
+ },
750
+
751
+ // - skip when the property is a method of an instance (OOP)
752
+ // - abort otherwise,
753
+ // initial === would have catch identical references anyway
754
+ "function": function () {
755
+ var caller = callers[callers.length - 1];
756
+ return caller !== Object &&
757
+ typeof caller !== "undefined";
758
+ },
759
+
760
+ "array": function (b, a) {
761
+ var i;
762
+ var len;
763
+
764
+ // b could be an object literal here
765
+ if ( ! (hoozit(b) === "array")) {
766
+ return false;
767
+ }
768
+
769
+ len = a.length;
770
+ if (len !== b.length) { // safe and faster
771
+ return false;
772
+ }
773
+ for (i = 0; i < len; i++) {
774
+ if ( ! innerEquiv(a[i], b[i])) {
775
+ return false;
776
+ }
777
+ }
778
+ return true;
779
+ },
780
+
781
+ "object": function (b, a) {
782
+ var i;
783
+ var eq = true; // unless we can proove it
784
+ var aProperties = [], bProperties = []; // collection of strings
785
+
786
+ // comparing constructors is more strict than using instanceof
787
+ if ( a.constructor !== b.constructor) {
788
+ return false;
789
+ }
790
+
791
+ // stack constructor before traversing properties
792
+ callers.push(a.constructor);
793
+
794
+ for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
795
+
796
+ aProperties.push(i); // collect a's properties
797
+
798
+ if ( ! innerEquiv(a[i], b[i])) {
799
+ eq = false;
800
+ }
801
+ }
802
+
803
+ callers.pop(); // unstack, we are done
804
+
805
+ for (i in b) {
806
+ bProperties.push(i); // collect b's properties
807
+ }
808
+
809
+ // Ensures identical properties name
810
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
811
+ }
812
+ };
813
+ }();
814
+
815
+ innerEquiv = function () { // can take multiple arguments
816
+ var args = Array.prototype.slice.apply(arguments);
817
+ if (args.length < 2) {
818
+ return true; // end transition
819
+ }
820
+
821
+ return (function (a, b) {
822
+ if (a === b) {
823
+ return true; // catch the most you can
824
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
825
+ return false; // don't lose time with error prone cases
826
+ } else {
827
+ return bindCallbacks(a, callbacks, [b, a]);
828
+ }
829
+
830
+ // apply transition with (1..n) arguments
831
+ })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
832
+ };
833
+
834
+ return innerEquiv;
835
+
836
+ }();
837
+
838
+ /**
839
+ * jsDump
840
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
841
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
842
+ * Date: 5/15/2008
843
+ * @projectDescription Advanced and extensible data dumping for Javascript.
844
+ * @version 1.0.0
845
+ * @author Ariel Flesler
846
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
847
+ */
848
+ QUnit.jsDump = (function() {
849
+ function quote( str ) {
850
+ return '"' + str.toString().replace(/"/g, '\\"') + '"';
851
+ };
852
+ function literal( o ) {
853
+ return o + '';
854
+ };
855
+ function join( pre, arr, post ) {
856
+ var s = jsDump.separator(),
857
+ base = jsDump.indent(),
858
+ inner = jsDump.indent(1);
859
+ if ( arr.join )
860
+ arr = arr.join( ',' + s + inner );
861
+ if ( !arr )
862
+ return pre + post;
863
+ return [ pre, inner + arr, base + post ].join(s);
864
+ };
865
+ function array( arr ) {
866
+ var i = arr.length, ret = Array(i);
867
+ this.up();
868
+ while ( i-- )
869
+ ret[i] = this.parse( arr[i] );
870
+ this.down();
871
+ return join( '[', ret, ']' );
872
+ };
873
+
874
+ var reName = /^function (\w+)/;
875
+
876
+ var jsDump = {
877
+ parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
878
+ var parser = this.parsers[ type || this.typeOf(obj) ];
879
+ type = typeof parser;
880
+
881
+ return type == 'function' ? parser.call( this, obj ) :
882
+ type == 'string' ? parser :
883
+ this.parsers.error;
884
+ },
885
+ typeOf:function( obj ) {
886
+ var type = typeof obj,
887
+ f = 'function';//we'll use it 3 times, save it
888
+ return type != 'object' && type != f ? type :
889
+ !obj ? 'null' :
890
+ obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions
891
+ obj.getHours ? 'date' :
892
+ obj.scrollBy ? 'window' :
893
+ obj.nodeName == '#document' ? 'document' :
894
+ obj.nodeName ? 'node' :
895
+ obj.item ? 'nodelist' : // Safari reports nodelists as functions
896
+ obj.callee ? 'arguments' :
897
+ obj.call || obj.constructor != Array && //an array would also fall on this hack
898
+ (obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects
899
+ 'length' in obj ? 'array' :
900
+ type;
901
+ },
902
+ separator:function() {
903
+ return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
904
+ },
905
+ indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
906
+ if ( !this.multiline )
907
+ return '';
908
+ var chr = this.indentChar;
909
+ if ( this.HTML )
910
+ chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
911
+ return Array( this._depth_ + (extra||0) ).join(chr);
912
+ },
913
+ up:function( a ) {
914
+ this._depth_ += a || 1;
915
+ },
916
+ down:function( a ) {
917
+ this._depth_ -= a || 1;
918
+ },
919
+ setParser:function( name, parser ) {
920
+ this.parsers[name] = parser;
921
+ },
922
+ // The next 3 are exposed so you can use them
923
+ quote:quote,
924
+ literal:literal,
925
+ join:join,
926
+ //
927
+ _depth_: 1,
928
+ // This is the list of parsers, to modify them, use jsDump.setParser
929
+ parsers:{
930
+ window: '[Window]',
931
+ document: '[Document]',
932
+ error:'[ERROR]', //when no parser is found, shouldn't happen
933
+ unknown: '[Unknown]',
934
+ 'null':'null',
935
+ undefined:'undefined',
936
+ 'function':function( fn ) {
937
+ var ret = 'function',
938
+ name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
939
+ if ( name )
940
+ ret += ' ' + name;
941
+ ret += '(';
942
+
943
+ ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
944
+ return join( ret, this.parse(fn,'functionCode'), '}' );
945
+ },
946
+ array: array,
947
+ nodelist: array,
948
+ arguments: array,
949
+ object:function( map ) {
950
+ var ret = [ ];
951
+ this.up();
952
+ for ( var key in map )
953
+ ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
954
+ this.down();
955
+ return join( '{', ret, '}' );
956
+ },
957
+ node:function( node ) {
958
+ var open = this.HTML ? '&lt;' : '<',
959
+ close = this.HTML ? '&gt;' : '>';
960
+
961
+ var tag = node.nodeName.toLowerCase(),
962
+ ret = open + tag;
963
+
964
+ for ( var a in this.DOMAttrs ) {
965
+ var val = node[this.DOMAttrs[a]];
966
+ if ( val )
967
+ ret += ' ' + a + '=' + this.parse( val, 'attribute' );
968
+ }
969
+ return ret + close + open + '/' + tag + close;
970
+ },
971
+ functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
972
+ var l = fn.length;
973
+ if ( !l ) return '';
974
+
975
+ var args = Array(l);
976
+ while ( l-- )
977
+ args[l] = String.fromCharCode(97+l);//97 is 'a'
978
+ return ' ' + args.join(', ') + ' ';
979
+ },
980
+ key:quote, //object calls it internally, the key part of an item in a map
981
+ functionCode:'[code]', //function calls it internally, it's the content of the function
982
+ attribute:quote, //node calls it internally, it's an html attribute value
983
+ string:quote,
984
+ date:quote,
985
+ regexp:literal, //regex
986
+ number:literal,
987
+ 'boolean':literal
988
+ },
989
+ DOMAttrs:{//attributes to dump from nodes, name=>realName
990
+ id:'id',
991
+ name:'name',
992
+ 'class':'className'
993
+ },
994
+ HTML:true,//if true, entities are escaped ( <, >, \t, space and \n )
995
+ indentChar:' ',//indentation unit
996
+ multiline:true //if true, items in a collection, are separated by a \n, else just a space.
997
+ };
998
+
999
+ return jsDump;
1000
+ })();
1001
+
1002
+ })(this);