1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | (function( window ) {
|
13 |
|
14 | var QUnit,
|
15 | config,
|
16 | onErrorFnPrev,
|
17 | fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ),
|
18 | toString = Object.prototype.toString,
|
19 | hasOwn = Object.prototype.hasOwnProperty,
|
20 |
|
21 | Date = window.Date,
|
22 | now = Date.now || function() {
|
23 | return new Date().getTime();
|
24 | },
|
25 | setTimeout = window.setTimeout,
|
26 | clearTimeout = window.clearTimeout,
|
27 | defined = {
|
28 | document: typeof window.document !== "undefined",
|
29 | setTimeout: typeof window.setTimeout !== "undefined",
|
30 | sessionStorage: (function() {
|
31 | var x = "qunit-test-string";
|
32 | try {
|
33 | sessionStorage.setItem( x, x );
|
34 | sessionStorage.removeItem( x );
|
35 | return true;
|
36 | } catch ( e ) {
|
37 | return false;
|
38 | }
|
39 | }())
|
40 | },
|
41 | |
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | errorString = function( error ) {
|
52 | var name, message,
|
53 | errorString = error.toString();
|
54 | if ( errorString.substring( 0, 7 ) === "[object" ) {
|
55 | name = error.name ? error.name.toString() : "Error";
|
56 | message = error.message ? error.message.toString() : "";
|
57 | if ( name && message ) {
|
58 | return name + ": " + message;
|
59 | } else if ( name ) {
|
60 | return name;
|
61 | } else if ( message ) {
|
62 | return message;
|
63 | } else {
|
64 | return "Error";
|
65 | }
|
66 | } else {
|
67 | return errorString;
|
68 | }
|
69 | },
|
70 | |
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | objectValues = function( obj ) {
|
78 | var key, val,
|
79 | vals = QUnit.is( "array", obj ) ? [] : {};
|
80 | for ( key in obj ) {
|
81 | if ( hasOwn.call( obj, key ) ) {
|
82 | val = obj[ key ];
|
83 | vals[ key ] = val === Object( val ) ? objectValues( val ) : val;
|
84 | }
|
85 | }
|
86 | return vals;
|
87 | };
|
88 |
|
89 |
|
90 |
|
91 | QUnit = {
|
92 |
|
93 |
|
94 | module: function( name, testEnvironment ) {
|
95 | config.currentModule = name;
|
96 | config.currentModuleTestEnvironment = testEnvironment;
|
97 | config.modules[ name ] = true;
|
98 | },
|
99 |
|
100 | asyncTest: function( testName, expected, callback ) {
|
101 | if ( arguments.length === 2 ) {
|
102 | callback = expected;
|
103 | expected = null;
|
104 | }
|
105 |
|
106 | QUnit.test( testName, expected, callback, true );
|
107 | },
|
108 |
|
109 | test: function( testName, expected, callback, async ) {
|
110 | var test;
|
111 |
|
112 | if ( arguments.length === 2 ) {
|
113 | callback = expected;
|
114 | expected = null;
|
115 | }
|
116 |
|
117 | test = new Test({
|
118 | testName: testName,
|
119 | expected: expected,
|
120 | async: async,
|
121 | callback: callback,
|
122 | module: config.currentModule,
|
123 | moduleTestEnvironment: config.currentModuleTestEnvironment,
|
124 | stack: sourceFromStacktrace( 2 )
|
125 | });
|
126 |
|
127 | if ( !validTest( test ) ) {
|
128 | return;
|
129 | }
|
130 |
|
131 | test.queue();
|
132 | },
|
133 |
|
134 | start: function( count ) {
|
135 | var message;
|
136 |
|
137 |
|
138 |
|
139 | if ( config.semaphore === undefined ) {
|
140 | QUnit.begin(function() {
|
141 |
|
142 | setTimeout(function() {
|
143 | QUnit.start( count );
|
144 | });
|
145 | });
|
146 | return;
|
147 | }
|
148 |
|
149 | config.semaphore -= count || 1;
|
150 |
|
151 | if ( config.semaphore > 0 ) {
|
152 | return;
|
153 | }
|
154 |
|
155 |
|
156 | QUnit.config.started = QUnit.config.started || now();
|
157 |
|
158 | if ( config.semaphore < 0 ) {
|
159 | config.semaphore = 0;
|
160 |
|
161 | message = "Called start() while already started (QUnit.config.semaphore was 0 already)";
|
162 |
|
163 | if ( config.current ) {
|
164 | QUnit.pushFailure( message, sourceFromStacktrace( 2 ) );
|
165 | } else {
|
166 | throw new Error( message );
|
167 | }
|
168 |
|
169 | return;
|
170 | }
|
171 |
|
172 | if ( defined.setTimeout ) {
|
173 | setTimeout(function() {
|
174 | if ( config.semaphore > 0 ) {
|
175 | return;
|
176 | }
|
177 | if ( config.timeout ) {
|
178 | clearTimeout( config.timeout );
|
179 | }
|
180 |
|
181 | config.blocking = false;
|
182 | process( true );
|
183 | }, 13 );
|
184 | } else {
|
185 | config.blocking = false;
|
186 | process( true );
|
187 | }
|
188 | },
|
189 |
|
190 | stop: function( count ) {
|
191 | config.semaphore += count || 1;
|
192 | config.blocking = true;
|
193 |
|
194 | if ( config.testTimeout && defined.setTimeout ) {
|
195 | clearTimeout( config.timeout );
|
196 | config.timeout = setTimeout(function() {
|
197 | QUnit.ok( false, "Test timed out" );
|
198 | config.semaphore = 1;
|
199 | QUnit.start();
|
200 | }, config.testTimeout );
|
201 | }
|
202 | }
|
203 | };
|
204 |
|
205 |
|
206 |
|
207 | (function() {
|
208 | function F() {}
|
209 | F.prototype = QUnit;
|
210 | QUnit = new F();
|
211 |
|
212 |
|
213 | QUnit.constructor = F;
|
214 | }());
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 | config = {
|
222 |
|
223 | queue: [],
|
224 |
|
225 |
|
226 | blocking: true,
|
227 |
|
228 |
|
229 |
|
230 | hidepassed: false,
|
231 |
|
232 |
|
233 |
|
234 | reorder: true,
|
235 |
|
236 |
|
237 | altertitle: true,
|
238 |
|
239 |
|
240 | scrolltop: true,
|
241 |
|
242 |
|
243 | requireExpects: false,
|
244 |
|
245 |
|
246 |
|
247 | urlConfig: [
|
248 | {
|
249 | id: "noglobals",
|
250 | label: "Check for Globals",
|
251 | tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
|
252 | },
|
253 | {
|
254 | id: "notrycatch",
|
255 | label: "No try-catch",
|
256 | tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
|
257 | }
|
258 | ],
|
259 |
|
260 |
|
261 | modules: {},
|
262 |
|
263 | callbacks: {}
|
264 | };
|
265 |
|
266 |
|
267 | (function() {
|
268 | var i, current,
|
269 | location = window.location || { search: "", protocol: "file:" },
|
270 | params = location.search.slice( 1 ).split( "&" ),
|
271 | length = params.length,
|
272 | urlParams = {};
|
273 |
|
274 | if ( params[ 0 ] ) {
|
275 | for ( i = 0; i < length; i++ ) {
|
276 | current = params[ i ].split( "=" );
|
277 | current[ 0 ] = decodeURIComponent( current[ 0 ] );
|
278 |
|
279 |
|
280 | current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
|
281 | if ( urlParams[ current[ 0 ] ] ) {
|
282 | urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] );
|
283 | } else {
|
284 | urlParams[ current[ 0 ] ] = current[ 1 ];
|
285 | }
|
286 | }
|
287 | }
|
288 |
|
289 | QUnit.urlParams = urlParams;
|
290 |
|
291 |
|
292 | config.filter = urlParams.filter;
|
293 |
|
294 |
|
295 | config.module = urlParams.module;
|
296 |
|
297 | config.testNumber = [];
|
298 | if ( urlParams.testNumber ) {
|
299 |
|
300 |
|
301 | urlParams.testNumber = [].concat( urlParams.testNumber );
|
302 | for ( i = 0; i < urlParams.testNumber.length; i++ ) {
|
303 | current = urlParams.testNumber[ i ];
|
304 | config.testNumber.push( parseInt( current, 10 ) );
|
305 | }
|
306 | }
|
307 |
|
308 |
|
309 | QUnit.isLocal = location.protocol === "file:";
|
310 | }());
|
311 |
|
312 | extend( QUnit, {
|
313 |
|
314 | config: config,
|
315 |
|
316 |
|
317 | is: function( type, obj ) {
|
318 | return QUnit.objectType( obj ) === type;
|
319 | },
|
320 |
|
321 | objectType: function( obj ) {
|
322 | if ( typeof obj === "undefined" ) {
|
323 | return "undefined";
|
324 | }
|
325 |
|
326 |
|
327 | if ( obj === null ) {
|
328 | return "null";
|
329 | }
|
330 |
|
331 | var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ),
|
332 | type = match && match[ 1 ] || "";
|
333 |
|
334 | switch ( type ) {
|
335 | case "Number":
|
336 | if ( isNaN( obj ) ) {
|
337 | return "nan";
|
338 | }
|
339 | return "number";
|
340 | case "String":
|
341 | case "Boolean":
|
342 | case "Array":
|
343 | case "Date":
|
344 | case "RegExp":
|
345 | case "Function":
|
346 | return type.toLowerCase();
|
347 | }
|
348 | if ( typeof obj === "object" ) {
|
349 | return "object";
|
350 | }
|
351 | return undefined;
|
352 | },
|
353 |
|
354 | url: function( params ) {
|
355 | params = extend( extend( {}, QUnit.urlParams ), params );
|
356 | var key,
|
357 | querystring = "?";
|
358 |
|
359 | for ( key in params ) {
|
360 | if ( hasOwn.call( params, key ) ) {
|
361 | querystring += encodeURIComponent( key ) + "=" +
|
362 | encodeURIComponent( params[ key ] ) + "&";
|
363 | }
|
364 | }
|
365 | return window.location.protocol + "//" + window.location.host +
|
366 | window.location.pathname + querystring.slice( 0, -1 );
|
367 | },
|
368 |
|
369 | extend: extend
|
370 | });
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 |
|
378 |
|
379 | extend( QUnit.constructor.prototype, {
|
380 |
|
381 |
|
382 |
|
383 | begin: registerLoggingCallback( "begin" ),
|
384 |
|
385 |
|
386 | done: registerLoggingCallback( "done" ),
|
387 |
|
388 |
|
389 | log: registerLoggingCallback( "log" ),
|
390 |
|
391 |
|
392 | testStart: registerLoggingCallback( "testStart" ),
|
393 |
|
394 |
|
395 | testDone: registerLoggingCallback( "testDone" ),
|
396 |
|
397 |
|
398 | moduleStart: registerLoggingCallback( "moduleStart" ),
|
399 |
|
400 |
|
401 | moduleDone: registerLoggingCallback( "moduleDone" )
|
402 | });
|
403 |
|
404 | QUnit.load = function() {
|
405 | runLoggingCallbacks( "begin", {
|
406 | totalTests: Test.count
|
407 | });
|
408 |
|
409 |
|
410 | extend( config, {
|
411 | stats: { all: 0, bad: 0 },
|
412 | moduleStats: { all: 0, bad: 0 },
|
413 | started: 0,
|
414 | updateRate: 1000,
|
415 | autostart: true,
|
416 | filter: "",
|
417 | semaphore: 1
|
418 | }, true );
|
419 |
|
420 | config.blocking = false;
|
421 |
|
422 | if ( config.autostart ) {
|
423 | QUnit.start();
|
424 | }
|
425 | };
|
426 |
|
427 |
|
428 |
|
429 | onErrorFnPrev = window.onerror;
|
430 |
|
431 |
|
432 |
|
433 |
|
434 | window.onerror = function( error, filePath, linerNr ) {
|
435 | var ret = false;
|
436 | if ( onErrorFnPrev ) {
|
437 | ret = onErrorFnPrev( error, filePath, linerNr );
|
438 | }
|
439 |
|
440 |
|
441 |
|
442 | if ( ret !== true ) {
|
443 | if ( QUnit.config.current ) {
|
444 | if ( QUnit.config.current.ignoreGlobalErrors ) {
|
445 | return true;
|
446 | }
|
447 | QUnit.pushFailure( error, filePath + ":" + linerNr );
|
448 | } else {
|
449 | QUnit.test( "global failure", extend(function() {
|
450 | QUnit.pushFailure( error, filePath + ":" + linerNr );
|
451 | }, { validTest: validTest } ) );
|
452 | }
|
453 | return false;
|
454 | }
|
455 |
|
456 | return ret;
|
457 | };
|
458 |
|
459 | function done() {
|
460 | config.autorun = true;
|
461 |
|
462 |
|
463 | if ( config.previousModule ) {
|
464 | runLoggingCallbacks( "moduleDone", {
|
465 | name: config.previousModule,
|
466 | failed: config.moduleStats.bad,
|
467 | passed: config.moduleStats.all - config.moduleStats.bad,
|
468 | total: config.moduleStats.all
|
469 | });
|
470 | }
|
471 | delete config.previousModule;
|
472 |
|
473 | var runtime = now() - config.started,
|
474 | passed = config.stats.all - config.stats.bad;
|
475 |
|
476 | runLoggingCallbacks( "done", {
|
477 | failed: config.stats.bad,
|
478 | passed: passed,
|
479 | total: config.stats.all,
|
480 | runtime: runtime
|
481 | });
|
482 | }
|
483 |
|
484 |
|
485 | function validTest( test ) {
|
486 | var include,
|
487 | filter = config.filter && config.filter.toLowerCase(),
|
488 | module = config.module && config.module.toLowerCase(),
|
489 | fullName = ( test.module + ": " + test.testName ).toLowerCase();
|
490 |
|
491 |
|
492 | if ( test.callback && test.callback.validTest === validTest ) {
|
493 | delete test.callback.validTest;
|
494 | return true;
|
495 | }
|
496 |
|
497 | if ( config.testNumber.length > 0 ) {
|
498 | if ( inArray( test.testNumber, config.testNumber ) < 0 ) {
|
499 | return false;
|
500 | }
|
501 | }
|
502 |
|
503 | if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
|
504 | return false;
|
505 | }
|
506 |
|
507 | if ( !filter ) {
|
508 | return true;
|
509 | }
|
510 |
|
511 | include = filter.charAt( 0 ) !== "!";
|
512 | if ( !include ) {
|
513 | filter = filter.slice( 1 );
|
514 | }
|
515 |
|
516 |
|
517 | if ( fullName.indexOf( filter ) !== -1 ) {
|
518 | return include;
|
519 | }
|
520 |
|
521 |
|
522 | return !include;
|
523 | }
|
524 |
|
525 |
|
526 |
|
527 | function extractStacktrace( e, offset ) {
|
528 | offset = offset === undefined ? 4 : offset;
|
529 |
|
530 | var stack, include, i;
|
531 |
|
532 | if ( e.stacktrace ) {
|
533 |
|
534 |
|
535 | return e.stacktrace.split( "\n" )[ offset + 3 ];
|
536 | } else if ( e.stack ) {
|
537 |
|
538 |
|
539 | stack = e.stack.split( "\n" );
|
540 | if ( /^error$/i.test( stack[ 0 ] ) ) {
|
541 | stack.shift();
|
542 | }
|
543 | if ( fileName ) {
|
544 | include = [];
|
545 | for ( i = offset; i < stack.length; i++ ) {
|
546 | if ( stack[ i ].indexOf( fileName ) !== -1 ) {
|
547 | break;
|
548 | }
|
549 | include.push( stack[ i ] );
|
550 | }
|
551 | if ( include.length ) {
|
552 | return include.join( "\n" );
|
553 | }
|
554 | }
|
555 | return stack[ offset ];
|
556 | } else if ( e.sourceURL ) {
|
557 |
|
558 |
|
559 |
|
560 | if ( /qunit.js$/.test( e.sourceURL ) ) {
|
561 | return;
|
562 | }
|
563 |
|
564 |
|
565 | return e.sourceURL + ":" + e.line;
|
566 | }
|
567 | }
|
568 | function sourceFromStacktrace( offset ) {
|
569 | try {
|
570 | throw new Error();
|
571 | } catch ( e ) {
|
572 | return extractStacktrace( e, offset );
|
573 | }
|
574 | }
|
575 |
|
576 | function synchronize( callback, last ) {
|
577 | config.queue.push( callback );
|
578 |
|
579 | if ( config.autorun && !config.blocking ) {
|
580 | process( last );
|
581 | }
|
582 | }
|
583 |
|
584 | function process( last ) {
|
585 | function next() {
|
586 | process( last );
|
587 | }
|
588 | var start = now();
|
589 | config.depth = config.depth ? config.depth + 1 : 1;
|
590 |
|
591 | while ( config.queue.length && !config.blocking ) {
|
592 | if ( !defined.setTimeout || config.updateRate <= 0 || ( ( now() - start ) < config.updateRate ) ) {
|
593 | config.queue.shift()();
|
594 | } else {
|
595 | setTimeout( next, 13 );
|
596 | break;
|
597 | }
|
598 | }
|
599 | config.depth--;
|
600 | if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
|
601 | done();
|
602 | }
|
603 | }
|
604 |
|
605 | function saveGlobal() {
|
606 | config.pollution = [];
|
607 |
|
608 | if ( config.noglobals ) {
|
609 | for ( var key in window ) {
|
610 | if ( hasOwn.call( window, key ) ) {
|
611 |
|
612 | if ( /^qunit-test-output/.test( key ) ) {
|
613 | continue;
|
614 | }
|
615 | config.pollution.push( key );
|
616 | }
|
617 | }
|
618 | }
|
619 | }
|
620 |
|
621 | function checkPollution() {
|
622 | var newGlobals,
|
623 | deletedGlobals,
|
624 | old = config.pollution;
|
625 |
|
626 | saveGlobal();
|
627 |
|
628 | newGlobals = diff( config.pollution, old );
|
629 | if ( newGlobals.length > 0 ) {
|
630 | QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) );
|
631 | }
|
632 |
|
633 | deletedGlobals = diff( old, config.pollution );
|
634 | if ( deletedGlobals.length > 0 ) {
|
635 | QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) );
|
636 | }
|
637 | }
|
638 |
|
639 |
|
640 | function diff( a, b ) {
|
641 | var i, j,
|
642 | result = a.slice();
|
643 |
|
644 | for ( i = 0; i < result.length; i++ ) {
|
645 | for ( j = 0; j < b.length; j++ ) {
|
646 | if ( result[ i ] === b[ j ] ) {
|
647 | result.splice( i, 1 );
|
648 | i--;
|
649 | break;
|
650 | }
|
651 | }
|
652 | }
|
653 | return result;
|
654 | }
|
655 |
|
656 | function extend( a, b, undefOnly ) {
|
657 | for ( var prop in b ) {
|
658 | if ( hasOwn.call( b, prop ) ) {
|
659 |
|
660 |
|
661 | if ( !( prop === "constructor" && a === window ) ) {
|
662 | if ( b[ prop ] === undefined ) {
|
663 | delete a[ prop ];
|
664 | } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) {
|
665 | a[ prop ] = b[ prop ];
|
666 | }
|
667 | }
|
668 | }
|
669 | }
|
670 |
|
671 | return a;
|
672 | }
|
673 |
|
674 | function registerLoggingCallback( key ) {
|
675 |
|
676 |
|
677 | if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) {
|
678 | config.callbacks[ key ] = [];
|
679 | }
|
680 |
|
681 | return function( callback ) {
|
682 | config.callbacks[ key ].push( callback );
|
683 | };
|
684 | }
|
685 |
|
686 | function runLoggingCallbacks( key, args ) {
|
687 | var i, l, callbacks;
|
688 |
|
689 | callbacks = config.callbacks[ key ];
|
690 | for ( i = 0, l = callbacks.length; i < l; i++ ) {
|
691 | callbacks[ i ]( args );
|
692 | }
|
693 | }
|
694 |
|
695 |
|
696 | function inArray( elem, array ) {
|
697 | if ( array.indexOf ) {
|
698 | return array.indexOf( elem );
|
699 | }
|
700 |
|
701 | for ( var i = 0, length = array.length; i < length; i++ ) {
|
702 | if ( array[ i ] === elem ) {
|
703 | return i;
|
704 | }
|
705 | }
|
706 |
|
707 | return -1;
|
708 | }
|
709 |
|
710 | function Test( settings ) {
|
711 | extend( this, settings );
|
712 | this.assert = new Assert( this );
|
713 | this.assertions = [];
|
714 | this.testNumber = ++Test.count;
|
715 | }
|
716 |
|
717 | Test.count = 0;
|
718 |
|
719 | Test.prototype = {
|
720 | setup: function() {
|
721 | if (
|
722 |
|
723 |
|
724 | this.module !== config.previousModule ||
|
725 |
|
726 |
|
727 |
|
728 |
|
729 |
|
730 | !hasOwn.call( config, "previousModule" )
|
731 | ) {
|
732 | if ( hasOwn.call( config, "previousModule" ) ) {
|
733 | runLoggingCallbacks( "moduleDone", {
|
734 | name: config.previousModule,
|
735 | failed: config.moduleStats.bad,
|
736 | passed: config.moduleStats.all - config.moduleStats.bad,
|
737 | total: config.moduleStats.all
|
738 | });
|
739 | }
|
740 | config.previousModule = this.module;
|
741 | config.moduleStats = { all: 0, bad: 0 };
|
742 | runLoggingCallbacks( "moduleStart", {
|
743 | name: this.module
|
744 | });
|
745 | }
|
746 |
|
747 | config.current = this;
|
748 |
|
749 | this.testEnvironment = extend({
|
750 | setup: function() {},
|
751 | teardown: function() {}
|
752 | }, this.moduleTestEnvironment );
|
753 |
|
754 | this.started = now();
|
755 | runLoggingCallbacks( "testStart", {
|
756 | name: this.testName,
|
757 | module: this.module,
|
758 | testNumber: this.testNumber
|
759 | });
|
760 |
|
761 | if ( !config.pollution ) {
|
762 | saveGlobal();
|
763 | }
|
764 | if ( config.notrycatch ) {
|
765 | this.testEnvironment.setup.call( this.testEnvironment, this.assert );
|
766 | return;
|
767 | }
|
768 | try {
|
769 | this.testEnvironment.setup.call( this.testEnvironment, this.assert );
|
770 | } catch ( e ) {
|
771 | this.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
|
772 | }
|
773 | },
|
774 | run: function() {
|
775 | config.current = this;
|
776 |
|
777 | if ( this.async ) {
|
778 | QUnit.stop();
|
779 | }
|
780 |
|
781 | this.callbackStarted = now();
|
782 |
|
783 | if ( config.notrycatch ) {
|
784 | this.callback.call( this.testEnvironment, this.assert );
|
785 | this.callbackRuntime = now() - this.callbackStarted;
|
786 | return;
|
787 | }
|
788 |
|
789 | try {
|
790 | this.callback.call( this.testEnvironment, this.assert );
|
791 | this.callbackRuntime = now() - this.callbackStarted;
|
792 | } catch ( e ) {
|
793 | this.callbackRuntime = now() - this.callbackStarted;
|
794 |
|
795 | this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
|
796 |
|
797 |
|
798 | saveGlobal();
|
799 |
|
800 |
|
801 | if ( config.blocking ) {
|
802 | QUnit.start();
|
803 | }
|
804 | }
|
805 | },
|
806 | teardown: function() {
|
807 | config.current = this;
|
808 | if ( config.notrycatch ) {
|
809 | if ( typeof this.callbackRuntime === "undefined" ) {
|
810 | this.callbackRuntime = now() - this.callbackStarted;
|
811 | }
|
812 | this.testEnvironment.teardown.call( this.testEnvironment, this.assert );
|
813 | return;
|
814 | } else {
|
815 | try {
|
816 | this.testEnvironment.teardown.call( this.testEnvironment, this.assert );
|
817 | } catch ( e ) {
|
818 | this.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
|
819 | }
|
820 | }
|
821 | checkPollution();
|
822 | },
|
823 | finish: function() {
|
824 | config.current = this;
|
825 | if ( config.requireExpects && this.expected === null ) {
|
826 | this.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
|
827 | } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
|
828 | this.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
|
829 | } else if ( this.expected === null && !this.assertions.length ) {
|
830 | this.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
|
831 | }
|
832 |
|
833 | var i,
|
834 | bad = 0;
|
835 |
|
836 | this.runtime = now() - this.started;
|
837 | config.stats.all += this.assertions.length;
|
838 | config.moduleStats.all += this.assertions.length;
|
839 |
|
840 | for ( i = 0; i < this.assertions.length; i++ ) {
|
841 | if ( !this.assertions[ i ].result ) {
|
842 | bad++;
|
843 | config.stats.bad++;
|
844 | config.moduleStats.bad++;
|
845 | }
|
846 | }
|
847 |
|
848 | runLoggingCallbacks( "testDone", {
|
849 | name: this.testName,
|
850 | module: this.module,
|
851 | failed: bad,
|
852 | passed: this.assertions.length - bad,
|
853 | total: this.assertions.length,
|
854 | runtime: this.runtime,
|
855 |
|
856 |
|
857 | assertions: this.assertions,
|
858 | testNumber: this.testNumber,
|
859 |
|
860 |
|
861 | duration: this.runtime
|
862 | });
|
863 |
|
864 | config.current = undefined;
|
865 | },
|
866 |
|
867 | queue: function() {
|
868 | var bad,
|
869 | test = this;
|
870 |
|
871 | function run() {
|
872 |
|
873 | synchronize(function() {
|
874 | test.setup();
|
875 | });
|
876 | synchronize(function() {
|
877 | test.run();
|
878 | });
|
879 | synchronize(function() {
|
880 | test.teardown();
|
881 | });
|
882 | synchronize(function() {
|
883 | test.finish();
|
884 | });
|
885 | }
|
886 |
|
887 |
|
888 |
|
889 | bad = QUnit.config.reorder && defined.sessionStorage &&
|
890 | +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
|
891 |
|
892 | if ( bad ) {
|
893 | run();
|
894 | } else {
|
895 | synchronize( run, true );
|
896 | }
|
897 | },
|
898 |
|
899 | push: function( result, actual, expected, message ) {
|
900 | var source,
|
901 | details = {
|
902 | module: this.module,
|
903 | name: this.testName,
|
904 | result: result,
|
905 | message: message,
|
906 | actual: actual,
|
907 | expected: expected,
|
908 | testNumber: this.testNumber
|
909 | };
|
910 |
|
911 | if ( !result ) {
|
912 | source = sourceFromStacktrace();
|
913 |
|
914 | if ( source ) {
|
915 | details.source = source;
|
916 | }
|
917 | }
|
918 |
|
919 | runLoggingCallbacks( "log", details );
|
920 |
|
921 | this.assertions.push({
|
922 | result: !!result,
|
923 | message: message
|
924 | });
|
925 | },
|
926 |
|
927 | pushFailure: function( message, source, actual ) {
|
928 | if ( !this instanceof Test ) {
|
929 | throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace( 2 ) );
|
930 | }
|
931 |
|
932 | var details = {
|
933 | module: this.module,
|
934 | name: this.testName,
|
935 | result: false,
|
936 | message: message || "error",
|
937 | actual: actual || null,
|
938 | testNumber: this.testNumber
|
939 | };
|
940 |
|
941 | if ( source ) {
|
942 | details.source = source;
|
943 | }
|
944 |
|
945 | runLoggingCallbacks( "log", details );
|
946 |
|
947 | this.assertions.push({
|
948 | result: false,
|
949 | message: message
|
950 | });
|
951 | }
|
952 | };
|
953 |
|
954 | QUnit.pushFailure = function() {
|
955 | if ( !QUnit.config.current ) {
|
956 | throw new Error( "pushFailure() assertion outside test context, in " + sourceFromStacktrace( 2 ) );
|
957 | }
|
958 |
|
959 |
|
960 | var currentTest = QUnit.config.current.assert.test;
|
961 |
|
962 | return currentTest.pushFailure.apply( currentTest, arguments );
|
963 | };
|
964 |
|
965 | function Assert( testContext ) {
|
966 | this.test = testContext;
|
967 | }
|
968 |
|
969 |
|
970 | QUnit.assert = Assert.prototype = {
|
971 |
|
972 |
|
973 | expect: function( asserts ) {
|
974 | if ( arguments.length === 1 ) {
|
975 | this.test.expected = asserts;
|
976 | } else {
|
977 | return this.test.expected;
|
978 | }
|
979 | },
|
980 |
|
981 |
|
982 | push: function() {
|
983 | var assert = this;
|
984 |
|
985 |
|
986 |
|
987 |
|
988 |
|
989 |
|
990 | if ( !QUnit.config.current ) {
|
991 | throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) );
|
992 | }
|
993 | if ( !( assert instanceof Assert ) ) {
|
994 | assert = QUnit.config.current.assert;
|
995 | }
|
996 | return assert.test.push.apply( assert.test, arguments );
|
997 | },
|
998 |
|
999 | |
1000 |
|
1001 |
|
1002 |
|
1003 |
|
1004 |
|
1005 | ok: function( result, message ) {
|
1006 | message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " +
|
1007 | QUnit.dump.parse( result ) );
|
1008 | if ( !!result ) {
|
1009 | this.push( true, result, true, message );
|
1010 | } else {
|
1011 | this.test.pushFailure( message, null, result );
|
1012 | }
|
1013 | },
|
1014 |
|
1015 | |
1016 |
|
1017 |
|
1018 |
|
1019 |
|
1020 |
|
1021 |
|
1022 | equal: function( actual, expected, message ) {
|
1023 |
|
1024 | this.push( expected == actual, actual, expected, message );
|
1025 | },
|
1026 |
|
1027 | |
1028 |
|
1029 |
|
1030 |
|
1031 | notEqual: function( actual, expected, message ) {
|
1032 |
|
1033 | this.push( expected != actual, actual, expected, message );
|
1034 | },
|
1035 |
|
1036 | |
1037 |
|
1038 |
|
1039 |
|
1040 | propEqual: function( actual, expected, message ) {
|
1041 | actual = objectValues( actual );
|
1042 | expected = objectValues( expected );
|
1043 | this.push( QUnit.equiv( actual, expected ), actual, expected, message );
|
1044 | },
|
1045 |
|
1046 | |
1047 |
|
1048 |
|
1049 |
|
1050 | notPropEqual: function( actual, expected, message ) {
|
1051 | actual = objectValues( actual );
|
1052 | expected = objectValues( expected );
|
1053 | this.push( !QUnit.equiv( actual, expected ), actual, expected, message );
|
1054 | },
|
1055 |
|
1056 | |
1057 |
|
1058 |
|
1059 |
|
1060 | deepEqual: function( actual, expected, message ) {
|
1061 | this.push( QUnit.equiv( actual, expected ), actual, expected, message );
|
1062 | },
|
1063 |
|
1064 | |
1065 |
|
1066 |
|
1067 |
|
1068 | notDeepEqual: function( actual, expected, message ) {
|
1069 | this.push( !QUnit.equiv( actual, expected ), actual, expected, message );
|
1070 | },
|
1071 |
|
1072 | |
1073 |
|
1074 |
|
1075 |
|
1076 | strictEqual: function( actual, expected, message ) {
|
1077 | this.push( expected === actual, actual, expected, message );
|
1078 | },
|
1079 |
|
1080 | |
1081 |
|
1082 |
|
1083 |
|
1084 | notStrictEqual: function( actual, expected, message ) {
|
1085 | this.push( expected !== actual, actual, expected, message );
|
1086 | },
|
1087 |
|
1088 | "throws": function( block, expected, message ) {
|
1089 | var actual, expectedType,
|
1090 | expectedOutput = expected,
|
1091 | ok = false;
|
1092 |
|
1093 |
|
1094 | if ( message == null && typeof expected === "string" ) {
|
1095 | message = expected;
|
1096 | expected = null;
|
1097 | }
|
1098 |
|
1099 | this.test.ignoreGlobalErrors = true;
|
1100 | try {
|
1101 | block.call( this.test.testEnvironment );
|
1102 | } catch (e) {
|
1103 | actual = e;
|
1104 | }
|
1105 | this.test.ignoreGlobalErrors = false;
|
1106 |
|
1107 | if ( actual ) {
|
1108 | expectedType = QUnit.objectType( expected );
|
1109 |
|
1110 |
|
1111 | if ( !expected ) {
|
1112 | ok = true;
|
1113 | expectedOutput = null;
|
1114 |
|
1115 |
|
1116 | } else if ( expectedType === "regexp" ) {
|
1117 | ok = expected.test( errorString( actual ) );
|
1118 |
|
1119 |
|
1120 | } else if ( expectedType === "string" ) {
|
1121 | ok = expected === errorString( actual );
|
1122 |
|
1123 |
|
1124 | } else if ( expectedType === "function" && actual instanceof expected ) {
|
1125 | ok = true;
|
1126 |
|
1127 |
|
1128 | } else if ( expectedType === "object" ) {
|
1129 | ok = actual instanceof expected.constructor &&
|
1130 | actual.name === expected.name &&
|
1131 | actual.message === expected.message;
|
1132 |
|
1133 |
|
1134 | } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) {
|
1135 | expectedOutput = null;
|
1136 | ok = true;
|
1137 | }
|
1138 |
|
1139 | this.push( ok, actual, expectedOutput, message );
|
1140 | } else {
|
1141 | this.test.pushFailure( message, null, "No exception was thrown." );
|
1142 | }
|
1143 | }
|
1144 | };
|
1145 |
|
1146 |
|
1147 |
|
1148 | QUnit.equiv = (function() {
|
1149 |
|
1150 |
|
1151 | function bindCallbacks( o, callbacks, args ) {
|
1152 | var prop = QUnit.objectType( o );
|
1153 | if ( prop ) {
|
1154 | if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
|
1155 | return callbacks[ prop ].apply( callbacks, args );
|
1156 | } else {
|
1157 | return callbacks[ prop ];
|
1158 | }
|
1159 | }
|
1160 | }
|
1161 |
|
1162 |
|
1163 | var innerEquiv,
|
1164 |
|
1165 |
|
1166 | callers = [],
|
1167 |
|
1168 |
|
1169 | parents = [],
|
1170 | parentsB = [],
|
1171 |
|
1172 | getProto = Object.getPrototypeOf || function( obj ) {
|
1173 |
|
1174 | return obj.__proto__;
|
1175 | },
|
1176 | callbacks = (function() {
|
1177 |
|
1178 |
|
1179 | function useStrictEquality( b, a ) {
|
1180 |
|
1181 |
|
1182 | if ( b instanceof a.constructor || a instanceof b.constructor ) {
|
1183 |
|
1184 |
|
1185 |
|
1186 |
|
1187 |
|
1188 | return a == b;
|
1189 | } else {
|
1190 | return a === b;
|
1191 | }
|
1192 | }
|
1193 |
|
1194 | return {
|
1195 | "string": useStrictEquality,
|
1196 | "boolean": useStrictEquality,
|
1197 | "number": useStrictEquality,
|
1198 | "null": useStrictEquality,
|
1199 | "undefined": useStrictEquality,
|
1200 |
|
1201 | "nan": function( b ) {
|
1202 | return isNaN( b );
|
1203 | },
|
1204 |
|
1205 | "date": function( b, a ) {
|
1206 | return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
|
1207 | },
|
1208 |
|
1209 | "regexp": function( b, a ) {
|
1210 | return QUnit.objectType( b ) === "regexp" &&
|
1211 |
|
1212 |
|
1213 | a.source === b.source &&
|
1214 |
|
1215 |
|
1216 | a.global === b.global &&
|
1217 |
|
1218 |
|
1219 | a.ignoreCase === b.ignoreCase &&
|
1220 | a.multiline === b.multiline &&
|
1221 | a.sticky === b.sticky;
|
1222 | },
|
1223 |
|
1224 |
|
1225 |
|
1226 |
|
1227 | "function": function() {
|
1228 | var caller = callers[ callers.length - 1 ];
|
1229 | return caller !== Object && typeof caller !== "undefined";
|
1230 | },
|
1231 |
|
1232 | "array": function( b, a ) {
|
1233 | var i, j, len, loop, aCircular, bCircular;
|
1234 |
|
1235 |
|
1236 | if ( QUnit.objectType( b ) !== "array" ) {
|
1237 | return false;
|
1238 | }
|
1239 |
|
1240 | len = a.length;
|
1241 | if ( len !== b.length ) {
|
1242 |
|
1243 | return false;
|
1244 | }
|
1245 |
|
1246 |
|
1247 | parents.push( a );
|
1248 | parentsB.push( b );
|
1249 | for ( i = 0; i < len; i++ ) {
|
1250 | loop = false;
|
1251 | for ( j = 0; j < parents.length; j++ ) {
|
1252 | aCircular = parents[ j ] === a[ i ];
|
1253 | bCircular = parentsB[ j ] === b[ i ];
|
1254 | if ( aCircular || bCircular ) {
|
1255 | if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
|
1256 | loop = true;
|
1257 | } else {
|
1258 | parents.pop();
|
1259 | parentsB.pop();
|
1260 | return false;
|
1261 | }
|
1262 | }
|
1263 | }
|
1264 | if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
|
1265 | parents.pop();
|
1266 | parentsB.pop();
|
1267 | return false;
|
1268 | }
|
1269 | }
|
1270 | parents.pop();
|
1271 | parentsB.pop();
|
1272 | return true;
|
1273 | },
|
1274 |
|
1275 | "object": function( b, a ) {
|
1276 |
|
1277 |
|
1278 | var i, j, loop, aCircular, bCircular,
|
1279 |
|
1280 | eq = true,
|
1281 | aProperties = [],
|
1282 | bProperties = [];
|
1283 |
|
1284 |
|
1285 |
|
1286 | if ( a.constructor !== b.constructor ) {
|
1287 |
|
1288 |
|
1289 |
|
1290 | if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) ||
|
1291 | ( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) {
|
1292 | return false;
|
1293 | }
|
1294 | }
|
1295 |
|
1296 |
|
1297 | callers.push( a.constructor );
|
1298 |
|
1299 |
|
1300 | parents.push( a );
|
1301 | parentsB.push( b );
|
1302 |
|
1303 |
|
1304 | for ( i in a ) {
|
1305 | loop = false;
|
1306 | for ( j = 0; j < parents.length; j++ ) {
|
1307 | aCircular = parents[ j ] === a[ i ];
|
1308 | bCircular = parentsB[ j ] === b[ i ];
|
1309 | if ( aCircular || bCircular ) {
|
1310 | if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
|
1311 | loop = true;
|
1312 | } else {
|
1313 | eq = false;
|
1314 | break;
|
1315 | }
|
1316 | }
|
1317 | }
|
1318 | aProperties.push( i );
|
1319 | if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
|
1320 | eq = false;
|
1321 | break;
|
1322 | }
|
1323 | }
|
1324 |
|
1325 | parents.pop();
|
1326 | parentsB.pop();
|
1327 | callers.pop();
|
1328 |
|
1329 | for ( i in b ) {
|
1330 | bProperties.push( i );
|
1331 | }
|
1332 |
|
1333 |
|
1334 | return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
|
1335 | }
|
1336 | };
|
1337 | }());
|
1338 |
|
1339 | innerEquiv = function() {
|
1340 | var args = [].slice.apply( arguments );
|
1341 | if ( args.length < 2 ) {
|
1342 | return true;
|
1343 | }
|
1344 |
|
1345 | return ( (function( a, b ) {
|
1346 | if ( a === b ) {
|
1347 | return true;
|
1348 | } else if ( a === null || b === null || typeof a === "undefined" ||
|
1349 | typeof b === "undefined" ||
|
1350 | QUnit.objectType( a ) !== QUnit.objectType( b ) ) {
|
1351 |
|
1352 |
|
1353 | return false;
|
1354 | } else {
|
1355 | return bindCallbacks( a, callbacks, [ b, a ] );
|
1356 | }
|
1357 |
|
1358 |
|
1359 | }( args[ 0 ], args[ 1 ] ) ) && innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) );
|
1360 | };
|
1361 |
|
1362 | return innerEquiv;
|
1363 | }());
|
1364 |
|
1365 |
|
1366 |
|
1367 | QUnit.dump = (function() {
|
1368 | function quote( str ) {
|
1369 | return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
|
1370 | }
|
1371 | function literal( o ) {
|
1372 | return o + "";
|
1373 | }
|
1374 | function join( pre, arr, post ) {
|
1375 | var s = dump.separator(),
|
1376 | base = dump.indent(),
|
1377 | inner = dump.indent( 1 );
|
1378 | if ( arr.join ) {
|
1379 | arr = arr.join( "," + s + inner );
|
1380 | }
|
1381 | if ( !arr ) {
|
1382 | return pre + post;
|
1383 | }
|
1384 | return [ pre, inner + arr, base + post ].join( s );
|
1385 | }
|
1386 | function array( arr, stack ) {
|
1387 | var i = arr.length,
|
1388 | ret = new Array( i );
|
1389 | this.up();
|
1390 | while ( i-- ) {
|
1391 | ret[ i ] = this.parse( arr[ i ], undefined, stack );
|
1392 | }
|
1393 | this.down();
|
1394 | return join( "[", ret, "]" );
|
1395 | }
|
1396 |
|
1397 | var reName = /^function (\w+)/,
|
1398 | dump = {
|
1399 |
|
1400 | parse: function( obj, type, stack ) {
|
1401 | stack = stack || [];
|
1402 | var inStack, res,
|
1403 | parser = this.parsers[ type || this.typeOf( obj ) ];
|
1404 |
|
1405 | type = typeof parser;
|
1406 | inStack = inArray( obj, stack );
|
1407 |
|
1408 | if ( inStack !== -1 ) {
|
1409 | return "recursion(" + ( inStack - stack.length ) + ")";
|
1410 | }
|
1411 | if ( type === "function" ) {
|
1412 | stack.push( obj );
|
1413 | res = parser.call( this, obj, stack );
|
1414 | stack.pop();
|
1415 | return res;
|
1416 | }
|
1417 | return ( type === "string" ) ? parser : this.parsers.error;
|
1418 | },
|
1419 | typeOf: function( obj ) {
|
1420 | var type;
|
1421 | if ( obj === null ) {
|
1422 | type = "null";
|
1423 | } else if ( typeof obj === "undefined" ) {
|
1424 | type = "undefined";
|
1425 | } else if ( QUnit.is( "regexp", obj ) ) {
|
1426 | type = "regexp";
|
1427 | } else if ( QUnit.is( "date", obj ) ) {
|
1428 | type = "date";
|
1429 | } else if ( QUnit.is( "function", obj ) ) {
|
1430 | type = "function";
|
1431 | } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
|
1432 | type = "window";
|
1433 | } else if ( obj.nodeType === 9 ) {
|
1434 | type = "document";
|
1435 | } else if ( obj.nodeType ) {
|
1436 | type = "node";
|
1437 | } else if (
|
1438 |
|
1439 |
|
1440 | toString.call( obj ) === "[object Array]" ||
|
1441 |
|
1442 |
|
1443 | ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null && typeof obj[ 0 ] === "undefined" ) ) )
|
1444 | ) {
|
1445 | type = "array";
|
1446 | } else if ( obj.constructor === Error.prototype.constructor ) {
|
1447 | type = "error";
|
1448 | } else {
|
1449 | type = typeof obj;
|
1450 | }
|
1451 | return type;
|
1452 | },
|
1453 | separator: function() {
|
1454 | return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " ";
|
1455 | },
|
1456 |
|
1457 | indent: function( extra ) {
|
1458 | if ( !this.multiline ) {
|
1459 | return "";
|
1460 | }
|
1461 | var chr = this.indentChar;
|
1462 | if ( this.HTML ) {
|
1463 | chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
|
1464 | }
|
1465 | return new Array( this.depth + ( extra || 0 ) ).join( chr );
|
1466 | },
|
1467 | up: function( a ) {
|
1468 | this.depth += a || 1;
|
1469 | },
|
1470 | down: function( a ) {
|
1471 | this.depth -= a || 1;
|
1472 | },
|
1473 | setParser: function( name, parser ) {
|
1474 | this.parsers[ name ] = parser;
|
1475 | },
|
1476 |
|
1477 | quote: quote,
|
1478 | literal: literal,
|
1479 | join: join,
|
1480 |
|
1481 | depth: 1,
|
1482 |
|
1483 | parsers: {
|
1484 | window: "[Window]",
|
1485 | document: "[Document]",
|
1486 | error: function( error ) {
|
1487 | return "Error(\"" + error.message + "\")";
|
1488 | },
|
1489 | unknown: "[Unknown]",
|
1490 | "null": "null",
|
1491 | "undefined": "undefined",
|
1492 | "function": function( fn ) {
|
1493 | var ret = "function",
|
1494 |
|
1495 | name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];
|
1496 |
|
1497 | if ( name ) {
|
1498 | ret += " " + name;
|
1499 | }
|
1500 | ret += "( ";
|
1501 |
|
1502 | ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" );
|
1503 | return join( ret, dump.parse( fn, "functionCode" ), "}" );
|
1504 | },
|
1505 | array: array,
|
1506 | nodelist: array,
|
1507 | "arguments": array,
|
1508 | object: function( map, stack ) {
|
1509 |
|
1510 | var ret = [], keys, key, val, i, nonEnumerableProperties;
|
1511 | dump.up();
|
1512 | keys = [];
|
1513 | for ( key in map ) {
|
1514 | keys.push( key );
|
1515 | }
|
1516 |
|
1517 |
|
1518 | nonEnumerableProperties = [ "message", "name" ];
|
1519 | for ( i in nonEnumerableProperties ) {
|
1520 | key = nonEnumerableProperties[ i ];
|
1521 | if ( key in map && !( key in keys ) ) {
|
1522 | keys.push( key );
|
1523 | }
|
1524 | }
|
1525 | keys.sort();
|
1526 | for ( i = 0; i < keys.length; i++ ) {
|
1527 | key = keys[ i ];
|
1528 | val = map[ key ];
|
1529 | ret.push( dump.parse( key, "key" ) + ": " + dump.parse( val, undefined, stack ) );
|
1530 | }
|
1531 | dump.down();
|
1532 | return join( "{", ret, "}" );
|
1533 | },
|
1534 | node: function( node ) {
|
1535 | var len, i, val,
|
1536 | open = dump.HTML ? "<" : "<",
|
1537 | close = dump.HTML ? ">" : ">",
|
1538 | tag = node.nodeName.toLowerCase(),
|
1539 | ret = open + tag,
|
1540 | attrs = node.attributes;
|
1541 |
|
1542 | if ( attrs ) {
|
1543 | for ( i = 0, len = attrs.length; i < len; i++ ) {
|
1544 | val = attrs[ i ].nodeValue;
|
1545 |
|
1546 |
|
1547 |
|
1548 | if ( val && val !== "inherit" ) {
|
1549 | ret += " " + attrs[ i ].nodeName + "=" + dump.parse( val, "attribute" );
|
1550 | }
|
1551 | }
|
1552 | }
|
1553 | ret += close;
|
1554 |
|
1555 |
|
1556 | if ( node.nodeType === 3 || node.nodeType === 4 ) {
|
1557 | ret += node.nodeValue;
|
1558 | }
|
1559 |
|
1560 | return ret + open + "/" + tag + close;
|
1561 | },
|
1562 |
|
1563 |
|
1564 | functionArgs: function( fn ) {
|
1565 | var args,
|
1566 | l = fn.length;
|
1567 |
|
1568 | if ( !l ) {
|
1569 | return "";
|
1570 | }
|
1571 |
|
1572 | args = new Array( l );
|
1573 | while ( l-- ) {
|
1574 |
|
1575 |
|
1576 | args[ l ] = String.fromCharCode( 97 + l );
|
1577 | }
|
1578 | return " " + args.join( ", " ) + " ";
|
1579 | },
|
1580 |
|
1581 | key: quote,
|
1582 |
|
1583 | functionCode: "[code]",
|
1584 |
|
1585 | attribute: quote,
|
1586 | string: quote,
|
1587 | date: quote,
|
1588 | regexp: literal,
|
1589 | number: literal,
|
1590 | "boolean": literal
|
1591 | },
|
1592 |
|
1593 | HTML: false,
|
1594 |
|
1595 | indentChar: " ",
|
1596 |
|
1597 | multiline: true
|
1598 | };
|
1599 |
|
1600 | return dump;
|
1601 | }());
|
1602 |
|
1603 |
|
1604 | QUnit.jsDump = QUnit.dump;
|
1605 |
|
1606 |
|
1607 | if ( typeof window !== "undefined" ) {
|
1608 |
|
1609 |
|
1610 |
|
1611 | (function() {
|
1612 | var i,
|
1613 | assertions = Assert.prototype;
|
1614 |
|
1615 | function applyCurrent( current ) {
|
1616 | return function() {
|
1617 | var assert = new Assert( QUnit.config.current );
|
1618 | current.apply( assert, arguments );
|
1619 | };
|
1620 | }
|
1621 |
|
1622 | for ( i in assertions ) {
|
1623 | QUnit[ i ] = applyCurrent( assertions[ i ] );
|
1624 | }
|
1625 | })();
|
1626 |
|
1627 | (function() {
|
1628 | var i, l,
|
1629 | keys = [
|
1630 | "test",
|
1631 | "module",
|
1632 | "expect",
|
1633 | "asyncTest",
|
1634 | "start",
|
1635 | "stop",
|
1636 | "ok",
|
1637 | "equal",
|
1638 | "notEqual",
|
1639 | "propEqual",
|
1640 | "notPropEqual",
|
1641 | "deepEqual",
|
1642 | "notDeepEqual",
|
1643 | "strictEqual",
|
1644 | "notStrictEqual",
|
1645 | "throws"
|
1646 | ];
|
1647 |
|
1648 | for ( i = 0, l = keys.length; i < l; i++ ) {
|
1649 | window[ keys[ i ] ] = QUnit[ keys[ i ] ];
|
1650 | }
|
1651 | })();
|
1652 |
|
1653 | window.QUnit = QUnit;
|
1654 | }
|
1655 |
|
1656 |
|
1657 | if ( typeof module !== "undefined" && module.exports ) {
|
1658 | module.exports = QUnit;
|
1659 | }
|
1660 |
|
1661 |
|
1662 | }( (function() {
|
1663 | return this;
|
1664 | })() ));
|
1665 |
|
1666 |
|
1667 |
|
1668 |
|
1669 |
|
1670 |
|
1671 |
|
1672 |
|
1673 |
|
1674 |
|
1675 |
|
1676 |
|
1677 |
|
1678 |
|
1679 |
|
1680 |
|
1681 | QUnit.diff = (function() {
|
1682 | var hasOwn = Object.prototype.hasOwnProperty;
|
1683 |
|
1684 |
|
1685 | function diff( o, n ) {
|
1686 | var i,
|
1687 | ns = {},
|
1688 | os = {};
|
1689 |
|
1690 | for ( i = 0; i < n.length; i++ ) {
|
1691 | if ( !hasOwn.call( ns, n[ i ] ) ) {
|
1692 | ns[ n[ i ] ] = {
|
1693 | rows: [],
|
1694 | o: null
|
1695 | };
|
1696 | }
|
1697 | ns[ n[ i ] ].rows.push( i );
|
1698 | }
|
1699 |
|
1700 | for ( i = 0; i < o.length; i++ ) {
|
1701 | if ( !hasOwn.call( os, o[ i ] ) ) {
|
1702 | os[ o[ i ] ] = {
|
1703 | rows: [],
|
1704 | n: null
|
1705 | };
|
1706 | }
|
1707 | os[ o[ i ] ].rows.push( i );
|
1708 | }
|
1709 |
|
1710 | for ( i in ns ) {
|
1711 | if ( hasOwn.call( ns, i ) ) {
|
1712 | if ( ns[ i ].rows.length === 1 && hasOwn.call( os, i ) && os[ i ].rows.length === 1 ) {
|
1713 | n[ ns[ i ].rows[ 0 ] ] = {
|
1714 | text: n[ ns[ i ].rows[ 0 ] ],
|
1715 | row: os[ i ].rows[ 0 ]
|
1716 | };
|
1717 | o[ os[ i ].rows[ 0 ] ] = {
|
1718 | text: o[ os[ i ].rows[ 0 ] ],
|
1719 | row: ns[ i ].rows[ 0 ]
|
1720 | };
|
1721 | }
|
1722 | }
|
1723 | }
|
1724 |
|
1725 | for ( i = 0; i < n.length - 1; i++ ) {
|
1726 | if ( n[ i ].text != null && n[ i + 1 ].text == null && n[ i ].row + 1 < o.length && o[ n[ i ].row + 1 ].text == null &&
|
1727 | n[ i + 1 ] == o[ n[ i ].row + 1 ] ) {
|
1728 |
|
1729 | n[ i + 1 ] = {
|
1730 | text: n[ i + 1 ],
|
1731 | row: n[ i ].row + 1
|
1732 | };
|
1733 | o[ n[ i ].row + 1 ] = {
|
1734 | text: o[ n[ i ].row + 1 ],
|
1735 | row: i + 1
|
1736 | };
|
1737 | }
|
1738 | }
|
1739 |
|
1740 | for ( i = n.length - 1; i > 0; i-- ) {
|
1741 | if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null &&
|
1742 | n[ i - 1 ] == o[ n[ i ].row - 1 ] ) {
|
1743 |
|
1744 | n[ i - 1 ] = {
|
1745 | text: n[ i - 1 ],
|
1746 | row: n[ i ].row - 1
|
1747 | };
|
1748 | o[ n[ i ].row - 1 ] = {
|
1749 | text: o[ n[ i ].row - 1 ],
|
1750 | row: i - 1
|
1751 | };
|
1752 | }
|
1753 | }
|
1754 |
|
1755 | return {
|
1756 | o: o,
|
1757 | n: n
|
1758 | };
|
1759 | }
|
1760 |
|
1761 | return function( o, n ) {
|
1762 | o = o.replace( /\s+$/, "" );
|
1763 | n = n.replace( /\s+$/, "" );
|
1764 |
|
1765 | var i, pre,
|
1766 | str = "",
|
1767 | out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ),
|
1768 | oSpace = o.match( /\s+/g ),
|
1769 | nSpace = n.match( /\s+/g );
|
1770 |
|
1771 | if ( oSpace == null ) {
|
1772 | oSpace = [ " " ];
|
1773 | } else {
|
1774 | oSpace.push( " " );
|
1775 | }
|
1776 |
|
1777 | if ( nSpace == null ) {
|
1778 | nSpace = [ " " ];
|
1779 | } else {
|
1780 | nSpace.push( " " );
|
1781 | }
|
1782 |
|
1783 | if ( out.n.length === 0 ) {
|
1784 | for ( i = 0; i < out.o.length; i++ ) {
|
1785 | str += "<del>" + out.o[ i ] + oSpace[ i ] + "</del>";
|
1786 | }
|
1787 | } else {
|
1788 | if ( out.n[ 0 ].text == null ) {
|
1789 | for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) {
|
1790 | str += "<del>" + out.o[ n ] + oSpace[ n ] + "</del>";
|
1791 | }
|
1792 | }
|
1793 |
|
1794 | for ( i = 0; i < out.n.length; i++ ) {
|
1795 | if ( out.n[ i ].text == null ) {
|
1796 | str += "<ins>" + out.n[ i ] + nSpace[ i ] + "</ins>";
|
1797 | } else {
|
1798 |
|
1799 |
|
1800 | pre = "";
|
1801 |
|
1802 | for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) {
|
1803 | pre += "<del>" + out.o[ n ] + oSpace[ n ] + "</del>";
|
1804 | }
|
1805 | str += " " + out.n[ i ].text + nSpace[ i ] + pre;
|
1806 | }
|
1807 | }
|
1808 | }
|
1809 |
|
1810 | return str;
|
1811 | };
|
1812 | }());
|
1813 |
|
1814 | (function() {
|
1815 |
|
1816 |
|
1817 |
|
1818 | QUnit.init = function() {
|
1819 | var tests, banner, result, qunit,
|
1820 | config = QUnit.config;
|
1821 |
|
1822 | config.stats = { all: 0, bad: 0 };
|
1823 | config.moduleStats = { all: 0, bad: 0 };
|
1824 | config.started = 0;
|
1825 | config.updateRate = 1000;
|
1826 | config.blocking = false;
|
1827 | config.autostart = true;
|
1828 | config.autorun = false;
|
1829 | config.filter = "";
|
1830 | config.queue = [];
|
1831 | config.semaphore = 1;
|
1832 |
|
1833 |
|
1834 |
|
1835 | if ( typeof window === "undefined" ) {
|
1836 | return;
|
1837 | }
|
1838 |
|
1839 | qunit = id( "qunit" );
|
1840 | if ( qunit ) {
|
1841 | qunit.innerHTML =
|
1842 | "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
|
1843 | "<h2 id='qunit-banner'></h2>" +
|
1844 | "<div id='qunit-testrunner-toolbar'></div>" +
|
1845 | "<h2 id='qunit-userAgent'></h2>" +
|
1846 | "<ol id='qunit-tests'></ol>";
|
1847 | }
|
1848 |
|
1849 | tests = id( "qunit-tests" );
|
1850 | banner = id( "qunit-banner" );
|
1851 | result = id( "qunit-testresult" );
|
1852 |
|
1853 | if ( tests ) {
|
1854 | tests.innerHTML = "";
|
1855 | }
|
1856 |
|
1857 | if ( banner ) {
|
1858 | banner.className = "";
|
1859 | }
|
1860 |
|
1861 | if ( result ) {
|
1862 | result.parentNode.removeChild( result );
|
1863 | }
|
1864 |
|
1865 | if ( tests ) {
|
1866 | result = document.createElement( "p" );
|
1867 | result.id = "qunit-testresult";
|
1868 | result.className = "result";
|
1869 | tests.parentNode.insertBefore( result, tests );
|
1870 | result.innerHTML = "Running...<br/> ";
|
1871 | }
|
1872 | };
|
1873 |
|
1874 |
|
1875 |
|
1876 |
|
1877 |
|
1878 |
|
1879 |
|
1880 | QUnit.reset = function() {
|
1881 |
|
1882 |
|
1883 |
|
1884 | if ( typeof window === "undefined" ) {
|
1885 | return;
|
1886 | }
|
1887 |
|
1888 | var fixture = id( "qunit-fixture" );
|
1889 | if ( fixture ) {
|
1890 | fixture.innerHTML = config.fixture;
|
1891 | }
|
1892 | };
|
1893 |
|
1894 |
|
1895 | if ( typeof window === "undefined" ) {
|
1896 | return;
|
1897 | }
|
1898 |
|
1899 | var config = QUnit.config,
|
1900 | hasOwn = Object.prototype.hasOwnProperty,
|
1901 | defined = {
|
1902 | document: typeof window.document !== "undefined",
|
1903 | sessionStorage: (function() {
|
1904 | var x = "qunit-test-string";
|
1905 | try {
|
1906 | sessionStorage.setItem( x, x );
|
1907 | sessionStorage.removeItem( x );
|
1908 | return true;
|
1909 | } catch ( e ) {
|
1910 | return false;
|
1911 | }
|
1912 | }())
|
1913 | };
|
1914 |
|
1915 |
|
1916 |
|
1917 |
|
1918 | function escapeText( s ) {
|
1919 | if ( !s ) {
|
1920 | return "";
|
1921 | }
|
1922 | s = s + "";
|
1923 |
|
1924 |
|
1925 | return s.replace( /['"<>&]/g, function( s ) {
|
1926 | switch ( s ) {
|
1927 | case "'":
|
1928 | return "'";
|
1929 | case "\"":
|
1930 | return """;
|
1931 | case "<":
|
1932 | return "<";
|
1933 | case ">":
|
1934 | return ">";
|
1935 | case "&":
|
1936 | return "&";
|
1937 | }
|
1938 | });
|
1939 | }
|
1940 |
|
1941 |
|
1942 |
|
1943 |
|
1944 |
|
1945 |
|
1946 | function addEvent( elem, type, fn ) {
|
1947 | if ( elem.addEventListener ) {
|
1948 |
|
1949 |
|
1950 | elem.addEventListener( type, fn, false );
|
1951 | } else if ( elem.attachEvent ) {
|
1952 |
|
1953 |
|
1954 | elem.attachEvent( "on" + type, fn );
|
1955 | }
|
1956 | }
|
1957 |
|
1958 |
|
1959 |
|
1960 |
|
1961 |
|
1962 |
|
1963 | function addEvents( elems, type, fn ) {
|
1964 | var i = elems.length;
|
1965 | while ( i-- ) {
|
1966 | addEvent( elems[ i ], type, fn );
|
1967 | }
|
1968 | }
|
1969 |
|
1970 | function hasClass( elem, name ) {
|
1971 | return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0;
|
1972 | }
|
1973 |
|
1974 | function addClass( elem, name ) {
|
1975 | if ( !hasClass( elem, name ) ) {
|
1976 | elem.className += ( elem.className ? " " : "" ) + name;
|
1977 | }
|
1978 | }
|
1979 |
|
1980 | function toggleClass( elem, name ) {
|
1981 | if ( hasClass( elem, name ) ) {
|
1982 | removeClass( elem, name );
|
1983 | } else {
|
1984 | addClass( elem, name );
|
1985 | }
|
1986 | }
|
1987 |
|
1988 | function removeClass( elem, name ) {
|
1989 | var set = " " + elem.className + " ";
|
1990 |
|
1991 | // Class name may appear multiple times
|
1992 | while ( set.indexOf( " " + name + " " ) >= 0 ) {
|
1993 | set = set.replace( " " + name + " ", " " );
|
1994 | }
|
1995 |
|
1996 | // trim for prettiness
|
1997 | elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" );
|
1998 | }
|
1999 |
|
2000 | function id( name ) {
|
2001 | return defined.document && document.getElementById && document.getElementById( name );
|
2002 | }
|
2003 |
|
2004 | function getUrlConfigHtml() {
|
2005 | var i, j, val,
|
2006 | escaped, escapedTooltip,
|
2007 | selection = false,
|
2008 | len = config.urlConfig.length,
|
2009 | urlConfigHtml = "";
|
2010 |
|
2011 | for ( i = 0; i < len; i++ ) {
|
2012 | val = config.urlConfig[ i ];
|
2013 | if ( typeof val === "string" ) {
|
2014 | val = {
|
2015 | id: val,
|
2016 | label: val
|
2017 | };
|
2018 | }
|
2019 |
|
2020 | escaped = escapeText( val.id );
|
2021 | escapedTooltip = escapeText( val.tooltip );
|
2022 |
|
2023 | config[ val.id ] = QUnit.urlParams[ val.id ];
|
2024 | if ( !val.value || typeof val.value === "string" ) {
|
2025 | urlConfigHtml += "<input id='qunit-urlconfig-" + escaped +
|
2026 | "' name='" + escaped + "' type='checkbox'" +
|
2027 | ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
|
2028 | ( config[ val.id ] ? " checked='checked'" : "" ) +
|
2029 | " title='" + escapedTooltip + "'><label for='qunit-urlconfig-" + escaped +
|
2030 | "' title='" + escapedTooltip + "'>" + val.label + "</label>";
|
2031 | } else {
|
2032 | urlConfigHtml += "<label for='qunit-urlconfig-" + escaped +
|
2033 | "' title='" + escapedTooltip + "'>" + val.label +
|
2034 | ": </label><select id='qunit-urlconfig-" + escaped +
|
2035 | "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>";
|
2036 |
|
2037 | if ( QUnit.is( "array", val.value ) ) {
|
2038 | for ( j = 0; j < val.value.length; j++ ) {
|
2039 | escaped = escapeText( val.value[ j ] );
|
2040 | urlConfigHtml += "<option value='" + escaped + "'" +
|
2041 | ( config[ val.id ] === val.value[ j ] ?
|
2042 | ( selection = true ) && " selected='selected'" : "" ) +
|
2043 | ">" + escaped + "</option>";
|
2044 | }
|
2045 | } else {
|
2046 | for ( j in val.value ) {
|
2047 | if ( hasOwn.call( val.value, j ) ) {
|
2048 | urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
|
2049 | ( config[ val.id ] === j ?
|
2050 | ( selection = true ) && " selected='selected'" : "" ) +
|
2051 | ">" + escapeText( val.value[ j ] ) + "</option>";
|
2052 | }
|
2053 | }
|
2054 | }
|
2055 | if ( config[ val.id ] && !selection ) {
|
2056 | escaped = escapeText( config[ val.id ] );
|
2057 | urlConfigHtml += "<option value='" + escaped +
|
2058 | "' selected='selected' disabled='disabled'>" + escaped + "</option>";
|
2059 | }
|
2060 | urlConfigHtml += "</select>";
|
2061 | }
|
2062 | }
|
2063 |
|
2064 | return urlConfigHtml;
|
2065 | }
|
2066 |
|
2067 | function toolbarUrlConfigContainer() {
|
2068 | var urlConfigContainer = document.createElement( "span" );
|
2069 |
|
2070 | urlConfigContainer.innerHTML = getUrlConfigHtml();
|
2071 |
|
2072 |
|
2073 |
|
2074 |
|
2075 |
|
2076 | addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", function( event ) {
|
2077 | var params = {},
|
2078 | target = event.target || event.srcElement;
|
2079 | params[ target.name ] = target.checked ?
|
2080 | target.defaultValue || true :
|
2081 | undefined;
|
2082 | window.location = QUnit.url( params );
|
2083 | });
|
2084 | addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", function( event ) {
|
2085 | var params = {},
|
2086 | target = event.target || event.srcElement;
|
2087 | params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
|
2088 | window.location = QUnit.url( params );
|
2089 | });
|
2090 |
|
2091 | return urlConfigContainer;
|
2092 | }
|
2093 |
|
2094 | function getModuleNames() {
|
2095 | var i,
|
2096 | moduleNames = [];
|
2097 |
|
2098 | for ( i in config.modules ) {
|
2099 | if ( config.modules.hasOwnProperty( i ) ) {
|
2100 | moduleNames.push( i );
|
2101 | }
|
2102 | }
|
2103 |
|
2104 | moduleNames.sort(function( a, b ) {
|
2105 | return a.localeCompare( b );
|
2106 | });
|
2107 |
|
2108 | return moduleNames;
|
2109 | }
|
2110 |
|
2111 | function toolbarModuleFilterHtml() {
|
2112 | var i,
|
2113 | moduleFilterHtml = "",
|
2114 | moduleNames = getModuleNames();
|
2115 |
|
2116 | if ( moduleNames.length <= 1 ) {
|
2117 | return false;
|
2118 | }
|
2119 |
|
2120 | moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" +
|
2121 | "<select id='qunit-modulefilter' name='modulefilter'><option value='' " +
|
2122 | ( config.module === undefined ? "selected='selected'" : "" ) +
|
2123 | ">< All Modules ></option>";
|
2124 |
|
2125 | for ( i = 0; i < moduleNames.length; i++ ) {
|
2126 | moduleFilterHtml += "<option value='" +
|
2127 | escapeText( encodeURIComponent( moduleNames[ i ] ) ) + "' " +
|
2128 | ( config.module === moduleNames[ i ] ? "selected='selected'" : "" ) +
|
2129 | ">" + escapeText( moduleNames[ i ] ) + "</option>";
|
2130 | }
|
2131 | moduleFilterHtml += "</select>";
|
2132 |
|
2133 | return moduleFilterHtml;
|
2134 | }
|
2135 |
|
2136 | function toolbarModuleFilter() {
|
2137 | var moduleFilter = document.createElement( "span" ),
|
2138 | moduleFilterHtml = toolbarModuleFilterHtml();
|
2139 |
|
2140 | if ( !moduleFilterHtml ) {
|
2141 | return false;
|
2142 | }
|
2143 |
|
2144 | moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
|
2145 | moduleFilter.innerHTML = moduleFilterHtml;
|
2146 |
|
2147 | addEvent( moduleFilter.lastChild, "change", function() {
|
2148 | var selectBox = moduleFilter.getElementsByTagName( "select" )[ 0 ],
|
2149 | selectedModule = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value );
|
2150 |
|
2151 | window.location = QUnit.url({
|
2152 | module: ( selectedModule === "" ) ? undefined : selectedModule,
|
2153 |
|
2154 |
|
2155 | filter: undefined,
|
2156 | testNumber: undefined
|
2157 | });
|
2158 | });
|
2159 |
|
2160 | return moduleFilter;
|
2161 | }
|
2162 |
|
2163 | function toolbarFilter() {
|
2164 | var testList = id( "qunit-tests" ),
|
2165 | filter = document.createElement( "input" );
|
2166 |
|
2167 | filter.type = "checkbox";
|
2168 | filter.id = "qunit-filter-pass";
|
2169 |
|
2170 | addEvent( filter, "click", function() {
|
2171 | if ( filter.checked ) {
|
2172 | addClass( testList, "hidepass" );
|
2173 | if ( defined.sessionStorage ) {
|
2174 | sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
|
2175 | }
|
2176 | } else {
|
2177 | removeClass( testList, "hidepass" );
|
2178 | if ( defined.sessionStorage ) {
|
2179 | sessionStorage.removeItem( "qunit-filter-passed-tests" );
|
2180 | }
|
2181 | }
|
2182 | });
|
2183 |
|
2184 | if ( config.hidepassed || defined.sessionStorage &&
|
2185 | sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
|
2186 | filter.checked = true;
|
2187 |
|
2188 | addClass( testList, "hidepass" );
|
2189 | }
|
2190 |
|
2191 | return filter;
|
2192 | }
|
2193 |
|
2194 | function toolbarLabel() {
|
2195 | var label = document.createElement( "label" );
|
2196 | label.setAttribute( "for", "qunit-filter-pass" );
|
2197 | label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
|
2198 | label.innerHTML = "Hide passed tests";
|
2199 |
|
2200 | return label;
|
2201 | }
|
2202 |
|
2203 | function appendToolbar() {
|
2204 | var moduleFilter,
|
2205 | toolbar = id( "qunit-testrunner-toolbar" );
|
2206 |
|
2207 | if ( toolbar ) {
|
2208 | toolbar.appendChild( toolbarFilter() );
|
2209 | toolbar.appendChild( toolbarLabel() );
|
2210 | toolbar.appendChild( toolbarUrlConfigContainer() );
|
2211 |
|
2212 | moduleFilter = toolbarModuleFilter();
|
2213 | if ( moduleFilter ) {
|
2214 | toolbar.appendChild( moduleFilter );
|
2215 | }
|
2216 | }
|
2217 | }
|
2218 |
|
2219 | function appendBanner() {
|
2220 | var banner = id( "qunit-banner" );
|
2221 |
|
2222 | if ( banner ) {
|
2223 | banner.className = "";
|
2224 | banner.innerHTML = "<a href='" +
|
2225 | QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) +
|
2226 | "'>" + banner.innerHTML + "</a> ";
|
2227 | }
|
2228 | }
|
2229 |
|
2230 | function appendTestResults() {
|
2231 | var tests = id( "qunit-tests" ),
|
2232 | result = id( "qunit-testresult" );
|
2233 |
|
2234 | if ( result ) {
|
2235 | result.parentNode.removeChild( result );
|
2236 | }
|
2237 |
|
2238 | if ( tests ) {
|
2239 | tests.innerHTML = "";
|
2240 | result = document.createElement( "p" );
|
2241 | result.id = "qunit-testresult";
|
2242 | result.className = "result";
|
2243 | tests.parentNode.insertBefore( result, tests );
|
2244 | result.innerHTML = "Running...<br> ";
|
2245 | }
|
2246 | }
|
2247 |
|
2248 | function storeFixture() {
|
2249 | var fixture = id( "qunit-fixture" );
|
2250 | if ( fixture ) {
|
2251 | config.fixture = fixture.innerHTML;
|
2252 | }
|
2253 | }
|
2254 |
|
2255 | function appendUserAgent() {
|
2256 | var userAgent = id( "qunit-userAgent" );
|
2257 | if ( userAgent ) {
|
2258 | userAgent.innerHTML = navigator.userAgent;
|
2259 | }
|
2260 | }
|
2261 |
|
2262 |
|
2263 | QUnit.begin(function() {
|
2264 | var qunit = id( "qunit" );
|
2265 |
|
2266 | if ( qunit ) {
|
2267 | qunit.innerHTML =
|
2268 | "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
|
2269 | "<h2 id='qunit-banner'></h2>" +
|
2270 | "<div id='qunit-testrunner-toolbar'></div>" +
|
2271 | "<h2 id='qunit-userAgent'></h2>" +
|
2272 | "<ol id='qunit-tests'></ol>";
|
2273 | }
|
2274 |
|
2275 | appendBanner();
|
2276 | appendTestResults();
|
2277 | appendUserAgent();
|
2278 | appendToolbar();
|
2279 | storeFixture();
|
2280 | });
|
2281 |
|
2282 | QUnit.done(function( details ) {
|
2283 | var i, key,
|
2284 | banner = id( "qunit-banner" ),
|
2285 | tests = id( "qunit-tests" ),
|
2286 | html = [
|
2287 | "Tests completed in ",
|
2288 | details.runtime,
|
2289 | " milliseconds.<br>",
|
2290 | "<span class='passed'>",
|
2291 | details.passed,
|
2292 | "</span> assertions of <span class='total'>",
|
2293 | details.total,
|
2294 | "</span> passed, <span class='failed'>",
|
2295 | details.failed,
|
2296 | "</span> failed."
|
2297 | ].join( "" );
|
2298 |
|
2299 | if ( banner ) {
|
2300 | banner.className = details.failed ? "qunit-fail" : "qunit-pass";
|
2301 | }
|
2302 |
|
2303 | if ( tests ) {
|
2304 | id( "qunit-testresult" ).innerHTML = html;
|
2305 | }
|
2306 |
|
2307 | if ( config.altertitle && defined.document && document.title ) {
|
2308 |
|
2309 |
|
2310 |
|
2311 | document.title = [
|
2312 | ( details.failed ? "\u2716" : "\u2714" ),
|
2313 | document.title.replace( /^[\u2714\u2716] /i, "" )
|
2314 | ].join( " " );
|
2315 | }
|
2316 |
|
2317 |
|
2318 | if ( config.reorder && defined.sessionStorage && details.failed === 0 ) {
|
2319 | for ( i = 0; i < sessionStorage.length; i++ ) {
|
2320 | key = sessionStorage.key( i++ );
|
2321 | if ( key.indexOf( "qunit-test-" ) === 0 ) {
|
2322 | sessionStorage.removeItem( key );
|
2323 | }
|
2324 | }
|
2325 | }
|
2326 |
|
2327 |
|
2328 | if ( config.scrolltop && window.scrollTo ) {
|
2329 | window.scrollTo( 0, 0 );
|
2330 | }
|
2331 | });
|
2332 |
|
2333 | function getNameHtml( name, module ) {
|
2334 | var nameHtml = "";
|
2335 |
|
2336 | if ( module ) {
|
2337 | nameHtml = "<span class='module-name'>" + escapeText( module ) + "</span>: ";
|
2338 | }
|
2339 |
|
2340 | nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>";
|
2341 |
|
2342 | return nameHtml;
|
2343 | }
|
2344 |
|
2345 | QUnit.testStart(function( details ) {
|
2346 | var a, b, li, running, assertList,
|
2347 | name = getNameHtml( details.name, details.module ),
|
2348 | tests = id( "qunit-tests" );
|
2349 |
|
2350 | if ( tests ) {
|
2351 | b = document.createElement( "strong" );
|
2352 | b.innerHTML = name;
|
2353 |
|
2354 | a = document.createElement( "a" );
|
2355 | a.innerHTML = "Rerun";
|
2356 | a.href = QUnit.url({ testNumber: details.testNumber });
|
2357 |
|
2358 | li = document.createElement( "li" );
|
2359 | li.appendChild( b );
|
2360 | li.appendChild( a );
|
2361 | li.className = "running";
|
2362 | li.id = "qunit-test-output" + details.testNumber;
|
2363 |
|
2364 | assertList = document.createElement( "ol" );
|
2365 | assertList.className = "qunit-assert-list";
|
2366 |
|
2367 | li.appendChild( assertList );
|
2368 |
|
2369 | tests.appendChild( li );
|
2370 | }
|
2371 |
|
2372 | running = id( "qunit-testresult" );
|
2373 | if ( running ) {
|
2374 | running.innerHTML = "Running: <br>" + name;
|
2375 | }
|
2376 |
|
2377 | });
|
2378 |
|
2379 | QUnit.log(function( details ) {
|
2380 | var assertList, assertLi,
|
2381 | message, expected, actual,
|
2382 | testItem = id( "qunit-test-output" + details.testNumber );
|
2383 |
|
2384 | if ( !testItem ) {
|
2385 | return;
|
2386 | }
|
2387 |
|
2388 | message = escapeText( details.message ) || ( details.result ? "okay" : "failed" );
|
2389 | message = "<span class='test-message'>" + message + "</span>";
|
2390 |
|
2391 |
|
2392 |
|
2393 |
|
2394 | if ( !details.result && hasOwn.call( details, "expected" ) ) {
|
2395 | expected = escapeText( QUnit.dump.parse( details.expected ) );
|
2396 | actual = escapeText( QUnit.dump.parse( details.actual ) );
|
2397 | message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" +
|
2398 | expected +
|
2399 | "</pre></td></tr>";
|
2400 |
|
2401 | if ( actual !== expected ) {
|
2402 | message += "<tr class='test-actual'><th>Result: </th><td><pre>" +
|
2403 | actual + "</pre></td></tr>" +
|
2404 | "<tr class='test-diff'><th>Diff: </th><td><pre>" +
|
2405 | QUnit.diff( expected, actual ) + "</pre></td></tr>";
|
2406 | }
|
2407 |
|
2408 | if ( details.source ) {
|
2409 | message += "<tr class='test-source'><th>Source: </th><td><pre>" +
|
2410 | escapeText( details.source ) + "</pre></td></tr>";
|
2411 | }
|
2412 |
|
2413 | message += "</table>";
|
2414 |
|
2415 |
|
2416 | } else if ( !details.result && details.source ) {
|
2417 | message += "<table>" +
|
2418 | "<tr class='test-source'><th>Source: </th><td><pre>" +
|
2419 | escapeText( details.source ) + "</pre></td></tr>" +
|
2420 | "</table>";
|
2421 | }
|
2422 |
|
2423 | assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
|
2424 |
|
2425 | assertLi = document.createElement( "li" );
|
2426 | assertLi.className = details.result ? "pass" : "fail";
|
2427 | assertLi.innerHTML = message;
|
2428 | assertList.appendChild( assertLi );
|
2429 | });
|
2430 |
|
2431 | QUnit.testDone(function( details ) {
|
2432 | var testTitle, time, testItem, assertList,
|
2433 | good, bad, testCounts,
|
2434 | tests = id( "qunit-tests" );
|
2435 |
|
2436 |
|
2437 |
|
2438 |
|
2439 | QUnit.reset();
|
2440 |
|
2441 | if ( !tests ) {
|
2442 | return;
|
2443 | }
|
2444 |
|
2445 | testItem = id( "qunit-test-output" + details.testNumber );
|
2446 | assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
|
2447 |
|
2448 | good = details.passed;
|
2449 | bad = details.failed;
|
2450 |
|
2451 |
|
2452 | if ( config.reorder && defined.sessionStorage ) {
|
2453 | if ( bad ) {
|
2454 | sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad );
|
2455 | } else {
|
2456 | sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name );
|
2457 | }
|
2458 | }
|
2459 |
|
2460 | if ( bad === 0 ) {
|
2461 | addClass( assertList, "qunit-collapsed" );
|
2462 | }
|
2463 |
|
2464 |
|
2465 | testTitle = testItem.firstChild;
|
2466 |
|
2467 | testCounts = bad ?
|
2468 | "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " :
|
2469 | "";
|
2470 |
|
2471 | testTitle.innerHTML += " <b class='counts'>(" + testCounts +
|
2472 | details.assertions.length + ")</b>";
|
2473 |
|
2474 | addEvent( testTitle, "click", function() {
|
2475 | toggleClass( assertList, "qunit-collapsed" );
|
2476 | });
|
2477 |
|
2478 | time = document.createElement( "span" );
|
2479 | time.className = "runtime";
|
2480 | time.innerHTML = details.runtime + " ms";
|
2481 |
|
2482 | testItem.className = bad ? "fail" : "pass";
|
2483 |
|
2484 | testItem.insertBefore( time, assertList );
|
2485 | });
|
2486 |
|
2487 | if ( !defined.document || document.readyState === "complete" ) {
|
2488 | config.autorun = true;
|
2489 | }
|
2490 |
|
2491 | if ( defined.document ) {
|
2492 | addEvent( window, "load", QUnit.load );
|
2493 | }
|
2494 |
|
2495 | })();
|