Projet

Général

Profil

Révision 503b3f7b

Ajouté par Assos Assos il y a environ 10 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/jquery_update/replace/ui/external/qunit.js
1
/*
2
 * QUnit - A JavaScript Unit Testing Framework
3
 * 
4
 * http://docs.jquery.com/QUnit
1
/**
2
 * QUnit v1.11.0 - A JavaScript Unit Testing Framework
3
 *
4
 * http://qunitjs.com
5 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.
6
 * Copyright 2012 jQuery Foundation and other contributors
7
 * Released under the MIT license.
8
 * http://jquery.org/license
9 9
 */
10 10

  
11
(function(window) {
11
(function( window ) {
12

  
13
var QUnit,
14
	assert,
15
	config,
16
	onErrorFnPrev,
17
	testId = 0,
18
	fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
19
	toString = Object.prototype.toString,
20
	hasOwn = Object.prototype.hasOwnProperty,
21
	// Keep a local reference to Date (GH-283)
22
	Date = window.Date,
23
	defined = {
24
		setTimeout: typeof window.setTimeout !== "undefined",
25
		sessionStorage: (function() {
26
			var x = "qunit-test-string";
27
			try {
28
				sessionStorage.setItem( x, x );
29
				sessionStorage.removeItem( x );
30
				return true;
31
			} catch( e ) {
32
				return false;
33
			}
34
		}())
35
	},
36
	/**
37
	 * Provides a normalized error string, correcting an issue
38
	 * with IE 7 (and prior) where Error.prototype.toString is
39
	 * not properly implemented
40
	 *
41
	 * Based on http://es5.github.com/#x15.11.4.4
42
	 *
43
	 * @param {String|Error} error
44
	 * @return {String} error message
45
	 */
46
	errorString = function( error ) {
47
		var name, message,
48
			errorString = error.toString();
49
		if ( errorString.substring( 0, 7 ) === "[object" ) {
50
			name = error.name ? error.name.toString() : "Error";
51
			message = error.message ? error.message.toString() : "";
52
			if ( name && message ) {
53
				return name + ": " + message;
54
			} else if ( name ) {
55
				return name;
56
			} else if ( message ) {
57
				return message;
58
			} else {
59
				return "Error";
60
			}
61
		} else {
62
			return errorString;
63
		}
64
	},
65
	/**
66
	 * Makes a clone of an object using only Array or Object as base,
67
	 * and copies over the own enumerable properties.
68
	 *
69
	 * @param {Object} obj
70
	 * @return {Object} New object with only the own properties (recursively).
71
	 */
72
	objectValues = function( obj ) {
73
		// Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
74
		/*jshint newcap: false */
75
		var key, val,
76
			vals = QUnit.is( "array", obj ) ? [] : {};
77
		for ( key in obj ) {
78
			if ( hasOwn.call( obj, key ) ) {
79
				val = obj[key];
80
				vals[key] = val === Object(val) ? objectValues(val) : val;
81
			}
82
		}
83
		return vals;
84
	};
12 85

  
13
var QUnit = {
86
function Test( settings ) {
87
	extend( this, settings );
88
	this.assertions = [];
89
	this.testNumber = ++Test.count;
90
}
14 91

  
15
	// call on start of module test to prepend name to all tests
16
	module: function(name, testEnvironment) {
17
		config.currentModule = name;
92
Test.count = 0;
18 93

  
19
		synchronize(function() {
20
			if ( config.currentModule ) {
21
				QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
22
			}
94
Test.prototype = {
95
	init: function() {
96
		var a, b, li,
97
			tests = id( "qunit-tests" );
23 98

  
24
			config.currentModule = name;
25
			config.moduleTestEnvironment = testEnvironment;
99
		if ( tests ) {
100
			b = document.createElement( "strong" );
101
			b.innerHTML = this.nameHtml;
102

  
103
			// `a` initialized at top of scope
104
			a = document.createElement( "a" );
105
			a.innerHTML = "Rerun";
106
			a.href = QUnit.url({ testNumber: this.testNumber });
107

  
108
			li = document.createElement( "li" );
109
			li.appendChild( b );
110
			li.appendChild( a );
111
			li.className = "running";
112
			li.id = this.id = "qunit-test-output" + testId++;
113

  
114
			tests.appendChild( li );
115
		}
116
	},
117
	setup: function() {
118
		if ( this.module !== config.previousModule ) {
119
			if ( config.previousModule ) {
120
				runLoggingCallbacks( "moduleDone", QUnit, {
121
					name: config.previousModule,
122
					failed: config.moduleStats.bad,
123
					passed: config.moduleStats.all - config.moduleStats.bad,
124
					total: config.moduleStats.all
125
				});
126
			}
127
			config.previousModule = this.module;
26 128
			config.moduleStats = { all: 0, bad: 0 };
129
			runLoggingCallbacks( "moduleStart", QUnit, {
130
				name: this.module
131
			});
132
		} else if ( config.autorun ) {
133
			runLoggingCallbacks( "moduleStart", QUnit, {
134
				name: this.module
135
			});
136
		}
27 137

  
28
			QUnit.moduleStart( name, testEnvironment );
138
		config.current = this;
139

  
140
		this.testEnvironment = extend({
141
			setup: function() {},
142
			teardown: function() {}
143
		}, this.moduleTestEnvironment );
144

  
145
		this.started = +new Date();
146
		runLoggingCallbacks( "testStart", QUnit, {
147
			name: this.testName,
148
			module: this.module
29 149
		});
30
	},
31 150

  
32
	asyncTest: function(testName, expected, callback) {
33
		if ( arguments.length === 2 ) {
34
			callback = expected;
35
			expected = 0;
36
		}
151
		// allow utility functions to access the current test environment
152
		// TODO why??
153
		QUnit.current_testEnvironment = this.testEnvironment;
37 154

  
38
		QUnit.test(testName, expected, callback, true);
155
		if ( !config.pollution ) {
156
			saveGlobal();
157
		}
158
		if ( config.notrycatch ) {
159
			this.testEnvironment.setup.call( this.testEnvironment );
160
			return;
161
		}
162
		try {
163
			this.testEnvironment.setup.call( this.testEnvironment );
164
		} catch( e ) {
165
			QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
166
		}
39 167
	},
40
	
41
	test: function(testName, expected, callback, async) {
42
		var name = '<span class="test-name">' + testName + '</span>', testEnvironment, testEnvironmentArg;
168
	run: function() {
169
		config.current = this;
43 170

  
44
		if ( arguments.length === 2 ) {
45
			callback = expected;
46
			expected = null;
47
		}
48
		// is 2nd argument a testEnvironment?
49
		if ( expected && typeof expected === 'object') {
50
			testEnvironmentArg =  expected;
51
			expected = null;
171
		var running = id( "qunit-testresult" );
172

  
173
		if ( running ) {
174
			running.innerHTML = "Running: <br/>" + this.nameHtml;
52 175
		}
53 176

  
54
		if ( config.currentModule ) {
55
			name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
177
		if ( this.async ) {
178
			QUnit.stop();
56 179
		}
57 180

  
58
		if ( !validTest(config.currentModule + ": " + testName) ) {
181
		this.callbackStarted = +new Date();
182

  
183
		if ( config.notrycatch ) {
184
			this.callback.call( this.testEnvironment, QUnit.assert );
185
			this.callbackRuntime = +new Date() - this.callbackStarted;
59 186
			return;
60 187
		}
61 188

  
62
		synchronize(function() {
189
		try {
190
			this.callback.call( this.testEnvironment, QUnit.assert );
191
			this.callbackRuntime = +new Date() - this.callbackStarted;
192
		} catch( e ) {
193
			this.callbackRuntime = +new Date() - this.callbackStarted;
63 194

  
64
			testEnvironment = extend({
65
				setup: function() {},
66
				teardown: function() {}
67
			}, config.moduleTestEnvironment);
68
			if (testEnvironmentArg) {
69
				extend(testEnvironment,testEnvironmentArg);
70
			}
195
			QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
196
			// else next test will carry the responsibility
197
			saveGlobal();
71 198

  
72
			QUnit.testStart( testName, testEnvironment );
73

  
74
			// allow utility functions to access the current test environment
75
			QUnit.current_testEnvironment = testEnvironment;
76
			
77
			config.assertions = [];
78
			config.expected = expected;
79
			
80
			var tests = id("qunit-tests");
81
			if (tests) {
82
				var b = document.createElement("strong");
83
					b.innerHTML = "Running " + name;
84
				var li = document.createElement("li");
85
					li.appendChild( b );
86
					li.id = "current-test-output";
87
				tests.appendChild( li )
199
			// Restart the tests if they're blocking
200
			if ( config.blocking ) {
201
				QUnit.start();
88 202
			}
89

  
203
		}
204
	},
205
	teardown: function() {
206
		config.current = this;
207
		if ( config.notrycatch ) {
208
			if ( typeof this.callbackRuntime === "undefined" ) {
209
				this.callbackRuntime = +new Date() - this.callbackStarted;
210
			}
211
			this.testEnvironment.teardown.call( this.testEnvironment );
212
			return;
213
		} else {
90 214
			try {
91
				if ( !config.pollution ) {
92
					saveGlobal();
215
				this.testEnvironment.teardown.call( this.testEnvironment );
216
			} catch( e ) {
217
				QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
218
			}
219
		}
220
		checkPollution();
221
	},
222
	finish: function() {
223
		config.current = this;
224
		if ( config.requireExpects && this.expected === null ) {
225
			QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
226
		} else if ( this.expected !== null && this.expected !== this.assertions.length ) {
227
			QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
228
		} else if ( this.expected === null && !this.assertions.length ) {
229
			QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
230
		}
231

  
232
		var i, assertion, a, b, time, li, ol,
233
			test = this,
234
			good = 0,
235
			bad = 0,
236
			tests = id( "qunit-tests" );
237

  
238
		this.runtime = +new Date() - this.started;
239
		config.stats.all += this.assertions.length;
240
		config.moduleStats.all += this.assertions.length;
241

  
242
		if ( tests ) {
243
			ol = document.createElement( "ol" );
244
			ol.className = "qunit-assert-list";
245

  
246
			for ( i = 0; i < this.assertions.length; i++ ) {
247
				assertion = this.assertions[i];
248

  
249
				li = document.createElement( "li" );
250
				li.className = assertion.result ? "pass" : "fail";
251
				li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
252
				ol.appendChild( li );
253

  
254
				if ( assertion.result ) {
255
					good++;
256
				} else {
257
					bad++;
258
					config.stats.bad++;
259
					config.moduleStats.bad++;
93 260
				}
261
			}
94 262

  
95
				testEnvironment.setup.call(testEnvironment);
96
			} catch(e) {
97
				QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
263
			// store result when possible
264
			if ( QUnit.config.reorder && defined.sessionStorage ) {
265
				if ( bad ) {
266
					sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
267
				} else {
268
					sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
269
				}
98 270
			}
99
	    });
100
	
101
	    synchronize(function() {
102
			if ( async ) {
103
				QUnit.stop();
271

  
272
			if ( bad === 0 ) {
273
				addClass( ol, "qunit-collapsed" );
104 274
			}
105 275

  
106
			try {
107
				callback.call(testEnvironment);
108
			} catch(e) {
109
				fail("Test " + name + " died, exception and test follows", e, callback);
110
				QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
111
				// else next test will carry the responsibility
112
				saveGlobal();
113

  
114
				// Restart the tests if they're blocking
115
				if ( config.blocking ) {
116
					start();
276
			// `b` initialized at top of scope
277
			b = document.createElement( "strong" );
278
			b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
279

  
280
			addEvent(b, "click", function() {
281
				var next = b.parentNode.lastChild,
282
					collapsed = hasClass( next, "qunit-collapsed" );
283
				( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
284
			});
285

  
286
			addEvent(b, "dblclick", function( e ) {
287
				var target = e && e.target ? e.target : window.event.srcElement;
288
				if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
289
					target = target.parentNode;
290
				}
291
				if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
292
					window.location = QUnit.url({ testNumber: test.testNumber });
293
				}
294
			});
295

  
296
			// `time` initialized at top of scope
297
			time = document.createElement( "span" );
298
			time.className = "runtime";
299
			time.innerHTML = this.runtime + " ms";
300

  
301
			// `li` initialized at top of scope
302
			li = id( this.id );
303
			li.className = bad ? "fail" : "pass";
304
			li.removeChild( li.firstChild );
305
			a = li.firstChild;
306
			li.appendChild( b );
307
			li.appendChild( a );
308
			li.appendChild( time );
309
			li.appendChild( ol );
310

  
311
		} else {
312
			for ( i = 0; i < this.assertions.length; i++ ) {
313
				if ( !this.assertions[i].result ) {
314
					bad++;
315
					config.stats.bad++;
316
					config.moduleStats.bad++;
117 317
				}
118 318
			}
319
		}
320

  
321
		runLoggingCallbacks( "testDone", QUnit, {
322
			name: this.testName,
323
			module: this.module,
324
			failed: bad,
325
			passed: this.assertions.length - bad,
326
			total: this.assertions.length,
327
			duration: this.runtime
119 328
		});
120 329

  
121
		synchronize(function() {
122
			try {
123
				checkPollution();
124
				testEnvironment.teardown.call(testEnvironment);
125
			} catch(e) {
126
				QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
127
			}
128
	    });
129
	
130
	    synchronize(function() {
131
			try {
132
				QUnit.reset();
133
			} catch(e) {
134
				fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
135
			}
330
		QUnit.reset();
136 331

  
137
			if ( config.expected && config.expected != config.assertions.length ) {
138
				QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
139
			}
332
		config.current = undefined;
333
	},
140 334

  
141
			var good = 0, bad = 0,
142
				tests = id("qunit-tests");
335
	queue: function() {
336
		var bad,
337
			test = this;
143 338

  
144
			config.stats.all += config.assertions.length;
145
			config.moduleStats.all += config.assertions.length;
339
		synchronize(function() {
340
			test.init();
341
		});
342
		function run() {
343
			// each of these can by async
344
			synchronize(function() {
345
				test.setup();
346
			});
347
			synchronize(function() {
348
				test.run();
349
			});
350
			synchronize(function() {
351
				test.teardown();
352
			});
353
			synchronize(function() {
354
				test.finish();
355
			});
356
		}
146 357

  
147
			if ( tests ) {
148
				var ol  = document.createElement("ol");
358
		// `bad` initialized at top of scope
359
		// defer when previous test run passed, if storage is available
360
		bad = QUnit.config.reorder && defined.sessionStorage &&
361
						+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
149 362

  
150
				for ( var i = 0; i < config.assertions.length; i++ ) {
151
					var assertion = config.assertions[i];
363
		if ( bad ) {
364
			run();
365
		} else {
366
			synchronize( run, true );
367
		}
368
	}
369
};
152 370

  
153
					var li = document.createElement("li");
154
					li.className = assertion.result ? "pass" : "fail";
155
					li.innerHTML = assertion.message || "(no message)";
156
					ol.appendChild( li );
371
// Root QUnit object.
372
// `QUnit` initialized at top of scope
373
QUnit = {
157 374

  
158
					if ( assertion.result ) {
159
						good++;
160
					} else {
161
						bad++;
162
						config.stats.bad++;
163
						config.moduleStats.bad++;
164
					}
165
				}
166
				if (bad == 0) {
167
					ol.style.display = "none";
168
				}
375
	// call on start of module test to prepend name to all tests
376
	module: function( name, testEnvironment ) {
377
		config.currentModule = name;
378
		config.currentModuleTestEnvironment = testEnvironment;
379
		config.modules[name] = true;
380
	},
169 381

  
170
				var b = document.createElement("strong");
171
				b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
172
				
173
				addEvent(b, "click", function() {
174
					var next = b.nextSibling, display = next.style.display;
175
					next.style.display = display === "none" ? "block" : "none";
176
				});
177
				
178
				addEvent(b, "dblclick", function(e) {
179
					var target = e && e.target ? e.target : window.event.srcElement;
180
					if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
181
						target = target.parentNode;
182
					}
183
					if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
184
						window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, ""));
185
					}
186
				});
382
	asyncTest: function( testName, expected, callback ) {
383
		if ( arguments.length === 2 ) {
384
			callback = expected;
385
			expected = null;
386
		}
187 387

  
188
				var li = id("current-test-output");
189
				li.id = "";
190
				li.className = bad ? "fail" : "pass";
191
				li.removeChild( li.firstChild );
192
				li.appendChild( b );
193
				li.appendChild( ol );
388
		QUnit.test( testName, expected, callback, true );
389
	},
194 390

  
195
				if ( bad ) {
196
					var toolbar = id("qunit-testrunner-toolbar");
197
					if ( toolbar ) {
198
						toolbar.style.display = "block";
199
						id("qunit-filter-pass").disabled = null;
200
						id("qunit-filter-missing").disabled = null;
201
					}
202
				}
391
	test: function( testName, expected, callback, async ) {
392
		var test,
393
			nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
203 394

  
204
			} else {
205
				for ( var i = 0; i < config.assertions.length; i++ ) {
206
					if ( !config.assertions[i].result ) {
207
						bad++;
208
						config.stats.bad++;
209
						config.moduleStats.bad++;
210
					}
211
				}
212
			}
395
		if ( arguments.length === 2 ) {
396
			callback = expected;
397
			expected = null;
398
		}
213 399

  
214
			QUnit.testDone( testName, bad, config.assertions.length );
400
		if ( config.currentModule ) {
401
			nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
402
		}
215 403

  
216
			if ( !window.setTimeout && !config.queue.length ) {
217
				done();
218
			}
404
		test = new Test({
405
			nameHtml: nameHtml,
406
			testName: testName,
407
			expected: expected,
408
			async: async,
409
			callback: callback,
410
			module: config.currentModule,
411
			moduleTestEnvironment: config.currentModuleTestEnvironment,
412
			stack: sourceFromStacktrace( 2 )
219 413
		});
220 414

  
221
		synchronize( done );
415
		if ( !validTest( test ) ) {
416
			return;
417
		}
418

  
419
		test.queue();
222 420
	},
223
	
224
	/**
225
	 * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
226
	 */
227
	expect: function(asserts) {
228
		config.expected = asserts;
421

  
422
	// Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
423
	expect: function( asserts ) {
424
		if (arguments.length === 1) {
425
			config.current.expected = asserts;
426
		} else {
427
			return config.current.expected;
428
		}
229 429
	},
230 430

  
431
	start: function( count ) {
432
		// QUnit hasn't been initialized yet.
433
		// Note: RequireJS (et al) may delay onLoad
434
		if ( config.semaphore === undefined ) {
435
			QUnit.begin(function() {
436
				// This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
437
				setTimeout(function() {
438
					QUnit.start( count );
439
				});
440
			});
441
			return;
442
		}
443

  
444
		config.semaphore -= count || 1;
445
		// don't start until equal number of stop-calls
446
		if ( config.semaphore > 0 ) {
447
			return;
448
		}
449
		// ignore if start is called more often then stop
450
		if ( config.semaphore < 0 ) {
451
			config.semaphore = 0;
452
			QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
453
			return;
454
		}
455
		// A slight delay, to avoid any current callbacks
456
		if ( defined.setTimeout ) {
457
			window.setTimeout(function() {
458
				if ( config.semaphore > 0 ) {
459
					return;
460
				}
461
				if ( config.timeout ) {
462
					clearTimeout( config.timeout );
463
				}
464

  
465
				config.blocking = false;
466
				process( true );
467
			}, 13);
468
		} else {
469
			config.blocking = false;
470
			process( true );
471
		}
472
	},
473

  
474
	stop: function( count ) {
475
		config.semaphore += count || 1;
476
		config.blocking = true;
477

  
478
		if ( config.testTimeout && defined.setTimeout ) {
479
			clearTimeout( config.timeout );
480
			config.timeout = window.setTimeout(function() {
481
				QUnit.ok( false, "Test timed out" );
482
				config.semaphore = 1;
483
				QUnit.start();
484
			}, config.testTimeout );
485
		}
486
	}
487
};
488

  
489
// `assert` initialized at top of scope
490
// Asssert helpers
491
// All of these must either call QUnit.push() or manually do:
492
// - runLoggingCallbacks( "log", .. );
493
// - config.current.assertions.push({ .. });
494
// We attach it to the QUnit object *after* we expose the public API,
495
// otherwise `assert` will become a global variable in browsers (#341).
496
assert = {
231 497
	/**
232
	 * Asserts true.
498
	 * Asserts rough true-ish result.
499
	 * @name ok
500
	 * @function
233 501
	 * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
234 502
	 */
235
	ok: function(a, msg) {
236
		msg = escapeHtml(msg);
237
		QUnit.log(a, msg);
503
	ok: function( result, msg ) {
504
		if ( !config.current ) {
505
			throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
506
		}
507
		result = !!result;
508

  
509
		var source,
510
			details = {
511
				module: config.current.module,
512
				name: config.current.testName,
513
				result: result,
514
				message: msg
515
			};
238 516

  
239
		config.assertions.push({
240
			result: !!a,
517
		msg = escapeText( msg || (result ? "okay" : "failed" ) );
518
		msg = "<span class='test-message'>" + msg + "</span>";
519

  
520
		if ( !result ) {
521
			source = sourceFromStacktrace( 2 );
522
			if ( source ) {
523
				details.source = source;
524
				msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr></table>";
525
			}
526
		}
527
		runLoggingCallbacks( "log", QUnit, details );
528
		config.current.assertions.push({
529
			result: result,
241 530
			message: msg
242 531
		});
243 532
	},
244 533

  
245 534
	/**
246
	 * Checks that the first two arguments are equal, with an optional message.
535
	 * Assert that the first two arguments are equal, with an optional message.
247 536
	 * Prints out both actual and expected values.
248
	 *
249
	 * Prefered to ok( actual == expected, message )
250
	 *
251
	 * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
252
	 *
253
	 * @param Object actual
254
	 * @param Object expected
255
	 * @param String message (optional)
537
	 * @name equal
538
	 * @function
539
	 * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
540
	 */
541
	equal: function( actual, expected, message ) {
542
		/*jshint eqeqeq:false */
543
		QUnit.push( expected == actual, actual, expected, message );
544
	},
545

  
546
	/**
547
	 * @name notEqual
548
	 * @function
256 549
	 */
257
	equal: function(actual, expected, message) {
258
		push(expected == actual, actual, expected, message);
550
	notEqual: function( actual, expected, message ) {
551
		/*jshint eqeqeq:false */
552
		QUnit.push( expected != actual, actual, expected, message );
259 553
	},
260 554

  
261
	notEqual: function(actual, expected, message) {
262
		push(expected != actual, actual, expected, message);
555
	/**
556
	 * @name propEqual
557
	 * @function
558
	 */
559
	propEqual: function( actual, expected, message ) {
560
		actual = objectValues(actual);
561
		expected = objectValues(expected);
562
		QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
263 563
	},
264
	
265
	deepEqual: function(actual, expected, message) {
266
		push(QUnit.equiv(actual, expected), actual, expected, message);
564

  
565
	/**
566
	 * @name notPropEqual
567
	 * @function
568
	 */
569
	notPropEqual: function( actual, expected, message ) {
570
		actual = objectValues(actual);
571
		expected = objectValues(expected);
572
		QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
267 573
	},
268 574

  
269
	notDeepEqual: function(actual, expected, message) {
270
		push(!QUnit.equiv(actual, expected), actual, expected, message);
575
	/**
576
	 * @name deepEqual
577
	 * @function
578
	 */
579
	deepEqual: function( actual, expected, message ) {
580
		QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
271 581
	},
272 582

  
273
	strictEqual: function(actual, expected, message) {
274
		push(expected === actual, actual, expected, message);
583
	/**
584
	 * @name notDeepEqual
585
	 * @function
586
	 */
587
	notDeepEqual: function( actual, expected, message ) {
588
		QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
275 589
	},
276 590

  
277
	notStrictEqual: function(actual, expected, message) {
278
		push(expected !== actual, actual, expected, message);
591
	/**
592
	 * @name strictEqual
593
	 * @function
594
	 */
595
	strictEqual: function( actual, expected, message ) {
596
		QUnit.push( expected === actual, actual, expected, message );
279 597
	},
280 598

  
281
	raises: function(fn,  message) {
282
		try {
283
			fn();
284
			ok( false, message );
285
		}
286
		catch (e) {
287
			ok( true, message );
288
		}
599
	/**
600
	 * @name notStrictEqual
601
	 * @function
602
	 */
603
	notStrictEqual: function( actual, expected, message ) {
604
		QUnit.push( expected !== actual, actual, expected, message );
289 605
	},
290 606

  
291
	start: function() {
292
		// A slight delay, to avoid any current callbacks
293
		if ( window.setTimeout ) {
294
			window.setTimeout(function() {
295
				if ( config.timeout ) {
296
					clearTimeout(config.timeout);
297
				}
607
	"throws": function( block, expected, message ) {
608
		var actual,
609
			expectedOutput = expected,
610
			ok = false;
298 611

  
299
				config.blocking = false;
300
				process();
301
			}, 13);
302
		} else {
303
			config.blocking = false;
304
			process();
612
		// 'expected' is optional
613
		if ( typeof expected === "string" ) {
614
			message = expected;
615
			expected = null;
305 616
		}
306
	},
307
	
308
	stop: function(timeout) {
309
		config.blocking = true;
310 617

  
311
		if ( timeout && window.setTimeout ) {
312
			config.timeout = window.setTimeout(function() {
313
				QUnit.ok( false, "Test timed out" );
314
				QUnit.start();
315
			}, timeout);
618
		config.current.ignoreGlobalErrors = true;
619
		try {
620
			block.call( config.current.testEnvironment );
621
		} catch (e) {
622
			actual = e;
623
		}
624
		config.current.ignoreGlobalErrors = false;
625

  
626
		if ( actual ) {
627
			// we don't want to validate thrown error
628
			if ( !expected ) {
629
				ok = true;
630
				expectedOutput = null;
631
			// expected is a regexp
632
			} else if ( QUnit.objectType( expected ) === "regexp" ) {
633
				ok = expected.test( errorString( actual ) );
634
			// expected is a constructor
635
			} else if ( actual instanceof expected ) {
636
				ok = true;
637
			// expected is a validation function which returns true is validation passed
638
			} else if ( expected.call( {}, actual ) === true ) {
639
				expectedOutput = null;
640
				ok = true;
641
			}
642

  
643
			QUnit.push( ok, actual, expectedOutput, message );
644
		} else {
645
			QUnit.pushFailure( message, null, 'No exception was thrown.' );
316 646
		}
317 647
	}
648
};
318 649

  
650
/**
651
 * @deprecate since 1.8.0
652
 * Kept assertion helpers in root for backwards compatibility.
653
 */
654
extend( QUnit, assert );
655

  
656
/**
657
 * @deprecated since 1.9.0
658
 * Kept root "raises()" for backwards compatibility.
659
 * (Note that we don't introduce assert.raises).
660
 */
661
QUnit.raises = assert[ "throws" ];
662

  
663
/**
664
 * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
665
 * Kept to avoid TypeErrors for undefined methods.
666
 */
667
QUnit.equals = function() {
668
	QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
669
};
670
QUnit.same = function() {
671
	QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
319 672
};
320 673

  
321
// Backwards compatibility, deprecated
322
QUnit.equals = QUnit.equal;
323
QUnit.same = QUnit.deepEqual;
674
// We want access to the constructor's prototype
675
(function() {
676
	function F() {}
677
	F.prototype = QUnit;
678
	QUnit = new F();
679
	// Make F QUnit's constructor so that we can add to the prototype later
680
	QUnit.constructor = F;
681
}());
324 682

  
325
// Maintain internal state
326
var config = {
683
/**
684
 * Config object: Maintain internal state
685
 * Later exposed as QUnit.config
686
 * `config` initialized at top of scope
687
 */
688
config = {
327 689
	// The queue of tests to run
328 690
	queue: [],
329 691

  
330 692
	// block until document ready
331
	blocking: true
693
	blocking: true,
694

  
695
	// when enabled, show only failing tests
696
	// gets persisted through sessionStorage and can be changed in UI via checkbox
697
	hidepassed: false,
698

  
699
	// by default, run previously failed tests first
700
	// very useful in combination with "Hide passed tests" checked
701
	reorder: true,
702

  
703
	// by default, modify document.title when suite is done
704
	altertitle: true,
705

  
706
	// when enabled, all tests must call expect()
707
	requireExpects: false,
708

  
709
	// add checkboxes that are persisted in the query-string
710
	// when enabled, the id is set to `true` as a `QUnit.config` property
711
	urlConfig: [
712
		{
713
			id: "noglobals",
714
			label: "Check for Globals",
715
			tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
716
		},
717
		{
718
			id: "notrycatch",
719
			label: "No try-catch",
720
			tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
721
		}
722
	],
723

  
724
	// Set of all modules.
725
	modules: {},
726

  
727
	// logging callback queues
728
	begin: [],
729
	done: [],
730
	log: [],
731
	testStart: [],
732
	testDone: [],
733
	moduleStart: [],
734
	moduleDone: []
332 735
};
333 736

  
334
// Load paramaters
737
// Export global variables, unless an 'exports' object exists,
738
// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
739
if ( typeof exports === "undefined" ) {
740
	extend( window, QUnit );
741

  
742
	// Expose QUnit object
743
	window.QUnit = QUnit;
744
}
745

  
746
// Initialize more QUnit.config and QUnit.urlParams
335 747
(function() {
336
	var location = window.location || { search: "", protocol: "file:" },
337
		GETParams = location.search.slice(1).split('&');
338

  
339
	for ( var i = 0; i < GETParams.length; i++ ) {
340
		GETParams[i] = decodeURIComponent( GETParams[i] );
341
		if ( GETParams[i] === "noglobals" ) {
342
			GETParams.splice( i, 1 );
343
			i--;
344
			config.noglobals = true;
345
		} else if ( GETParams[i].search('=') > -1 ) {
346
			GETParams.splice( i, 1 );
347
			i--;
748
	var i,
749
		location = window.location || { search: "", protocol: "file:" },
750
		params = location.search.slice( 1 ).split( "&" ),
751
		length = params.length,
752
		urlParams = {},
753
		current;
754

  
755
	if ( params[ 0 ] ) {
756
		for ( i = 0; i < length; i++ ) {
757
			current = params[ i ].split( "=" );
758
			current[ 0 ] = decodeURIComponent( current[ 0 ] );
759
			// allow just a key to turn on a flag, e.g., test.html?noglobals
760
			current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
761
			urlParams[ current[ 0 ] ] = current[ 1 ];
348 762
		}
349 763
	}
350
	
351
	// restrict modules/tests by get parameters
352
	config.filters = GETParams;
353
	
764

  
765
	QUnit.urlParams = urlParams;
766

  
767
	// String search anywhere in moduleName+testName
768
	config.filter = urlParams.filter;
769

  
770
	// Exact match of the module name
771
	config.module = urlParams.module;
772

  
773
	config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
774

  
354 775
	// Figure out if we're running the tests from a server or not
355
	QUnit.isLocal = !!(location.protocol === 'file:');
356
})();
776
	QUnit.isLocal = location.protocol === "file:";
777
}());
357 778

  
358
// Expose the API as global variables, unless an 'exports'
359
// object exists, in that case we assume we're in CommonJS
360
if ( typeof exports === "undefined" || typeof require === "undefined" ) {
361
	extend(window, QUnit);
362
	window.QUnit = QUnit;
363
} else {
364
	extend(exports, QUnit);
365
	exports.QUnit = QUnit;
366
}
779
// Extend QUnit object,
780
// these after set here because they should not be exposed as global functions
781
extend( QUnit, {
782
	assert: assert,
367 783

  
368
// define these after exposing globals to keep them in these QUnit namespace only
369
extend(QUnit, {
370 784
	config: config,
371 785

  
372 786
	// Initialize the configuration options
373 787
	init: function() {
374
		extend(config, {
788
		extend( config, {
375 789
			stats: { all: 0, bad: 0 },
376 790
			moduleStats: { all: 0, bad: 0 },
377
			started: +new Date,
791
			started: +new Date(),
378 792
			updateRate: 1000,
379 793
			blocking: false,
380 794
			autostart: true,
381 795
			autorun: false,
382
			assertions: [],
383
			filters: [],
384
			queue: []
796
			filter: "",
797
			queue: [],
798
			semaphore: 1
385 799
		});
386 800

  
387
		var tests = id("qunit-tests"),
388
			banner = id("qunit-banner"),
389
			result = id("qunit-testresult");
801
		var tests, banner, result,
802
			qunit = id( "qunit" );
803

  
804
		if ( qunit ) {
805
			qunit.innerHTML =
806
				"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
807
				"<h2 id='qunit-banner'></h2>" +
808
				"<div id='qunit-testrunner-toolbar'></div>" +
809
				"<h2 id='qunit-userAgent'></h2>" +
810
				"<ol id='qunit-tests'></ol>";
811
		}
812

  
813
		tests = id( "qunit-tests" );
814
		banner = id( "qunit-banner" );
815
		result = id( "qunit-testresult" );
390 816

  
391 817
		if ( tests ) {
392 818
			tests.innerHTML = "";
......
399 825
		if ( result ) {
400 826
			result.parentNode.removeChild( result );
401 827
		}
828

  
829
		if ( tests ) {
830
			result = document.createElement( "p" );
831
			result.id = "qunit-testresult";
832
			result.className = "result";
833
			tests.parentNode.insertBefore( result, tests );
834
			result.innerHTML = "Running...<br/>&nbsp;";
835
		}
402 836
	},
403
	
404
	/**
405
	 * Resets the test setup. Useful for tests that modify the DOM.
406
	 */
837

  
838
	// Resets the test setup. Useful for tests that modify the DOM.
407 839
	reset: function() {
408
		if ( window.jQuery ) {
409
			jQuery("#main, #qunit-fixture").html( config.fixture );
840
		var fixture = id( "qunit-fixture" );
841
		if ( fixture ) {
842
			fixture.innerHTML = config.fixture;
410 843
		}
411 844
	},
412
	
413
	/**
414
	 * Trigger an event on an element.
415
	 *
416
	 * @example triggerEvent( document.body, "click" );
417
	 *
418
	 * @param DOMElement elem
419
	 * @param String type
420
	 */
845

  
846
	// Trigger an event on an element.
847
	// @example triggerEvent( document.body, "click" );
421 848
	triggerEvent: function( elem, type, event ) {
422 849
		if ( document.createEvent ) {
423
			event = document.createEvent("MouseEvents");
850
			event = document.createEvent( "MouseEvents" );
424 851
			event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
425 852
				0, 0, 0, 0, 0, false, false, false, false, 0, null);
426
			elem.dispatchEvent( event );
427 853

  
854
			elem.dispatchEvent( event );
428 855
		} else if ( elem.fireEvent ) {
429
			elem.fireEvent("on"+type);
856
			elem.fireEvent( "on" + type );
430 857
		}
431 858
	},
432
	
859

  
433 860
	// Safe object type checking
434 861
	is: function( type, obj ) {
435
		return QUnit.objectType( obj ) == type;
862
		return QUnit.objectType( obj ) === type;
436 863
	},
437
	
864

  
438 865
	objectType: function( obj ) {
439
		if (typeof obj === "undefined") {
866
		if ( typeof obj === "undefined" ) {
440 867
				return "undefined";
868
		// consider: typeof null === object
869
		}
870
		if ( obj === null ) {
871
				return "null";
872
		}
873

  
874
		var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
875
			type = match && match[1] || "";
876

  
877
		switch ( type ) {
878
			case "Number":
879
				if ( isNaN(obj) ) {
880
					return "nan";
881
				}
882
				return "number";
883
			case "String":
884
			case "Boolean":
885
			case "Array":
886
			case "Date":
887
			case "RegExp":
888
			case "Function":
889
				return type.toLowerCase();
890
		}
891
		if ( typeof obj === "object" ) {
892
			return "object";
893
		}
894
		return undefined;
895
	},
896

  
897
	push: function( result, actual, expected, message ) {
898
		if ( !config.current ) {
899
			throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
900
		}
901

  
902
		var output, source,
903
			details = {
904
				module: config.current.module,
905
				name: config.current.testName,
906
				result: result,
907
				message: message,
908
				actual: actual,
909
				expected: expected
910
			};
911

  
912
		message = escapeText( message ) || ( result ? "okay" : "failed" );
913
		message = "<span class='test-message'>" + message + "</span>";
914
		output = message;
915

  
916
		if ( !result ) {
917
			expected = escapeText( QUnit.jsDump.parse(expected) );
918
			actual = escapeText( QUnit.jsDump.parse(actual) );
919
			output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
920

  
921
			if ( actual !== expected ) {
922
				output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
923
				output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
924
			}
925

  
926
			source = sourceFromStacktrace();
927

  
928
			if ( source ) {
929
				details.source = source;
930
				output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
931
			}
441 932

  
442
		// consider: typeof null === object
933
			output += "</table>";
443 934
		}
444
		if (obj === null) {
445
				return "null";
935

  
936
		runLoggingCallbacks( "log", QUnit, details );
937

  
938
		config.current.assertions.push({
939
			result: !!result,
940
			message: output
941
		});
942
	},
943

  
944
	pushFailure: function( message, source, actual ) {
945
		if ( !config.current ) {
946
			throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
446 947
		}
447 948

  
448
		var type = Object.prototype.toString.call( obj )
449
			.match(/^\[object\s(.*)\]$/)[1] || '';
949
		var output,
950
			details = {
951
				module: config.current.module,
952
				name: config.current.testName,
953
				result: false,
954
				message: message
955
			};
450 956

  
451
		switch (type) {
452
				case 'Number':
453
						if (isNaN(obj)) {
454
								return "nan";
455
						} else {
456
								return "number";
457
						}
458
				case 'String':
459
				case 'Boolean':
460
				case 'Array':
461
				case 'Date':
462
				case 'RegExp':
463
				case 'Function':
464
						return type.toLowerCase();
957
		message = escapeText( message ) || "error";
958
		message = "<span class='test-message'>" + message + "</span>";
959
		output = message;
960

  
961
		output += "<table>";
962

  
963
		if ( actual ) {
964
			output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
465 965
		}
466
		if (typeof obj === "object") {
467
				return "object";
966

  
967
		if ( source ) {
968
			details.source = source;
969
			output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
468 970
		}
469
		return undefined;
971

  
972
		output += "</table>";
973

  
974
		runLoggingCallbacks( "log", QUnit, details );
975

  
976
		config.current.assertions.push({
977
			result: false,
978
			message: output
979
		});
470 980
	},
471
	
472
	// Logging callbacks
473
	begin: function() {},
474
	done: function(failures, total) {},
475
	log: function(result, message) {},
476
	testStart: function(name, testEnvironment) {},
477
	testDone: function(name, failures, total) {},
478
	moduleStart: function(name, testEnvironment) {},
479
	moduleDone: function(name, failures, total) {}
981

  
982
	url: function( params ) {
983
		params = extend( extend( {}, QUnit.urlParams ), params );
984
		var key,
985
			querystring = "?";
986

  
987
		for ( key in params ) {
988
			if ( !hasOwn.call( params, key ) ) {
989
				continue;
990
			}
991
			querystring += encodeURIComponent( key ) + "=" +
992
				encodeURIComponent( params[ key ] ) + "&";
993
		}
994
		return window.location.protocol + "//" + window.location.host +
995
			window.location.pathname + querystring.slice( 0, -1 );
996
	},
997

  
998
	extend: extend,
999
	id: id,
1000
	addEvent: addEvent
1001
	// load, equiv, jsDump, diff: Attached later
1002
});
1003

  
1004
/**
1005
 * @deprecated: Created for backwards compatibility with test runner that set the hook function
1006
 * into QUnit.{hook}, instead of invoking it and passing the hook function.
1007
 * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
1008
 * Doing this allows us to tell if the following methods have been overwritten on the actual
1009
 * QUnit object.
1010
 */
1011
extend( QUnit.constructor.prototype, {
1012

  
1013
	// Logging callbacks; all receive a single argument with the listed properties
1014
	// run test/logs.html for any related changes
1015
	begin: registerLoggingCallback( "begin" ),
1016

  
1017
	// done: { failed, passed, total, runtime }
1018
	done: registerLoggingCallback( "done" ),
1019

  
1020
	// log: { result, actual, expected, message }
1021
	log: registerLoggingCallback( "log" ),
1022

  
1023
	// testStart: { name }
1024
	testStart: registerLoggingCallback( "testStart" ),
1025

  
1026
	// testDone: { name, failed, passed, total, duration }
1027
	testDone: registerLoggingCallback( "testDone" ),
1028

  
1029
	// moduleStart: { name }
1030
	moduleStart: registerLoggingCallback( "moduleStart" ),
1031

  
1032
	// moduleDone: { name, failed, passed, total }
1033
	moduleDone: registerLoggingCallback( "moduleDone" )
480 1034
});
481 1035

  
482 1036
if ( typeof document === "undefined" || document.readyState === "complete" ) {
483 1037
	config.autorun = true;
484 1038
}
485 1039

  
486
addEvent(window, "load", function() {
487
	QUnit.begin();
488
	
1040
QUnit.load = function() {
1041
	runLoggingCallbacks( "begin", QUnit, {} );
1042

  
489 1043
	// Initialize the config, saving the execution queue
490
	var oldconfig = extend({}, config);
1044
	var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
1045
		urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
1046
		numModules = 0,
1047
		moduleFilterHtml = "",
1048
		urlConfigHtml = "",
1049
		oldconfig = extend( {}, config );
1050

  
491 1051
	QUnit.init();
492 1052
	extend(config, oldconfig);
493 1053

  
494 1054
	config.blocking = false;
495 1055

  
496
	var userAgent = id("qunit-userAgent");
1056
	len = config.urlConfig.length;
1057

  
1058
	for ( i = 0; i < len; i++ ) {
1059
		val = config.urlConfig[i];
1060
		if ( typeof val === "string" ) {
1061
			val = {
1062
				id: val,
1063
				label: val,
1064
				tooltip: "[no tooltip available]"
1065
			};
1066
		}
1067
		config[ val.id ] = QUnit.urlParams[ val.id ];
1068
		urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
1069
			"' name='" + escapeText( val.id ) +
1070
			"' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
1071
			" title='" + escapeText( val.tooltip ) +
1072
			"'><label for='qunit-urlconfig-" + escapeText( val.id ) +
1073
			"' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
1074
	}
1075

  
1076
	moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
1077
		( config.module === undefined  ? "selected='selected'" : "" ) +
1078
		">< All Modules ></option>";
1079

  
1080
	for ( i in config.modules ) {
1081
		if ( config.modules.hasOwnProperty( i ) ) {
1082
			numModules += 1;
1083
			moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(i) ) + "' " +
1084
				( config.module === i ? "selected='selected'" : "" ) +
1085
				">" + escapeText(i) + "</option>";
1086
		}
1087
	}
1088
	moduleFilterHtml += "</select>";
1089

  
1090
	// `userAgent` initialized at top of scope
1091
	userAgent = id( "qunit-userAgent" );
497 1092
	if ( userAgent ) {
498 1093
		userAgent.innerHTML = navigator.userAgent;
499 1094
	}
500
	var banner = id("qunit-header");
1095

  
1096
	// `banner` initialized at top of scope
1097
	banner = id( "qunit-header" );
501 1098
	if ( banner ) {
502
		banner.innerHTML = '<a href="' + location.href + '">' + banner.innerHTML + '</a>'; 
1099
		banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
503 1100
	}
504
	
505
	var toolbar = id("qunit-testrunner-toolbar");
1101

  
1102
	// `toolbar` initialized at top of scope
1103
	toolbar = id( "qunit-testrunner-toolbar" );
506 1104
	if ( toolbar ) {
507
		toolbar.style.display = "none";
508
		
509
		var filter = document.createElement("input");
1105
		// `filter` initialized at top of scope
1106
		filter = document.createElement( "input" );
510 1107
		filter.type = "checkbox";
511 1108
		filter.id = "qunit-filter-pass";
512
		filter.disabled = true;
1109

  
513 1110
		addEvent( filter, "click", function() {
514
			var li = document.getElementsByTagName("li");
515
			for ( var i = 0; i < li.length; i++ ) {
516
				if ( li[i].className.indexOf("pass") > -1 ) {
517
					li[i].style.display = filter.checked ? "none" : "";
1111
			var tmp,
1112
				ol = document.getElementById( "qunit-tests" );
1113

  
1114
			if ( filter.checked ) {
1115
				ol.className = ol.className + " hidepass";
1116
			} else {
1117
				tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
1118
				ol.className = tmp.replace( / hidepass /, " " );
1119
			}
1120
			if ( defined.sessionStorage ) {
1121
				if (filter.checked) {
1122
					sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
1123
				} else {
1124
					sessionStorage.removeItem( "qunit-filter-passed-tests" );
518 1125
				}
519 1126
			}
520 1127
		});
1128

  
1129
		if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
1130
			filter.checked = true;
1131
			// `ol` initialized at top of scope
1132
			ol = document.getElementById( "qunit-tests" );
1133
			ol.className = ol.className + " hidepass";
1134
		}
521 1135
		toolbar.appendChild( filter );
522 1136

  
523
		var label = document.createElement("label");
524
		label.setAttribute("for", "qunit-filter-pass");
1137
		// `label` initialized at top of scope
1138
		label = document.createElement( "label" );
1139
		label.setAttribute( "for", "qunit-filter-pass" );
1140
		label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
525 1141
		label.innerHTML = "Hide passed tests";
526 1142
		toolbar.appendChild( label );
527 1143

  
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff