qunit-rails 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gems +1 -0
- data/CHANGELOG.md +8 -0
- data/README.md +69 -60
- data/UNLICENSE +24 -0
- data/app/controllers/qunit/rails/test_controller.rb +1 -4
- data/config/initializers/qunit-rails.rb +5 -1
- data/config/routes.rb +6 -3
- data/{vendor → lib}/assets/javascripts/qunit.js +1274 -1276
- data/{vendor → lib}/assets/stylesheets/qunit.css +7 -6
- data/lib/generators/qunit/install_generator.rb +32 -14
- data/lib/qunit/rails/engine.rb +7 -2
- data/lib/qunit-rails.rb +1 -6
- data/qunit-rails.gemspec +13 -18
- metadata +21 -27
- data/.gitignore +0 -7
- data/Gemfile +0 -2
- data/Gemfile.lock +0 -61
- data/LICENSE.md +0 -22
- data/Rakefile +0 -2
@@ -1,11 +1,12 @@
|
|
1
|
-
|
2
|
-
* QUnit
|
3
|
-
*
|
4
|
-
* http://qunitjs.com
|
1
|
+
/*!
|
2
|
+
* QUnit 1.13.0
|
3
|
+
* http://qunitjs.com/
|
5
4
|
*
|
6
5
|
* Copyright 2013 jQuery Foundation and other contributors
|
7
|
-
* Released under the MIT license
|
8
|
-
*
|
6
|
+
* Released under the MIT license
|
7
|
+
* http://jquery.org/license
|
8
|
+
*
|
9
|
+
* Date: 2014-01-04T17:09Z
|
9
10
|
*/
|
10
11
|
|
11
12
|
(function( window ) {
|
@@ -22,6 +23,7 @@ var QUnit,
|
|
22
23
|
Date = window.Date,
|
23
24
|
setTimeout = window.setTimeout,
|
24
25
|
defined = {
|
26
|
+
document: typeof window.document !== "undefined",
|
25
27
|
setTimeout: typeof window.setTimeout !== "undefined",
|
26
28
|
sessionStorage: (function() {
|
27
29
|
var x = "qunit-test-string";
|
@@ -84,1522 +86,1524 @@ var QUnit,
|
|
84
86
|
return vals;
|
85
87
|
};
|
86
88
|
|
87
|
-
function Test( settings ) {
|
88
|
-
extend( this, settings );
|
89
|
-
this.assertions = [];
|
90
|
-
this.testNumber = ++Test.count;
|
91
|
-
}
|
92
89
|
|
93
|
-
|
90
|
+
// Root QUnit object.
|
91
|
+
// `QUnit` initialized at top of scope
|
92
|
+
QUnit = {
|
94
93
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
// call on start of module test to prepend name to all tests
|
95
|
+
module: function( name, testEnvironment ) {
|
96
|
+
config.currentModule = name;
|
97
|
+
config.currentModuleTestEnvironment = testEnvironment;
|
98
|
+
config.modules[name] = true;
|
99
|
+
},
|
99
100
|
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
asyncTest: function( testName, expected, callback ) {
|
102
|
+
if ( arguments.length === 2 ) {
|
103
|
+
callback = expected;
|
104
|
+
expected = null;
|
105
|
+
}
|
103
106
|
|
104
|
-
|
105
|
-
|
106
|
-
a.innerHTML = "Rerun";
|
107
|
-
a.href = QUnit.url({ testNumber: this.testNumber });
|
107
|
+
QUnit.test( testName, expected, callback, true );
|
108
|
+
},
|
108
109
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
li.className = "running";
|
113
|
-
li.id = this.id = "qunit-test-output" + testId++;
|
110
|
+
test: function( testName, expected, callback, async ) {
|
111
|
+
var test,
|
112
|
+
nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
|
114
113
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
setup: function() {
|
119
|
-
if (
|
120
|
-
// Emit moduleStart when we're switching from one module to another
|
121
|
-
this.module !== config.previousModule ||
|
122
|
-
// They could be equal (both undefined) but if the previousModule property doesn't
|
123
|
-
// yet exist it means this is the first test in a suite that isn't wrapped in a
|
124
|
-
// module, in which case we'll just emit a moduleStart event for 'undefined'.
|
125
|
-
// Without this, reporters can get testStart before moduleStart which is a problem.
|
126
|
-
!hasOwn.call( config, "previousModule" )
|
127
|
-
) {
|
128
|
-
if ( hasOwn.call( config, "previousModule" ) ) {
|
129
|
-
runLoggingCallbacks( "moduleDone", QUnit, {
|
130
|
-
name: config.previousModule,
|
131
|
-
failed: config.moduleStats.bad,
|
132
|
-
passed: config.moduleStats.all - config.moduleStats.bad,
|
133
|
-
total: config.moduleStats.all
|
134
|
-
});
|
135
|
-
}
|
136
|
-
config.previousModule = this.module;
|
137
|
-
config.moduleStats = { all: 0, bad: 0 };
|
138
|
-
runLoggingCallbacks( "moduleStart", QUnit, {
|
139
|
-
name: this.module
|
140
|
-
});
|
114
|
+
if ( arguments.length === 2 ) {
|
115
|
+
callback = expected;
|
116
|
+
expected = null;
|
141
117
|
}
|
142
118
|
|
143
|
-
config.
|
144
|
-
|
145
|
-
|
146
|
-
setup: function() {},
|
147
|
-
teardown: function() {}
|
148
|
-
}, this.moduleTestEnvironment );
|
119
|
+
if ( config.currentModule ) {
|
120
|
+
nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
|
121
|
+
}
|
149
122
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
123
|
+
test = new Test({
|
124
|
+
nameHtml: nameHtml,
|
125
|
+
testName: testName,
|
126
|
+
expected: expected,
|
127
|
+
async: async,
|
128
|
+
callback: callback,
|
129
|
+
module: config.currentModule,
|
130
|
+
moduleTestEnvironment: config.currentModuleTestEnvironment,
|
131
|
+
stack: sourceFromStacktrace( 2 )
|
154
132
|
});
|
155
133
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
/**
|
160
|
-
* Expose the current test environment.
|
161
|
-
*
|
162
|
-
* @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
|
163
|
-
*/
|
164
|
-
QUnit.current_testEnvironment = this.testEnvironment;
|
165
|
-
|
166
|
-
/*jshint camelcase:true */
|
167
|
-
|
168
|
-
if ( !config.pollution ) {
|
169
|
-
saveGlobal();
|
170
|
-
}
|
171
|
-
if ( config.notrycatch ) {
|
172
|
-
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
|
134
|
+
if ( !validTest( test ) ) {
|
173
135
|
return;
|
174
136
|
}
|
175
|
-
try {
|
176
|
-
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
|
177
|
-
} catch( e ) {
|
178
|
-
QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
|
179
|
-
}
|
180
|
-
},
|
181
|
-
run: function() {
|
182
|
-
config.current = this;
|
183
|
-
|
184
|
-
var running = id( "qunit-testresult" );
|
185
137
|
|
186
|
-
|
187
|
-
|
188
|
-
}
|
138
|
+
test.queue();
|
139
|
+
},
|
189
140
|
|
190
|
-
|
191
|
-
|
141
|
+
// Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
|
142
|
+
expect: function( asserts ) {
|
143
|
+
if (arguments.length === 1) {
|
144
|
+
config.current.expected = asserts;
|
145
|
+
} else {
|
146
|
+
return config.current.expected;
|
192
147
|
}
|
148
|
+
},
|
193
149
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
150
|
+
start: function( count ) {
|
151
|
+
// QUnit hasn't been initialized yet.
|
152
|
+
// Note: RequireJS (et al) may delay onLoad
|
153
|
+
if ( config.semaphore === undefined ) {
|
154
|
+
QUnit.begin(function() {
|
155
|
+
// This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
|
156
|
+
setTimeout(function() {
|
157
|
+
QUnit.start( count );
|
158
|
+
});
|
159
|
+
});
|
199
160
|
return;
|
200
161
|
}
|
201
162
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
this.callbackRuntime = +new Date() - this.callbackStarted;
|
207
|
-
|
208
|
-
QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
|
209
|
-
// else next test will carry the responsibility
|
210
|
-
saveGlobal();
|
211
|
-
|
212
|
-
// Restart the tests if they're blocking
|
213
|
-
if ( config.blocking ) {
|
214
|
-
QUnit.start();
|
215
|
-
}
|
163
|
+
config.semaphore -= count || 1;
|
164
|
+
// don't start until equal number of stop-calls
|
165
|
+
if ( config.semaphore > 0 ) {
|
166
|
+
return;
|
216
167
|
}
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
if ( typeof this.callbackRuntime === "undefined" ) {
|
222
|
-
this.callbackRuntime = +new Date() - this.callbackStarted;
|
223
|
-
}
|
224
|
-
this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
|
168
|
+
// ignore if start is called more often then stop
|
169
|
+
if ( config.semaphore < 0 ) {
|
170
|
+
config.semaphore = 0;
|
171
|
+
QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
|
225
172
|
return;
|
173
|
+
}
|
174
|
+
// A slight delay, to avoid any current callbacks
|
175
|
+
if ( defined.setTimeout ) {
|
176
|
+
setTimeout(function() {
|
177
|
+
if ( config.semaphore > 0 ) {
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
if ( config.timeout ) {
|
181
|
+
clearTimeout( config.timeout );
|
182
|
+
}
|
183
|
+
|
184
|
+
config.blocking = false;
|
185
|
+
process( true );
|
186
|
+
}, 13);
|
226
187
|
} else {
|
227
|
-
|
228
|
-
|
229
|
-
} catch( e ) {
|
230
|
-
QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
|
231
|
-
}
|
188
|
+
config.blocking = false;
|
189
|
+
process( true );
|
232
190
|
}
|
233
|
-
checkPollution();
|
234
191
|
},
|
235
|
-
finish: function() {
|
236
|
-
config.current = this;
|
237
|
-
if ( config.requireExpects && this.expected === null ) {
|
238
|
-
QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
|
239
|
-
} else if ( this.expected !== null && this.expected !== this.assertions.length ) {
|
240
|
-
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
|
241
|
-
} else if ( this.expected === null && !this.assertions.length ) {
|
242
|
-
QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
|
243
|
-
}
|
244
192
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
bad = 0,
|
249
|
-
tests = id( "qunit-tests" );
|
193
|
+
stop: function( count ) {
|
194
|
+
config.semaphore += count || 1;
|
195
|
+
config.blocking = true;
|
250
196
|
|
251
|
-
|
252
|
-
|
253
|
-
|
197
|
+
if ( config.testTimeout && defined.setTimeout ) {
|
198
|
+
clearTimeout( config.timeout );
|
199
|
+
config.timeout = setTimeout(function() {
|
200
|
+
QUnit.ok( false, "Test timed out" );
|
201
|
+
config.semaphore = 1;
|
202
|
+
QUnit.start();
|
203
|
+
}, config.testTimeout );
|
204
|
+
}
|
205
|
+
}
|
206
|
+
};
|
254
207
|
|
255
|
-
|
256
|
-
|
257
|
-
|
208
|
+
// We use the prototype to distinguish between properties that should
|
209
|
+
// be exposed as globals (and in exports) and those that shouldn't
|
210
|
+
(function() {
|
211
|
+
function F() {}
|
212
|
+
F.prototype = QUnit;
|
213
|
+
QUnit = new F();
|
214
|
+
// Make F QUnit's constructor so that we can add to the prototype later
|
215
|
+
QUnit.constructor = F;
|
216
|
+
}());
|
258
217
|
|
259
|
-
|
260
|
-
|
218
|
+
/**
|
219
|
+
* Config object: Maintain internal state
|
220
|
+
* Later exposed as QUnit.config
|
221
|
+
* `config` initialized at top of scope
|
222
|
+
*/
|
223
|
+
config = {
|
224
|
+
// The queue of tests to run
|
225
|
+
queue: [],
|
261
226
|
|
262
|
-
|
263
|
-
|
264
|
-
li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
|
265
|
-
ol.appendChild( li );
|
227
|
+
// block until document ready
|
228
|
+
blocking: true,
|
266
229
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
bad++;
|
271
|
-
config.stats.bad++;
|
272
|
-
config.moduleStats.bad++;
|
273
|
-
}
|
274
|
-
}
|
230
|
+
// when enabled, show only failing tests
|
231
|
+
// gets persisted through sessionStorage and can be changed in UI via checkbox
|
232
|
+
hidepassed: false,
|
275
233
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
|
280
|
-
} else {
|
281
|
-
sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
|
282
|
-
}
|
283
|
-
}
|
234
|
+
// by default, run previously failed tests first
|
235
|
+
// very useful in combination with "Hide passed tests" checked
|
236
|
+
reorder: true,
|
284
237
|
|
285
|
-
|
286
|
-
|
287
|
-
}
|
238
|
+
// by default, modify document.title when suite is done
|
239
|
+
altertitle: true,
|
288
240
|
|
289
|
-
|
290
|
-
|
291
|
-
b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
|
241
|
+
// when enabled, all tests must call expect()
|
242
|
+
requireExpects: false,
|
292
243
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
244
|
+
// add checkboxes that are persisted in the query-string
|
245
|
+
// when enabled, the id is set to `true` as a `QUnit.config` property
|
246
|
+
urlConfig: [
|
247
|
+
{
|
248
|
+
id: "noglobals",
|
249
|
+
label: "Check for Globals",
|
250
|
+
tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
|
251
|
+
},
|
252
|
+
{
|
253
|
+
id: "notrycatch",
|
254
|
+
label: "No try-catch",
|
255
|
+
tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
|
256
|
+
}
|
257
|
+
],
|
298
258
|
|
299
|
-
|
300
|
-
|
301
|
-
if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
|
302
|
-
target = target.parentNode;
|
303
|
-
}
|
304
|
-
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
|
305
|
-
window.location = QUnit.url({ testNumber: test.testNumber });
|
306
|
-
}
|
307
|
-
});
|
259
|
+
// Set of all modules.
|
260
|
+
modules: {},
|
308
261
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
262
|
+
// logging callback queues
|
263
|
+
begin: [],
|
264
|
+
done: [],
|
265
|
+
log: [],
|
266
|
+
testStart: [],
|
267
|
+
testDone: [],
|
268
|
+
moduleStart: [],
|
269
|
+
moduleDone: []
|
270
|
+
};
|
313
271
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
li.appendChild( ol );
|
272
|
+
// Initialize more QUnit.config and QUnit.urlParams
|
273
|
+
(function() {
|
274
|
+
var i,
|
275
|
+
location = window.location || { search: "", protocol: "file:" },
|
276
|
+
params = location.search.slice( 1 ).split( "&" ),
|
277
|
+
length = params.length,
|
278
|
+
urlParams = {},
|
279
|
+
current;
|
323
280
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
}
|
281
|
+
if ( params[ 0 ] ) {
|
282
|
+
for ( i = 0; i < length; i++ ) {
|
283
|
+
current = params[ i ].split( "=" );
|
284
|
+
current[ 0 ] = decodeURIComponent( current[ 0 ] );
|
285
|
+
// allow just a key to turn on a flag, e.g., test.html?noglobals
|
286
|
+
current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
|
287
|
+
urlParams[ current[ 0 ] ] = current[ 1 ];
|
332
288
|
}
|
289
|
+
}
|
333
290
|
|
334
|
-
|
335
|
-
name: this.testName,
|
336
|
-
module: this.module,
|
337
|
-
failed: bad,
|
338
|
-
passed: this.assertions.length - bad,
|
339
|
-
total: this.assertions.length,
|
340
|
-
duration: this.runtime
|
341
|
-
});
|
291
|
+
QUnit.urlParams = urlParams;
|
342
292
|
|
343
|
-
|
293
|
+
// String search anywhere in moduleName+testName
|
294
|
+
config.filter = urlParams.filter;
|
344
295
|
|
345
|
-
|
346
|
-
|
296
|
+
// Exact match of the module name
|
297
|
+
config.module = urlParams.module;
|
347
298
|
|
348
|
-
|
349
|
-
var bad,
|
350
|
-
test = this;
|
299
|
+
config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
|
351
300
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
function run() {
|
356
|
-
// each of these can by async
|
357
|
-
synchronize(function() {
|
358
|
-
test.setup();
|
359
|
-
});
|
360
|
-
synchronize(function() {
|
361
|
-
test.run();
|
362
|
-
});
|
363
|
-
synchronize(function() {
|
364
|
-
test.teardown();
|
365
|
-
});
|
366
|
-
synchronize(function() {
|
367
|
-
test.finish();
|
368
|
-
});
|
369
|
-
}
|
301
|
+
// Figure out if we're running the tests from a server or not
|
302
|
+
QUnit.isLocal = location.protocol === "file:";
|
303
|
+
}());
|
370
304
|
|
371
|
-
|
372
|
-
// defer when previous test run passed, if storage is available
|
373
|
-
bad = QUnit.config.reorder && defined.sessionStorage &&
|
374
|
-
+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
|
305
|
+
extend( QUnit, {
|
375
306
|
|
376
|
-
|
377
|
-
run();
|
378
|
-
} else {
|
379
|
-
synchronize( run, true );
|
380
|
-
}
|
381
|
-
}
|
382
|
-
};
|
307
|
+
config: config,
|
383
308
|
|
384
|
-
//
|
385
|
-
|
386
|
-
|
309
|
+
// Initialize the configuration options
|
310
|
+
init: function() {
|
311
|
+
extend( config, {
|
312
|
+
stats: { all: 0, bad: 0 },
|
313
|
+
moduleStats: { all: 0, bad: 0 },
|
314
|
+
started: +new Date(),
|
315
|
+
updateRate: 1000,
|
316
|
+
blocking: false,
|
317
|
+
autostart: true,
|
318
|
+
autorun: false,
|
319
|
+
filter: "",
|
320
|
+
queue: [],
|
321
|
+
semaphore: 1
|
322
|
+
});
|
387
323
|
|
388
|
-
|
389
|
-
|
390
|
-
config.currentModule = name;
|
391
|
-
config.currentModuleTestEnvironment = testEnvironment;
|
392
|
-
config.modules[name] = true;
|
393
|
-
},
|
324
|
+
var tests, banner, result,
|
325
|
+
qunit = id( "qunit" );
|
394
326
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
327
|
+
if ( qunit ) {
|
328
|
+
qunit.innerHTML =
|
329
|
+
"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
|
330
|
+
"<h2 id='qunit-banner'></h2>" +
|
331
|
+
"<div id='qunit-testrunner-toolbar'></div>" +
|
332
|
+
"<h2 id='qunit-userAgent'></h2>" +
|
333
|
+
"<ol id='qunit-tests'></ol>";
|
399
334
|
}
|
400
335
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
test: function( testName, expected, callback, async ) {
|
405
|
-
var test,
|
406
|
-
nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
|
336
|
+
tests = id( "qunit-tests" );
|
337
|
+
banner = id( "qunit-banner" );
|
338
|
+
result = id( "qunit-testresult" );
|
407
339
|
|
408
|
-
if (
|
409
|
-
|
410
|
-
expected = null;
|
340
|
+
if ( tests ) {
|
341
|
+
tests.innerHTML = "";
|
411
342
|
}
|
412
343
|
|
413
|
-
if (
|
414
|
-
|
344
|
+
if ( banner ) {
|
345
|
+
banner.className = "";
|
415
346
|
}
|
416
347
|
|
417
|
-
|
418
|
-
|
419
|
-
testName: testName,
|
420
|
-
expected: expected,
|
421
|
-
async: async,
|
422
|
-
callback: callback,
|
423
|
-
module: config.currentModule,
|
424
|
-
moduleTestEnvironment: config.currentModuleTestEnvironment,
|
425
|
-
stack: sourceFromStacktrace( 2 )
|
426
|
-
});
|
427
|
-
|
428
|
-
if ( !validTest( test ) ) {
|
429
|
-
return;
|
348
|
+
if ( result ) {
|
349
|
+
result.parentNode.removeChild( result );
|
430
350
|
}
|
431
351
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
config.current.expected = asserts;
|
439
|
-
} else {
|
440
|
-
return config.current.expected;
|
352
|
+
if ( tests ) {
|
353
|
+
result = document.createElement( "p" );
|
354
|
+
result.id = "qunit-testresult";
|
355
|
+
result.className = "result";
|
356
|
+
tests.parentNode.insertBefore( result, tests );
|
357
|
+
result.innerHTML = "Running...<br/> ";
|
441
358
|
}
|
442
359
|
},
|
443
360
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
return;
|
361
|
+
// Resets the test setup. Useful for tests that modify the DOM.
|
362
|
+
/*
|
363
|
+
DEPRECATED: Use multiple tests instead of resetting inside a test.
|
364
|
+
Use testStart or testDone for custom cleanup.
|
365
|
+
This method will throw an error in 2.0, and will be removed in 2.1
|
366
|
+
*/
|
367
|
+
reset: function() {
|
368
|
+
var fixture = id( "qunit-fixture" );
|
369
|
+
if ( fixture ) {
|
370
|
+
fixture.innerHTML = config.fixture;
|
455
371
|
}
|
372
|
+
},
|
456
373
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
if (
|
464
|
-
|
465
|
-
QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
|
466
|
-
return;
|
374
|
+
// Safe object type checking
|
375
|
+
is: function( type, obj ) {
|
376
|
+
return QUnit.objectType( obj ) === type;
|
377
|
+
},
|
378
|
+
|
379
|
+
objectType: function( obj ) {
|
380
|
+
if ( typeof obj === "undefined" ) {
|
381
|
+
return "undefined";
|
467
382
|
}
|
468
|
-
// A slight delay, to avoid any current callbacks
|
469
|
-
if ( defined.setTimeout ) {
|
470
|
-
setTimeout(function() {
|
471
|
-
if ( config.semaphore > 0 ) {
|
472
|
-
return;
|
473
|
-
}
|
474
|
-
if ( config.timeout ) {
|
475
|
-
clearTimeout( config.timeout );
|
476
|
-
}
|
477
383
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
} else {
|
482
|
-
config.blocking = false;
|
483
|
-
process( true );
|
384
|
+
// Consider: typeof null === object
|
385
|
+
if ( obj === null ) {
|
386
|
+
return "null";
|
484
387
|
}
|
485
|
-
},
|
486
388
|
|
487
|
-
|
488
|
-
|
489
|
-
config.blocking = true;
|
389
|
+
var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
|
390
|
+
type = match && match[1] || "";
|
490
391
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
392
|
+
switch ( type ) {
|
393
|
+
case "Number":
|
394
|
+
if ( isNaN(obj) ) {
|
395
|
+
return "nan";
|
396
|
+
}
|
397
|
+
return "number";
|
398
|
+
case "String":
|
399
|
+
case "Boolean":
|
400
|
+
case "Array":
|
401
|
+
case "Date":
|
402
|
+
case "RegExp":
|
403
|
+
case "Function":
|
404
|
+
return type.toLowerCase();
|
498
405
|
}
|
499
|
-
|
500
|
-
|
406
|
+
if ( typeof obj === "object" ) {
|
407
|
+
return "object";
|
408
|
+
}
|
409
|
+
return undefined;
|
410
|
+
},
|
501
411
|
|
502
|
-
|
503
|
-
// Assert helpers
|
504
|
-
// All of these must either call QUnit.push() or manually do:
|
505
|
-
// - runLoggingCallbacks( "log", .. );
|
506
|
-
// - config.current.assertions.push({ .. });
|
507
|
-
// We attach it to the QUnit object *after* we expose the public API,
|
508
|
-
// otherwise `assert` will become a global variable in browsers (#341).
|
509
|
-
assert = {
|
510
|
-
/**
|
511
|
-
* Asserts rough true-ish result.
|
512
|
-
* @name ok
|
513
|
-
* @function
|
514
|
-
* @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
|
515
|
-
*/
|
516
|
-
ok: function( result, msg ) {
|
412
|
+
push: function( result, actual, expected, message ) {
|
517
413
|
if ( !config.current ) {
|
518
|
-
throw new Error( "
|
414
|
+
throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
|
519
415
|
}
|
520
|
-
result = !!result;
|
521
|
-
msg = msg || (result ? "okay" : "failed" );
|
522
416
|
|
523
|
-
var source,
|
417
|
+
var output, source,
|
524
418
|
details = {
|
525
419
|
module: config.current.module,
|
526
420
|
name: config.current.testName,
|
527
421
|
result: result,
|
528
|
-
message:
|
422
|
+
message: message,
|
423
|
+
actual: actual,
|
424
|
+
expected: expected
|
529
425
|
};
|
530
426
|
|
531
|
-
|
427
|
+
message = escapeText( message ) || ( result ? "okay" : "failed" );
|
428
|
+
message = "<span class='test-message'>" + message + "</span>";
|
429
|
+
output = message;
|
532
430
|
|
533
431
|
if ( !result ) {
|
534
|
-
|
432
|
+
expected = escapeText( QUnit.jsDump.parse(expected) );
|
433
|
+
actual = escapeText( QUnit.jsDump.parse(actual) );
|
434
|
+
output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
|
435
|
+
|
436
|
+
if ( actual !== expected ) {
|
437
|
+
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
|
438
|
+
output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
|
439
|
+
}
|
440
|
+
|
441
|
+
source = sourceFromStacktrace();
|
442
|
+
|
535
443
|
if ( source ) {
|
536
444
|
details.source = source;
|
537
|
-
|
445
|
+
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
|
538
446
|
}
|
447
|
+
|
448
|
+
output += "</table>";
|
539
449
|
}
|
450
|
+
|
540
451
|
runLoggingCallbacks( "log", QUnit, details );
|
452
|
+
|
541
453
|
config.current.assertions.push({
|
542
|
-
result: result,
|
543
|
-
message:
|
454
|
+
result: !!result,
|
455
|
+
message: output
|
544
456
|
});
|
545
457
|
},
|
546
458
|
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
* @function
|
552
|
-
* @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
|
553
|
-
*/
|
554
|
-
equal: function( actual, expected, message ) {
|
555
|
-
/*jshint eqeqeq:false */
|
556
|
-
QUnit.push( expected == actual, actual, expected, message );
|
557
|
-
},
|
459
|
+
pushFailure: function( message, source, actual ) {
|
460
|
+
if ( !config.current ) {
|
461
|
+
throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
|
462
|
+
}
|
558
463
|
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
},
|
464
|
+
var output,
|
465
|
+
details = {
|
466
|
+
module: config.current.module,
|
467
|
+
name: config.current.testName,
|
468
|
+
result: false,
|
469
|
+
message: message
|
470
|
+
};
|
567
471
|
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
*/
|
572
|
-
propEqual: function( actual, expected, message ) {
|
573
|
-
actual = objectValues(actual);
|
574
|
-
expected = objectValues(expected);
|
575
|
-
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
|
576
|
-
},
|
472
|
+
message = escapeText( message ) || "error";
|
473
|
+
message = "<span class='test-message'>" + message + "</span>";
|
474
|
+
output = message;
|
577
475
|
|
578
|
-
|
579
|
-
* @name notPropEqual
|
580
|
-
* @function
|
581
|
-
*/
|
582
|
-
notPropEqual: function( actual, expected, message ) {
|
583
|
-
actual = objectValues(actual);
|
584
|
-
expected = objectValues(expected);
|
585
|
-
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
|
586
|
-
},
|
476
|
+
output += "<table>";
|
587
477
|
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
*/
|
592
|
-
deepEqual: function( actual, expected, message ) {
|
593
|
-
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
|
594
|
-
},
|
478
|
+
if ( actual ) {
|
479
|
+
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
|
480
|
+
}
|
595
481
|
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
notDeepEqual: function( actual, expected, message ) {
|
601
|
-
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
|
602
|
-
},
|
482
|
+
if ( source ) {
|
483
|
+
details.source = source;
|
484
|
+
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
|
485
|
+
}
|
603
486
|
|
604
|
-
|
605
|
-
* @name strictEqual
|
606
|
-
* @function
|
607
|
-
*/
|
608
|
-
strictEqual: function( actual, expected, message ) {
|
609
|
-
QUnit.push( expected === actual, actual, expected, message );
|
610
|
-
},
|
487
|
+
output += "</table>";
|
611
488
|
|
612
|
-
|
613
|
-
* @name notStrictEqual
|
614
|
-
* @function
|
615
|
-
*/
|
616
|
-
notStrictEqual: function( actual, expected, message ) {
|
617
|
-
QUnit.push( expected !== actual, actual, expected, message );
|
618
|
-
},
|
489
|
+
runLoggingCallbacks( "log", QUnit, details );
|
619
490
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
491
|
+
config.current.assertions.push({
|
492
|
+
result: false,
|
493
|
+
message: output
|
494
|
+
});
|
495
|
+
},
|
624
496
|
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
}
|
497
|
+
url: function( params ) {
|
498
|
+
params = extend( extend( {}, QUnit.urlParams ), params );
|
499
|
+
var key,
|
500
|
+
querystring = "?";
|
630
501
|
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
502
|
+
for ( key in params ) {
|
503
|
+
if ( hasOwn.call( params, key ) ) {
|
504
|
+
querystring += encodeURIComponent( key ) + "=" +
|
505
|
+
encodeURIComponent( params[ key ] ) + "&";
|
506
|
+
}
|
636
507
|
}
|
637
|
-
|
508
|
+
return window.location.protocol + "//" + window.location.host +
|
509
|
+
window.location.pathname + querystring.slice( 0, -1 );
|
510
|
+
},
|
638
511
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
// expected is a constructor
|
648
|
-
} else if ( actual instanceof expected ) {
|
649
|
-
ok = true;
|
650
|
-
// expected is a validation function which returns true is validation passed
|
651
|
-
} else if ( expected.call( {}, actual ) === true ) {
|
652
|
-
expectedOutput = null;
|
653
|
-
ok = true;
|
654
|
-
}
|
655
|
-
|
656
|
-
QUnit.push( ok, actual, expectedOutput, message );
|
657
|
-
} else {
|
658
|
-
QUnit.pushFailure( message, null, "No exception was thrown." );
|
659
|
-
}
|
660
|
-
}
|
661
|
-
};
|
662
|
-
|
663
|
-
/**
|
664
|
-
* @deprecated since 1.8.0
|
665
|
-
* Kept assertion helpers in root for backwards compatibility.
|
666
|
-
*/
|
667
|
-
extend( QUnit, assert );
|
668
|
-
|
669
|
-
/**
|
670
|
-
* @deprecated since 1.9.0
|
671
|
-
* Kept root "raises()" for backwards compatibility.
|
672
|
-
* (Note that we don't introduce assert.raises).
|
673
|
-
*/
|
674
|
-
QUnit.raises = assert[ "throws" ];
|
512
|
+
extend: extend,
|
513
|
+
id: id,
|
514
|
+
addEvent: addEvent,
|
515
|
+
addClass: addClass,
|
516
|
+
hasClass: hasClass,
|
517
|
+
removeClass: removeClass
|
518
|
+
// load, equiv, jsDump, diff: Attached later
|
519
|
+
});
|
675
520
|
|
676
521
|
/**
|
677
|
-
* @deprecated
|
678
|
-
*
|
522
|
+
* @deprecated: Created for backwards compatibility with test runner that set the hook function
|
523
|
+
* into QUnit.{hook}, instead of invoking it and passing the hook function.
|
524
|
+
* QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
|
525
|
+
* Doing this allows us to tell if the following methods have been overwritten on the actual
|
526
|
+
* QUnit object.
|
679
527
|
*/
|
680
|
-
QUnit.
|
681
|
-
QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
|
682
|
-
};
|
683
|
-
QUnit.same = function() {
|
684
|
-
QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
|
685
|
-
};
|
528
|
+
extend( QUnit.constructor.prototype, {
|
686
529
|
|
687
|
-
//
|
688
|
-
|
689
|
-
|
690
|
-
F.prototype = QUnit;
|
691
|
-
QUnit = new F();
|
692
|
-
// Make F QUnit's constructor so that we can add to the prototype later
|
693
|
-
QUnit.constructor = F;
|
694
|
-
}());
|
530
|
+
// Logging callbacks; all receive a single argument with the listed properties
|
531
|
+
// run test/logs.html for any related changes
|
532
|
+
begin: registerLoggingCallback( "begin" ),
|
695
533
|
|
696
|
-
|
697
|
-
|
698
|
-
* Later exposed as QUnit.config
|
699
|
-
* `config` initialized at top of scope
|
700
|
-
*/
|
701
|
-
config = {
|
702
|
-
// The queue of tests to run
|
703
|
-
queue: [],
|
534
|
+
// done: { failed, passed, total, runtime }
|
535
|
+
done: registerLoggingCallback( "done" ),
|
704
536
|
|
705
|
-
//
|
706
|
-
|
537
|
+
// log: { result, actual, expected, message }
|
538
|
+
log: registerLoggingCallback( "log" ),
|
707
539
|
|
708
|
-
//
|
709
|
-
|
710
|
-
hidepassed: false,
|
540
|
+
// testStart: { name }
|
541
|
+
testStart: registerLoggingCallback( "testStart" ),
|
711
542
|
|
712
|
-
//
|
713
|
-
|
714
|
-
reorder: true,
|
543
|
+
// testDone: { name, failed, passed, total, runtime }
|
544
|
+
testDone: registerLoggingCallback( "testDone" ),
|
715
545
|
|
716
|
-
//
|
717
|
-
|
546
|
+
// moduleStart: { name }
|
547
|
+
moduleStart: registerLoggingCallback( "moduleStart" ),
|
718
548
|
|
719
|
-
//
|
720
|
-
|
549
|
+
// moduleDone: { name, failed, passed, total }
|
550
|
+
moduleDone: registerLoggingCallback( "moduleDone" )
|
551
|
+
});
|
721
552
|
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
{
|
726
|
-
id: "noglobals",
|
727
|
-
label: "Check for Globals",
|
728
|
-
tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
|
729
|
-
},
|
730
|
-
{
|
731
|
-
id: "notrycatch",
|
732
|
-
label: "No try-catch",
|
733
|
-
tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
|
734
|
-
}
|
735
|
-
],
|
553
|
+
if ( !defined.document || document.readyState === "complete" ) {
|
554
|
+
config.autorun = true;
|
555
|
+
}
|
736
556
|
|
737
|
-
|
738
|
-
|
557
|
+
QUnit.load = function() {
|
558
|
+
runLoggingCallbacks( "begin", QUnit, {} );
|
739
559
|
|
740
|
-
//
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
};
|
560
|
+
// Initialize the config, saving the execution queue
|
561
|
+
var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
|
562
|
+
urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
|
563
|
+
numModules = 0,
|
564
|
+
moduleNames = [],
|
565
|
+
moduleFilterHtml = "",
|
566
|
+
urlConfigHtml = "",
|
567
|
+
oldconfig = extend( {}, config );
|
749
568
|
|
750
|
-
|
751
|
-
|
752
|
-
if ( typeof exports === "undefined" ) {
|
753
|
-
extend( window, QUnit.constructor.prototype );
|
569
|
+
QUnit.init();
|
570
|
+
extend(config, oldconfig);
|
754
571
|
|
755
|
-
|
756
|
-
window.QUnit = QUnit;
|
757
|
-
}
|
572
|
+
config.blocking = false;
|
758
573
|
|
759
|
-
|
760
|
-
(function() {
|
761
|
-
var i,
|
762
|
-
location = window.location || { search: "", protocol: "file:" },
|
763
|
-
params = location.search.slice( 1 ).split( "&" ),
|
764
|
-
length = params.length,
|
765
|
-
urlParams = {},
|
766
|
-
current;
|
574
|
+
len = config.urlConfig.length;
|
767
575
|
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
576
|
+
for ( i = 0; i < len; i++ ) {
|
577
|
+
val = config.urlConfig[i];
|
578
|
+
if ( typeof val === "string" ) {
|
579
|
+
val = {
|
580
|
+
id: val,
|
581
|
+
label: val,
|
582
|
+
tooltip: "[no tooltip available]"
|
583
|
+
};
|
584
|
+
}
|
585
|
+
config[ val.id ] = QUnit.urlParams[ val.id ];
|
586
|
+
urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
|
587
|
+
"' name='" + escapeText( val.id ) +
|
588
|
+
"' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
|
589
|
+
" title='" + escapeText( val.tooltip ) +
|
590
|
+
"'><label for='qunit-urlconfig-" + escapeText( val.id ) +
|
591
|
+
"' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
|
592
|
+
}
|
593
|
+
for ( i in config.modules ) {
|
594
|
+
if ( config.modules.hasOwnProperty( i ) ) {
|
595
|
+
moduleNames.push(i);
|
775
596
|
}
|
776
597
|
}
|
598
|
+
numModules = moduleNames.length;
|
599
|
+
moduleNames.sort( function( a, b ) {
|
600
|
+
return a.localeCompare( b );
|
601
|
+
});
|
602
|
+
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
|
603
|
+
( config.module === undefined ? "selected='selected'" : "" ) +
|
604
|
+
">< All Modules ></option>";
|
777
605
|
|
778
|
-
QUnit.urlParams = urlParams;
|
779
|
-
|
780
|
-
// String search anywhere in moduleName+testName
|
781
|
-
config.filter = urlParams.filter;
|
782
606
|
|
783
|
-
|
784
|
-
|
607
|
+
for ( i = 0; i < numModules; i++) {
|
608
|
+
moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(moduleNames[i]) ) + "' " +
|
609
|
+
( config.module === moduleNames[i] ? "selected='selected'" : "" ) +
|
610
|
+
">" + escapeText(moduleNames[i]) + "</option>";
|
611
|
+
}
|
612
|
+
moduleFilterHtml += "</select>";
|
785
613
|
|
786
|
-
|
614
|
+
// `userAgent` initialized at top of scope
|
615
|
+
userAgent = id( "qunit-userAgent" );
|
616
|
+
if ( userAgent ) {
|
617
|
+
userAgent.innerHTML = navigator.userAgent;
|
618
|
+
}
|
787
619
|
|
788
|
-
//
|
789
|
-
|
790
|
-
|
620
|
+
// `banner` initialized at top of scope
|
621
|
+
banner = id( "qunit-header" );
|
622
|
+
if ( banner ) {
|
623
|
+
banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
|
624
|
+
}
|
791
625
|
|
792
|
-
//
|
793
|
-
|
794
|
-
|
795
|
-
|
626
|
+
// `toolbar` initialized at top of scope
|
627
|
+
toolbar = id( "qunit-testrunner-toolbar" );
|
628
|
+
if ( toolbar ) {
|
629
|
+
// `filter` initialized at top of scope
|
630
|
+
filter = document.createElement( "input" );
|
631
|
+
filter.type = "checkbox";
|
632
|
+
filter.id = "qunit-filter-pass";
|
796
633
|
|
797
|
-
|
634
|
+
addEvent( filter, "click", function() {
|
635
|
+
var tmp,
|
636
|
+
ol = id( "qunit-tests" );
|
798
637
|
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
638
|
+
if ( filter.checked ) {
|
639
|
+
ol.className = ol.className + " hidepass";
|
640
|
+
} else {
|
641
|
+
tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
|
642
|
+
ol.className = tmp.replace( / hidepass /, " " );
|
643
|
+
}
|
644
|
+
if ( defined.sessionStorage ) {
|
645
|
+
if (filter.checked) {
|
646
|
+
sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
|
647
|
+
} else {
|
648
|
+
sessionStorage.removeItem( "qunit-filter-passed-tests" );
|
649
|
+
}
|
650
|
+
}
|
812
651
|
});
|
813
652
|
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
|
820
|
-
"<h2 id='qunit-banner'></h2>" +
|
821
|
-
"<div id='qunit-testrunner-toolbar'></div>" +
|
822
|
-
"<h2 id='qunit-userAgent'></h2>" +
|
823
|
-
"<ol id='qunit-tests'></ol>";
|
653
|
+
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
|
654
|
+
filter.checked = true;
|
655
|
+
// `ol` initialized at top of scope
|
656
|
+
ol = id( "qunit-tests" );
|
657
|
+
ol.className = ol.className + " hidepass";
|
824
658
|
}
|
659
|
+
toolbar.appendChild( filter );
|
825
660
|
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
}
|
833
|
-
|
834
|
-
if ( banner ) {
|
835
|
-
banner.className = "";
|
836
|
-
}
|
661
|
+
// `label` initialized at top of scope
|
662
|
+
label = document.createElement( "label" );
|
663
|
+
label.setAttribute( "for", "qunit-filter-pass" );
|
664
|
+
label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
|
665
|
+
label.innerHTML = "Hide passed tests";
|
666
|
+
toolbar.appendChild( label );
|
837
667
|
|
838
|
-
|
839
|
-
|
840
|
-
|
668
|
+
urlConfigCheckboxesContainer = document.createElement("span");
|
669
|
+
urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
|
670
|
+
urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
|
671
|
+
// For oldIE support:
|
672
|
+
// * Add handlers to the individual elements instead of the container
|
673
|
+
// * Use "click" instead of "change"
|
674
|
+
// * Fallback from event.target to event.srcElement
|
675
|
+
addEvents( urlConfigCheckboxes, "click", function( event ) {
|
676
|
+
var params = {},
|
677
|
+
target = event.target || event.srcElement;
|
678
|
+
params[ target.name ] = target.checked ? true : undefined;
|
679
|
+
window.location = QUnit.url( params );
|
680
|
+
});
|
681
|
+
toolbar.appendChild( urlConfigCheckboxesContainer );
|
841
682
|
|
842
|
-
if (
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
},
|
683
|
+
if (numModules > 1) {
|
684
|
+
moduleFilter = document.createElement( "span" );
|
685
|
+
moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
|
686
|
+
moduleFilter.innerHTML = moduleFilterHtml;
|
687
|
+
addEvent( moduleFilter.lastChild, "change", function() {
|
688
|
+
var selectBox = moduleFilter.getElementsByTagName("select")[0],
|
689
|
+
selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
|
850
690
|
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
if ( fixture ) {
|
860
|
-
fixture.innerHTML = config.fixture;
|
691
|
+
window.location = QUnit.url({
|
692
|
+
module: ( selectedModule === "" ) ? undefined : selectedModule,
|
693
|
+
// Remove any existing filters
|
694
|
+
filter: undefined,
|
695
|
+
testNumber: undefined
|
696
|
+
});
|
697
|
+
});
|
698
|
+
toolbar.appendChild(moduleFilter);
|
861
699
|
}
|
862
|
-
}
|
700
|
+
}
|
863
701
|
|
864
|
-
//
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
|
870
|
-
0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
702
|
+
// `main` initialized at top of scope
|
703
|
+
main = id( "qunit-fixture" );
|
704
|
+
if ( main ) {
|
705
|
+
config.fixture = main.innerHTML;
|
706
|
+
}
|
871
707
|
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
},
|
708
|
+
if ( config.autostart ) {
|
709
|
+
QUnit.start();
|
710
|
+
}
|
711
|
+
};
|
877
712
|
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
},
|
713
|
+
if ( defined.document ) {
|
714
|
+
addEvent( window, "load", QUnit.load );
|
715
|
+
}
|
882
716
|
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
// consider: typeof null === object
|
887
|
-
}
|
888
|
-
if ( obj === null ) {
|
889
|
-
return "null";
|
890
|
-
}
|
717
|
+
// `onErrorFnPrev` initialized at top of scope
|
718
|
+
// Preserve other handlers
|
719
|
+
onErrorFnPrev = window.onerror;
|
891
720
|
|
892
|
-
|
893
|
-
|
721
|
+
// Cover uncaught exceptions
|
722
|
+
// Returning true will suppress the default browser handler,
|
723
|
+
// returning false will let it run.
|
724
|
+
window.onerror = function ( error, filePath, linerNr ) {
|
725
|
+
var ret = false;
|
726
|
+
if ( onErrorFnPrev ) {
|
727
|
+
ret = onErrorFnPrev( error, filePath, linerNr );
|
728
|
+
}
|
894
729
|
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
return
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
return type.toLowerCase();
|
908
|
-
}
|
909
|
-
if ( typeof obj === "object" ) {
|
910
|
-
return "object";
|
730
|
+
// Treat return value as window.onerror itself does,
|
731
|
+
// Only do our handling if not suppressed.
|
732
|
+
if ( ret !== true ) {
|
733
|
+
if ( QUnit.config.current ) {
|
734
|
+
if ( QUnit.config.current.ignoreGlobalErrors ) {
|
735
|
+
return true;
|
736
|
+
}
|
737
|
+
QUnit.pushFailure( error, filePath + ":" + linerNr );
|
738
|
+
} else {
|
739
|
+
QUnit.test( "global failure", extend( function() {
|
740
|
+
QUnit.pushFailure( error, filePath + ":" + linerNr );
|
741
|
+
}, { validTest: validTest } ) );
|
911
742
|
}
|
912
|
-
return
|
913
|
-
}
|
743
|
+
return false;
|
744
|
+
}
|
914
745
|
|
915
|
-
|
916
|
-
|
917
|
-
throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
|
918
|
-
}
|
746
|
+
return ret;
|
747
|
+
};
|
919
748
|
|
920
|
-
|
921
|
-
|
922
|
-
module: config.current.module,
|
923
|
-
name: config.current.testName,
|
924
|
-
result: result,
|
925
|
-
message: message,
|
926
|
-
actual: actual,
|
927
|
-
expected: expected
|
928
|
-
};
|
749
|
+
function done() {
|
750
|
+
config.autorun = true;
|
929
751
|
|
930
|
-
|
931
|
-
|
932
|
-
|
752
|
+
// Log the last module results
|
753
|
+
if ( config.previousModule ) {
|
754
|
+
runLoggingCallbacks( "moduleDone", QUnit, {
|
755
|
+
name: config.previousModule,
|
756
|
+
failed: config.moduleStats.bad,
|
757
|
+
passed: config.moduleStats.all - config.moduleStats.bad,
|
758
|
+
total: config.moduleStats.all
|
759
|
+
});
|
760
|
+
}
|
761
|
+
delete config.previousModule;
|
933
762
|
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
763
|
+
var i, key,
|
764
|
+
banner = id( "qunit-banner" ),
|
765
|
+
tests = id( "qunit-tests" ),
|
766
|
+
runtime = +new Date() - config.started,
|
767
|
+
passed = config.stats.all - config.stats.bad,
|
768
|
+
html = [
|
769
|
+
"Tests completed in ",
|
770
|
+
runtime,
|
771
|
+
" milliseconds.<br/>",
|
772
|
+
"<span class='passed'>",
|
773
|
+
passed,
|
774
|
+
"</span> assertions of <span class='total'>",
|
775
|
+
config.stats.all,
|
776
|
+
"</span> passed, <span class='failed'>",
|
777
|
+
config.stats.bad,
|
778
|
+
"</span> failed."
|
779
|
+
].join( "" );
|
938
780
|
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
}
|
781
|
+
if ( banner ) {
|
782
|
+
banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
|
783
|
+
}
|
943
784
|
|
944
|
-
|
785
|
+
if ( tests ) {
|
786
|
+
id( "qunit-testresult" ).innerHTML = html;
|
787
|
+
}
|
945
788
|
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
789
|
+
if ( config.altertitle && defined.document && document.title ) {
|
790
|
+
// show ✖ for good, ✔ for bad suite result in title
|
791
|
+
// use escape sequences in case file gets loaded with non-utf-8-charset
|
792
|
+
document.title = [
|
793
|
+
( config.stats.bad ? "\u2716" : "\u2714" ),
|
794
|
+
document.title.replace( /^[\u2714\u2716] /i, "" )
|
795
|
+
].join( " " );
|
796
|
+
}
|
950
797
|
|
951
|
-
|
798
|
+
// clear own sessionStorage items if all tests passed
|
799
|
+
if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
|
800
|
+
// `key` & `i` initialized at top of scope
|
801
|
+
for ( i = 0; i < sessionStorage.length; i++ ) {
|
802
|
+
key = sessionStorage.key( i++ );
|
803
|
+
if ( key.indexOf( "qunit-test-" ) === 0 ) {
|
804
|
+
sessionStorage.removeItem( key );
|
805
|
+
}
|
952
806
|
}
|
807
|
+
}
|
953
808
|
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
message: output
|
959
|
-
});
|
960
|
-
},
|
809
|
+
// scroll back to top to show results
|
810
|
+
if ( window.scrollTo ) {
|
811
|
+
window.scrollTo(0, 0);
|
812
|
+
}
|
961
813
|
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
814
|
+
runLoggingCallbacks( "done", QUnit, {
|
815
|
+
failed: config.stats.bad,
|
816
|
+
passed: passed,
|
817
|
+
total: config.stats.all,
|
818
|
+
runtime: runtime
|
819
|
+
});
|
820
|
+
}
|
966
821
|
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
};
|
822
|
+
/** @return Boolean: true if this test should be ran */
|
823
|
+
function validTest( test ) {
|
824
|
+
var include,
|
825
|
+
filter = config.filter && config.filter.toLowerCase(),
|
826
|
+
module = config.module && config.module.toLowerCase(),
|
827
|
+
fullName = (test.module + ": " + test.testName).toLowerCase();
|
974
828
|
|
975
|
-
|
976
|
-
|
977
|
-
|
829
|
+
// Internally-generated tests are always valid
|
830
|
+
if ( test.callback && test.callback.validTest === validTest ) {
|
831
|
+
delete test.callback.validTest;
|
832
|
+
return true;
|
833
|
+
}
|
978
834
|
|
979
|
-
|
835
|
+
if ( config.testNumber ) {
|
836
|
+
return test.testNumber === config.testNumber;
|
837
|
+
}
|
980
838
|
|
981
|
-
|
982
|
-
|
983
|
-
|
839
|
+
if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
|
840
|
+
return false;
|
841
|
+
}
|
984
842
|
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
}
|
843
|
+
if ( !filter ) {
|
844
|
+
return true;
|
845
|
+
}
|
989
846
|
|
990
|
-
|
847
|
+
include = filter.charAt( 0 ) !== "!";
|
848
|
+
if ( !include ) {
|
849
|
+
filter = filter.slice( 1 );
|
850
|
+
}
|
991
851
|
|
992
|
-
|
852
|
+
// If the filter matches, we need to honour include
|
853
|
+
if ( fullName.indexOf( filter ) !== -1 ) {
|
854
|
+
return include;
|
855
|
+
}
|
993
856
|
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
});
|
998
|
-
},
|
857
|
+
// Otherwise, do the opposite
|
858
|
+
return !include;
|
859
|
+
}
|
999
860
|
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
861
|
+
// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
|
862
|
+
// Later Safari and IE10 are supposed to support error.stack as well
|
863
|
+
// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
|
864
|
+
function extractStacktrace( e, offset ) {
|
865
|
+
offset = offset === undefined ? 3 : offset;
|
1004
866
|
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
867
|
+
var stack, include, i;
|
868
|
+
|
869
|
+
if ( e.stacktrace ) {
|
870
|
+
// Opera
|
871
|
+
return e.stacktrace.split( "\n" )[ offset + 3 ];
|
872
|
+
} else if ( e.stack ) {
|
873
|
+
// Firefox, Chrome
|
874
|
+
stack = e.stack.split( "\n" );
|
875
|
+
if (/^error$/i.test( stack[0] ) ) {
|
876
|
+
stack.shift();
|
877
|
+
}
|
878
|
+
if ( fileName ) {
|
879
|
+
include = [];
|
880
|
+
for ( i = offset; i < stack.length; i++ ) {
|
881
|
+
if ( stack[ i ].indexOf( fileName ) !== -1 ) {
|
882
|
+
break;
|
883
|
+
}
|
884
|
+
include.push( stack[ i ] );
|
885
|
+
}
|
886
|
+
if ( include.length ) {
|
887
|
+
return include.join( "\n" );
|
1009
888
|
}
|
1010
889
|
}
|
1011
|
-
return
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
}
|
890
|
+
return stack[ offset ];
|
891
|
+
} else if ( e.sourceURL ) {
|
892
|
+
// Safari, PhantomJS
|
893
|
+
// hopefully one day Safari provides actual stacktraces
|
894
|
+
// exclude useless self-reference for generated Error objects
|
895
|
+
if ( /qunit.js$/.test( e.sourceURL ) ) {
|
896
|
+
return;
|
897
|
+
}
|
898
|
+
// for actual exceptions, this is useful
|
899
|
+
return e.sourceURL + ":" + e.line;
|
900
|
+
}
|
901
|
+
}
|
902
|
+
function sourceFromStacktrace( offset ) {
|
903
|
+
try {
|
904
|
+
throw new Error();
|
905
|
+
} catch ( e ) {
|
906
|
+
return extractStacktrace( e, offset );
|
907
|
+
}
|
908
|
+
}
|
1023
909
|
|
1024
910
|
/**
|
1025
|
-
*
|
1026
|
-
* into QUnit.{hook}, instead of invoking it and passing the hook function.
|
1027
|
-
* QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
|
1028
|
-
* Doing this allows us to tell if the following methods have been overwritten on the actual
|
1029
|
-
* QUnit object.
|
911
|
+
* Escape text for attribute or text content.
|
1030
912
|
*/
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
913
|
+
function escapeText( s ) {
|
914
|
+
if ( !s ) {
|
915
|
+
return "";
|
916
|
+
}
|
917
|
+
s = s + "";
|
918
|
+
// Both single quotes and double quotes (for attributes)
|
919
|
+
return s.replace( /['"<>&]/g, function( s ) {
|
920
|
+
switch( s ) {
|
921
|
+
case "'":
|
922
|
+
return "'";
|
923
|
+
case "\"":
|
924
|
+
return """;
|
925
|
+
case "<":
|
926
|
+
return "<";
|
927
|
+
case ">":
|
928
|
+
return ">";
|
929
|
+
case "&":
|
930
|
+
return "&";
|
931
|
+
}
|
932
|
+
});
|
933
|
+
}
|
1039
934
|
|
1040
|
-
|
1041
|
-
|
935
|
+
function synchronize( callback, last ) {
|
936
|
+
config.queue.push( callback );
|
1042
937
|
|
1043
|
-
|
1044
|
-
|
938
|
+
if ( config.autorun && !config.blocking ) {
|
939
|
+
process( last );
|
940
|
+
}
|
941
|
+
}
|
1045
942
|
|
1046
|
-
|
1047
|
-
|
943
|
+
function process( last ) {
|
944
|
+
function next() {
|
945
|
+
process( last );
|
946
|
+
}
|
947
|
+
var start = new Date().getTime();
|
948
|
+
config.depth = config.depth ? config.depth + 1 : 1;
|
1048
949
|
|
1049
|
-
|
1050
|
-
|
950
|
+
while ( config.queue.length && !config.blocking ) {
|
951
|
+
if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
|
952
|
+
config.queue.shift()();
|
953
|
+
} else {
|
954
|
+
setTimeout( next, 13 );
|
955
|
+
break;
|
956
|
+
}
|
957
|
+
}
|
958
|
+
config.depth--;
|
959
|
+
if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
|
960
|
+
done();
|
961
|
+
}
|
962
|
+
}
|
1051
963
|
|
1052
|
-
|
1053
|
-
|
1054
|
-
});
|
964
|
+
function saveGlobal() {
|
965
|
+
config.pollution = [];
|
1055
966
|
|
1056
|
-
if (
|
1057
|
-
|
967
|
+
if ( config.noglobals ) {
|
968
|
+
for ( var key in window ) {
|
969
|
+
if ( hasOwn.call( window, key ) ) {
|
970
|
+
// in Opera sometimes DOM element ids show up here, ignore them
|
971
|
+
if ( /^qunit-test-output/.test( key ) ) {
|
972
|
+
continue;
|
973
|
+
}
|
974
|
+
config.pollution.push( key );
|
975
|
+
}
|
976
|
+
}
|
977
|
+
}
|
1058
978
|
}
|
1059
979
|
|
1060
|
-
|
1061
|
-
|
980
|
+
function checkPollution() {
|
981
|
+
var newGlobals,
|
982
|
+
deletedGlobals,
|
983
|
+
old = config.pollution;
|
1062
984
|
|
1063
|
-
|
1064
|
-
var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
|
1065
|
-
urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
|
1066
|
-
numModules = 0,
|
1067
|
-
moduleNames = [],
|
1068
|
-
moduleFilterHtml = "",
|
1069
|
-
urlConfigHtml = "",
|
1070
|
-
oldconfig = extend( {}, config );
|
985
|
+
saveGlobal();
|
1071
986
|
|
1072
|
-
|
1073
|
-
|
987
|
+
newGlobals = diff( config.pollution, old );
|
988
|
+
if ( newGlobals.length > 0 ) {
|
989
|
+
QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
|
990
|
+
}
|
1074
991
|
|
1075
|
-
config.
|
992
|
+
deletedGlobals = diff( old, config.pollution );
|
993
|
+
if ( deletedGlobals.length > 0 ) {
|
994
|
+
QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
|
995
|
+
}
|
996
|
+
}
|
1076
997
|
|
1077
|
-
|
998
|
+
// returns a new Array with the elements that are in a but not in b
|
999
|
+
function diff( a, b ) {
|
1000
|
+
var i, j,
|
1001
|
+
result = a.slice();
|
1078
1002
|
|
1079
|
-
for ( i = 0; i <
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
};
|
1003
|
+
for ( i = 0; i < result.length; i++ ) {
|
1004
|
+
for ( j = 0; j < b.length; j++ ) {
|
1005
|
+
if ( result[i] === b[j] ) {
|
1006
|
+
result.splice( i, 1 );
|
1007
|
+
i--;
|
1008
|
+
break;
|
1009
|
+
}
|
1087
1010
|
}
|
1088
|
-
config[ val.id ] = QUnit.urlParams[ val.id ];
|
1089
|
-
urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
|
1090
|
-
"' name='" + escapeText( val.id ) +
|
1091
|
-
"' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
|
1092
|
-
" title='" + escapeText( val.tooltip ) +
|
1093
|
-
"'><label for='qunit-urlconfig-" + escapeText( val.id ) +
|
1094
|
-
"' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
|
1095
1011
|
}
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1012
|
+
return result;
|
1013
|
+
}
|
1014
|
+
|
1015
|
+
function extend( a, b ) {
|
1016
|
+
for ( var prop in b ) {
|
1017
|
+
if ( hasOwn.call( b, prop ) ) {
|
1018
|
+
// Avoid "Member not found" error in IE8 caused by messing with window.constructor
|
1019
|
+
if ( !( prop === "constructor" && a === window ) ) {
|
1020
|
+
if ( b[ prop ] === undefined ) {
|
1021
|
+
delete a[ prop ];
|
1022
|
+
} else {
|
1023
|
+
a[ prop ] = b[ prop ];
|
1024
|
+
}
|
1025
|
+
}
|
1099
1026
|
}
|
1100
1027
|
}
|
1101
|
-
numModules = moduleNames.length;
|
1102
|
-
moduleNames.sort( function( a, b ) {
|
1103
|
-
return a.localeCompare( b );
|
1104
|
-
});
|
1105
|
-
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
|
1106
|
-
( config.module === undefined ? "selected='selected'" : "" ) +
|
1107
|
-
">< All Modules ></option>";
|
1108
1028
|
|
1029
|
+
return a;
|
1030
|
+
}
|
1109
1031
|
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1032
|
+
/**
|
1033
|
+
* @param {HTMLElement} elem
|
1034
|
+
* @param {string} type
|
1035
|
+
* @param {Function} fn
|
1036
|
+
*/
|
1037
|
+
function addEvent( elem, type, fn ) {
|
1038
|
+
if ( elem.addEventListener ) {
|
1116
1039
|
|
1117
|
-
|
1118
|
-
|
1119
|
-
if (
|
1120
|
-
userAgent.innerHTML = navigator.userAgent;
|
1121
|
-
}
|
1040
|
+
// Standards-based browsers
|
1041
|
+
elem.addEventListener( type, fn, false );
|
1042
|
+
} else if ( elem.attachEvent ) {
|
1122
1043
|
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
|
1127
|
-
}
|
1044
|
+
// support: IE <9
|
1045
|
+
elem.attachEvent( "on" + type, fn );
|
1046
|
+
} else {
|
1128
1047
|
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
filter = document.createElement( "input" );
|
1134
|
-
filter.type = "checkbox";
|
1135
|
-
filter.id = "qunit-filter-pass";
|
1048
|
+
// Caller must ensure support for event listeners is present
|
1049
|
+
throw new Error( "addEvent() was called in a context without event listener support" );
|
1050
|
+
}
|
1051
|
+
}
|
1136
1052
|
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1053
|
+
/**
|
1054
|
+
* @param {Array|NodeList} elems
|
1055
|
+
* @param {string} type
|
1056
|
+
* @param {Function} fn
|
1057
|
+
*/
|
1058
|
+
function addEvents( elems, type, fn ) {
|
1059
|
+
var i = elems.length;
|
1060
|
+
while ( i-- ) {
|
1061
|
+
addEvent( elems[i], type, fn );
|
1062
|
+
}
|
1063
|
+
}
|
1140
1064
|
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
|
1145
|
-
ol.className = tmp.replace( / hidepass /, " " );
|
1146
|
-
}
|
1147
|
-
if ( defined.sessionStorage ) {
|
1148
|
-
if (filter.checked) {
|
1149
|
-
sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
|
1150
|
-
} else {
|
1151
|
-
sessionStorage.removeItem( "qunit-filter-passed-tests" );
|
1152
|
-
}
|
1153
|
-
}
|
1154
|
-
});
|
1065
|
+
function hasClass( elem, name ) {
|
1066
|
+
return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
|
1067
|
+
}
|
1155
1068
|
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
}
|
1162
|
-
toolbar.appendChild( filter );
|
1069
|
+
function addClass( elem, name ) {
|
1070
|
+
if ( !hasClass( elem, name ) ) {
|
1071
|
+
elem.className += (elem.className ? " " : "") + name;
|
1072
|
+
}
|
1073
|
+
}
|
1163
1074
|
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1075
|
+
function removeClass( elem, name ) {
|
1076
|
+
var set = " " + elem.className + " ";
|
1077
|
+
// Class name may appear multiple times
|
1078
|
+
while ( set.indexOf(" " + name + " ") > -1 ) {
|
1079
|
+
set = set.replace(" " + name + " " , " ");
|
1080
|
+
}
|
1081
|
+
// If possible, trim it for prettiness, but not necessarily
|
1082
|
+
elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
|
1083
|
+
}
|
1170
1084
|
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
// For oldIE support:
|
1175
|
-
// * Add handlers to the individual elements instead of the container
|
1176
|
-
// * Use "click" instead of "change"
|
1177
|
-
// * Fallback from event.target to event.srcElement
|
1178
|
-
addEvents( urlConfigCheckboxes, "click", function( event ) {
|
1179
|
-
var params = {},
|
1180
|
-
target = event.target || event.srcElement;
|
1181
|
-
params[ target.name ] = target.checked ? true : undefined;
|
1182
|
-
window.location = QUnit.url( params );
|
1183
|
-
});
|
1184
|
-
toolbar.appendChild( urlConfigCheckboxesContainer );
|
1085
|
+
function id( name ) {
|
1086
|
+
return defined.document && document.getElementById && document.getElementById( name );
|
1087
|
+
}
|
1185
1088
|
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
var selectBox = moduleFilter.getElementsByTagName("select")[0],
|
1192
|
-
selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
|
1089
|
+
function registerLoggingCallback( key ) {
|
1090
|
+
return function( callback ) {
|
1091
|
+
config[key].push( callback );
|
1092
|
+
};
|
1093
|
+
}
|
1193
1094
|
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1095
|
+
// Supports deprecated method of completely overwriting logging callbacks
|
1096
|
+
function runLoggingCallbacks( key, scope, args ) {
|
1097
|
+
var i, callbacks;
|
1098
|
+
if ( QUnit.hasOwnProperty( key ) ) {
|
1099
|
+
QUnit[ key ].call(scope, args );
|
1100
|
+
} else {
|
1101
|
+
callbacks = config[ key ];
|
1102
|
+
for ( i = 0; i < callbacks.length; i++ ) {
|
1103
|
+
callbacks[ i ].call( scope, args );
|
1202
1104
|
}
|
1203
1105
|
}
|
1106
|
+
}
|
1204
1107
|
|
1205
|
-
|
1206
|
-
|
1207
|
-
if (
|
1208
|
-
|
1108
|
+
// from jquery.js
|
1109
|
+
function inArray( elem, array ) {
|
1110
|
+
if ( array.indexOf ) {
|
1111
|
+
return array.indexOf( elem );
|
1209
1112
|
}
|
1210
1113
|
|
1211
|
-
|
1212
|
-
|
1114
|
+
for ( var i = 0, length = array.length; i < length; i++ ) {
|
1115
|
+
if ( array[ i ] === elem ) {
|
1116
|
+
return i;
|
1117
|
+
}
|
1213
1118
|
}
|
1214
|
-
};
|
1215
1119
|
|
1216
|
-
|
1120
|
+
return -1;
|
1121
|
+
}
|
1122
|
+
|
1123
|
+
function Test( settings ) {
|
1124
|
+
extend( this, settings );
|
1125
|
+
this.assertions = [];
|
1126
|
+
this.testNumber = ++Test.count;
|
1127
|
+
}
|
1217
1128
|
|
1218
|
-
|
1219
|
-
// Preserve other handlers
|
1220
|
-
onErrorFnPrev = window.onerror;
|
1129
|
+
Test.count = 0;
|
1221
1130
|
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
var ret = false;
|
1227
|
-
if ( onErrorFnPrev ) {
|
1228
|
-
ret = onErrorFnPrev( error, filePath, linerNr );
|
1229
|
-
}
|
1131
|
+
Test.prototype = {
|
1132
|
+
init: function() {
|
1133
|
+
var a, b, li,
|
1134
|
+
tests = id( "qunit-tests" );
|
1230
1135
|
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1136
|
+
if ( tests ) {
|
1137
|
+
b = document.createElement( "strong" );
|
1138
|
+
b.innerHTML = this.nameHtml;
|
1139
|
+
|
1140
|
+
// `a` initialized at top of scope
|
1141
|
+
a = document.createElement( "a" );
|
1142
|
+
a.innerHTML = "Rerun";
|
1143
|
+
a.href = QUnit.url({ testNumber: this.testNumber });
|
1144
|
+
|
1145
|
+
li = document.createElement( "li" );
|
1146
|
+
li.appendChild( b );
|
1147
|
+
li.appendChild( a );
|
1148
|
+
li.className = "running";
|
1149
|
+
li.id = this.id = "qunit-test-output" + testId++;
|
1150
|
+
|
1151
|
+
tests.appendChild( li );
|
1152
|
+
}
|
1153
|
+
},
|
1154
|
+
setup: function() {
|
1155
|
+
if (
|
1156
|
+
// Emit moduleStart when we're switching from one module to another
|
1157
|
+
this.module !== config.previousModule ||
|
1158
|
+
// They could be equal (both undefined) but if the previousModule property doesn't
|
1159
|
+
// yet exist it means this is the first test in a suite that isn't wrapped in a
|
1160
|
+
// module, in which case we'll just emit a moduleStart event for 'undefined'.
|
1161
|
+
// Without this, reporters can get testStart before moduleStart which is a problem.
|
1162
|
+
!hasOwn.call( config, "previousModule" )
|
1163
|
+
) {
|
1164
|
+
if ( hasOwn.call( config, "previousModule" ) ) {
|
1165
|
+
runLoggingCallbacks( "moduleDone", QUnit, {
|
1166
|
+
name: config.previousModule,
|
1167
|
+
failed: config.moduleStats.bad,
|
1168
|
+
passed: config.moduleStats.all - config.moduleStats.bad,
|
1169
|
+
total: config.moduleStats.all
|
1170
|
+
});
|
1237
1171
|
}
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
}
|
1172
|
+
config.previousModule = this.module;
|
1173
|
+
config.moduleStats = { all: 0, bad: 0 };
|
1174
|
+
runLoggingCallbacks( "moduleStart", QUnit, {
|
1175
|
+
name: this.module
|
1176
|
+
});
|
1243
1177
|
}
|
1244
|
-
return false;
|
1245
|
-
}
|
1246
1178
|
|
1247
|
-
|
1248
|
-
};
|
1179
|
+
config.current = this;
|
1249
1180
|
|
1250
|
-
|
1251
|
-
|
1181
|
+
this.testEnvironment = extend({
|
1182
|
+
setup: function() {},
|
1183
|
+
teardown: function() {}
|
1184
|
+
}, this.moduleTestEnvironment );
|
1252
1185
|
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
failed: config.moduleStats.bad,
|
1258
|
-
passed: config.moduleStats.all - config.moduleStats.bad,
|
1259
|
-
total: config.moduleStats.all
|
1186
|
+
this.started = +new Date();
|
1187
|
+
runLoggingCallbacks( "testStart", QUnit, {
|
1188
|
+
name: this.testName,
|
1189
|
+
module: this.module
|
1260
1190
|
});
|
1261
|
-
}
|
1262
|
-
delete config.previousModule;
|
1263
1191
|
|
1264
|
-
|
1265
|
-
banner = id( "qunit-banner" ),
|
1266
|
-
tests = id( "qunit-tests" ),
|
1267
|
-
runtime = +new Date() - config.started,
|
1268
|
-
passed = config.stats.all - config.stats.bad,
|
1269
|
-
html = [
|
1270
|
-
"Tests completed in ",
|
1271
|
-
runtime,
|
1272
|
-
" milliseconds.<br/>",
|
1273
|
-
"<span class='passed'>",
|
1274
|
-
passed,
|
1275
|
-
"</span> assertions of <span class='total'>",
|
1276
|
-
config.stats.all,
|
1277
|
-
"</span> passed, <span class='failed'>",
|
1278
|
-
config.stats.bad,
|
1279
|
-
"</span> failed."
|
1280
|
-
].join( "" );
|
1192
|
+
/*jshint camelcase:false */
|
1281
1193
|
|
1282
|
-
if ( banner ) {
|
1283
|
-
banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
|
1284
|
-
}
|
1285
1194
|
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1195
|
+
/**
|
1196
|
+
* Expose the current test environment.
|
1197
|
+
*
|
1198
|
+
* @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
|
1199
|
+
*/
|
1200
|
+
QUnit.current_testEnvironment = this.testEnvironment;
|
1289
1201
|
|
1290
|
-
|
1291
|
-
// show ✖ for good, ✔ for bad suite result in title
|
1292
|
-
// use escape sequences in case file gets loaded with non-utf-8-charset
|
1293
|
-
document.title = [
|
1294
|
-
( config.stats.bad ? "\u2716" : "\u2714" ),
|
1295
|
-
document.title.replace( /^[\u2714\u2716] /i, "" )
|
1296
|
-
].join( " " );
|
1297
|
-
}
|
1202
|
+
/*jshint camelcase:true */
|
1298
1203
|
|
1299
|
-
|
1300
|
-
|
1301
|
-
// `key` & `i` initialized at top of scope
|
1302
|
-
for ( i = 0; i < sessionStorage.length; i++ ) {
|
1303
|
-
key = sessionStorage.key( i++ );
|
1304
|
-
if ( key.indexOf( "qunit-test-" ) === 0 ) {
|
1305
|
-
sessionStorage.removeItem( key );
|
1306
|
-
}
|
1204
|
+
if ( !config.pollution ) {
|
1205
|
+
saveGlobal();
|
1307
1206
|
}
|
1308
|
-
|
1207
|
+
if ( config.notrycatch ) {
|
1208
|
+
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
|
1209
|
+
return;
|
1210
|
+
}
|
1211
|
+
try {
|
1212
|
+
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
|
1213
|
+
} catch( e ) {
|
1214
|
+
QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
|
1215
|
+
}
|
1216
|
+
},
|
1217
|
+
run: function() {
|
1218
|
+
config.current = this;
|
1309
1219
|
|
1310
|
-
|
1311
|
-
if ( window.scrollTo ) {
|
1312
|
-
window.scrollTo(0, 0);
|
1313
|
-
}
|
1220
|
+
var running = id( "qunit-testresult" );
|
1314
1221
|
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
total: config.stats.all,
|
1319
|
-
runtime: runtime
|
1320
|
-
});
|
1321
|
-
}
|
1222
|
+
if ( running ) {
|
1223
|
+
running.innerHTML = "Running: <br/>" + this.nameHtml;
|
1224
|
+
}
|
1322
1225
|
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
filter = config.filter && config.filter.toLowerCase(),
|
1327
|
-
module = config.module && config.module.toLowerCase(),
|
1328
|
-
fullName = (test.module + ": " + test.testName).toLowerCase();
|
1226
|
+
if ( this.async ) {
|
1227
|
+
QUnit.stop();
|
1228
|
+
}
|
1329
1229
|
|
1330
|
-
|
1331
|
-
if ( test.callback && test.callback.validTest === validTest ) {
|
1332
|
-
delete test.callback.validTest;
|
1333
|
-
return true;
|
1334
|
-
}
|
1230
|
+
this.callbackStarted = +new Date();
|
1335
1231
|
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1232
|
+
if ( config.notrycatch ) {
|
1233
|
+
this.callback.call( this.testEnvironment, QUnit.assert );
|
1234
|
+
this.callbackRuntime = +new Date() - this.callbackStarted;
|
1235
|
+
return;
|
1236
|
+
}
|
1339
1237
|
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1238
|
+
try {
|
1239
|
+
this.callback.call( this.testEnvironment, QUnit.assert );
|
1240
|
+
this.callbackRuntime = +new Date() - this.callbackStarted;
|
1241
|
+
} catch( e ) {
|
1242
|
+
this.callbackRuntime = +new Date() - this.callbackStarted;
|
1343
1243
|
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1244
|
+
QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
|
1245
|
+
// else next test will carry the responsibility
|
1246
|
+
saveGlobal();
|
1347
1247
|
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1248
|
+
// Restart the tests if they're blocking
|
1249
|
+
if ( config.blocking ) {
|
1250
|
+
QUnit.start();
|
1251
|
+
}
|
1252
|
+
}
|
1253
|
+
},
|
1254
|
+
teardown: function() {
|
1255
|
+
config.current = this;
|
1256
|
+
if ( config.notrycatch ) {
|
1257
|
+
if ( typeof this.callbackRuntime === "undefined" ) {
|
1258
|
+
this.callbackRuntime = +new Date() - this.callbackStarted;
|
1259
|
+
}
|
1260
|
+
this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
|
1261
|
+
return;
|
1262
|
+
} else {
|
1263
|
+
try {
|
1264
|
+
this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
|
1265
|
+
} catch( e ) {
|
1266
|
+
QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
|
1267
|
+
}
|
1268
|
+
}
|
1269
|
+
checkPollution();
|
1270
|
+
},
|
1271
|
+
finish: function() {
|
1272
|
+
config.current = this;
|
1273
|
+
if ( config.requireExpects && this.expected === null ) {
|
1274
|
+
QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
|
1275
|
+
} else if ( this.expected !== null && this.expected !== this.assertions.length ) {
|
1276
|
+
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
|
1277
|
+
} else if ( this.expected === null && !this.assertions.length ) {
|
1278
|
+
QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
|
1279
|
+
}
|
1352
1280
|
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1281
|
+
var i, assertion, a, b, time, li, ol,
|
1282
|
+
test = this,
|
1283
|
+
good = 0,
|
1284
|
+
bad = 0,
|
1285
|
+
tests = id( "qunit-tests" );
|
1357
1286
|
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1287
|
+
this.runtime = +new Date() - this.started;
|
1288
|
+
config.stats.all += this.assertions.length;
|
1289
|
+
config.moduleStats.all += this.assertions.length;
|
1361
1290
|
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
function extractStacktrace( e, offset ) {
|
1366
|
-
offset = offset === undefined ? 3 : offset;
|
1291
|
+
if ( tests ) {
|
1292
|
+
ol = document.createElement( "ol" );
|
1293
|
+
ol.className = "qunit-assert-list";
|
1367
1294
|
|
1368
|
-
|
1295
|
+
for ( i = 0; i < this.assertions.length; i++ ) {
|
1296
|
+
assertion = this.assertions[i];
|
1369
1297
|
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
for ( i = offset; i < stack.length; i++ ) {
|
1382
|
-
if ( stack[ i ].indexOf( fileName ) !== -1 ) {
|
1383
|
-
break;
|
1298
|
+
li = document.createElement( "li" );
|
1299
|
+
li.className = assertion.result ? "pass" : "fail";
|
1300
|
+
li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
|
1301
|
+
ol.appendChild( li );
|
1302
|
+
|
1303
|
+
if ( assertion.result ) {
|
1304
|
+
good++;
|
1305
|
+
} else {
|
1306
|
+
bad++;
|
1307
|
+
config.stats.bad++;
|
1308
|
+
config.moduleStats.bad++;
|
1384
1309
|
}
|
1385
|
-
include.push( stack[ i ] );
|
1386
1310
|
}
|
1387
|
-
|
1388
|
-
|
1311
|
+
|
1312
|
+
// store result when possible
|
1313
|
+
if ( QUnit.config.reorder && defined.sessionStorage ) {
|
1314
|
+
if ( bad ) {
|
1315
|
+
sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
|
1316
|
+
} else {
|
1317
|
+
sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
|
1318
|
+
}
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
if ( bad === 0 ) {
|
1322
|
+
addClass( ol, "qunit-collapsed" );
|
1323
|
+
}
|
1324
|
+
|
1325
|
+
// `b` initialized at top of scope
|
1326
|
+
b = document.createElement( "strong" );
|
1327
|
+
b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
|
1328
|
+
|
1329
|
+
addEvent(b, "click", function() {
|
1330
|
+
var next = b.parentNode.lastChild,
|
1331
|
+
collapsed = hasClass( next, "qunit-collapsed" );
|
1332
|
+
( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
|
1333
|
+
});
|
1334
|
+
|
1335
|
+
addEvent(b, "dblclick", function( e ) {
|
1336
|
+
var target = e && e.target ? e.target : window.event.srcElement;
|
1337
|
+
if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
|
1338
|
+
target = target.parentNode;
|
1339
|
+
}
|
1340
|
+
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
|
1341
|
+
window.location = QUnit.url({ testNumber: test.testNumber });
|
1342
|
+
}
|
1343
|
+
});
|
1344
|
+
|
1345
|
+
// `time` initialized at top of scope
|
1346
|
+
time = document.createElement( "span" );
|
1347
|
+
time.className = "runtime";
|
1348
|
+
time.innerHTML = this.runtime + " ms";
|
1349
|
+
|
1350
|
+
// `li` initialized at top of scope
|
1351
|
+
li = id( this.id );
|
1352
|
+
li.className = bad ? "fail" : "pass";
|
1353
|
+
li.removeChild( li.firstChild );
|
1354
|
+
a = li.firstChild;
|
1355
|
+
li.appendChild( b );
|
1356
|
+
li.appendChild( a );
|
1357
|
+
li.appendChild( time );
|
1358
|
+
li.appendChild( ol );
|
1359
|
+
|
1360
|
+
} else {
|
1361
|
+
for ( i = 0; i < this.assertions.length; i++ ) {
|
1362
|
+
if ( !this.assertions[i].result ) {
|
1363
|
+
bad++;
|
1364
|
+
config.stats.bad++;
|
1365
|
+
config.moduleStats.bad++;
|
1366
|
+
}
|
1389
1367
|
}
|
1390
1368
|
}
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1369
|
+
|
1370
|
+
runLoggingCallbacks( "testDone", QUnit, {
|
1371
|
+
name: this.testName,
|
1372
|
+
module: this.module,
|
1373
|
+
failed: bad,
|
1374
|
+
passed: this.assertions.length - bad,
|
1375
|
+
total: this.assertions.length,
|
1376
|
+
runtime: this.runtime,
|
1377
|
+
// DEPRECATED: this property will be removed in 2.0.0, use runtime instead
|
1378
|
+
duration: this.runtime,
|
1379
|
+
});
|
1380
|
+
|
1381
|
+
QUnit.reset();
|
1382
|
+
|
1383
|
+
config.current = undefined;
|
1384
|
+
},
|
1385
|
+
|
1386
|
+
queue: function() {
|
1387
|
+
var bad,
|
1388
|
+
test = this;
|
1389
|
+
|
1390
|
+
synchronize(function() {
|
1391
|
+
test.init();
|
1392
|
+
});
|
1393
|
+
function run() {
|
1394
|
+
// each of these can by async
|
1395
|
+
synchronize(function() {
|
1396
|
+
test.setup();
|
1397
|
+
});
|
1398
|
+
synchronize(function() {
|
1399
|
+
test.run();
|
1400
|
+
});
|
1401
|
+
synchronize(function() {
|
1402
|
+
test.teardown();
|
1403
|
+
});
|
1404
|
+
synchronize(function() {
|
1405
|
+
test.finish();
|
1406
|
+
});
|
1398
1407
|
}
|
1399
|
-
// for actual exceptions, this is useful
|
1400
|
-
return e.sourceURL + ":" + e.line;
|
1401
|
-
}
|
1402
|
-
}
|
1403
|
-
function sourceFromStacktrace( offset ) {
|
1404
|
-
try {
|
1405
|
-
throw new Error();
|
1406
|
-
} catch ( e ) {
|
1407
|
-
return extractStacktrace( e, offset );
|
1408
|
-
}
|
1409
|
-
}
|
1410
1408
|
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1409
|
+
// `bad` initialized at top of scope
|
1410
|
+
// defer when previous test run passed, if storage is available
|
1411
|
+
bad = QUnit.config.reorder && defined.sessionStorage &&
|
1412
|
+
+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
|
1413
|
+
|
1414
|
+
if ( bad ) {
|
1415
|
+
run();
|
1416
|
+
} else {
|
1417
|
+
synchronize( run, true );
|
1418
|
+
}
|
1417
1419
|
}
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1420
|
+
};
|
1421
|
+
|
1422
|
+
// `assert` initialized at top of scope
|
1423
|
+
// Assert helpers
|
1424
|
+
// All of these must either call QUnit.push() or manually do:
|
1425
|
+
// - runLoggingCallbacks( "log", .. );
|
1426
|
+
// - config.current.assertions.push({ .. });
|
1427
|
+
assert = QUnit.assert = {
|
1428
|
+
/**
|
1429
|
+
* Asserts rough true-ish result.
|
1430
|
+
* @name ok
|
1431
|
+
* @function
|
1432
|
+
* @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
|
1433
|
+
*/
|
1434
|
+
ok: function( result, msg ) {
|
1435
|
+
if ( !config.current ) {
|
1436
|
+
throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
|
1432
1437
|
}
|
1433
|
-
|
1434
|
-
|
1438
|
+
result = !!result;
|
1439
|
+
msg = msg || ( result ? "okay" : "failed" );
|
1435
1440
|
|
1436
|
-
|
1437
|
-
|
1441
|
+
var source,
|
1442
|
+
details = {
|
1443
|
+
module: config.current.module,
|
1444
|
+
name: config.current.testName,
|
1445
|
+
result: result,
|
1446
|
+
message: msg
|
1447
|
+
};
|
1438
1448
|
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1449
|
+
msg = "<span class='test-message'>" + escapeText( msg ) + "</span>";
|
1450
|
+
|
1451
|
+
if ( !result ) {
|
1452
|
+
source = sourceFromStacktrace( 2 );
|
1453
|
+
if ( source ) {
|
1454
|
+
details.source = source;
|
1455
|
+
msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" +
|
1456
|
+
escapeText( source ) +
|
1457
|
+
"</pre></td></tr></table>";
|
1458
|
+
}
|
1459
|
+
}
|
1460
|
+
runLoggingCallbacks( "log", QUnit, details );
|
1461
|
+
config.current.assertions.push({
|
1462
|
+
result: result,
|
1463
|
+
message: msg
|
1464
|
+
});
|
1465
|
+
},
|
1466
|
+
|
1467
|
+
/**
|
1468
|
+
* Assert that the first two arguments are equal, with an optional message.
|
1469
|
+
* Prints out both actual and expected values.
|
1470
|
+
* @name equal
|
1471
|
+
* @function
|
1472
|
+
* @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
|
1473
|
+
*/
|
1474
|
+
equal: function( actual, expected, message ) {
|
1475
|
+
/*jshint eqeqeq:false */
|
1476
|
+
QUnit.push( expected == actual, actual, expected, message );
|
1477
|
+
},
|
1443
1478
|
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1479
|
+
/**
|
1480
|
+
* @name notEqual
|
1481
|
+
* @function
|
1482
|
+
*/
|
1483
|
+
notEqual: function( actual, expected, message ) {
|
1484
|
+
/*jshint eqeqeq:false */
|
1485
|
+
QUnit.push( expected != actual, actual, expected, message );
|
1486
|
+
},
|
1450
1487
|
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
|
1461
|
-
done();
|
1462
|
-
}
|
1463
|
-
}
|
1488
|
+
/**
|
1489
|
+
* @name propEqual
|
1490
|
+
* @function
|
1491
|
+
*/
|
1492
|
+
propEqual: function( actual, expected, message ) {
|
1493
|
+
actual = objectValues(actual);
|
1494
|
+
expected = objectValues(expected);
|
1495
|
+
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
|
1496
|
+
},
|
1464
1497
|
|
1465
|
-
|
1466
|
-
|
1498
|
+
/**
|
1499
|
+
* @name notPropEqual
|
1500
|
+
* @function
|
1501
|
+
*/
|
1502
|
+
notPropEqual: function( actual, expected, message ) {
|
1503
|
+
actual = objectValues(actual);
|
1504
|
+
expected = objectValues(expected);
|
1505
|
+
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
|
1506
|
+
},
|
1467
1507
|
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
config.pollution.push( key );
|
1476
|
-
}
|
1477
|
-
}
|
1478
|
-
}
|
1479
|
-
}
|
1508
|
+
/**
|
1509
|
+
* @name deepEqual
|
1510
|
+
* @function
|
1511
|
+
*/
|
1512
|
+
deepEqual: function( actual, expected, message ) {
|
1513
|
+
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
|
1514
|
+
},
|
1480
1515
|
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1516
|
+
/**
|
1517
|
+
* @name notDeepEqual
|
1518
|
+
* @function
|
1519
|
+
*/
|
1520
|
+
notDeepEqual: function( actual, expected, message ) {
|
1521
|
+
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
|
1522
|
+
},
|
1485
1523
|
|
1486
|
-
|
1524
|
+
/**
|
1525
|
+
* @name strictEqual
|
1526
|
+
* @function
|
1527
|
+
*/
|
1528
|
+
strictEqual: function( actual, expected, message ) {
|
1529
|
+
QUnit.push( expected === actual, actual, expected, message );
|
1530
|
+
},
|
1487
1531
|
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1532
|
+
/**
|
1533
|
+
* @name notStrictEqual
|
1534
|
+
* @function
|
1535
|
+
*/
|
1536
|
+
notStrictEqual: function( actual, expected, message ) {
|
1537
|
+
QUnit.push( expected !== actual, actual, expected, message );
|
1538
|
+
},
|
1492
1539
|
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
}
|
1540
|
+
"throws": function( block, expected, message ) {
|
1541
|
+
var actual,
|
1542
|
+
expectedOutput = expected,
|
1543
|
+
ok = false;
|
1498
1544
|
|
1499
|
-
//
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1545
|
+
// 'expected' is optional
|
1546
|
+
if ( typeof expected === "string" ) {
|
1547
|
+
message = expected;
|
1548
|
+
expected = null;
|
1549
|
+
}
|
1503
1550
|
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
break;
|
1510
|
-
}
|
1551
|
+
config.current.ignoreGlobalErrors = true;
|
1552
|
+
try {
|
1553
|
+
block.call( config.current.testEnvironment );
|
1554
|
+
} catch (e) {
|
1555
|
+
actual = e;
|
1511
1556
|
}
|
1512
|
-
|
1513
|
-
return result;
|
1514
|
-
}
|
1557
|
+
config.current.ignoreGlobalErrors = false;
|
1515
1558
|
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1559
|
+
if ( actual ) {
|
1560
|
+
// we don't want to validate thrown error
|
1561
|
+
if ( !expected ) {
|
1562
|
+
ok = true;
|
1563
|
+
expectedOutput = null;
|
1564
|
+
// expected is a regexp
|
1565
|
+
} else if ( QUnit.objectType( expected ) === "regexp" ) {
|
1566
|
+
ok = expected.test( errorString( actual ) );
|
1567
|
+
// expected is a constructor
|
1568
|
+
} else if ( actual instanceof expected ) {
|
1569
|
+
ok = true;
|
1570
|
+
// expected is a validation function which returns true is validation passed
|
1571
|
+
} else if ( expected.call( {}, actual ) === true ) {
|
1572
|
+
expectedOutput = null;
|
1573
|
+
ok = true;
|
1526
1574
|
}
|
1575
|
+
|
1576
|
+
QUnit.push( ok, actual, expectedOutput, message );
|
1577
|
+
} else {
|
1578
|
+
QUnit.pushFailure( message, null, "No exception was thrown." );
|
1527
1579
|
}
|
1528
1580
|
}
|
1529
|
-
|
1530
|
-
return a;
|
1531
|
-
}
|
1581
|
+
};
|
1532
1582
|
|
1533
1583
|
/**
|
1534
|
-
* @
|
1535
|
-
*
|
1536
|
-
* @param {Function} fn
|
1584
|
+
* @deprecated since 1.8.0
|
1585
|
+
* Kept assertion helpers in root for backwards compatibility.
|
1537
1586
|
*/
|
1538
|
-
|
1539
|
-
// Standards-based browsers
|
1540
|
-
if ( elem.addEventListener ) {
|
1541
|
-
elem.addEventListener( type, fn, false );
|
1542
|
-
// IE
|
1543
|
-
} else {
|
1544
|
-
elem.attachEvent( "on" + type, fn );
|
1545
|
-
}
|
1546
|
-
}
|
1587
|
+
extend( QUnit.constructor.prototype, assert );
|
1547
1588
|
|
1548
1589
|
/**
|
1549
|
-
* @
|
1550
|
-
*
|
1551
|
-
* @param {Function} fn
|
1590
|
+
* @deprecated since 1.9.0
|
1591
|
+
* Kept to avoid TypeErrors for undefined methods.
|
1552
1592
|
*/
|
1553
|
-
function
|
1554
|
-
|
1555
|
-
|
1556
|
-
addEvent( elems[i], type, fn );
|
1557
|
-
}
|
1558
|
-
}
|
1559
|
-
|
1560
|
-
function hasClass( elem, name ) {
|
1561
|
-
return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
|
1562
|
-
}
|
1563
|
-
|
1564
|
-
function addClass( elem, name ) {
|
1565
|
-
if ( !hasClass( elem, name ) ) {
|
1566
|
-
elem.className += (elem.className ? " " : "") + name;
|
1567
|
-
}
|
1568
|
-
}
|
1569
|
-
|
1570
|
-
function removeClass( elem, name ) {
|
1571
|
-
var set = " " + elem.className + " ";
|
1572
|
-
// Class name may appear multiple times
|
1573
|
-
while ( set.indexOf(" " + name + " ") > -1 ) {
|
1574
|
-
set = set.replace(" " + name + " " , " ");
|
1575
|
-
}
|
1576
|
-
// If possible, trim it for prettiness, but not necessarily
|
1577
|
-
elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
|
1578
|
-
}
|
1579
|
-
|
1580
|
-
function id( name ) {
|
1581
|
-
return !!( typeof document !== "undefined" && document && document.getElementById ) &&
|
1582
|
-
document.getElementById( name );
|
1583
|
-
}
|
1584
|
-
|
1585
|
-
function registerLoggingCallback( key ) {
|
1586
|
-
return function( callback ) {
|
1587
|
-
config[key].push( callback );
|
1588
|
-
};
|
1589
|
-
}
|
1593
|
+
QUnit.constructor.prototype.raises = function() {
|
1594
|
+
QUnit.push( false, false, false, "QUnit.raises has been deprecated since 2012 (fad3c1ea), use QUnit.throws instead" );
|
1595
|
+
};
|
1590
1596
|
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
}
|
1602
|
-
}
|
1597
|
+
/**
|
1598
|
+
* @deprecated since 1.0.0, replaced with error pushes since 1.3.0
|
1599
|
+
* Kept to avoid TypeErrors for undefined methods.
|
1600
|
+
*/
|
1601
|
+
QUnit.constructor.prototype.equals = function() {
|
1602
|
+
QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
|
1603
|
+
};
|
1604
|
+
QUnit.constructor.prototype.same = function() {
|
1605
|
+
QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
|
1606
|
+
};
|
1603
1607
|
|
1604
1608
|
// Test for equality any JavaScript type.
|
1605
1609
|
// Author: Philippe Rathé <prathe@gmail.com>
|
@@ -2040,21 +2044,6 @@ QUnit.jsDump = (function() {
|
|
2040
2044
|
return jsDump;
|
2041
2045
|
}());
|
2042
2046
|
|
2043
|
-
// from jquery.js
|
2044
|
-
function inArray( elem, array ) {
|
2045
|
-
if ( array.indexOf ) {
|
2046
|
-
return array.indexOf( elem );
|
2047
|
-
}
|
2048
|
-
|
2049
|
-
for ( var i = 0, length = array.length; i < length; i++ ) {
|
2050
|
-
if ( array[ i ] === elem ) {
|
2051
|
-
return i;
|
2052
|
-
}
|
2053
|
-
}
|
2054
|
-
|
2055
|
-
return -1;
|
2056
|
-
}
|
2057
|
-
|
2058
2047
|
/*
|
2059
2048
|
* Javascript Diff Algorithm
|
2060
2049
|
* By John Resig (http://ejohn.org/)
|
@@ -2203,10 +2192,19 @@ QUnit.diff = (function() {
|
|
2203
2192
|
};
|
2204
2193
|
}());
|
2205
2194
|
|
2206
|
-
//
|
2207
|
-
if ( typeof
|
2208
|
-
extend(
|
2195
|
+
// For browser, export only select globals
|
2196
|
+
if ( typeof window !== "undefined" ) {
|
2197
|
+
extend( window, QUnit.constructor.prototype );
|
2198
|
+
window.QUnit = QUnit;
|
2199
|
+
}
|
2200
|
+
|
2201
|
+
// For CommonJS environments, export everything
|
2202
|
+
if ( typeof module !== "undefined" && module.exports ) {
|
2203
|
+
module.exports = QUnit;
|
2209
2204
|
}
|
2210
2205
|
|
2211
|
-
|
2212
|
-
|
2206
|
+
|
2207
|
+
// Get a reference to the global object, like window in browsers
|
2208
|
+
}( (function() {
|
2209
|
+
return this;
|
2210
|
+
})() ));
|