multi_mocha_rails 0.0.4
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.
- data/MIT-LICENSE +22 -0
- data/Rakefile +38 -0
- data/Readme.md +7 -0
- data/app/assets/javascripts/mocha_rails/application.js +4 -0
- data/app/assets/javascripts/mocha_rails/mocha-rails.js +7 -0
- data/app/assets/stylesheets/mocha_rails/application.css +13 -0
- data/app/controllers/mocha_rails/application_controller.rb +4 -0
- data/app/controllers/mocha_rails/tests_controller.rb +52 -0
- data/app/helpers/mocha_rails/application_helper.rb +4 -0
- data/app/views/layouts/mocha.html.erb +14 -0
- data/app/views/mocha_rails/tests/index.html.erb +10 -0
- data/app/views/mocha_rails/tests/list.html.erb +11 -0
- data/config/initializers/mocha_rails.rb +4 -0
- data/config/routes.rb +8 -0
- data/lib/generators/mocha_rails/install_generator.rb +15 -0
- data/lib/generators/mocha_rails/templates/mocha-suite.js +12 -0
- data/lib/mocha_rails.rb +4 -0
- data/lib/mocha_rails/engine.rb +5 -0
- data/lib/mocha_rails/version.rb +3 -0
- data/lib/tasks/mocha_rails_tasks.rake +4 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +62 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +31 -0
- data/test/dummy/config/environments/production.rb +64 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +10 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/log/test.log +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/navigation_test.rb +9 -0
- data/test/mocha_rails_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- data/vendor/assets/javascripts/chai.js +2223 -0
- data/vendor/assets/javascripts/mocha.js +4068 -0
- data/vendor/assets/stylesheets/mocha.css +137 -0
- metadata +141 -0
@@ -0,0 +1,4068 @@
|
|
1
|
+
;(function(){
|
2
|
+
|
3
|
+
|
4
|
+
// CommonJS require()
|
5
|
+
|
6
|
+
function require(p){
|
7
|
+
var path = require.resolve(p)
|
8
|
+
, mod = require.modules[path];
|
9
|
+
if (!mod) throw new Error('failed to require "' + p + '"');
|
10
|
+
if (!mod.exports) {
|
11
|
+
mod.exports = {};
|
12
|
+
mod.call(mod.exports, mod, mod.exports, require.relative(path));
|
13
|
+
}
|
14
|
+
return mod.exports;
|
15
|
+
}
|
16
|
+
|
17
|
+
require.modules = {};
|
18
|
+
|
19
|
+
require.resolve = function (path){
|
20
|
+
var orig = path
|
21
|
+
, reg = path + '.js'
|
22
|
+
, index = path + '/index.js';
|
23
|
+
return require.modules[reg] && reg
|
24
|
+
|| require.modules[index] && index
|
25
|
+
|| orig;
|
26
|
+
};
|
27
|
+
|
28
|
+
require.register = function (path, fn){
|
29
|
+
require.modules[path] = fn;
|
30
|
+
};
|
31
|
+
|
32
|
+
require.relative = function (parent) {
|
33
|
+
return function(p){
|
34
|
+
if ('.' != p.charAt(0)) return require(p);
|
35
|
+
|
36
|
+
var path = parent.split('/')
|
37
|
+
, segs = p.split('/');
|
38
|
+
path.pop();
|
39
|
+
|
40
|
+
for (var i = 0; i < segs.length; i++) {
|
41
|
+
var seg = segs[i];
|
42
|
+
if ('..' == seg) path.pop();
|
43
|
+
else if ('.' != seg) path.push(seg);
|
44
|
+
}
|
45
|
+
|
46
|
+
return require(path.join('/'));
|
47
|
+
};
|
48
|
+
};
|
49
|
+
|
50
|
+
|
51
|
+
require.register("browser/debug.js", function(module, exports, require){
|
52
|
+
|
53
|
+
module.exports = function(type){
|
54
|
+
return function(){
|
55
|
+
|
56
|
+
}
|
57
|
+
};
|
58
|
+
}); // module: browser/debug.js
|
59
|
+
|
60
|
+
require.register("browser/diff.js", function(module, exports, require){
|
61
|
+
|
62
|
+
}); // module: browser/diff.js
|
63
|
+
|
64
|
+
require.register("browser/events.js", function(module, exports, require){
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Module exports.
|
68
|
+
*/
|
69
|
+
|
70
|
+
exports.EventEmitter = EventEmitter;
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Check if `obj` is an array.
|
74
|
+
*/
|
75
|
+
|
76
|
+
function isArray(obj) {
|
77
|
+
return '[object Array]' == {}.toString.call(obj);
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Event emitter constructor.
|
82
|
+
*
|
83
|
+
* @api public.
|
84
|
+
*/
|
85
|
+
|
86
|
+
function EventEmitter(){};
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Adds a listener.
|
90
|
+
*
|
91
|
+
* @api public
|
92
|
+
*/
|
93
|
+
|
94
|
+
EventEmitter.prototype.on = function (name, fn) {
|
95
|
+
if (!this.$events) {
|
96
|
+
this.$events = {};
|
97
|
+
}
|
98
|
+
|
99
|
+
if (!this.$events[name]) {
|
100
|
+
this.$events[name] = fn;
|
101
|
+
} else if (isArray(this.$events[name])) {
|
102
|
+
this.$events[name].push(fn);
|
103
|
+
} else {
|
104
|
+
this.$events[name] = [this.$events[name], fn];
|
105
|
+
}
|
106
|
+
|
107
|
+
return this;
|
108
|
+
};
|
109
|
+
|
110
|
+
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Adds a volatile listener.
|
114
|
+
*
|
115
|
+
* @api public
|
116
|
+
*/
|
117
|
+
|
118
|
+
EventEmitter.prototype.once = function (name, fn) {
|
119
|
+
var self = this;
|
120
|
+
|
121
|
+
function on () {
|
122
|
+
self.removeListener(name, on);
|
123
|
+
fn.apply(this, arguments);
|
124
|
+
};
|
125
|
+
|
126
|
+
on.listener = fn;
|
127
|
+
this.on(name, on);
|
128
|
+
|
129
|
+
return this;
|
130
|
+
};
|
131
|
+
|
132
|
+
/**
|
133
|
+
* Removes a listener.
|
134
|
+
*
|
135
|
+
* @api public
|
136
|
+
*/
|
137
|
+
|
138
|
+
EventEmitter.prototype.removeListener = function (name, fn) {
|
139
|
+
if (this.$events && this.$events[name]) {
|
140
|
+
var list = this.$events[name];
|
141
|
+
|
142
|
+
if (isArray(list)) {
|
143
|
+
var pos = -1;
|
144
|
+
|
145
|
+
for (var i = 0, l = list.length; i < l; i++) {
|
146
|
+
if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
|
147
|
+
pos = i;
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
if (pos < 0) {
|
153
|
+
return this;
|
154
|
+
}
|
155
|
+
|
156
|
+
list.splice(pos, 1);
|
157
|
+
|
158
|
+
if (!list.length) {
|
159
|
+
delete this.$events[name];
|
160
|
+
}
|
161
|
+
} else if (list === fn || (list.listener && list.listener === fn)) {
|
162
|
+
delete this.$events[name];
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
return this;
|
167
|
+
};
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Removes all listeners for an event.
|
171
|
+
*
|
172
|
+
* @api public
|
173
|
+
*/
|
174
|
+
|
175
|
+
EventEmitter.prototype.removeAllListeners = function (name) {
|
176
|
+
if (name === undefined) {
|
177
|
+
this.$events = {};
|
178
|
+
return this;
|
179
|
+
}
|
180
|
+
|
181
|
+
if (this.$events && this.$events[name]) {
|
182
|
+
this.$events[name] = null;
|
183
|
+
}
|
184
|
+
|
185
|
+
return this;
|
186
|
+
};
|
187
|
+
|
188
|
+
/**
|
189
|
+
* Gets all listeners for a certain event.
|
190
|
+
*
|
191
|
+
* @api publci
|
192
|
+
*/
|
193
|
+
|
194
|
+
EventEmitter.prototype.listeners = function (name) {
|
195
|
+
if (!this.$events) {
|
196
|
+
this.$events = {};
|
197
|
+
}
|
198
|
+
|
199
|
+
if (!this.$events[name]) {
|
200
|
+
this.$events[name] = [];
|
201
|
+
}
|
202
|
+
|
203
|
+
if (!isArray(this.$events[name])) {
|
204
|
+
this.$events[name] = [this.$events[name]];
|
205
|
+
}
|
206
|
+
|
207
|
+
return this.$events[name];
|
208
|
+
};
|
209
|
+
|
210
|
+
/**
|
211
|
+
* Emits an event.
|
212
|
+
*
|
213
|
+
* @api public
|
214
|
+
*/
|
215
|
+
|
216
|
+
EventEmitter.prototype.emit = function (name) {
|
217
|
+
if (!this.$events) {
|
218
|
+
return false;
|
219
|
+
}
|
220
|
+
|
221
|
+
var handler = this.$events[name];
|
222
|
+
|
223
|
+
if (!handler) {
|
224
|
+
return false;
|
225
|
+
}
|
226
|
+
|
227
|
+
var args = [].slice.call(arguments, 1);
|
228
|
+
|
229
|
+
if ('function' == typeof handler) {
|
230
|
+
handler.apply(this, args);
|
231
|
+
} else if (isArray(handler)) {
|
232
|
+
var listeners = handler.slice();
|
233
|
+
|
234
|
+
for (var i = 0, l = listeners.length; i < l; i++) {
|
235
|
+
listeners[i].apply(this, args);
|
236
|
+
}
|
237
|
+
} else {
|
238
|
+
return false;
|
239
|
+
}
|
240
|
+
|
241
|
+
return true;
|
242
|
+
};
|
243
|
+
}); // module: browser/events.js
|
244
|
+
|
245
|
+
require.register("browser/fs.js", function(module, exports, require){
|
246
|
+
|
247
|
+
}); // module: browser/fs.js
|
248
|
+
|
249
|
+
require.register("browser/path.js", function(module, exports, require){
|
250
|
+
|
251
|
+
}); // module: browser/path.js
|
252
|
+
|
253
|
+
require.register("browser/progress.js", function(module, exports, require){
|
254
|
+
|
255
|
+
/**
|
256
|
+
* Expose `Progress`.
|
257
|
+
*/
|
258
|
+
|
259
|
+
module.exports = Progress;
|
260
|
+
|
261
|
+
/**
|
262
|
+
* Initialize a new `Progress` indicator.
|
263
|
+
*/
|
264
|
+
|
265
|
+
function Progress() {
|
266
|
+
this.percent = 0;
|
267
|
+
this.size(0);
|
268
|
+
this.fontSize(11);
|
269
|
+
this.font('helvetica, arial, sans-serif');
|
270
|
+
}
|
271
|
+
|
272
|
+
/**
|
273
|
+
* Set progress size to `n`.
|
274
|
+
*
|
275
|
+
* @param {Number} n
|
276
|
+
* @return {Progress} for chaining
|
277
|
+
* @api public
|
278
|
+
*/
|
279
|
+
|
280
|
+
Progress.prototype.size = function(n){
|
281
|
+
this._size = n;
|
282
|
+
return this;
|
283
|
+
};
|
284
|
+
|
285
|
+
/**
|
286
|
+
* Set text to `str`.
|
287
|
+
*
|
288
|
+
* @param {String} str
|
289
|
+
* @return {Progress} for chaining
|
290
|
+
* @api public
|
291
|
+
*/
|
292
|
+
|
293
|
+
Progress.prototype.text = function(str){
|
294
|
+
this._text = str;
|
295
|
+
return this;
|
296
|
+
};
|
297
|
+
|
298
|
+
/**
|
299
|
+
* Set font size to `n`.
|
300
|
+
*
|
301
|
+
* @param {Number} n
|
302
|
+
* @return {Progress} for chaining
|
303
|
+
* @api public
|
304
|
+
*/
|
305
|
+
|
306
|
+
Progress.prototype.fontSize = function(n){
|
307
|
+
this._fontSize = n;
|
308
|
+
return this;
|
309
|
+
};
|
310
|
+
|
311
|
+
/**
|
312
|
+
* Set font `family`.
|
313
|
+
*
|
314
|
+
* @param {String} family
|
315
|
+
* @return {Progress} for chaining
|
316
|
+
*/
|
317
|
+
|
318
|
+
Progress.prototype.font = function(family){
|
319
|
+
this._font = family;
|
320
|
+
return this;
|
321
|
+
};
|
322
|
+
|
323
|
+
/**
|
324
|
+
* Update percentage to `n`.
|
325
|
+
*
|
326
|
+
* @param {Number} n
|
327
|
+
* @return {Progress} for chaining
|
328
|
+
*/
|
329
|
+
|
330
|
+
Progress.prototype.update = function(n){
|
331
|
+
this.percent = n;
|
332
|
+
return this;
|
333
|
+
};
|
334
|
+
|
335
|
+
/**
|
336
|
+
* Draw on `ctx`.
|
337
|
+
*
|
338
|
+
* @param {CanvasRenderingContext2d} ctx
|
339
|
+
* @return {Progress} for chaining
|
340
|
+
*/
|
341
|
+
|
342
|
+
Progress.prototype.draw = function(ctx){
|
343
|
+
var percent = Math.min(this.percent, 100)
|
344
|
+
, size = this._size
|
345
|
+
, half = size / 2
|
346
|
+
, x = half
|
347
|
+
, y = half
|
348
|
+
, rad = half - 1
|
349
|
+
, fontSize = this._fontSize;
|
350
|
+
|
351
|
+
ctx.font = fontSize + 'px ' + this._font;
|
352
|
+
|
353
|
+
var angle = Math.PI * 2 * (percent / 100);
|
354
|
+
ctx.clearRect(0, 0, size, size);
|
355
|
+
|
356
|
+
// outer circle
|
357
|
+
ctx.strokeStyle = '#9f9f9f';
|
358
|
+
ctx.beginPath();
|
359
|
+
ctx.arc(x, y, rad, 0, angle, false);
|
360
|
+
ctx.stroke();
|
361
|
+
|
362
|
+
// inner circle
|
363
|
+
ctx.strokeStyle = '#eee';
|
364
|
+
ctx.beginPath();
|
365
|
+
ctx.arc(x, y, rad - 1, 0, angle, true);
|
366
|
+
ctx.stroke();
|
367
|
+
|
368
|
+
// text
|
369
|
+
var text = this._text || (percent | 0) + '%'
|
370
|
+
, w = ctx.measureText(text).width;
|
371
|
+
|
372
|
+
ctx.fillText(
|
373
|
+
text
|
374
|
+
, x - w / 2 + 1
|
375
|
+
, y + fontSize / 2 - 1);
|
376
|
+
|
377
|
+
return this;
|
378
|
+
};
|
379
|
+
|
380
|
+
}); // module: browser/progress.js
|
381
|
+
|
382
|
+
require.register("browser/tty.js", function(module, exports, require){
|
383
|
+
|
384
|
+
exports.isatty = function(){
|
385
|
+
return true;
|
386
|
+
};
|
387
|
+
|
388
|
+
exports.getWindowSize = function(){
|
389
|
+
return [window.innerHeight, window.innerWidth];
|
390
|
+
};
|
391
|
+
}); // module: browser/tty.js
|
392
|
+
|
393
|
+
require.register("context.js", function(module, exports, require){
|
394
|
+
|
395
|
+
/**
|
396
|
+
* Expose `Context`.
|
397
|
+
*/
|
398
|
+
|
399
|
+
module.exports = Context;
|
400
|
+
|
401
|
+
/**
|
402
|
+
* Initialize a new `Context`.
|
403
|
+
*
|
404
|
+
* @api private
|
405
|
+
*/
|
406
|
+
|
407
|
+
function Context(){}
|
408
|
+
|
409
|
+
/**
|
410
|
+
* Set the context `Test` to `test`.
|
411
|
+
*
|
412
|
+
* @param {Test} test
|
413
|
+
* @return {Context}
|
414
|
+
* @api private
|
415
|
+
*/
|
416
|
+
|
417
|
+
Context.prototype.test = function(test){
|
418
|
+
this._test = test;
|
419
|
+
return this;
|
420
|
+
};
|
421
|
+
|
422
|
+
/**
|
423
|
+
* Set test timeout `ms`.
|
424
|
+
*
|
425
|
+
* @param {Number} ms
|
426
|
+
* @return {Context} self
|
427
|
+
* @api private
|
428
|
+
*/
|
429
|
+
|
430
|
+
Context.prototype.timeout = function(ms){
|
431
|
+
this._test.timeout(ms);
|
432
|
+
return this;
|
433
|
+
};
|
434
|
+
|
435
|
+
/**
|
436
|
+
* Inspect the context void of `._test`.
|
437
|
+
*
|
438
|
+
* @return {String}
|
439
|
+
* @api private
|
440
|
+
*/
|
441
|
+
|
442
|
+
Context.prototype.inspect = function(){
|
443
|
+
return JSON.stringify(this, function(key, val){
|
444
|
+
return '_test' == key
|
445
|
+
? undefined
|
446
|
+
: val;
|
447
|
+
}, 2);
|
448
|
+
};
|
449
|
+
|
450
|
+
}); // module: context.js
|
451
|
+
|
452
|
+
require.register("hook.js", function(module, exports, require){
|
453
|
+
|
454
|
+
/**
|
455
|
+
* Module dependencies.
|
456
|
+
*/
|
457
|
+
|
458
|
+
var Runnable = require('./runnable');
|
459
|
+
|
460
|
+
/**
|
461
|
+
* Expose `Hook`.
|
462
|
+
*/
|
463
|
+
|
464
|
+
module.exports = Hook;
|
465
|
+
|
466
|
+
/**
|
467
|
+
* Initialize a new `Hook` with the given `title` and callback `fn`.
|
468
|
+
*
|
469
|
+
* @param {String} title
|
470
|
+
* @param {Function} fn
|
471
|
+
* @api private
|
472
|
+
*/
|
473
|
+
|
474
|
+
function Hook(title, fn) {
|
475
|
+
Runnable.call(this, title, fn);
|
476
|
+
this.type = 'hook';
|
477
|
+
}
|
478
|
+
|
479
|
+
/**
|
480
|
+
* Inherit from `Runnable.prototype`.
|
481
|
+
*/
|
482
|
+
|
483
|
+
Hook.prototype = new Runnable;
|
484
|
+
Hook.prototype.constructor = Hook;
|
485
|
+
|
486
|
+
|
487
|
+
}); // module: hook.js
|
488
|
+
|
489
|
+
require.register("interfaces/bdd.js", function(module, exports, require){
|
490
|
+
|
491
|
+
/**
|
492
|
+
* Module dependencies.
|
493
|
+
*/
|
494
|
+
|
495
|
+
var Suite = require('../suite')
|
496
|
+
, Test = require('../test');
|
497
|
+
|
498
|
+
/**
|
499
|
+
* BDD-style interface:
|
500
|
+
*
|
501
|
+
* describe('Array', function(){
|
502
|
+
* describe('#indexOf()', function(){
|
503
|
+
* it('should return -1 when not present', function(){
|
504
|
+
*
|
505
|
+
* });
|
506
|
+
*
|
507
|
+
* it('should return the index when present', function(){
|
508
|
+
*
|
509
|
+
* });
|
510
|
+
* });
|
511
|
+
* });
|
512
|
+
*
|
513
|
+
*/
|
514
|
+
|
515
|
+
module.exports = function(suite){
|
516
|
+
var suites = [suite];
|
517
|
+
|
518
|
+
suite.on('pre-require', function(context){
|
519
|
+
|
520
|
+
// noop variants
|
521
|
+
|
522
|
+
context.xdescribe = function(){};
|
523
|
+
context.xit = function(){};
|
524
|
+
|
525
|
+
/**
|
526
|
+
* Execute before running tests.
|
527
|
+
*/
|
528
|
+
|
529
|
+
context.before = function(fn){
|
530
|
+
suites[0].beforeAll(fn);
|
531
|
+
};
|
532
|
+
|
533
|
+
/**
|
534
|
+
* Execute after running tests.
|
535
|
+
*/
|
536
|
+
|
537
|
+
context.after = function(fn){
|
538
|
+
suites[0].afterAll(fn);
|
539
|
+
};
|
540
|
+
|
541
|
+
/**
|
542
|
+
* Execute before each test case.
|
543
|
+
*/
|
544
|
+
|
545
|
+
context.beforeEach = function(fn){
|
546
|
+
suites[0].beforeEach(fn);
|
547
|
+
};
|
548
|
+
|
549
|
+
/**
|
550
|
+
* Execute after each test case.
|
551
|
+
*/
|
552
|
+
|
553
|
+
context.afterEach = function(fn){
|
554
|
+
suites[0].afterEach(fn);
|
555
|
+
};
|
556
|
+
|
557
|
+
/**
|
558
|
+
* Describe a "suite" with the given `title`
|
559
|
+
* and callback `fn` containing nested suites
|
560
|
+
* and/or tests.
|
561
|
+
*/
|
562
|
+
|
563
|
+
context.describe = function(title, fn){
|
564
|
+
var suite = Suite.create(suites[0], title);
|
565
|
+
suites.unshift(suite);
|
566
|
+
fn();
|
567
|
+
suites.shift();
|
568
|
+
};
|
569
|
+
|
570
|
+
/**
|
571
|
+
* Describe a specification or test-case
|
572
|
+
* with the given `title` and callback `fn`
|
573
|
+
* acting as a thunk.
|
574
|
+
*/
|
575
|
+
|
576
|
+
context.it = function(title, fn){
|
577
|
+
suites[0].addTest(new Test(title, fn));
|
578
|
+
};
|
579
|
+
});
|
580
|
+
};
|
581
|
+
|
582
|
+
}); // module: interfaces/bdd.js
|
583
|
+
|
584
|
+
require.register("interfaces/exports.js", function(module, exports, require){
|
585
|
+
|
586
|
+
/**
|
587
|
+
* Module dependencies.
|
588
|
+
*/
|
589
|
+
|
590
|
+
var Suite = require('../suite')
|
591
|
+
, Test = require('../test');
|
592
|
+
|
593
|
+
/**
|
594
|
+
* TDD-style interface:
|
595
|
+
*
|
596
|
+
* exports.Array = {
|
597
|
+
* '#indexOf()': {
|
598
|
+
* 'should return -1 when the value is not present': function(){
|
599
|
+
*
|
600
|
+
* },
|
601
|
+
*
|
602
|
+
* 'should return the correct index when the value is present': function(){
|
603
|
+
*
|
604
|
+
* }
|
605
|
+
* }
|
606
|
+
* };
|
607
|
+
*
|
608
|
+
*/
|
609
|
+
|
610
|
+
module.exports = function(suite){
|
611
|
+
var suites = [suite];
|
612
|
+
|
613
|
+
suite.on('require', visit);
|
614
|
+
|
615
|
+
function visit(obj) {
|
616
|
+
var suite;
|
617
|
+
for (var key in obj) {
|
618
|
+
if ('function' == typeof obj[key]) {
|
619
|
+
var fn = obj[key];
|
620
|
+
switch (key) {
|
621
|
+
case 'before':
|
622
|
+
suites[0].beforeAll(fn);
|
623
|
+
break;
|
624
|
+
case 'after':
|
625
|
+
suites[0].afterAll(fn);
|
626
|
+
break;
|
627
|
+
case 'beforeEach':
|
628
|
+
suites[0].beforeEach(fn);
|
629
|
+
break;
|
630
|
+
case 'afterEach':
|
631
|
+
suites[0].afterEach(fn);
|
632
|
+
break;
|
633
|
+
default:
|
634
|
+
suites[0].addTest(new Test(key, fn));
|
635
|
+
}
|
636
|
+
} else {
|
637
|
+
var suite = Suite.create(suites[0], key);
|
638
|
+
suites.unshift(suite);
|
639
|
+
visit(obj[key]);
|
640
|
+
suites.shift();
|
641
|
+
}
|
642
|
+
}
|
643
|
+
}
|
644
|
+
};
|
645
|
+
}); // module: interfaces/exports.js
|
646
|
+
|
647
|
+
require.register("interfaces/index.js", function(module, exports, require){
|
648
|
+
|
649
|
+
exports.bdd = require('./bdd');
|
650
|
+
exports.tdd = require('./tdd');
|
651
|
+
exports.qunit = require('./qunit');
|
652
|
+
exports.exports = require('./exports');
|
653
|
+
|
654
|
+
}); // module: interfaces/index.js
|
655
|
+
|
656
|
+
require.register("interfaces/qunit.js", function(module, exports, require){
|
657
|
+
|
658
|
+
/**
|
659
|
+
* Module dependencies.
|
660
|
+
*/
|
661
|
+
|
662
|
+
var Suite = require('../suite')
|
663
|
+
, Test = require('../test');
|
664
|
+
|
665
|
+
/**
|
666
|
+
* QUnit-style interface:
|
667
|
+
*
|
668
|
+
* suite('Array');
|
669
|
+
*
|
670
|
+
* test('#length', function(){
|
671
|
+
* var arr = [1,2,3];
|
672
|
+
* ok(arr.length == 3);
|
673
|
+
* });
|
674
|
+
*
|
675
|
+
* test('#indexOf()', function(){
|
676
|
+
* var arr = [1,2,3];
|
677
|
+
* ok(arr.indexOf(1) == 0);
|
678
|
+
* ok(arr.indexOf(2) == 1);
|
679
|
+
* ok(arr.indexOf(3) == 2);
|
680
|
+
* });
|
681
|
+
*
|
682
|
+
* suite('String');
|
683
|
+
*
|
684
|
+
* test('#length', function(){
|
685
|
+
* ok('foo'.length == 3);
|
686
|
+
* });
|
687
|
+
*
|
688
|
+
*/
|
689
|
+
|
690
|
+
module.exports = function(suite){
|
691
|
+
var suites = [suite];
|
692
|
+
|
693
|
+
suite.on('pre-require', function(context){
|
694
|
+
|
695
|
+
/**
|
696
|
+
* Execute before running tests.
|
697
|
+
*/
|
698
|
+
|
699
|
+
context.before = function(fn){
|
700
|
+
suites[0].beforeAll(fn);
|
701
|
+
};
|
702
|
+
|
703
|
+
/**
|
704
|
+
* Execute after running tests.
|
705
|
+
*/
|
706
|
+
|
707
|
+
context.after = function(fn){
|
708
|
+
suites[0].afterAll(fn);
|
709
|
+
};
|
710
|
+
|
711
|
+
/**
|
712
|
+
* Execute before each test case.
|
713
|
+
*/
|
714
|
+
|
715
|
+
context.beforeEach = function(fn){
|
716
|
+
suites[0].beforeEach(fn);
|
717
|
+
};
|
718
|
+
|
719
|
+
/**
|
720
|
+
* Execute after each test case.
|
721
|
+
*/
|
722
|
+
|
723
|
+
context.afterEach = function(fn){
|
724
|
+
suites[0].afterEach(fn);
|
725
|
+
};
|
726
|
+
|
727
|
+
/**
|
728
|
+
* Describe a "suite" with the given `title`.
|
729
|
+
*/
|
730
|
+
|
731
|
+
context.suite = function(title){
|
732
|
+
if (suites.length > 1) suites.shift();
|
733
|
+
var suite = Suite.create(suites[0], title);
|
734
|
+
suites.unshift(suite);
|
735
|
+
};
|
736
|
+
|
737
|
+
/**
|
738
|
+
* Describe a specification or test-case
|
739
|
+
* with the given `title` and callback `fn`
|
740
|
+
* acting as a thunk.
|
741
|
+
*/
|
742
|
+
|
743
|
+
context.test = function(title, fn){
|
744
|
+
suites[0].addTest(new Test(title, fn));
|
745
|
+
};
|
746
|
+
});
|
747
|
+
};
|
748
|
+
|
749
|
+
}); // module: interfaces/qunit.js
|
750
|
+
|
751
|
+
require.register("interfaces/tdd.js", function(module, exports, require){
|
752
|
+
|
753
|
+
/**
|
754
|
+
* Module dependencies.
|
755
|
+
*/
|
756
|
+
|
757
|
+
var Suite = require('../suite')
|
758
|
+
, Test = require('../test');
|
759
|
+
|
760
|
+
/**
|
761
|
+
* TDD-style interface:
|
762
|
+
*
|
763
|
+
* suite('Array', function(){
|
764
|
+
* suite('#indexOf()', function(){
|
765
|
+
* suiteSetup(function(){
|
766
|
+
*
|
767
|
+
* });
|
768
|
+
*
|
769
|
+
* test('should return -1 when not present', function(){
|
770
|
+
*
|
771
|
+
* });
|
772
|
+
*
|
773
|
+
* test('should return the index when present', function(){
|
774
|
+
*
|
775
|
+
* });
|
776
|
+
*
|
777
|
+
* suiteTeardown(function(){
|
778
|
+
*
|
779
|
+
* });
|
780
|
+
* });
|
781
|
+
* });
|
782
|
+
*
|
783
|
+
*/
|
784
|
+
|
785
|
+
module.exports = function(suite){
|
786
|
+
var suites = [suite];
|
787
|
+
|
788
|
+
suite.on('pre-require', function(context){
|
789
|
+
|
790
|
+
/**
|
791
|
+
* Execute before each test case.
|
792
|
+
*/
|
793
|
+
|
794
|
+
context.setup = function(fn){
|
795
|
+
suites[0].beforeEach(fn);
|
796
|
+
};
|
797
|
+
|
798
|
+
/**
|
799
|
+
* Execute after each test case.
|
800
|
+
*/
|
801
|
+
|
802
|
+
context.teardown = function(fn){
|
803
|
+
suites[0].afterEach(fn);
|
804
|
+
};
|
805
|
+
|
806
|
+
/**
|
807
|
+
* Execute before the suite.
|
808
|
+
*/
|
809
|
+
|
810
|
+
context.suiteSetup = function(fn){
|
811
|
+
suites[0].beforeAll(fn);
|
812
|
+
};
|
813
|
+
|
814
|
+
/**
|
815
|
+
* Execute after the suite.
|
816
|
+
*/
|
817
|
+
|
818
|
+
context.suiteTeardown = function(fn){
|
819
|
+
suites[0].afterAll(fn);
|
820
|
+
};
|
821
|
+
|
822
|
+
/**
|
823
|
+
* Describe a "suite" with the given `title`
|
824
|
+
* and callback `fn` containing nested suites
|
825
|
+
* and/or tests.
|
826
|
+
*/
|
827
|
+
|
828
|
+
context.suite = function(title, fn){
|
829
|
+
var suite = Suite.create(suites[0], title);
|
830
|
+
suites.unshift(suite);
|
831
|
+
fn();
|
832
|
+
suites.shift();
|
833
|
+
};
|
834
|
+
|
835
|
+
/**
|
836
|
+
* Describe a specification or test-case
|
837
|
+
* with the given `title` and callback `fn`
|
838
|
+
* acting as a thunk.
|
839
|
+
*/
|
840
|
+
|
841
|
+
context.test = function(title, fn){
|
842
|
+
suites[0].addTest(new Test(title, fn));
|
843
|
+
};
|
844
|
+
});
|
845
|
+
};
|
846
|
+
|
847
|
+
}); // module: interfaces/tdd.js
|
848
|
+
|
849
|
+
require.register("mocha.js", function(module, exports, require){
|
850
|
+
|
851
|
+
/*!
|
852
|
+
* mocha
|
853
|
+
* Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
|
854
|
+
* MIT Licensed
|
855
|
+
*/
|
856
|
+
|
857
|
+
/**
|
858
|
+
* Module dependencies.
|
859
|
+
*/
|
860
|
+
|
861
|
+
var path = require('browser/path');
|
862
|
+
|
863
|
+
/**
|
864
|
+
* Expose `Mocha`.
|
865
|
+
*/
|
866
|
+
|
867
|
+
exports = module.exports = Mocha;
|
868
|
+
|
869
|
+
/**
|
870
|
+
* Library version.
|
871
|
+
*/
|
872
|
+
|
873
|
+
exports.version = '1.0.0';
|
874
|
+
|
875
|
+
/**
|
876
|
+
* Expose internals.
|
877
|
+
*/
|
878
|
+
|
879
|
+
exports.utils = require('./utils');
|
880
|
+
exports.interfaces = require('./interfaces');
|
881
|
+
exports.reporters = require('./reporters');
|
882
|
+
exports.Runnable = require('./runnable');
|
883
|
+
exports.Context = require('./context');
|
884
|
+
exports.Runner = require('./runner');
|
885
|
+
exports.Suite = require('./suite');
|
886
|
+
exports.Hook = require('./hook');
|
887
|
+
exports.Test = require('./test');
|
888
|
+
|
889
|
+
/**
|
890
|
+
* Return image `name` path.
|
891
|
+
*
|
892
|
+
* @param {String} name
|
893
|
+
* @return {String}
|
894
|
+
* @api private
|
895
|
+
*/
|
896
|
+
|
897
|
+
function image(name) {
|
898
|
+
return __dirname + '/../images/' + name + '.png';
|
899
|
+
}
|
900
|
+
|
901
|
+
/**
|
902
|
+
* Setup mocha with `options`.
|
903
|
+
*
|
904
|
+
* Options:
|
905
|
+
*
|
906
|
+
* - `ui` name "bdd", "tdd", "exports" etc
|
907
|
+
* - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
|
908
|
+
* - `globals` array of accepted globals
|
909
|
+
* - `timeout` timeout in milliseconds
|
910
|
+
* - `ignoreLeaks` ignore global leaks
|
911
|
+
*
|
912
|
+
* @param {Object} options
|
913
|
+
* @api public
|
914
|
+
*/
|
915
|
+
|
916
|
+
function Mocha(options) {
|
917
|
+
options = options || {};
|
918
|
+
this.files = [];
|
919
|
+
this.options = options;
|
920
|
+
this.suite = new exports.Suite('', new exports.Context);
|
921
|
+
this.ui(options.ui);
|
922
|
+
this.reporter(options.reporter);
|
923
|
+
if (options.timeout) this.suite.timeout(options.timeout);
|
924
|
+
}
|
925
|
+
|
926
|
+
/**
|
927
|
+
* Add test `file`.
|
928
|
+
*
|
929
|
+
* @param {String} file
|
930
|
+
* @api public
|
931
|
+
*/
|
932
|
+
|
933
|
+
Mocha.prototype.addFile = function(file){
|
934
|
+
this.files.push(file);
|
935
|
+
return this;
|
936
|
+
};
|
937
|
+
|
938
|
+
/**
|
939
|
+
* Set reporter to `name`, defaults to "dot".
|
940
|
+
*
|
941
|
+
* @param {String} name
|
942
|
+
* @api public
|
943
|
+
*/
|
944
|
+
|
945
|
+
Mocha.prototype.reporter = function(name){
|
946
|
+
name = name || 'dot';
|
947
|
+
this._reporter = require('./reporters/' + name);
|
948
|
+
if (!this._reporter) throw new Error('invalid reporter "' + name + '"');
|
949
|
+
return this;
|
950
|
+
};
|
951
|
+
|
952
|
+
/**
|
953
|
+
* Set test UI `name`, defaults to "bdd".
|
954
|
+
*
|
955
|
+
* @param {String} bdd
|
956
|
+
* @api public
|
957
|
+
*/
|
958
|
+
|
959
|
+
Mocha.prototype.ui = function(name){
|
960
|
+
name = name || 'bdd';
|
961
|
+
this._ui = exports.interfaces[name];
|
962
|
+
if (!this._ui) throw new Error('invalid interface "' + name + '"');
|
963
|
+
this._ui = this._ui(this.suite);
|
964
|
+
return this;
|
965
|
+
};
|
966
|
+
|
967
|
+
/**
|
968
|
+
* Load registered files.
|
969
|
+
*
|
970
|
+
* @api private
|
971
|
+
*/
|
972
|
+
|
973
|
+
Mocha.prototype.loadFiles = function(){
|
974
|
+
var suite = this.suite;
|
975
|
+
this.files.forEach(function(file){
|
976
|
+
file = path.resolve(file);
|
977
|
+
suite.emit('pre-require', global, file);
|
978
|
+
suite.emit('require', require(file), file);
|
979
|
+
suite.emit('post-require', global, file);
|
980
|
+
});
|
981
|
+
};
|
982
|
+
|
983
|
+
/**
|
984
|
+
* Enable growl support.
|
985
|
+
*
|
986
|
+
* @api private
|
987
|
+
*/
|
988
|
+
|
989
|
+
Mocha.prototype.growl = function(runner, reporter) {
|
990
|
+
var notify = require('growl');
|
991
|
+
|
992
|
+
runner.on('end', function(){
|
993
|
+
var stats = reporter.stats;
|
994
|
+
if (stats.failures) {
|
995
|
+
var msg = stats.failures + ' of ' + runner.total + ' tests failed';
|
996
|
+
notify(msg, { title: 'Failed', image: image('fail') });
|
997
|
+
} else {
|
998
|
+
notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
|
999
|
+
title: 'Passed'
|
1000
|
+
, image: image('pass')
|
1001
|
+
});
|
1002
|
+
}
|
1003
|
+
});
|
1004
|
+
};
|
1005
|
+
|
1006
|
+
/**
|
1007
|
+
* Run tests and invoke `fn()` when complete.
|
1008
|
+
*
|
1009
|
+
* @param {Function} fn
|
1010
|
+
* @return {Runner}
|
1011
|
+
* @api public
|
1012
|
+
*/
|
1013
|
+
|
1014
|
+
Mocha.prototype.run = function(fn){
|
1015
|
+
this.loadFiles();
|
1016
|
+
var suite = this.suite;
|
1017
|
+
var options = this.options;
|
1018
|
+
var runner = new exports.Runner(suite);
|
1019
|
+
var reporter = new this._reporter(runner);
|
1020
|
+
runner.ignoreLeaks = options.ignoreLeaks;
|
1021
|
+
if (options.grep) runner.grep(options.grep);
|
1022
|
+
if (options.globals) runner.globals(options.globals);
|
1023
|
+
if (options.growl) this.growl(runner, reporter);
|
1024
|
+
return runner.run(fn);
|
1025
|
+
};
|
1026
|
+
|
1027
|
+
}); // module: mocha.js
|
1028
|
+
|
1029
|
+
require.register("reporters/base.js", function(module, exports, require){
|
1030
|
+
|
1031
|
+
/**
|
1032
|
+
* Module dependencies.
|
1033
|
+
*/
|
1034
|
+
|
1035
|
+
var tty = require('browser/tty')
|
1036
|
+
, diff = require('browser/diff');
|
1037
|
+
|
1038
|
+
/**
|
1039
|
+
* Check if both stdio streams are associated with a tty.
|
1040
|
+
*/
|
1041
|
+
|
1042
|
+
var isatty = tty.isatty(1) && tty.isatty(2);
|
1043
|
+
|
1044
|
+
/**
|
1045
|
+
* Expose `Base`.
|
1046
|
+
*/
|
1047
|
+
|
1048
|
+
exports = module.exports = Base;
|
1049
|
+
|
1050
|
+
/**
|
1051
|
+
* Enable coloring by default.
|
1052
|
+
*/
|
1053
|
+
|
1054
|
+
exports.useColors = isatty;
|
1055
|
+
|
1056
|
+
/**
|
1057
|
+
* Default color map.
|
1058
|
+
*/
|
1059
|
+
|
1060
|
+
exports.colors = {
|
1061
|
+
'pass': 90
|
1062
|
+
, 'fail': 31
|
1063
|
+
, 'bright pass': 92
|
1064
|
+
, 'bright fail': 91
|
1065
|
+
, 'bright yellow': 93
|
1066
|
+
, 'pending': 36
|
1067
|
+
, 'suite': 0
|
1068
|
+
, 'error title': 0
|
1069
|
+
, 'error message': 31
|
1070
|
+
, 'error stack': 90
|
1071
|
+
, 'checkmark': 32
|
1072
|
+
, 'fast': 90
|
1073
|
+
, 'medium': 33
|
1074
|
+
, 'slow': 31
|
1075
|
+
, 'green': 32
|
1076
|
+
, 'light': 90
|
1077
|
+
, 'diff gutter': 90
|
1078
|
+
, 'diff added': 42
|
1079
|
+
, 'diff removed': 41
|
1080
|
+
};
|
1081
|
+
|
1082
|
+
/**
|
1083
|
+
* Color `str` with the given `type`,
|
1084
|
+
* allowing colors to be disabled,
|
1085
|
+
* as well as user-defined color
|
1086
|
+
* schemes.
|
1087
|
+
*
|
1088
|
+
* @param {String} type
|
1089
|
+
* @param {String} str
|
1090
|
+
* @return {String}
|
1091
|
+
* @api private
|
1092
|
+
*/
|
1093
|
+
|
1094
|
+
var color = exports.color = function(type, str) {
|
1095
|
+
if (!exports.useColors) return str;
|
1096
|
+
return '\033[' + exports.colors[type] + 'm' + str + '\033[0m';
|
1097
|
+
};
|
1098
|
+
|
1099
|
+
/**
|
1100
|
+
* Expose term window size, with some
|
1101
|
+
* defaults for when stderr is not a tty.
|
1102
|
+
*/
|
1103
|
+
|
1104
|
+
exports.window = {
|
1105
|
+
width: isatty
|
1106
|
+
? process.stdout.getWindowSize
|
1107
|
+
? process.stdout.getWindowSize(1)[0]
|
1108
|
+
: tty.getWindowSize()[1]
|
1109
|
+
: 75
|
1110
|
+
};
|
1111
|
+
|
1112
|
+
/**
|
1113
|
+
* Expose some basic cursor interactions
|
1114
|
+
* that are common among reporters.
|
1115
|
+
*/
|
1116
|
+
|
1117
|
+
exports.cursor = {
|
1118
|
+
hide: function(){
|
1119
|
+
process.stdout.write('\033[?25l');
|
1120
|
+
},
|
1121
|
+
|
1122
|
+
show: function(){
|
1123
|
+
process.stdout.write('\033[?25h');
|
1124
|
+
},
|
1125
|
+
|
1126
|
+
deleteLine: function(){
|
1127
|
+
process.stdout.write('\033[2K');
|
1128
|
+
},
|
1129
|
+
|
1130
|
+
beginningOfLine: function(){
|
1131
|
+
process.stdout.write('\033[0G');
|
1132
|
+
},
|
1133
|
+
|
1134
|
+
CR: function(){
|
1135
|
+
exports.cursor.deleteLine();
|
1136
|
+
exports.cursor.beginningOfLine();
|
1137
|
+
}
|
1138
|
+
};
|
1139
|
+
|
1140
|
+
/**
|
1141
|
+
* A test is considered slow if it
|
1142
|
+
* exceeds the following value in milliseconds.
|
1143
|
+
*/
|
1144
|
+
|
1145
|
+
exports.slow = 75;
|
1146
|
+
|
1147
|
+
/**
|
1148
|
+
* Outut the given `failures` as a list.
|
1149
|
+
*
|
1150
|
+
* @param {Array} failures
|
1151
|
+
* @api public
|
1152
|
+
*/
|
1153
|
+
|
1154
|
+
exports.list = function(failures){
|
1155
|
+
console.error();
|
1156
|
+
failures.forEach(function(test, i){
|
1157
|
+
// format
|
1158
|
+
var fmt = color('error title', ' %s) %s:\n')
|
1159
|
+
+ color('error message', ' %s')
|
1160
|
+
+ color('error stack', '\n%s\n');
|
1161
|
+
|
1162
|
+
// msg
|
1163
|
+
var err = test.err
|
1164
|
+
, message = err.message || ''
|
1165
|
+
, stack = err.stack || message
|
1166
|
+
, index = stack.indexOf(message) + message.length
|
1167
|
+
, msg = stack.slice(0, index)
|
1168
|
+
, actual = err.actual
|
1169
|
+
, expected = err.expected;
|
1170
|
+
|
1171
|
+
// actual / expected diff
|
1172
|
+
if ('string' == typeof actual && 'string' == typeof expected) {
|
1173
|
+
var len = Math.max(actual.length, expected.length);
|
1174
|
+
|
1175
|
+
if (len < 20) msg = errorDiff(err, 'Chars');
|
1176
|
+
else msg = errorDiff(err, 'Words');
|
1177
|
+
|
1178
|
+
// linenos
|
1179
|
+
var lines = msg.split('\n');
|
1180
|
+
if (lines.length > 4) {
|
1181
|
+
var width = String(lines.length).length;
|
1182
|
+
msg = lines.map(function(str, i){
|
1183
|
+
return pad(++i, width) + ' |' + ' ' + str;
|
1184
|
+
}).join('\n');
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
// legend
|
1188
|
+
msg = '\n'
|
1189
|
+
+ color('diff removed', 'actual')
|
1190
|
+
+ ' '
|
1191
|
+
+ color('diff added', 'expected')
|
1192
|
+
+ '\n\n'
|
1193
|
+
+ msg
|
1194
|
+
+ '\n';
|
1195
|
+
|
1196
|
+
// indent
|
1197
|
+
msg = msg.replace(/^/gm, ' ');
|
1198
|
+
|
1199
|
+
fmt = color('error title', ' %s) %s:\n%s')
|
1200
|
+
+ color('error stack', '\n%s\n');
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
// indent stack trace without msg
|
1204
|
+
stack = stack.slice(index ? index + 1 : index)
|
1205
|
+
.replace(/^/gm, ' ');
|
1206
|
+
|
1207
|
+
console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
|
1208
|
+
});
|
1209
|
+
};
|
1210
|
+
|
1211
|
+
/**
|
1212
|
+
* Initialize a new `Base` reporter.
|
1213
|
+
*
|
1214
|
+
* All other reporters generally
|
1215
|
+
* inherit from this reporter, providing
|
1216
|
+
* stats such as test duration, number
|
1217
|
+
* of tests passed / failed etc.
|
1218
|
+
*
|
1219
|
+
* @param {Runner} runner
|
1220
|
+
* @api public
|
1221
|
+
*/
|
1222
|
+
|
1223
|
+
function Base(runner) {
|
1224
|
+
var self = this
|
1225
|
+
, stats = this.stats = { suites: 0, tests: 0, passes: 0, failures: 0 }
|
1226
|
+
, failures = this.failures = [];
|
1227
|
+
|
1228
|
+
if (!runner) return;
|
1229
|
+
this.runner = runner;
|
1230
|
+
|
1231
|
+
runner.on('start', function(){
|
1232
|
+
stats.start = new Date;
|
1233
|
+
});
|
1234
|
+
|
1235
|
+
runner.on('suite', function(suite){
|
1236
|
+
stats.suites = stats.suites || 0;
|
1237
|
+
suite.root || stats.suites++;
|
1238
|
+
});
|
1239
|
+
|
1240
|
+
runner.on('test end', function(test){
|
1241
|
+
stats.tests = stats.tests || 0;
|
1242
|
+
stats.tests++;
|
1243
|
+
});
|
1244
|
+
|
1245
|
+
runner.on('pass', function(test){
|
1246
|
+
stats.passes = stats.passes || 0;
|
1247
|
+
|
1248
|
+
var medium = exports.slow / 2;
|
1249
|
+
test.speed = test.duration > exports.slow
|
1250
|
+
? 'slow'
|
1251
|
+
: test.duration > medium
|
1252
|
+
? 'medium'
|
1253
|
+
: 'fast';
|
1254
|
+
|
1255
|
+
stats.passes++;
|
1256
|
+
});
|
1257
|
+
|
1258
|
+
runner.on('fail', function(test, err){
|
1259
|
+
stats.failures = stats.failures || 0;
|
1260
|
+
stats.failures++;
|
1261
|
+
test.err = err;
|
1262
|
+
failures.push(test);
|
1263
|
+
});
|
1264
|
+
|
1265
|
+
runner.on('end', function(){
|
1266
|
+
stats.end = new Date;
|
1267
|
+
stats.duration = new Date - stats.start;
|
1268
|
+
});
|
1269
|
+
}
|
1270
|
+
|
1271
|
+
/**
|
1272
|
+
* Output common epilogue used by many of
|
1273
|
+
* the bundled reporters.
|
1274
|
+
*
|
1275
|
+
* @api public
|
1276
|
+
*/
|
1277
|
+
|
1278
|
+
Base.prototype.epilogue = function(){
|
1279
|
+
var stats = this.stats
|
1280
|
+
, fmt;
|
1281
|
+
|
1282
|
+
console.log();
|
1283
|
+
|
1284
|
+
// failure
|
1285
|
+
if (stats.failures) {
|
1286
|
+
fmt = color('bright fail', ' ✖')
|
1287
|
+
+ color('fail', ' %d of %d tests failed')
|
1288
|
+
+ color('light', ':')
|
1289
|
+
|
1290
|
+
console.error(fmt, stats.failures, this.runner.total);
|
1291
|
+
Base.list(this.failures);
|
1292
|
+
console.error();
|
1293
|
+
return;
|
1294
|
+
}
|
1295
|
+
|
1296
|
+
// pass
|
1297
|
+
fmt = color('bright pass', ' ✔')
|
1298
|
+
+ color('green', ' %d tests complete')
|
1299
|
+
+ color('light', ' (%dms)');
|
1300
|
+
|
1301
|
+
console.log(fmt, stats.tests || 0, stats.duration);
|
1302
|
+
console.log();
|
1303
|
+
};
|
1304
|
+
|
1305
|
+
/**
|
1306
|
+
* Pad the given `str` to `len`.
|
1307
|
+
*
|
1308
|
+
* @param {String} str
|
1309
|
+
* @param {String} len
|
1310
|
+
* @return {String}
|
1311
|
+
* @api private
|
1312
|
+
*/
|
1313
|
+
|
1314
|
+
function pad(str, len) {
|
1315
|
+
str = String(str);
|
1316
|
+
return Array(len - str.length + 1).join(' ') + str;
|
1317
|
+
}
|
1318
|
+
|
1319
|
+
/**
|
1320
|
+
* Return a character diff for `err`.
|
1321
|
+
*
|
1322
|
+
* @param {Error} err
|
1323
|
+
* @return {String}
|
1324
|
+
* @api private
|
1325
|
+
*/
|
1326
|
+
|
1327
|
+
function errorDiff(err, type) {
|
1328
|
+
return diff['diff' + type](err.actual, err.expected).map(function(str){
|
1329
|
+
if (str.added) return colorLines('diff added', str.value);
|
1330
|
+
if (str.removed) return colorLines('diff removed', str.value);
|
1331
|
+
return str.value;
|
1332
|
+
}).join('');
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
/**
|
1336
|
+
* Color lines for `str`, using the color `name`.
|
1337
|
+
*
|
1338
|
+
* @param {String} name
|
1339
|
+
* @param {String} str
|
1340
|
+
* @return {String}
|
1341
|
+
* @api private
|
1342
|
+
*/
|
1343
|
+
|
1344
|
+
function colorLines(name, str) {
|
1345
|
+
return str.split('\n').map(function(str){
|
1346
|
+
return color(name, str);
|
1347
|
+
}).join('\n');
|
1348
|
+
}
|
1349
|
+
|
1350
|
+
}); // module: reporters/base.js
|
1351
|
+
|
1352
|
+
require.register("reporters/doc.js", function(module, exports, require){
|
1353
|
+
|
1354
|
+
/**
|
1355
|
+
* Module dependencies.
|
1356
|
+
*/
|
1357
|
+
|
1358
|
+
var Base = require('./base')
|
1359
|
+
, utils = require('../utils');
|
1360
|
+
|
1361
|
+
/**
|
1362
|
+
* Expose `Doc`.
|
1363
|
+
*/
|
1364
|
+
|
1365
|
+
exports = module.exports = Doc;
|
1366
|
+
|
1367
|
+
/**
|
1368
|
+
* Initialize a new `Doc` reporter.
|
1369
|
+
*
|
1370
|
+
* @param {Runner} runner
|
1371
|
+
* @api public
|
1372
|
+
*/
|
1373
|
+
|
1374
|
+
function Doc(runner) {
|
1375
|
+
Base.call(this, runner);
|
1376
|
+
|
1377
|
+
var self = this
|
1378
|
+
, stats = this.stats
|
1379
|
+
, total = runner.total
|
1380
|
+
, indents = 2;
|
1381
|
+
|
1382
|
+
function indent() {
|
1383
|
+
return Array(indents).join(' ');
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
runner.on('suite', function(suite){
|
1387
|
+
if (suite.root) return;
|
1388
|
+
++indents;
|
1389
|
+
console.log('%s<section class="suite">', indent());
|
1390
|
+
++indents;
|
1391
|
+
console.log('%s<h1>%s</h1>', indent(), suite.title);
|
1392
|
+
console.log('%s<dl>', indent());
|
1393
|
+
});
|
1394
|
+
|
1395
|
+
runner.on('suite end', function(suite){
|
1396
|
+
if (suite.root) return;
|
1397
|
+
console.log('%s</dl>', indent());
|
1398
|
+
--indents;
|
1399
|
+
console.log('%s</section>', indent());
|
1400
|
+
--indents;
|
1401
|
+
});
|
1402
|
+
|
1403
|
+
runner.on('pass', function(test){
|
1404
|
+
console.log('%s <dt>%s</dt>', indent(), test.title);
|
1405
|
+
var code = utils.escape(clean(test.fn.toString()));
|
1406
|
+
console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
|
1407
|
+
});
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
/**
|
1411
|
+
* Strip the function definition from `str`,
|
1412
|
+
* and re-indent for pre whitespace.
|
1413
|
+
*/
|
1414
|
+
|
1415
|
+
function clean(str) {
|
1416
|
+
str = str
|
1417
|
+
.replace(/^function *\(.*\) *{/, '')
|
1418
|
+
.replace(/\s+\}$/, '');
|
1419
|
+
|
1420
|
+
var spaces = str.match(/^\n?( *)/)[1].length
|
1421
|
+
, re = new RegExp('^ {' + spaces + '}', 'gm');
|
1422
|
+
|
1423
|
+
str = str.replace(re, '');
|
1424
|
+
|
1425
|
+
return str;
|
1426
|
+
}
|
1427
|
+
}); // module: reporters/doc.js
|
1428
|
+
|
1429
|
+
require.register("reporters/dot.js", function(module, exports, require){
|
1430
|
+
|
1431
|
+
/**
|
1432
|
+
* Module dependencies.
|
1433
|
+
*/
|
1434
|
+
|
1435
|
+
var Base = require('./base')
|
1436
|
+
, color = Base.color;
|
1437
|
+
|
1438
|
+
/**
|
1439
|
+
* Expose `Dot`.
|
1440
|
+
*/
|
1441
|
+
|
1442
|
+
exports = module.exports = Dot;
|
1443
|
+
|
1444
|
+
/**
|
1445
|
+
* Initialize a new `Dot` matrix test reporter.
|
1446
|
+
*
|
1447
|
+
* @param {Runner} runner
|
1448
|
+
* @api public
|
1449
|
+
*/
|
1450
|
+
|
1451
|
+
function Dot(runner) {
|
1452
|
+
Base.call(this, runner);
|
1453
|
+
|
1454
|
+
var self = this
|
1455
|
+
, stats = this.stats
|
1456
|
+
, width = Base.window.width * .75 | 0
|
1457
|
+
, n = 0;
|
1458
|
+
|
1459
|
+
runner.on('start', function(){
|
1460
|
+
process.stdout.write('\n ');
|
1461
|
+
});
|
1462
|
+
|
1463
|
+
runner.on('pending', function(test){
|
1464
|
+
process.stdout.write(color('pending', '.'));
|
1465
|
+
});
|
1466
|
+
|
1467
|
+
runner.on('pass', function(test){
|
1468
|
+
if (++n % width == 0) process.stdout.write('\n ');
|
1469
|
+
if ('slow' == test.speed) {
|
1470
|
+
process.stdout.write(color('bright yellow', '.'));
|
1471
|
+
} else {
|
1472
|
+
process.stdout.write(color(test.speed, '.'));
|
1473
|
+
}
|
1474
|
+
});
|
1475
|
+
|
1476
|
+
runner.on('fail', function(test, err){
|
1477
|
+
if (++n % width == 0) process.stdout.write('\n ');
|
1478
|
+
process.stdout.write(color('fail', '.'));
|
1479
|
+
});
|
1480
|
+
|
1481
|
+
runner.on('end', function(){
|
1482
|
+
console.log();
|
1483
|
+
self.epilogue();
|
1484
|
+
});
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
/**
|
1488
|
+
* Inherit from `Base.prototype`.
|
1489
|
+
*/
|
1490
|
+
|
1491
|
+
Dot.prototype = new Base;
|
1492
|
+
Dot.prototype.constructor = Dot;
|
1493
|
+
|
1494
|
+
}); // module: reporters/dot.js
|
1495
|
+
|
1496
|
+
require.register("reporters/html-cov.js", function(module, exports, require){
|
1497
|
+
|
1498
|
+
/**
|
1499
|
+
* Module dependencies.
|
1500
|
+
*/
|
1501
|
+
|
1502
|
+
var JSONCov = require('./json-cov')
|
1503
|
+
, fs = require('browser/fs');
|
1504
|
+
|
1505
|
+
/**
|
1506
|
+
* Expose `HTMLCov`.
|
1507
|
+
*/
|
1508
|
+
|
1509
|
+
exports = module.exports = HTMLCov;
|
1510
|
+
|
1511
|
+
/**
|
1512
|
+
* Initialize a new `JsCoverage` reporter.
|
1513
|
+
*
|
1514
|
+
* @param {Runner} runner
|
1515
|
+
* @api public
|
1516
|
+
*/
|
1517
|
+
|
1518
|
+
function HTMLCov(runner) {
|
1519
|
+
var jade = require('jade')
|
1520
|
+
, file = __dirname + '/templates/coverage.jade'
|
1521
|
+
, str = fs.readFileSync(file, 'utf8')
|
1522
|
+
, fn = jade.compile(str, { filename: file })
|
1523
|
+
, self = this;
|
1524
|
+
|
1525
|
+
JSONCov.call(this, runner, false);
|
1526
|
+
|
1527
|
+
runner.on('end', function(){
|
1528
|
+
process.stdout.write(fn({
|
1529
|
+
cov: self.cov
|
1530
|
+
, coverageClass: coverageClass
|
1531
|
+
}));
|
1532
|
+
});
|
1533
|
+
}
|
1534
|
+
|
1535
|
+
function coverageClass(n) {
|
1536
|
+
if (n >= 75) return 'high';
|
1537
|
+
if (n >= 50) return 'medium';
|
1538
|
+
if (n >= 25) return 'low';
|
1539
|
+
return 'terrible';
|
1540
|
+
}
|
1541
|
+
}); // module: reporters/html-cov.js
|
1542
|
+
|
1543
|
+
require.register("reporters/html.js", function(module, exports, require){
|
1544
|
+
|
1545
|
+
/**
|
1546
|
+
* Module dependencies.
|
1547
|
+
*/
|
1548
|
+
|
1549
|
+
var Base = require('./base')
|
1550
|
+
, utils = require('../utils')
|
1551
|
+
, Progress = require('../browser/progress')
|
1552
|
+
, escape = utils.escape;
|
1553
|
+
|
1554
|
+
/**
|
1555
|
+
* Expose `Doc`.
|
1556
|
+
*/
|
1557
|
+
|
1558
|
+
exports = module.exports = HTML;
|
1559
|
+
|
1560
|
+
/**
|
1561
|
+
* Stats template.
|
1562
|
+
*/
|
1563
|
+
|
1564
|
+
var statsTemplate = '<ul id="stats">'
|
1565
|
+
+ '<li class="progress"><canvas width="40" height="40"></canvas></li>'
|
1566
|
+
+ '<li class="passes">passes: <em>0</em></li>'
|
1567
|
+
+ '<li class="failures">failures: <em>0</em></li>'
|
1568
|
+
+ '<li class="duration">duration: <em>0</em>s</li>'
|
1569
|
+
+ '</ul>';
|
1570
|
+
|
1571
|
+
/**
|
1572
|
+
* Initialize a new `Doc` reporter.
|
1573
|
+
*
|
1574
|
+
* @param {Runner} runner
|
1575
|
+
* @api public
|
1576
|
+
*/
|
1577
|
+
|
1578
|
+
function HTML(runner) {
|
1579
|
+
Base.call(this, runner);
|
1580
|
+
|
1581
|
+
var self = this
|
1582
|
+
, stats = this.stats
|
1583
|
+
, total = runner.total
|
1584
|
+
, root = document.getElementById('mocha')
|
1585
|
+
, stat = fragment(statsTemplate)
|
1586
|
+
, items = stat.getElementsByTagName('li')
|
1587
|
+
, passes = items[1].getElementsByTagName('em')[0]
|
1588
|
+
, failures = items[2].getElementsByTagName('em')[0]
|
1589
|
+
, duration = items[3].getElementsByTagName('em')[0]
|
1590
|
+
, canvas = stat.getElementsByTagName('canvas')[0]
|
1591
|
+
, stack = [root]
|
1592
|
+
, progress
|
1593
|
+
, ctx
|
1594
|
+
|
1595
|
+
if (canvas.getContext) {
|
1596
|
+
ctx = canvas.getContext('2d');
|
1597
|
+
progress = new Progress;
|
1598
|
+
}
|
1599
|
+
|
1600
|
+
if (!root) return error('#mocha div missing, add it to your document');
|
1601
|
+
|
1602
|
+
root.appendChild(stat);
|
1603
|
+
|
1604
|
+
if (progress) progress.size(40);
|
1605
|
+
|
1606
|
+
runner.on('suite', function(suite){
|
1607
|
+
if (suite.root) return;
|
1608
|
+
|
1609
|
+
// suite
|
1610
|
+
var el = fragment('<div class="suite"><h1>%s</h1></div>', suite.title);
|
1611
|
+
|
1612
|
+
// container
|
1613
|
+
stack[0].appendChild(el);
|
1614
|
+
stack.unshift(document.createElement('div'));
|
1615
|
+
el.appendChild(stack[0]);
|
1616
|
+
});
|
1617
|
+
|
1618
|
+
runner.on('suite end', function(suite){
|
1619
|
+
if (suite.root) return;
|
1620
|
+
stack.shift();
|
1621
|
+
});
|
1622
|
+
|
1623
|
+
runner.on('fail', function(test, err){
|
1624
|
+
if (err.uncaught) runner.emit('test end', test);
|
1625
|
+
});
|
1626
|
+
|
1627
|
+
runner.on('test end', function(test){
|
1628
|
+
// TODO: add to stats
|
1629
|
+
var percent = stats.tests / total * 100 | 0;
|
1630
|
+
if (progress) progress.update(percent).draw(ctx);
|
1631
|
+
|
1632
|
+
// update stats
|
1633
|
+
var ms = new Date - stats.start;
|
1634
|
+
text(passes, stats.passes);
|
1635
|
+
text(failures, stats.failures);
|
1636
|
+
text(duration, (ms / 1000).toFixed(2));
|
1637
|
+
|
1638
|
+
// test
|
1639
|
+
if ('passed' == test.state) {
|
1640
|
+
var el = fragment('<div class="test pass"><h2>%e</h2></div>', test.title);
|
1641
|
+
} else if (test.pending) {
|
1642
|
+
var el = fragment('<div class="test pass pending"><h2>%e</h2></div>', test.title);
|
1643
|
+
} else {
|
1644
|
+
var el = fragment('<div class="test fail"><h2>%e</h2></div>', test.title);
|
1645
|
+
var str = test.err.stack || test.err.toString();
|
1646
|
+
|
1647
|
+
// FF / Opera do not add the message
|
1648
|
+
if (!~str.indexOf(test.err.message)) {
|
1649
|
+
str = test.err.message + '\n' + str;
|
1650
|
+
}
|
1651
|
+
|
1652
|
+
// <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
|
1653
|
+
// check for the result of the stringifying.
|
1654
|
+
if ('[object Error]' == str) str = test.err.message;
|
1655
|
+
|
1656
|
+
// Safari doesn't give you a stack. Let's at least provide a source line.
|
1657
|
+
if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {
|
1658
|
+
str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")";
|
1659
|
+
}
|
1660
|
+
|
1661
|
+
el.appendChild(fragment('<pre class="error">%e</pre>', str));
|
1662
|
+
}
|
1663
|
+
|
1664
|
+
// toggle code
|
1665
|
+
var h2 = el.getElementsByTagName('h2')[0];
|
1666
|
+
|
1667
|
+
on(h2, 'click', function(){
|
1668
|
+
pre.style.display = 'none' == pre.style.display
|
1669
|
+
? 'block'
|
1670
|
+
: 'none';
|
1671
|
+
});
|
1672
|
+
|
1673
|
+
// code
|
1674
|
+
// TODO: defer
|
1675
|
+
if (!test.pending) {
|
1676
|
+
var pre = fragment('<pre><code>%e</code></pre>', clean(test.fn.toString()));
|
1677
|
+
el.appendChild(pre);
|
1678
|
+
pre.style.display = 'none';
|
1679
|
+
}
|
1680
|
+
|
1681
|
+
stack[0].appendChild(el);
|
1682
|
+
});
|
1683
|
+
}
|
1684
|
+
|
1685
|
+
/**
|
1686
|
+
* Display error `msg`.
|
1687
|
+
*/
|
1688
|
+
|
1689
|
+
function error(msg) {
|
1690
|
+
document.body.appendChild(fragment('<div id="error">%s</div>', msg));
|
1691
|
+
}
|
1692
|
+
|
1693
|
+
/**
|
1694
|
+
* Return a DOM fragment from `html`.
|
1695
|
+
*/
|
1696
|
+
|
1697
|
+
function fragment(html) {
|
1698
|
+
var args = arguments
|
1699
|
+
, div = document.createElement('div')
|
1700
|
+
, i = 1;
|
1701
|
+
|
1702
|
+
div.innerHTML = html.replace(/%([se])/g, function(_, type){
|
1703
|
+
switch (type) {
|
1704
|
+
case 's': return String(args[i++]);
|
1705
|
+
case 'e': return escape(args[i++]);
|
1706
|
+
}
|
1707
|
+
});
|
1708
|
+
|
1709
|
+
return div.firstChild;
|
1710
|
+
}
|
1711
|
+
|
1712
|
+
/**
|
1713
|
+
* Set `el` text to `str`.
|
1714
|
+
*/
|
1715
|
+
|
1716
|
+
function text(el, str) {
|
1717
|
+
if (el.textContent) {
|
1718
|
+
el.textContent = str;
|
1719
|
+
} else {
|
1720
|
+
el.innerText = str;
|
1721
|
+
}
|
1722
|
+
}
|
1723
|
+
|
1724
|
+
/**
|
1725
|
+
* Listen on `event` with callback `fn`.
|
1726
|
+
*/
|
1727
|
+
|
1728
|
+
function on(el, event, fn) {
|
1729
|
+
if (el.addEventListener) {
|
1730
|
+
el.addEventListener(event, fn, false);
|
1731
|
+
} else {
|
1732
|
+
el.attachEvent('on' + event, fn);
|
1733
|
+
}
|
1734
|
+
}
|
1735
|
+
|
1736
|
+
/**
|
1737
|
+
* Strip the function definition from `str`,
|
1738
|
+
* and re-indent for pre whitespace.
|
1739
|
+
*/
|
1740
|
+
|
1741
|
+
function clean(str) {
|
1742
|
+
str = str
|
1743
|
+
.replace(/^function *\(.*\) *{/, '')
|
1744
|
+
.replace(/\s+\}$/, '');
|
1745
|
+
|
1746
|
+
var spaces = str.match(/^\n?( *)/)[1].length
|
1747
|
+
, re = new RegExp('^ {' + spaces + '}', 'gm');
|
1748
|
+
|
1749
|
+
str = str
|
1750
|
+
.replace(re, '')
|
1751
|
+
.replace(/^\s+/, '');
|
1752
|
+
|
1753
|
+
return str;
|
1754
|
+
}
|
1755
|
+
|
1756
|
+
}); // module: reporters/html.js
|
1757
|
+
|
1758
|
+
require.register("reporters/index.js", function(module, exports, require){
|
1759
|
+
|
1760
|
+
exports.Base = require('./base');
|
1761
|
+
exports.Dot = require('./dot');
|
1762
|
+
exports.Doc = require('./doc');
|
1763
|
+
exports.TAP = require('./tap');
|
1764
|
+
exports.JSON = require('./json');
|
1765
|
+
exports.HTML = require('./html');
|
1766
|
+
exports.List = require('./list');
|
1767
|
+
exports.Min = require('./min');
|
1768
|
+
exports.Spec = require('./spec');
|
1769
|
+
exports.Progress = require('./progress');
|
1770
|
+
exports.Landing = require('./landing');
|
1771
|
+
exports.JSONCov = require('./json-cov');
|
1772
|
+
exports.HTMLCov = require('./html-cov');
|
1773
|
+
exports.JSONStream = require('./json-stream');
|
1774
|
+
exports.XUnit = require('./xunit')
|
1775
|
+
exports.Teamcity = require('./teamcity')
|
1776
|
+
|
1777
|
+
}); // module: reporters/index.js
|
1778
|
+
|
1779
|
+
require.register("reporters/json-cov.js", function(module, exports, require){
|
1780
|
+
|
1781
|
+
/**
|
1782
|
+
* Module dependencies.
|
1783
|
+
*/
|
1784
|
+
|
1785
|
+
var Base = require('./base');
|
1786
|
+
|
1787
|
+
/**
|
1788
|
+
* Expose `JSONCov`.
|
1789
|
+
*/
|
1790
|
+
|
1791
|
+
exports = module.exports = JSONCov;
|
1792
|
+
|
1793
|
+
/**
|
1794
|
+
* Initialize a new `JsCoverage` reporter.
|
1795
|
+
*
|
1796
|
+
* @param {Runner} runner
|
1797
|
+
* @param {Boolean} output
|
1798
|
+
* @api public
|
1799
|
+
*/
|
1800
|
+
|
1801
|
+
function JSONCov(runner, output) {
|
1802
|
+
var self = this
|
1803
|
+
, output = 1 == arguments.length ? true : output;
|
1804
|
+
|
1805
|
+
Base.call(this, runner);
|
1806
|
+
|
1807
|
+
var tests = []
|
1808
|
+
, failures = []
|
1809
|
+
, passes = [];
|
1810
|
+
|
1811
|
+
runner.on('test end', function(test){
|
1812
|
+
tests.push(test);
|
1813
|
+
});
|
1814
|
+
|
1815
|
+
runner.on('pass', function(test){
|
1816
|
+
passes.push(test);
|
1817
|
+
});
|
1818
|
+
|
1819
|
+
runner.on('fail', function(test){
|
1820
|
+
failures.push(test);
|
1821
|
+
});
|
1822
|
+
|
1823
|
+
runner.on('end', function(){
|
1824
|
+
var cov = global._$jscoverage || {};
|
1825
|
+
var result = self.cov = map(cov);
|
1826
|
+
result.stats = self.stats;
|
1827
|
+
result.tests = tests.map(clean);
|
1828
|
+
result.failures = failures.map(clean);
|
1829
|
+
result.passes = passes.map(clean);
|
1830
|
+
if (!output) return;
|
1831
|
+
process.stdout.write(JSON.stringify(result, null, 2 ));
|
1832
|
+
});
|
1833
|
+
}
|
1834
|
+
|
1835
|
+
/**
|
1836
|
+
* Map jscoverage data to a JSON structure
|
1837
|
+
* suitable for reporting.
|
1838
|
+
*
|
1839
|
+
* @param {Object} cov
|
1840
|
+
* @return {Object}
|
1841
|
+
* @api private
|
1842
|
+
*/
|
1843
|
+
|
1844
|
+
function map(cov) {
|
1845
|
+
var ret = {
|
1846
|
+
instrumentation: 'node-jscoverage'
|
1847
|
+
, sloc: 0
|
1848
|
+
, hits: 0
|
1849
|
+
, misses: 0
|
1850
|
+
, coverage: 0
|
1851
|
+
, files: []
|
1852
|
+
};
|
1853
|
+
|
1854
|
+
for (var filename in cov) {
|
1855
|
+
var data = coverage(filename, cov[filename]);
|
1856
|
+
ret.files.push(data);
|
1857
|
+
ret.hits += data.hits;
|
1858
|
+
ret.misses += data.misses;
|
1859
|
+
ret.sloc += data.sloc;
|
1860
|
+
}
|
1861
|
+
|
1862
|
+
if (ret.sloc > 0) {
|
1863
|
+
ret.coverage = (ret.hits / ret.sloc) * 100;
|
1864
|
+
}
|
1865
|
+
|
1866
|
+
return ret;
|
1867
|
+
};
|
1868
|
+
|
1869
|
+
/**
|
1870
|
+
* Map jscoverage data for a single source file
|
1871
|
+
* to a JSON structure suitable for reporting.
|
1872
|
+
*
|
1873
|
+
* @param {String} filename name of the source file
|
1874
|
+
* @param {Object} data jscoverage coverage data
|
1875
|
+
* @return {Object}
|
1876
|
+
* @api private
|
1877
|
+
*/
|
1878
|
+
|
1879
|
+
function coverage(filename, data) {
|
1880
|
+
var ret = {
|
1881
|
+
filename: filename,
|
1882
|
+
coverage: 0,
|
1883
|
+
hits: 0,
|
1884
|
+
misses: 0,
|
1885
|
+
sloc: 0,
|
1886
|
+
source: {}
|
1887
|
+
};
|
1888
|
+
|
1889
|
+
data.source.forEach(function(line, num){
|
1890
|
+
num++;
|
1891
|
+
|
1892
|
+
if (data[num] === 0) {
|
1893
|
+
ret.misses++;
|
1894
|
+
ret.sloc++;
|
1895
|
+
} else if (data[num] !== undefined) {
|
1896
|
+
ret.hits++;
|
1897
|
+
ret.sloc++;
|
1898
|
+
}
|
1899
|
+
|
1900
|
+
ret.source[num] = {
|
1901
|
+
source: line
|
1902
|
+
, coverage: data[num] === undefined
|
1903
|
+
? ''
|
1904
|
+
: data[num]
|
1905
|
+
};
|
1906
|
+
});
|
1907
|
+
|
1908
|
+
ret.coverage = ret.hits / ret.sloc * 100;
|
1909
|
+
|
1910
|
+
return ret;
|
1911
|
+
}
|
1912
|
+
|
1913
|
+
/**
|
1914
|
+
* Return a plain-object representation of `test`
|
1915
|
+
* free of cyclic properties etc.
|
1916
|
+
*
|
1917
|
+
* @param {Object} test
|
1918
|
+
* @return {Object}
|
1919
|
+
* @api private
|
1920
|
+
*/
|
1921
|
+
|
1922
|
+
function clean(test) {
|
1923
|
+
return {
|
1924
|
+
title: test.title
|
1925
|
+
, fullTitle: test.fullTitle()
|
1926
|
+
, duration: test.duration
|
1927
|
+
}
|
1928
|
+
}
|
1929
|
+
|
1930
|
+
}); // module: reporters/json-cov.js
|
1931
|
+
|
1932
|
+
require.register("reporters/json-stream.js", function(module, exports, require){
|
1933
|
+
|
1934
|
+
/**
|
1935
|
+
* Module dependencies.
|
1936
|
+
*/
|
1937
|
+
|
1938
|
+
var Base = require('./base')
|
1939
|
+
, color = Base.color;
|
1940
|
+
|
1941
|
+
/**
|
1942
|
+
* Expose `List`.
|
1943
|
+
*/
|
1944
|
+
|
1945
|
+
exports = module.exports = List;
|
1946
|
+
|
1947
|
+
/**
|
1948
|
+
* Initialize a new `List` test reporter.
|
1949
|
+
*
|
1950
|
+
* @param {Runner} runner
|
1951
|
+
* @api public
|
1952
|
+
*/
|
1953
|
+
|
1954
|
+
function List(runner) {
|
1955
|
+
Base.call(this, runner);
|
1956
|
+
|
1957
|
+
var self = this
|
1958
|
+
, stats = this.stats
|
1959
|
+
, total = runner.total;
|
1960
|
+
|
1961
|
+
runner.on('start', function(){
|
1962
|
+
console.log(JSON.stringify(['start', { total: total }]));
|
1963
|
+
});
|
1964
|
+
|
1965
|
+
runner.on('pass', function(test){
|
1966
|
+
console.log(JSON.stringify(['pass', clean(test)]));
|
1967
|
+
});
|
1968
|
+
|
1969
|
+
runner.on('fail', function(test, err){
|
1970
|
+
console.log(JSON.stringify(['fail', clean(test)]));
|
1971
|
+
});
|
1972
|
+
|
1973
|
+
runner.on('end', function(){
|
1974
|
+
process.stdout.write(JSON.stringify(['end', self.stats]));
|
1975
|
+
});
|
1976
|
+
}
|
1977
|
+
|
1978
|
+
/**
|
1979
|
+
* Return a plain-object representation of `test`
|
1980
|
+
* free of cyclic properties etc.
|
1981
|
+
*
|
1982
|
+
* @param {Object} test
|
1983
|
+
* @return {Object}
|
1984
|
+
* @api private
|
1985
|
+
*/
|
1986
|
+
|
1987
|
+
function clean(test) {
|
1988
|
+
return {
|
1989
|
+
title: test.title
|
1990
|
+
, fullTitle: test.fullTitle()
|
1991
|
+
, duration: test.duration
|
1992
|
+
}
|
1993
|
+
}
|
1994
|
+
}); // module: reporters/json-stream.js
|
1995
|
+
|
1996
|
+
require.register("reporters/json.js", function(module, exports, require){
|
1997
|
+
|
1998
|
+
/**
|
1999
|
+
* Module dependencies.
|
2000
|
+
*/
|
2001
|
+
|
2002
|
+
var Base = require('./base')
|
2003
|
+
, cursor = Base.cursor
|
2004
|
+
, color = Base.color;
|
2005
|
+
|
2006
|
+
/**
|
2007
|
+
* Expose `JSON`.
|
2008
|
+
*/
|
2009
|
+
|
2010
|
+
exports = module.exports = JSONReporter;
|
2011
|
+
|
2012
|
+
/**
|
2013
|
+
* Initialize a new `JSON` reporter.
|
2014
|
+
*
|
2015
|
+
* @param {Runner} runner
|
2016
|
+
* @api public
|
2017
|
+
*/
|
2018
|
+
|
2019
|
+
function JSONReporter(runner) {
|
2020
|
+
var self = this;
|
2021
|
+
Base.call(this, runner);
|
2022
|
+
|
2023
|
+
var tests = []
|
2024
|
+
, failures = []
|
2025
|
+
, passes = [];
|
2026
|
+
|
2027
|
+
runner.on('test end', function(test){
|
2028
|
+
tests.push(test);
|
2029
|
+
});
|
2030
|
+
|
2031
|
+
runner.on('pass', function(test){
|
2032
|
+
passes.push(test);
|
2033
|
+
});
|
2034
|
+
|
2035
|
+
runner.on('fail', function(test){
|
2036
|
+
failures.push(test);
|
2037
|
+
});
|
2038
|
+
|
2039
|
+
runner.on('end', function(){
|
2040
|
+
var obj = {
|
2041
|
+
stats: self.stats
|
2042
|
+
, tests: tests.map(clean)
|
2043
|
+
, failures: failures.map(clean)
|
2044
|
+
, passes: passes.map(clean)
|
2045
|
+
};
|
2046
|
+
|
2047
|
+
process.stdout.write(JSON.stringify(obj, null, 2));
|
2048
|
+
});
|
2049
|
+
}
|
2050
|
+
|
2051
|
+
/**
|
2052
|
+
* Return a plain-object representation of `test`
|
2053
|
+
* free of cyclic properties etc.
|
2054
|
+
*
|
2055
|
+
* @param {Object} test
|
2056
|
+
* @return {Object}
|
2057
|
+
* @api private
|
2058
|
+
*/
|
2059
|
+
|
2060
|
+
function clean(test) {
|
2061
|
+
return {
|
2062
|
+
title: test.title
|
2063
|
+
, fullTitle: test.fullTitle()
|
2064
|
+
, duration: test.duration
|
2065
|
+
}
|
2066
|
+
}
|
2067
|
+
}); // module: reporters/json.js
|
2068
|
+
|
2069
|
+
require.register("reporters/landing.js", function(module, exports, require){
|
2070
|
+
|
2071
|
+
/**
|
2072
|
+
* Module dependencies.
|
2073
|
+
*/
|
2074
|
+
|
2075
|
+
var Base = require('./base')
|
2076
|
+
, cursor = Base.cursor
|
2077
|
+
, color = Base.color;
|
2078
|
+
|
2079
|
+
/**
|
2080
|
+
* Expose `Landing`.
|
2081
|
+
*/
|
2082
|
+
|
2083
|
+
exports = module.exports = Landing;
|
2084
|
+
|
2085
|
+
/**
|
2086
|
+
* Airplane color.
|
2087
|
+
*/
|
2088
|
+
|
2089
|
+
Base.colors.plane = 0;
|
2090
|
+
|
2091
|
+
/**
|
2092
|
+
* Airplane crash color.
|
2093
|
+
*/
|
2094
|
+
|
2095
|
+
Base.colors['plane crash'] = 31;
|
2096
|
+
|
2097
|
+
/**
|
2098
|
+
* Runway color.
|
2099
|
+
*/
|
2100
|
+
|
2101
|
+
Base.colors.runway = 90;
|
2102
|
+
|
2103
|
+
/**
|
2104
|
+
* Initialize a new `Landing` reporter.
|
2105
|
+
*
|
2106
|
+
* @param {Runner} runner
|
2107
|
+
* @api public
|
2108
|
+
*/
|
2109
|
+
|
2110
|
+
function Landing(runner) {
|
2111
|
+
Base.call(this, runner);
|
2112
|
+
|
2113
|
+
var self = this
|
2114
|
+
, stats = this.stats
|
2115
|
+
, width = Base.window.width * .75 | 0
|
2116
|
+
, total = runner.total
|
2117
|
+
, stream = process.stdout
|
2118
|
+
, plane = color('plane', '✈')
|
2119
|
+
, crashed = -1
|
2120
|
+
, n = 0;
|
2121
|
+
|
2122
|
+
function runway() {
|
2123
|
+
var buf = Array(width).join('-');
|
2124
|
+
return ' ' + color('runway', buf);
|
2125
|
+
}
|
2126
|
+
|
2127
|
+
runner.on('start', function(){
|
2128
|
+
stream.write('\n ');
|
2129
|
+
cursor.hide();
|
2130
|
+
});
|
2131
|
+
|
2132
|
+
runner.on('test end', function(test){
|
2133
|
+
// check if the plane crashed
|
2134
|
+
var col = -1 == crashed
|
2135
|
+
? width * ++n / total | 0
|
2136
|
+
: crashed;
|
2137
|
+
|
2138
|
+
// show the crash
|
2139
|
+
if ('failed' == test.state) {
|
2140
|
+
plane = color('plane crash', '✈');
|
2141
|
+
crashed = col;
|
2142
|
+
}
|
2143
|
+
|
2144
|
+
// render landing strip
|
2145
|
+
stream.write('\033[4F\n\n');
|
2146
|
+
stream.write(runway());
|
2147
|
+
stream.write('\n ');
|
2148
|
+
stream.write(color('runway', Array(col).join('⋅')));
|
2149
|
+
stream.write(plane)
|
2150
|
+
stream.write(color('runway', Array(width - col).join('⋅') + '\n'));
|
2151
|
+
stream.write(runway());
|
2152
|
+
stream.write('\033[0m');
|
2153
|
+
});
|
2154
|
+
|
2155
|
+
runner.on('end', function(){
|
2156
|
+
cursor.show();
|
2157
|
+
console.log();
|
2158
|
+
self.epilogue();
|
2159
|
+
});
|
2160
|
+
}
|
2161
|
+
|
2162
|
+
/**
|
2163
|
+
* Inherit from `Base.prototype`.
|
2164
|
+
*/
|
2165
|
+
|
2166
|
+
Landing.prototype = new Base;
|
2167
|
+
Landing.prototype.constructor = Landing;
|
2168
|
+
|
2169
|
+
}); // module: reporters/landing.js
|
2170
|
+
|
2171
|
+
require.register("reporters/list.js", function(module, exports, require){
|
2172
|
+
|
2173
|
+
/**
|
2174
|
+
* Module dependencies.
|
2175
|
+
*/
|
2176
|
+
|
2177
|
+
var Base = require('./base')
|
2178
|
+
, cursor = Base.cursor
|
2179
|
+
, color = Base.color;
|
2180
|
+
|
2181
|
+
/**
|
2182
|
+
* Expose `List`.
|
2183
|
+
*/
|
2184
|
+
|
2185
|
+
exports = module.exports = List;
|
2186
|
+
|
2187
|
+
/**
|
2188
|
+
* Initialize a new `List` test reporter.
|
2189
|
+
*
|
2190
|
+
* @param {Runner} runner
|
2191
|
+
* @api public
|
2192
|
+
*/
|
2193
|
+
|
2194
|
+
function List(runner) {
|
2195
|
+
Base.call(this, runner);
|
2196
|
+
|
2197
|
+
var self = this
|
2198
|
+
, stats = this.stats
|
2199
|
+
, n = 0;
|
2200
|
+
|
2201
|
+
runner.on('start', function(){
|
2202
|
+
console.log();
|
2203
|
+
});
|
2204
|
+
|
2205
|
+
runner.on('test', function(test){
|
2206
|
+
process.stdout.write(color('pass', ' ' + test.fullTitle() + ': '));
|
2207
|
+
});
|
2208
|
+
|
2209
|
+
runner.on('pending', function(test){
|
2210
|
+
var fmt = color('checkmark', ' -')
|
2211
|
+
+ color('pending', ' %s');
|
2212
|
+
console.log(fmt, test.fullTitle());
|
2213
|
+
});
|
2214
|
+
|
2215
|
+
runner.on('pass', function(test){
|
2216
|
+
var fmt = color('checkmark', ' ✓')
|
2217
|
+
+ color('pass', ' %s: ')
|
2218
|
+
+ color(test.speed, '%dms');
|
2219
|
+
cursor.CR();
|
2220
|
+
console.log(fmt, test.fullTitle(), test.duration);
|
2221
|
+
});
|
2222
|
+
|
2223
|
+
runner.on('fail', function(test, err){
|
2224
|
+
cursor.CR();
|
2225
|
+
console.log(color('fail', ' %d) %s'), ++n, test.fullTitle());
|
2226
|
+
});
|
2227
|
+
|
2228
|
+
runner.on('end', self.epilogue.bind(self));
|
2229
|
+
}
|
2230
|
+
|
2231
|
+
/**
|
2232
|
+
* Inherit from `Base.prototype`.
|
2233
|
+
*/
|
2234
|
+
|
2235
|
+
List.prototype = new Base;
|
2236
|
+
List.prototype.constructor = List;
|
2237
|
+
|
2238
|
+
|
2239
|
+
}); // module: reporters/list.js
|
2240
|
+
|
2241
|
+
require.register("reporters/markdown.js", function(module, exports, require){
|
2242
|
+
|
2243
|
+
/**
|
2244
|
+
* Module dependencies.
|
2245
|
+
*/
|
2246
|
+
|
2247
|
+
var Base = require('./base')
|
2248
|
+
, utils = require('../utils');
|
2249
|
+
|
2250
|
+
/**
|
2251
|
+
* Expose `Markdown`.
|
2252
|
+
*/
|
2253
|
+
|
2254
|
+
exports = module.exports = Markdown;
|
2255
|
+
|
2256
|
+
/**
|
2257
|
+
* Initialize a new `Markdown` reporter.
|
2258
|
+
*
|
2259
|
+
* @param {Runner} runner
|
2260
|
+
* @api public
|
2261
|
+
*/
|
2262
|
+
|
2263
|
+
function Markdown(runner) {
|
2264
|
+
Base.call(this, runner);
|
2265
|
+
|
2266
|
+
var self = this
|
2267
|
+
, stats = this.stats
|
2268
|
+
, total = runner.total
|
2269
|
+
, level = 0
|
2270
|
+
, buf = '';
|
2271
|
+
|
2272
|
+
function title(str) {
|
2273
|
+
return Array(level).join('#') + ' ' + str;
|
2274
|
+
}
|
2275
|
+
|
2276
|
+
function indent() {
|
2277
|
+
return Array(level).join(' ');
|
2278
|
+
}
|
2279
|
+
|
2280
|
+
function mapTOC(suite, obj) {
|
2281
|
+
var ret = obj;
|
2282
|
+
obj = obj[suite.title] = obj[suite.title] || { suite: suite };
|
2283
|
+
suite.suites.forEach(function(suite){
|
2284
|
+
mapTOC(suite, obj);
|
2285
|
+
});
|
2286
|
+
return ret;
|
2287
|
+
}
|
2288
|
+
|
2289
|
+
function stringifyTOC(obj, level) {
|
2290
|
+
++level;
|
2291
|
+
var buf = '';
|
2292
|
+
var link;
|
2293
|
+
for (var key in obj) {
|
2294
|
+
if ('suite' == key) continue;
|
2295
|
+
if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
|
2296
|
+
if (key) buf += Array(level).join(' ') + link;
|
2297
|
+
buf += stringifyTOC(obj[key], level);
|
2298
|
+
}
|
2299
|
+
--level;
|
2300
|
+
return buf;
|
2301
|
+
}
|
2302
|
+
|
2303
|
+
function generateTOC(suite) {
|
2304
|
+
var obj = mapTOC(suite, {});
|
2305
|
+
return stringifyTOC(obj, 0);
|
2306
|
+
}
|
2307
|
+
|
2308
|
+
generateTOC(runner.suite);
|
2309
|
+
|
2310
|
+
runner.on('suite', function(suite){
|
2311
|
+
++level;
|
2312
|
+
var slug = utils.slug(suite.fullTitle());
|
2313
|
+
buf += '<a name="' + slug + '" />' + '\n';
|
2314
|
+
buf += title(suite.title) + '\n';
|
2315
|
+
});
|
2316
|
+
|
2317
|
+
runner.on('suite end', function(suite){
|
2318
|
+
--level;
|
2319
|
+
});
|
2320
|
+
|
2321
|
+
runner.on('pass', function(test){
|
2322
|
+
var code = clean(test.fn.toString());
|
2323
|
+
buf += test.title + '.\n';
|
2324
|
+
buf += '\n```js';
|
2325
|
+
buf += code + '\n';
|
2326
|
+
buf += '```\n\n';
|
2327
|
+
});
|
2328
|
+
|
2329
|
+
runner.on('end', function(){
|
2330
|
+
process.stdout.write('# TOC\n');
|
2331
|
+
process.stdout.write(generateTOC(runner.suite));
|
2332
|
+
process.stdout.write(buf);
|
2333
|
+
});
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
/**
|
2337
|
+
* Strip the function definition from `str`,
|
2338
|
+
* and re-indent for pre whitespace.
|
2339
|
+
*/
|
2340
|
+
|
2341
|
+
function clean(str) {
|
2342
|
+
str = str
|
2343
|
+
.replace(/^function *\(.*\) *{/, '')
|
2344
|
+
.replace(/\s+\}$/, '');
|
2345
|
+
|
2346
|
+
var spaces = str.match(/^\n?( *)/)[1].length
|
2347
|
+
, re = new RegExp('^ {' + spaces + '}', 'gm');
|
2348
|
+
|
2349
|
+
str = str.replace(re, '');
|
2350
|
+
|
2351
|
+
return str;
|
2352
|
+
}
|
2353
|
+
}); // module: reporters/markdown.js
|
2354
|
+
|
2355
|
+
require.register("reporters/min.js", function(module, exports, require){
|
2356
|
+
/**
|
2357
|
+
* Module dependencies.
|
2358
|
+
*/
|
2359
|
+
|
2360
|
+
var Base = require('./base');
|
2361
|
+
|
2362
|
+
/**
|
2363
|
+
* Expose `Min`.
|
2364
|
+
*/
|
2365
|
+
|
2366
|
+
exports = module.exports = Min;
|
2367
|
+
|
2368
|
+
/**
|
2369
|
+
* Initialize a new `Min` minimal test reporter (best used with --watch).
|
2370
|
+
*
|
2371
|
+
* @param {Runner} runner
|
2372
|
+
* @api public
|
2373
|
+
*/
|
2374
|
+
|
2375
|
+
function Min(runner) {
|
2376
|
+
Base.call(this, runner);
|
2377
|
+
|
2378
|
+
runner.on('start', function(){
|
2379
|
+
// clear screen
|
2380
|
+
process.stdout.write('\033[2J');
|
2381
|
+
// set cursor position
|
2382
|
+
process.stdout.write('\033[1;3H');
|
2383
|
+
});
|
2384
|
+
|
2385
|
+
runner.on('end', this.epilogue.bind(this));
|
2386
|
+
}
|
2387
|
+
|
2388
|
+
/**
|
2389
|
+
* Inherit from `Base.prototype`.
|
2390
|
+
*/
|
2391
|
+
|
2392
|
+
Min.prototype = new Base;
|
2393
|
+
Min.prototype.constructor = Min;
|
2394
|
+
|
2395
|
+
}); // module: reporters/min.js
|
2396
|
+
|
2397
|
+
require.register("reporters/progress.js", function(module, exports, require){
|
2398
|
+
|
2399
|
+
/**
|
2400
|
+
* Module dependencies.
|
2401
|
+
*/
|
2402
|
+
|
2403
|
+
var Base = require('./base')
|
2404
|
+
, cursor = Base.cursor
|
2405
|
+
, color = Base.color;
|
2406
|
+
|
2407
|
+
/**
|
2408
|
+
* Expose `Progress`.
|
2409
|
+
*/
|
2410
|
+
|
2411
|
+
exports = module.exports = Progress;
|
2412
|
+
|
2413
|
+
/**
|
2414
|
+
* General progress bar color.
|
2415
|
+
*/
|
2416
|
+
|
2417
|
+
Base.colors.progress = 90;
|
2418
|
+
|
2419
|
+
/**
|
2420
|
+
* Initialize a new `Progress` bar test reporter.
|
2421
|
+
*
|
2422
|
+
* @param {Runner} runner
|
2423
|
+
* @param {Object} options
|
2424
|
+
* @api public
|
2425
|
+
*/
|
2426
|
+
|
2427
|
+
function Progress(runner, options) {
|
2428
|
+
Base.call(this, runner);
|
2429
|
+
|
2430
|
+
var self = this
|
2431
|
+
, options = options || {}
|
2432
|
+
, stats = this.stats
|
2433
|
+
, width = Base.window.width * .50 | 0
|
2434
|
+
, total = runner.total
|
2435
|
+
, complete = 0
|
2436
|
+
, max = Math.max;
|
2437
|
+
|
2438
|
+
// default chars
|
2439
|
+
options.open = options.open || '[';
|
2440
|
+
options.complete = options.complete || '▬';
|
2441
|
+
options.incomplete = options.incomplete || '⋅';
|
2442
|
+
options.close = options.close || ']';
|
2443
|
+
options.verbose = false;
|
2444
|
+
|
2445
|
+
// tests started
|
2446
|
+
runner.on('start', function(){
|
2447
|
+
console.log();
|
2448
|
+
cursor.hide();
|
2449
|
+
});
|
2450
|
+
|
2451
|
+
// tests complete
|
2452
|
+
runner.on('test end', function(){
|
2453
|
+
var incomplete = total - complete
|
2454
|
+
, percent = complete++ / total
|
2455
|
+
, n = width * percent | 0
|
2456
|
+
, i = width - n;
|
2457
|
+
|
2458
|
+
cursor.CR();
|
2459
|
+
process.stdout.write('\033[J');
|
2460
|
+
process.stdout.write(color('progress', ' ' + options.open));
|
2461
|
+
process.stdout.write(Array(n).join(options.complete));
|
2462
|
+
process.stdout.write(Array(i).join(options.incomplete));
|
2463
|
+
process.stdout.write(color('progress', options.close));
|
2464
|
+
if (options.verbose) {
|
2465
|
+
process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
|
2466
|
+
}
|
2467
|
+
});
|
2468
|
+
|
2469
|
+
// tests are complete, output some stats
|
2470
|
+
// and the failures if any
|
2471
|
+
runner.on('end', function(){
|
2472
|
+
cursor.show();
|
2473
|
+
console.log();
|
2474
|
+
self.epilogue();
|
2475
|
+
});
|
2476
|
+
}
|
2477
|
+
|
2478
|
+
/**
|
2479
|
+
* Inherit from `Base.prototype`.
|
2480
|
+
*/
|
2481
|
+
|
2482
|
+
Progress.prototype = new Base;
|
2483
|
+
Progress.prototype.constructor = Progress;
|
2484
|
+
|
2485
|
+
|
2486
|
+
}); // module: reporters/progress.js
|
2487
|
+
|
2488
|
+
require.register("reporters/spec.js", function(module, exports, require){
|
2489
|
+
|
2490
|
+
/**
|
2491
|
+
* Module dependencies.
|
2492
|
+
*/
|
2493
|
+
|
2494
|
+
var Base = require('./base')
|
2495
|
+
, cursor = Base.cursor
|
2496
|
+
, color = Base.color;
|
2497
|
+
|
2498
|
+
/**
|
2499
|
+
* Expose `Spec`.
|
2500
|
+
*/
|
2501
|
+
|
2502
|
+
exports = module.exports = Spec;
|
2503
|
+
|
2504
|
+
/**
|
2505
|
+
* Initialize a new `Spec` test reporter.
|
2506
|
+
*
|
2507
|
+
* @param {Runner} runner
|
2508
|
+
* @api public
|
2509
|
+
*/
|
2510
|
+
|
2511
|
+
function Spec(runner) {
|
2512
|
+
Base.call(this, runner);
|
2513
|
+
|
2514
|
+
var self = this
|
2515
|
+
, stats = this.stats
|
2516
|
+
, indents = 0
|
2517
|
+
, n = 0;
|
2518
|
+
|
2519
|
+
function indent() {
|
2520
|
+
return Array(indents).join(' ')
|
2521
|
+
}
|
2522
|
+
|
2523
|
+
runner.on('start', function(){
|
2524
|
+
console.log();
|
2525
|
+
});
|
2526
|
+
|
2527
|
+
runner.on('suite', function(suite){
|
2528
|
+
++indents;
|
2529
|
+
console.log(color('suite', '%s%s'), indent(), suite.title);
|
2530
|
+
});
|
2531
|
+
|
2532
|
+
runner.on('suite end', function(suite){
|
2533
|
+
--indents;
|
2534
|
+
if (1 == indents) console.log();
|
2535
|
+
});
|
2536
|
+
|
2537
|
+
runner.on('test', function(test){
|
2538
|
+
process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': '));
|
2539
|
+
});
|
2540
|
+
|
2541
|
+
runner.on('pending', function(test){
|
2542
|
+
var fmt = indent() + color('pending', ' - %s');
|
2543
|
+
console.log(fmt, test.title);
|
2544
|
+
});
|
2545
|
+
|
2546
|
+
runner.on('pass', function(test){
|
2547
|
+
if ('fast' == test.speed) {
|
2548
|
+
var fmt = indent()
|
2549
|
+
+ color('checkmark', ' ✓')
|
2550
|
+
+ color('pass', ' %s ');
|
2551
|
+
cursor.CR();
|
2552
|
+
console.log(fmt, test.title);
|
2553
|
+
} else {
|
2554
|
+
var fmt = indent()
|
2555
|
+
+ color('checkmark', ' ✓')
|
2556
|
+
+ color('pass', ' %s ')
|
2557
|
+
+ color(test.speed, '(%dms)');
|
2558
|
+
cursor.CR();
|
2559
|
+
console.log(fmt, test.title, test.duration);
|
2560
|
+
}
|
2561
|
+
});
|
2562
|
+
|
2563
|
+
runner.on('fail', function(test, err){
|
2564
|
+
cursor.CR();
|
2565
|
+
console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
|
2566
|
+
});
|
2567
|
+
|
2568
|
+
runner.on('end', self.epilogue.bind(self));
|
2569
|
+
}
|
2570
|
+
|
2571
|
+
/**
|
2572
|
+
* Inherit from `Base.prototype`.
|
2573
|
+
*/
|
2574
|
+
|
2575
|
+
Spec.prototype = new Base;
|
2576
|
+
Spec.prototype.constructor = Spec;
|
2577
|
+
|
2578
|
+
|
2579
|
+
}); // module: reporters/spec.js
|
2580
|
+
|
2581
|
+
require.register("reporters/tap.js", function(module, exports, require){
|
2582
|
+
|
2583
|
+
/**
|
2584
|
+
* Module dependencies.
|
2585
|
+
*/
|
2586
|
+
|
2587
|
+
var Base = require('./base')
|
2588
|
+
, cursor = Base.cursor
|
2589
|
+
, color = Base.color;
|
2590
|
+
|
2591
|
+
/**
|
2592
|
+
* Expose `TAP`.
|
2593
|
+
*/
|
2594
|
+
|
2595
|
+
exports = module.exports = TAP;
|
2596
|
+
|
2597
|
+
/**
|
2598
|
+
* Initialize a new `TAP` reporter.
|
2599
|
+
*
|
2600
|
+
* @param {Runner} runner
|
2601
|
+
* @api public
|
2602
|
+
*/
|
2603
|
+
|
2604
|
+
function TAP(runner) {
|
2605
|
+
Base.call(this, runner);
|
2606
|
+
|
2607
|
+
var self = this
|
2608
|
+
, stats = this.stats
|
2609
|
+
, total = runner.total
|
2610
|
+
, n = 1;
|
2611
|
+
|
2612
|
+
runner.on('start', function(){
|
2613
|
+
console.log('%d..%d', 1, total);
|
2614
|
+
});
|
2615
|
+
|
2616
|
+
runner.on('test end', function(){
|
2617
|
+
++n;
|
2618
|
+
});
|
2619
|
+
|
2620
|
+
runner.on('pending', function(test){
|
2621
|
+
console.log('ok %d %s # SKIP -', n, title(test));
|
2622
|
+
});
|
2623
|
+
|
2624
|
+
runner.on('pass', function(test){
|
2625
|
+
console.log('ok %d %s', n, title(test));
|
2626
|
+
});
|
2627
|
+
|
2628
|
+
runner.on('fail', function(test, err){
|
2629
|
+
console.log('not ok %d %s', n, title(test));
|
2630
|
+
console.log(err.stack.replace(/^/gm, ' '));
|
2631
|
+
});
|
2632
|
+
}
|
2633
|
+
|
2634
|
+
/**
|
2635
|
+
* Return a TAP-safe title of `test`
|
2636
|
+
*
|
2637
|
+
* @param {Object} test
|
2638
|
+
* @return {String}
|
2639
|
+
* @api private
|
2640
|
+
*/
|
2641
|
+
|
2642
|
+
function title(test) {
|
2643
|
+
return test.fullTitle().replace(/#/g, '');
|
2644
|
+
}
|
2645
|
+
|
2646
|
+
}); // module: reporters/tap.js
|
2647
|
+
|
2648
|
+
require.register("reporters/teamcity.js", function(module, exports, require){
|
2649
|
+
|
2650
|
+
/**
|
2651
|
+
* Module dependencies.
|
2652
|
+
*/
|
2653
|
+
|
2654
|
+
var Base = require('./base');
|
2655
|
+
|
2656
|
+
/**
|
2657
|
+
* Expose `Teamcity`.
|
2658
|
+
*/
|
2659
|
+
|
2660
|
+
exports = module.exports = Teamcity;
|
2661
|
+
|
2662
|
+
/**
|
2663
|
+
* Initialize a new `Teamcity` reporter.
|
2664
|
+
*
|
2665
|
+
* @param {Runner} runner
|
2666
|
+
* @api public
|
2667
|
+
*/
|
2668
|
+
|
2669
|
+
function Teamcity(runner) {
|
2670
|
+
Base.call(this, runner);
|
2671
|
+
var stats = this.stats;
|
2672
|
+
|
2673
|
+
runner.on('start', function() {
|
2674
|
+
console.log("##teamcity[testSuiteStarted name='mocha.suite']");
|
2675
|
+
});
|
2676
|
+
|
2677
|
+
runner.on('test', function(test) {
|
2678
|
+
console.log("##teamcity[testStarted name='%s']", escape(test.fullTitle()));
|
2679
|
+
});
|
2680
|
+
|
2681
|
+
runner.on('fail', function(test, err) {
|
2682
|
+
console.log("##teamcity[testFailed name='%s' message='%s']", escape(test.fullTitle()), escape(err.message));
|
2683
|
+
});
|
2684
|
+
|
2685
|
+
runner.on('pending', function(test) {
|
2686
|
+
console.log("##teamcity[testIgnored name='%s' message='pending']", escape(test.fullTitle()));
|
2687
|
+
});
|
2688
|
+
|
2689
|
+
runner.on('test end', function(test) {
|
2690
|
+
console.log("##teamcity[testFinished name='%s' duration='%s']", escape(test.fullTitle()), test.duration);
|
2691
|
+
});
|
2692
|
+
|
2693
|
+
runner.on('end', function() {
|
2694
|
+
console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='%s']", stats.duration);
|
2695
|
+
});
|
2696
|
+
}
|
2697
|
+
|
2698
|
+
/**
|
2699
|
+
* Escape the given `str`.
|
2700
|
+
*/
|
2701
|
+
|
2702
|
+
function escape(str) {
|
2703
|
+
return str.replace(/'/g, "|'");
|
2704
|
+
}
|
2705
|
+
}); // module: reporters/teamcity.js
|
2706
|
+
|
2707
|
+
require.register("reporters/xunit.js", function(module, exports, require){
|
2708
|
+
|
2709
|
+
/**
|
2710
|
+
* Module dependencies.
|
2711
|
+
*/
|
2712
|
+
|
2713
|
+
var Base = require('./base')
|
2714
|
+
, utils = require('../utils')
|
2715
|
+
, escape = utils.escape;
|
2716
|
+
|
2717
|
+
/**
|
2718
|
+
* Expose `XUnit`.
|
2719
|
+
*/
|
2720
|
+
|
2721
|
+
exports = module.exports = XUnit;
|
2722
|
+
|
2723
|
+
/**
|
2724
|
+
* Initialize a new `XUnit` reporter.
|
2725
|
+
*
|
2726
|
+
* @param {Runner} runner
|
2727
|
+
* @api public
|
2728
|
+
*/
|
2729
|
+
|
2730
|
+
function XUnit(runner) {
|
2731
|
+
Base.call(this, runner);
|
2732
|
+
var stats = this.stats
|
2733
|
+
, tests = []
|
2734
|
+
, self = this;
|
2735
|
+
|
2736
|
+
runner.on('test end', function(test){
|
2737
|
+
tests.push(test);
|
2738
|
+
});
|
2739
|
+
|
2740
|
+
runner.on('end', function(){
|
2741
|
+
console.log(tag('testsuite', {
|
2742
|
+
name: 'Mocha Tests'
|
2743
|
+
, tests: stats.tests
|
2744
|
+
, failures: stats.failures
|
2745
|
+
, errors: stats.failures
|
2746
|
+
, skip: stats.tests - stats.failures - stats.passes
|
2747
|
+
, timestamp: (new Date).toUTCString()
|
2748
|
+
, time: stats.duration / 1000
|
2749
|
+
}, false));
|
2750
|
+
|
2751
|
+
tests.forEach(test);
|
2752
|
+
console.log('</testsuite>');
|
2753
|
+
});
|
2754
|
+
}
|
2755
|
+
|
2756
|
+
/**
|
2757
|
+
* Inherit from `Base.prototype`.
|
2758
|
+
*/
|
2759
|
+
|
2760
|
+
XUnit.prototype = new Base;
|
2761
|
+
XUnit.prototype.constructor = XUnit;
|
2762
|
+
|
2763
|
+
|
2764
|
+
/**
|
2765
|
+
* Output tag for the given `test.`
|
2766
|
+
*/
|
2767
|
+
|
2768
|
+
function test(test) {
|
2769
|
+
var attrs = {
|
2770
|
+
classname: test.parent.fullTitle()
|
2771
|
+
, name: test.title
|
2772
|
+
, time: test.duration / 1000
|
2773
|
+
};
|
2774
|
+
|
2775
|
+
if ('failed' == test.state) {
|
2776
|
+
var err = test.err;
|
2777
|
+
attrs.message = escape(err.message);
|
2778
|
+
console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
|
2779
|
+
} else if (test.pending) {
|
2780
|
+
console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
|
2781
|
+
} else {
|
2782
|
+
console.log(tag('testcase', attrs, true) );
|
2783
|
+
}
|
2784
|
+
}
|
2785
|
+
|
2786
|
+
/**
|
2787
|
+
* HTML tag helper.
|
2788
|
+
*/
|
2789
|
+
|
2790
|
+
function tag(name, attrs, close, content) {
|
2791
|
+
var end = close ? '/>' : '>'
|
2792
|
+
, pairs = []
|
2793
|
+
, tag;
|
2794
|
+
|
2795
|
+
for (var key in attrs) {
|
2796
|
+
pairs.push(key + '="' + escape(attrs[key]) + '"');
|
2797
|
+
}
|
2798
|
+
|
2799
|
+
tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
|
2800
|
+
if (content) tag += content + '</' + name + end;
|
2801
|
+
return tag;
|
2802
|
+
}
|
2803
|
+
|
2804
|
+
/**
|
2805
|
+
* Return cdata escaped CDATA `str`.
|
2806
|
+
*/
|
2807
|
+
|
2808
|
+
function cdata(str) {
|
2809
|
+
return '<![CDATA[' + escape(str) + ']]>';
|
2810
|
+
}
|
2811
|
+
|
2812
|
+
}); // module: reporters/xunit.js
|
2813
|
+
|
2814
|
+
require.register("runnable.js", function(module, exports, require){
|
2815
|
+
|
2816
|
+
/**
|
2817
|
+
* Module dependencies.
|
2818
|
+
*/
|
2819
|
+
|
2820
|
+
var EventEmitter = require('browser/events').EventEmitter
|
2821
|
+
, debug = require('browser/debug')('runnable');
|
2822
|
+
|
2823
|
+
/**
|
2824
|
+
* Expose `Runnable`.
|
2825
|
+
*/
|
2826
|
+
|
2827
|
+
module.exports = Runnable;
|
2828
|
+
|
2829
|
+
/**
|
2830
|
+
* Initialize a new `Runnable` with the given `title` and callback `fn`.
|
2831
|
+
*
|
2832
|
+
* @param {String} title
|
2833
|
+
* @param {Function} fn
|
2834
|
+
* @api private
|
2835
|
+
*/
|
2836
|
+
|
2837
|
+
function Runnable(title, fn) {
|
2838
|
+
this.title = title;
|
2839
|
+
this.fn = fn;
|
2840
|
+
this.async = fn && fn.length;
|
2841
|
+
this.sync = ! this.async;
|
2842
|
+
this._timeout = 2000;
|
2843
|
+
this.timedOut = false;
|
2844
|
+
}
|
2845
|
+
|
2846
|
+
/**
|
2847
|
+
* Inherit from `EventEmitter.prototype`.
|
2848
|
+
*/
|
2849
|
+
|
2850
|
+
Runnable.prototype = new EventEmitter;
|
2851
|
+
Runnable.prototype.constructor = Runnable;
|
2852
|
+
|
2853
|
+
|
2854
|
+
/**
|
2855
|
+
* Set & get timeout `ms`.
|
2856
|
+
*
|
2857
|
+
* @param {Number} ms
|
2858
|
+
* @return {Runnable|Number} ms or self
|
2859
|
+
* @api private
|
2860
|
+
*/
|
2861
|
+
|
2862
|
+
Runnable.prototype.timeout = function(ms){
|
2863
|
+
if (0 == arguments.length) return this._timeout;
|
2864
|
+
debug('timeout %d', ms);
|
2865
|
+
this._timeout = ms;
|
2866
|
+
if (this.timer) this.resetTimeout();
|
2867
|
+
return this;
|
2868
|
+
};
|
2869
|
+
|
2870
|
+
/**
|
2871
|
+
* Return the full title generated by recursively
|
2872
|
+
* concatenating the parent's full title.
|
2873
|
+
*
|
2874
|
+
* @return {String}
|
2875
|
+
* @api public
|
2876
|
+
*/
|
2877
|
+
|
2878
|
+
Runnable.prototype.fullTitle = function(){
|
2879
|
+
return this.parent.fullTitle() + ' ' + this.title;
|
2880
|
+
};
|
2881
|
+
|
2882
|
+
/**
|
2883
|
+
* Clear the timeout.
|
2884
|
+
*
|
2885
|
+
* @api private
|
2886
|
+
*/
|
2887
|
+
|
2888
|
+
Runnable.prototype.clearTimeout = function(){
|
2889
|
+
clearTimeout(this.timer);
|
2890
|
+
};
|
2891
|
+
|
2892
|
+
/**
|
2893
|
+
* Reset the timeout.
|
2894
|
+
*
|
2895
|
+
* @api private
|
2896
|
+
*/
|
2897
|
+
|
2898
|
+
Runnable.prototype.resetTimeout = function(){
|
2899
|
+
var self = this
|
2900
|
+
, ms = this.timeout();
|
2901
|
+
|
2902
|
+
this.clearTimeout();
|
2903
|
+
if (ms) {
|
2904
|
+
this.timer = setTimeout(function(){
|
2905
|
+
self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
|
2906
|
+
self.timedOut = true;
|
2907
|
+
}, ms);
|
2908
|
+
}
|
2909
|
+
};
|
2910
|
+
|
2911
|
+
/**
|
2912
|
+
* Run the test and invoke `fn(err)`.
|
2913
|
+
*
|
2914
|
+
* @param {Function} fn
|
2915
|
+
* @api private
|
2916
|
+
*/
|
2917
|
+
|
2918
|
+
Runnable.prototype.run = function(fn){
|
2919
|
+
var self = this
|
2920
|
+
, ms = this.timeout()
|
2921
|
+
, start = new Date
|
2922
|
+
, ctx = this.ctx
|
2923
|
+
, finished
|
2924
|
+
, emitted;
|
2925
|
+
|
2926
|
+
// timeout
|
2927
|
+
if (this.async) {
|
2928
|
+
if (ms) {
|
2929
|
+
this.timer = setTimeout(function(){
|
2930
|
+
done(new Error('timeout of ' + ms + 'ms exceeded'));
|
2931
|
+
self.timedOut = true;
|
2932
|
+
}, ms);
|
2933
|
+
}
|
2934
|
+
}
|
2935
|
+
|
2936
|
+
// called multiple times
|
2937
|
+
function multiple() {
|
2938
|
+
if (emitted) return;
|
2939
|
+
emitted = true;
|
2940
|
+
self.emit('error', new Error('done() called multiple times'));
|
2941
|
+
}
|
2942
|
+
|
2943
|
+
// finished
|
2944
|
+
function done(err) {
|
2945
|
+
if (self.timedOut) return;
|
2946
|
+
if (finished) return multiple();
|
2947
|
+
self.clearTimeout();
|
2948
|
+
self.duration = new Date - start;
|
2949
|
+
finished = true;
|
2950
|
+
fn(err);
|
2951
|
+
}
|
2952
|
+
|
2953
|
+
// for .resetTimeout()
|
2954
|
+
this.callback = done;
|
2955
|
+
|
2956
|
+
// async
|
2957
|
+
if (this.async) {
|
2958
|
+
try {
|
2959
|
+
this.fn.call(ctx, function(err){
|
2960
|
+
if (err instanceof Error) return done(err);
|
2961
|
+
if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
|
2962
|
+
done();
|
2963
|
+
});
|
2964
|
+
} catch (err) {
|
2965
|
+
done(err);
|
2966
|
+
}
|
2967
|
+
return;
|
2968
|
+
}
|
2969
|
+
|
2970
|
+
// sync
|
2971
|
+
try {
|
2972
|
+
if (!this.pending) this.fn.call(ctx);
|
2973
|
+
this.duration = new Date - start;
|
2974
|
+
fn();
|
2975
|
+
} catch (err) {
|
2976
|
+
fn(err);
|
2977
|
+
}
|
2978
|
+
};
|
2979
|
+
|
2980
|
+
}); // module: runnable.js
|
2981
|
+
|
2982
|
+
require.register("runner.js", function(module, exports, require){
|
2983
|
+
|
2984
|
+
/**
|
2985
|
+
* Module dependencies.
|
2986
|
+
*/
|
2987
|
+
|
2988
|
+
var EventEmitter = require('browser/events').EventEmitter
|
2989
|
+
, debug = require('browser/debug')('runner')
|
2990
|
+
, Test = require('./test')
|
2991
|
+
, utils = require('./utils')
|
2992
|
+
, noop = function(){};
|
2993
|
+
|
2994
|
+
/**
|
2995
|
+
* Expose `Runner`.
|
2996
|
+
*/
|
2997
|
+
|
2998
|
+
module.exports = Runner;
|
2999
|
+
|
3000
|
+
/**
|
3001
|
+
* Initialize a `Runner` for the given `suite`.
|
3002
|
+
*
|
3003
|
+
* Events:
|
3004
|
+
*
|
3005
|
+
* - `start` execution started
|
3006
|
+
* - `end` execution complete
|
3007
|
+
* - `suite` (suite) test suite execution started
|
3008
|
+
* - `suite end` (suite) all tests (and sub-suites) have finished
|
3009
|
+
* - `test` (test) test execution started
|
3010
|
+
* - `test end` (test) test completed
|
3011
|
+
* - `hook` (hook) hook execution started
|
3012
|
+
* - `hook end` (hook) hook complete
|
3013
|
+
* - `pass` (test) test passed
|
3014
|
+
* - `fail` (test, err) test failed
|
3015
|
+
*
|
3016
|
+
* @api public
|
3017
|
+
*/
|
3018
|
+
|
3019
|
+
function Runner(suite) {
|
3020
|
+
var self = this;
|
3021
|
+
this._globals = [];
|
3022
|
+
this.suite = suite;
|
3023
|
+
this.total = suite.total();
|
3024
|
+
this.failures = 0;
|
3025
|
+
this.on('test end', function(test){ self.checkGlobals(test); });
|
3026
|
+
this.on('hook end', function(hook){ self.checkGlobals(hook); });
|
3027
|
+
this.grep(/.*/);
|
3028
|
+
this.globals(utils.keys(global).concat(['errno']));
|
3029
|
+
}
|
3030
|
+
|
3031
|
+
/**
|
3032
|
+
* Inherit from `EventEmitter.prototype`.
|
3033
|
+
*/
|
3034
|
+
|
3035
|
+
Runner.prototype = new EventEmitter;
|
3036
|
+
Runner.prototype.constructor = Runner;
|
3037
|
+
|
3038
|
+
|
3039
|
+
/**
|
3040
|
+
* Run tests with full titles matching `re`.
|
3041
|
+
*
|
3042
|
+
* @param {RegExp} re
|
3043
|
+
* @return {Runner} for chaining
|
3044
|
+
* @api public
|
3045
|
+
*/
|
3046
|
+
|
3047
|
+
Runner.prototype.grep = function(re){
|
3048
|
+
debug('grep %s', re);
|
3049
|
+
this._grep = re;
|
3050
|
+
return this;
|
3051
|
+
};
|
3052
|
+
|
3053
|
+
/**
|
3054
|
+
* Allow the given `arr` of globals.
|
3055
|
+
*
|
3056
|
+
* @param {Array} arr
|
3057
|
+
* @return {Runner} for chaining
|
3058
|
+
* @api public
|
3059
|
+
*/
|
3060
|
+
|
3061
|
+
Runner.prototype.globals = function(arr){
|
3062
|
+
if (0 == arguments.length) return this._globals;
|
3063
|
+
debug('globals %j', arr);
|
3064
|
+
utils.forEach(arr, function(arr){
|
3065
|
+
this._globals.push(arr);
|
3066
|
+
}, this);
|
3067
|
+
return this;
|
3068
|
+
};
|
3069
|
+
|
3070
|
+
/**
|
3071
|
+
* Check for global variable leaks.
|
3072
|
+
*
|
3073
|
+
* @api private
|
3074
|
+
*/
|
3075
|
+
|
3076
|
+
Runner.prototype.checkGlobals = function(test){
|
3077
|
+
if (this.ignoreLeaks) return;
|
3078
|
+
|
3079
|
+
var leaks = utils.filter(utils.keys(global), function(key){
|
3080
|
+
return !~utils.indexOf(this._globals, key) && (!global.navigator || 'onerror' !== key);
|
3081
|
+
}, this);
|
3082
|
+
|
3083
|
+
this._globals = this._globals.concat(leaks);
|
3084
|
+
|
3085
|
+
if (leaks.length > 1) {
|
3086
|
+
this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
|
3087
|
+
} else if (leaks.length) {
|
3088
|
+
this.fail(test, new Error('global leak detected: ' + leaks[0]));
|
3089
|
+
}
|
3090
|
+
};
|
3091
|
+
|
3092
|
+
/**
|
3093
|
+
* Fail the given `test`.
|
3094
|
+
*
|
3095
|
+
* @param {Test} test
|
3096
|
+
* @param {Error} err
|
3097
|
+
* @api private
|
3098
|
+
*/
|
3099
|
+
|
3100
|
+
Runner.prototype.fail = function(test, err){
|
3101
|
+
++this.failures;
|
3102
|
+
test.state = 'failed';
|
3103
|
+
this.emit('fail', test, err);
|
3104
|
+
};
|
3105
|
+
|
3106
|
+
/**
|
3107
|
+
* Fail the given `hook` with `err`.
|
3108
|
+
*
|
3109
|
+
* Hook failures (currently) hard-end due
|
3110
|
+
* to that fact that a failing hook will
|
3111
|
+
* surely cause subsequent tests to fail,
|
3112
|
+
* causing jumbled reporting.
|
3113
|
+
*
|
3114
|
+
* @param {Hook} hook
|
3115
|
+
* @param {Error} err
|
3116
|
+
* @api private
|
3117
|
+
*/
|
3118
|
+
|
3119
|
+
Runner.prototype.failHook = function(hook, err){
|
3120
|
+
this.fail(hook, err);
|
3121
|
+
this.emit('end');
|
3122
|
+
};
|
3123
|
+
|
3124
|
+
/**
|
3125
|
+
* Run hook `name` callbacks and then invoke `fn()`.
|
3126
|
+
*
|
3127
|
+
* @param {String} name
|
3128
|
+
* @param {Function} function
|
3129
|
+
* @api private
|
3130
|
+
*/
|
3131
|
+
|
3132
|
+
Runner.prototype.hook = function(name, fn){
|
3133
|
+
var suite = this.suite
|
3134
|
+
, hooks = suite['_' + name]
|
3135
|
+
, ms = suite._timeout
|
3136
|
+
, self = this
|
3137
|
+
, timer;
|
3138
|
+
|
3139
|
+
function next(i) {
|
3140
|
+
var hook = hooks[i];
|
3141
|
+
if (!hook) return fn();
|
3142
|
+
self.currentRunnable = hook;
|
3143
|
+
hook.ctx.test(self.test);
|
3144
|
+
|
3145
|
+
self.emit('hook', hook);
|
3146
|
+
|
3147
|
+
hook.on('error', function(err){
|
3148
|
+
self.failHook(hook, err);
|
3149
|
+
});
|
3150
|
+
|
3151
|
+
hook.run(function(err){
|
3152
|
+
hook.removeAllListeners('error');
|
3153
|
+
if (err) return self.failHook(hook, err);
|
3154
|
+
self.emit('hook end', hook);
|
3155
|
+
next(++i);
|
3156
|
+
});
|
3157
|
+
}
|
3158
|
+
|
3159
|
+
process.nextTick(function(){
|
3160
|
+
next(0);
|
3161
|
+
});
|
3162
|
+
};
|
3163
|
+
|
3164
|
+
/**
|
3165
|
+
* Run hook `name` for the given array of `suites`
|
3166
|
+
* in order, and callback `fn(err)`.
|
3167
|
+
*
|
3168
|
+
* @param {String} name
|
3169
|
+
* @param {Array} suites
|
3170
|
+
* @param {Function} fn
|
3171
|
+
* @api private
|
3172
|
+
*/
|
3173
|
+
|
3174
|
+
Runner.prototype.hooks = function(name, suites, fn){
|
3175
|
+
var self = this
|
3176
|
+
, orig = this.suite;
|
3177
|
+
|
3178
|
+
function next(suite) {
|
3179
|
+
self.suite = suite;
|
3180
|
+
|
3181
|
+
if (!suite) {
|
3182
|
+
self.suite = orig;
|
3183
|
+
return fn();
|
3184
|
+
}
|
3185
|
+
|
3186
|
+
self.hook(name, function(err){
|
3187
|
+
if (err) {
|
3188
|
+
self.suite = orig;
|
3189
|
+
return fn(err);
|
3190
|
+
}
|
3191
|
+
|
3192
|
+
next(suites.pop());
|
3193
|
+
});
|
3194
|
+
}
|
3195
|
+
|
3196
|
+
next(suites.pop());
|
3197
|
+
};
|
3198
|
+
|
3199
|
+
/**
|
3200
|
+
* Run hooks from the top level down.
|
3201
|
+
*
|
3202
|
+
* @param {String} name
|
3203
|
+
* @param {Function} fn
|
3204
|
+
* @api private
|
3205
|
+
*/
|
3206
|
+
|
3207
|
+
Runner.prototype.hookUp = function(name, fn){
|
3208
|
+
var suites = [this.suite].concat(this.parents()).reverse();
|
3209
|
+
this.hooks(name, suites, fn);
|
3210
|
+
};
|
3211
|
+
|
3212
|
+
/**
|
3213
|
+
* Run hooks from the bottom up.
|
3214
|
+
*
|
3215
|
+
* @param {String} name
|
3216
|
+
* @param {Function} fn
|
3217
|
+
* @api private
|
3218
|
+
*/
|
3219
|
+
|
3220
|
+
Runner.prototype.hookDown = function(name, fn){
|
3221
|
+
var suites = [this.suite].concat(this.parents());
|
3222
|
+
this.hooks(name, suites, fn);
|
3223
|
+
};
|
3224
|
+
|
3225
|
+
/**
|
3226
|
+
* Return an array of parent Suites from
|
3227
|
+
* closest to furthest.
|
3228
|
+
*
|
3229
|
+
* @return {Array}
|
3230
|
+
* @api private
|
3231
|
+
*/
|
3232
|
+
|
3233
|
+
Runner.prototype.parents = function(){
|
3234
|
+
var suite = this.suite
|
3235
|
+
, suites = [];
|
3236
|
+
while (suite = suite.parent) suites.push(suite);
|
3237
|
+
return suites;
|
3238
|
+
};
|
3239
|
+
|
3240
|
+
/**
|
3241
|
+
* Run the current test and callback `fn(err)`.
|
3242
|
+
*
|
3243
|
+
* @param {Function} fn
|
3244
|
+
* @api private
|
3245
|
+
*/
|
3246
|
+
|
3247
|
+
Runner.prototype.runTest = function(fn){
|
3248
|
+
var test = this.test
|
3249
|
+
, self = this;
|
3250
|
+
|
3251
|
+
try {
|
3252
|
+
test.ctx.test(test);
|
3253
|
+
test.on('error', function(err){
|
3254
|
+
self.fail(test, err);
|
3255
|
+
});
|
3256
|
+
test.run(fn);
|
3257
|
+
} catch (err) {
|
3258
|
+
fn(err);
|
3259
|
+
}
|
3260
|
+
};
|
3261
|
+
|
3262
|
+
/**
|
3263
|
+
* Run tests in the given `suite` and invoke
|
3264
|
+
* the callback `fn()` when complete.
|
3265
|
+
*
|
3266
|
+
* @param {Suite} suite
|
3267
|
+
* @param {Function} fn
|
3268
|
+
* @api private
|
3269
|
+
*/
|
3270
|
+
|
3271
|
+
Runner.prototype.runTests = function(suite, fn){
|
3272
|
+
var self = this
|
3273
|
+
, tests = suite.tests
|
3274
|
+
, test;
|
3275
|
+
|
3276
|
+
function next(err) {
|
3277
|
+
// if we bail after first err
|
3278
|
+
if (self.failures && suite._bail) return fn();
|
3279
|
+
|
3280
|
+
// next test
|
3281
|
+
test = tests.shift();
|
3282
|
+
|
3283
|
+
// all done
|
3284
|
+
if (!test) return fn();
|
3285
|
+
|
3286
|
+
// grep
|
3287
|
+
if (!self._grep.test(test.fullTitle())) return next();
|
3288
|
+
|
3289
|
+
// pending
|
3290
|
+
if (test.pending) {
|
3291
|
+
self.emit('pending', test);
|
3292
|
+
self.emit('test end', test);
|
3293
|
+
return next();
|
3294
|
+
}
|
3295
|
+
|
3296
|
+
// execute test and hook(s)
|
3297
|
+
self.emit('test', self.test = test);
|
3298
|
+
self.hookDown('beforeEach', function(){
|
3299
|
+
self.currentRunnable = self.test;
|
3300
|
+
self.runTest(function(err){
|
3301
|
+
test = self.test;
|
3302
|
+
|
3303
|
+
if (err) {
|
3304
|
+
self.fail(test, err);
|
3305
|
+
self.emit('test end', test);
|
3306
|
+
return self.hookUp('afterEach', next);
|
3307
|
+
}
|
3308
|
+
|
3309
|
+
test.state = 'passed';
|
3310
|
+
self.emit('pass', test);
|
3311
|
+
self.emit('test end', test);
|
3312
|
+
self.hookUp('afterEach', next);
|
3313
|
+
});
|
3314
|
+
});
|
3315
|
+
}
|
3316
|
+
|
3317
|
+
this.next = next;
|
3318
|
+
next();
|
3319
|
+
};
|
3320
|
+
|
3321
|
+
/**
|
3322
|
+
* Run the given `suite` and invoke the
|
3323
|
+
* callback `fn()` when complete.
|
3324
|
+
*
|
3325
|
+
* @param {Suite} suite
|
3326
|
+
* @param {Function} fn
|
3327
|
+
* @api private
|
3328
|
+
*/
|
3329
|
+
|
3330
|
+
Runner.prototype.runSuite = function(suite, fn){
|
3331
|
+
var self = this
|
3332
|
+
, i = 0;
|
3333
|
+
|
3334
|
+
debug('run suite %s', suite.fullTitle());
|
3335
|
+
this.emit('suite', this.suite = suite);
|
3336
|
+
|
3337
|
+
function next() {
|
3338
|
+
var curr = suite.suites[i++];
|
3339
|
+
if (!curr) return done();
|
3340
|
+
self.runSuite(curr, next);
|
3341
|
+
}
|
3342
|
+
|
3343
|
+
function done() {
|
3344
|
+
self.suite = suite;
|
3345
|
+
self.hook('afterAll', function(){
|
3346
|
+
self.emit('suite end', suite);
|
3347
|
+
fn();
|
3348
|
+
});
|
3349
|
+
}
|
3350
|
+
|
3351
|
+
this.hook('beforeAll', function(){
|
3352
|
+
self.runTests(suite, next);
|
3353
|
+
});
|
3354
|
+
};
|
3355
|
+
|
3356
|
+
/**
|
3357
|
+
* Handle uncaught exceptions.
|
3358
|
+
*
|
3359
|
+
* @param {Error} err
|
3360
|
+
* @api private
|
3361
|
+
*/
|
3362
|
+
|
3363
|
+
Runner.prototype.uncaught = function(err){
|
3364
|
+
debug('uncaught exception');
|
3365
|
+
var runnable = this.currentRunnable;
|
3366
|
+
if ('failed' == runnable.state) return;
|
3367
|
+
runnable.clearTimeout();
|
3368
|
+
err.uncaught = true;
|
3369
|
+
this.fail(runnable, err);
|
3370
|
+
|
3371
|
+
// recover from test
|
3372
|
+
if ('test' == runnable.type) {
|
3373
|
+
this.emit('test end', runnable);
|
3374
|
+
this.hookUp('afterEach', this.next);
|
3375
|
+
return;
|
3376
|
+
}
|
3377
|
+
|
3378
|
+
// bail on hooks
|
3379
|
+
this.emit('end');
|
3380
|
+
};
|
3381
|
+
|
3382
|
+
/**
|
3383
|
+
* Run the root suite and invoke `fn(failures)`
|
3384
|
+
* on completion.
|
3385
|
+
*
|
3386
|
+
* @param {Function} fn
|
3387
|
+
* @return {Runner} for chaining
|
3388
|
+
* @api public
|
3389
|
+
*/
|
3390
|
+
|
3391
|
+
Runner.prototype.run = function(fn){
|
3392
|
+
var self = this
|
3393
|
+
, fn = fn || function(){};
|
3394
|
+
|
3395
|
+
debug('start');
|
3396
|
+
|
3397
|
+
// callback
|
3398
|
+
this.on('end', function(){
|
3399
|
+
debug('end');
|
3400
|
+
process.removeListener('uncaughtException', this.uncaught);
|
3401
|
+
fn(self.failures);
|
3402
|
+
});
|
3403
|
+
|
3404
|
+
// run suites
|
3405
|
+
this.emit('start');
|
3406
|
+
this.runSuite(this.suite, function(){
|
3407
|
+
debug('finished running');
|
3408
|
+
self.emit('end');
|
3409
|
+
});
|
3410
|
+
|
3411
|
+
// uncaught exception
|
3412
|
+
process.on('uncaughtException', function(err){
|
3413
|
+
self.uncaught(err);
|
3414
|
+
});
|
3415
|
+
|
3416
|
+
return this;
|
3417
|
+
};
|
3418
|
+
|
3419
|
+
}); // module: runner.js
|
3420
|
+
|
3421
|
+
require.register("suite.js", function(module, exports, require){
|
3422
|
+
|
3423
|
+
/**
|
3424
|
+
* Module dependencies.
|
3425
|
+
*/
|
3426
|
+
|
3427
|
+
var EventEmitter = require('browser/events').EventEmitter
|
3428
|
+
, debug = require('browser/debug')('suite')
|
3429
|
+
, utils = require('./utils')
|
3430
|
+
, Hook = require('./hook');
|
3431
|
+
|
3432
|
+
/**
|
3433
|
+
* Expose `Suite`.
|
3434
|
+
*/
|
3435
|
+
|
3436
|
+
exports = module.exports = Suite;
|
3437
|
+
|
3438
|
+
/**
|
3439
|
+
* Create a new `Suite` with the given `title`
|
3440
|
+
* and parent `Suite`. When a suite with the
|
3441
|
+
* same title is already present, that suite
|
3442
|
+
* is returned to provide nicer reporter
|
3443
|
+
* and more flexible meta-testing.
|
3444
|
+
*
|
3445
|
+
* @param {Suite} parent
|
3446
|
+
* @param {String} title
|
3447
|
+
* @return {Suite}
|
3448
|
+
* @api public
|
3449
|
+
*/
|
3450
|
+
|
3451
|
+
exports.create = function(parent, title){
|
3452
|
+
var suite = new Suite(title, parent.ctx);
|
3453
|
+
suite.parent = parent;
|
3454
|
+
title = suite.fullTitle();
|
3455
|
+
parent.addSuite(suite);
|
3456
|
+
return suite;
|
3457
|
+
};
|
3458
|
+
|
3459
|
+
/**
|
3460
|
+
* Initialize a new `Suite` with the given
|
3461
|
+
* `title` and `ctx`.
|
3462
|
+
*
|
3463
|
+
* @param {String} title
|
3464
|
+
* @param {Context} ctx
|
3465
|
+
* @api private
|
3466
|
+
*/
|
3467
|
+
|
3468
|
+
function Suite(title, ctx) {
|
3469
|
+
this.title = title;
|
3470
|
+
this.ctx = ctx;
|
3471
|
+
this.suites = [];
|
3472
|
+
this.tests = [];
|
3473
|
+
this._beforeEach = [];
|
3474
|
+
this._beforeAll = [];
|
3475
|
+
this._afterEach = [];
|
3476
|
+
this._afterAll = [];
|
3477
|
+
this.root = !title;
|
3478
|
+
this._timeout = 2000;
|
3479
|
+
this._bail = false;
|
3480
|
+
}
|
3481
|
+
|
3482
|
+
/**
|
3483
|
+
* Inherit from `EventEmitter.prototype`.
|
3484
|
+
*/
|
3485
|
+
|
3486
|
+
Suite.prototype = new EventEmitter;
|
3487
|
+
Suite.prototype.constructor = Suite;
|
3488
|
+
|
3489
|
+
|
3490
|
+
/**
|
3491
|
+
* Return a clone of this `Suite`.
|
3492
|
+
*
|
3493
|
+
* @return {Suite}
|
3494
|
+
* @api private
|
3495
|
+
*/
|
3496
|
+
|
3497
|
+
Suite.prototype.clone = function(){
|
3498
|
+
var suite = new Suite(this.title);
|
3499
|
+
debug('clone');
|
3500
|
+
suite.ctx = this.ctx;
|
3501
|
+
suite.timeout(this.timeout());
|
3502
|
+
suite.bail(this.bail());
|
3503
|
+
return suite;
|
3504
|
+
};
|
3505
|
+
|
3506
|
+
/**
|
3507
|
+
* Set timeout `ms` or short-hand such as "2s".
|
3508
|
+
*
|
3509
|
+
* @param {Number|String} ms
|
3510
|
+
* @return {Suite|Number} for chaining
|
3511
|
+
* @api private
|
3512
|
+
*/
|
3513
|
+
|
3514
|
+
Suite.prototype.timeout = function(ms){
|
3515
|
+
if (0 == arguments.length) return this._timeout;
|
3516
|
+
if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000;
|
3517
|
+
debug('timeout %d', ms);
|
3518
|
+
this._timeout = parseInt(ms, 10);
|
3519
|
+
return this;
|
3520
|
+
};
|
3521
|
+
|
3522
|
+
/**
|
3523
|
+
* Sets whether to bail after first error.
|
3524
|
+
*
|
3525
|
+
* @parma {Boolean} bail
|
3526
|
+
* @return {Suite|Number} for chaining
|
3527
|
+
* @api private
|
3528
|
+
*/
|
3529
|
+
|
3530
|
+
Suite.prototype.bail = function(bail){
|
3531
|
+
if (0 == arguments.length) return this._bail;
|
3532
|
+
debug('bail %s', bail);
|
3533
|
+
this._bail = bail;
|
3534
|
+
return this;
|
3535
|
+
};
|
3536
|
+
|
3537
|
+
/**
|
3538
|
+
* Run `fn(test[, done])` before running tests.
|
3539
|
+
*
|
3540
|
+
* @param {Function} fn
|
3541
|
+
* @return {Suite} for chaining
|
3542
|
+
* @api private
|
3543
|
+
*/
|
3544
|
+
|
3545
|
+
Suite.prototype.beforeAll = function(fn){
|
3546
|
+
var hook = new Hook('"before all" hook', fn);
|
3547
|
+
hook.parent = this;
|
3548
|
+
hook.timeout(this.timeout());
|
3549
|
+
hook.ctx = this.ctx;
|
3550
|
+
this._beforeAll.push(hook);
|
3551
|
+
this.emit('beforeAll', hook);
|
3552
|
+
return this;
|
3553
|
+
};
|
3554
|
+
|
3555
|
+
/**
|
3556
|
+
* Run `fn(test[, done])` after running tests.
|
3557
|
+
*
|
3558
|
+
* @param {Function} fn
|
3559
|
+
* @return {Suite} for chaining
|
3560
|
+
* @api private
|
3561
|
+
*/
|
3562
|
+
|
3563
|
+
Suite.prototype.afterAll = function(fn){
|
3564
|
+
var hook = new Hook('"after all" hook', fn);
|
3565
|
+
hook.parent = this;
|
3566
|
+
hook.timeout(this.timeout());
|
3567
|
+
hook.ctx = this.ctx;
|
3568
|
+
this._afterAll.push(hook);
|
3569
|
+
this.emit('afterAll', hook);
|
3570
|
+
return this;
|
3571
|
+
};
|
3572
|
+
|
3573
|
+
/**
|
3574
|
+
* Run `fn(test[, done])` before each test case.
|
3575
|
+
*
|
3576
|
+
* @param {Function} fn
|
3577
|
+
* @return {Suite} for chaining
|
3578
|
+
* @api private
|
3579
|
+
*/
|
3580
|
+
|
3581
|
+
Suite.prototype.beforeEach = function(fn){
|
3582
|
+
var hook = new Hook('"before each" hook', fn);
|
3583
|
+
hook.parent = this;
|
3584
|
+
hook.timeout(this.timeout());
|
3585
|
+
hook.ctx = this.ctx;
|
3586
|
+
this._beforeEach.push(hook);
|
3587
|
+
this.emit('beforeEach', hook);
|
3588
|
+
return this;
|
3589
|
+
};
|
3590
|
+
|
3591
|
+
/**
|
3592
|
+
* Run `fn(test[, done])` after each test case.
|
3593
|
+
*
|
3594
|
+
* @param {Function} fn
|
3595
|
+
* @return {Suite} for chaining
|
3596
|
+
* @api private
|
3597
|
+
*/
|
3598
|
+
|
3599
|
+
Suite.prototype.afterEach = function(fn){
|
3600
|
+
var hook = new Hook('"after each" hook', fn);
|
3601
|
+
hook.parent = this;
|
3602
|
+
hook.timeout(this.timeout());
|
3603
|
+
hook.ctx = this.ctx;
|
3604
|
+
this._afterEach.push(hook);
|
3605
|
+
this.emit('afterEach', hook);
|
3606
|
+
return this;
|
3607
|
+
};
|
3608
|
+
|
3609
|
+
/**
|
3610
|
+
* Add a test `suite`.
|
3611
|
+
*
|
3612
|
+
* @param {Suite} suite
|
3613
|
+
* @return {Suite} for chaining
|
3614
|
+
* @api private
|
3615
|
+
*/
|
3616
|
+
|
3617
|
+
Suite.prototype.addSuite = function(suite){
|
3618
|
+
suite.parent = this;
|
3619
|
+
suite.timeout(this.timeout());
|
3620
|
+
suite.bail(this.bail());
|
3621
|
+
this.suites.push(suite);
|
3622
|
+
this.emit('suite', suite);
|
3623
|
+
return this;
|
3624
|
+
};
|
3625
|
+
|
3626
|
+
/**
|
3627
|
+
* Add a `test` to this suite.
|
3628
|
+
*
|
3629
|
+
* @param {Test} test
|
3630
|
+
* @return {Suite} for chaining
|
3631
|
+
* @api private
|
3632
|
+
*/
|
3633
|
+
|
3634
|
+
Suite.prototype.addTest = function(test){
|
3635
|
+
test.parent = this;
|
3636
|
+
test.timeout(this.timeout());
|
3637
|
+
test.ctx = this.ctx;
|
3638
|
+
this.tests.push(test);
|
3639
|
+
this.emit('test', test);
|
3640
|
+
return this;
|
3641
|
+
};
|
3642
|
+
|
3643
|
+
/**
|
3644
|
+
* Return the full title generated by recursively
|
3645
|
+
* concatenating the parent's full title.
|
3646
|
+
*
|
3647
|
+
* @return {String}
|
3648
|
+
* @api public
|
3649
|
+
*/
|
3650
|
+
|
3651
|
+
Suite.prototype.fullTitle = function(){
|
3652
|
+
if (this.parent) {
|
3653
|
+
var full = this.parent.fullTitle();
|
3654
|
+
if (full) return full + ' ' + this.title;
|
3655
|
+
}
|
3656
|
+
return this.title;
|
3657
|
+
};
|
3658
|
+
|
3659
|
+
/**
|
3660
|
+
* Return the total number of tests.
|
3661
|
+
*
|
3662
|
+
* @return {Number}
|
3663
|
+
* @api public
|
3664
|
+
*/
|
3665
|
+
|
3666
|
+
Suite.prototype.total = function(){
|
3667
|
+
return utils.reduce(this.suites, function(sum, suite){
|
3668
|
+
return sum + suite.total();
|
3669
|
+
}, 0) + this.tests.length;
|
3670
|
+
};
|
3671
|
+
|
3672
|
+
}); // module: suite.js
|
3673
|
+
|
3674
|
+
require.register("test.js", function(module, exports, require){
|
3675
|
+
|
3676
|
+
/**
|
3677
|
+
* Module dependencies.
|
3678
|
+
*/
|
3679
|
+
|
3680
|
+
var Runnable = require('./runnable');
|
3681
|
+
|
3682
|
+
/**
|
3683
|
+
* Expose `Test`.
|
3684
|
+
*/
|
3685
|
+
|
3686
|
+
module.exports = Test;
|
3687
|
+
|
3688
|
+
/**
|
3689
|
+
* Initialize a new `Test` with the given `title` and callback `fn`.
|
3690
|
+
*
|
3691
|
+
* @param {String} title
|
3692
|
+
* @param {Function} fn
|
3693
|
+
* @api private
|
3694
|
+
*/
|
3695
|
+
|
3696
|
+
function Test(title, fn) {
|
3697
|
+
Runnable.call(this, title, fn);
|
3698
|
+
this.pending = !fn;
|
3699
|
+
this.type = 'test';
|
3700
|
+
}
|
3701
|
+
|
3702
|
+
/**
|
3703
|
+
* Inherit from `Runnable.prototype`.
|
3704
|
+
*/
|
3705
|
+
|
3706
|
+
Test.prototype = new Runnable;
|
3707
|
+
Test.prototype.constructor = Test;
|
3708
|
+
|
3709
|
+
|
3710
|
+
/**
|
3711
|
+
* Inspect the context void of private properties.
|
3712
|
+
*
|
3713
|
+
* @return {String}
|
3714
|
+
* @api private
|
3715
|
+
*/
|
3716
|
+
|
3717
|
+
Test.prototype.inspect = function(){
|
3718
|
+
return JSON.stringify(this, function(key, val){
|
3719
|
+
return '_' == key[0]
|
3720
|
+
? undefined
|
3721
|
+
: 'parent' == key
|
3722
|
+
? '#<Suite>'
|
3723
|
+
: val;
|
3724
|
+
}, 2);
|
3725
|
+
};
|
3726
|
+
}); // module: test.js
|
3727
|
+
|
3728
|
+
require.register("utils.js", function(module, exports, require){
|
3729
|
+
|
3730
|
+
/**
|
3731
|
+
* Module dependencies.
|
3732
|
+
*/
|
3733
|
+
|
3734
|
+
var fs = require('browser/fs')
|
3735
|
+
, path = require('browser/path')
|
3736
|
+
, join = path.join
|
3737
|
+
, debug = require('browser/debug')('watch');
|
3738
|
+
|
3739
|
+
/**
|
3740
|
+
* Ignored directories.
|
3741
|
+
*/
|
3742
|
+
|
3743
|
+
var ignore = ['node_modules', '.git'];
|
3744
|
+
|
3745
|
+
/**
|
3746
|
+
* Escape special characters in the given string of html.
|
3747
|
+
*
|
3748
|
+
* @param {String} html
|
3749
|
+
* @return {String}
|
3750
|
+
* @api private
|
3751
|
+
*/
|
3752
|
+
|
3753
|
+
exports.escape = function(html) {
|
3754
|
+
return String(html)
|
3755
|
+
.replace(/&/g, '&')
|
3756
|
+
.replace(/"/g, '"')
|
3757
|
+
.replace(/</g, '<')
|
3758
|
+
.replace(/>/g, '>');
|
3759
|
+
};
|
3760
|
+
|
3761
|
+
/**
|
3762
|
+
* Array#forEach (<=IE8)
|
3763
|
+
*
|
3764
|
+
* @param {Array} array
|
3765
|
+
* @param {Function} fn
|
3766
|
+
* @param {Object} scope
|
3767
|
+
* @api private
|
3768
|
+
*/
|
3769
|
+
|
3770
|
+
exports.forEach = function(arr, fn, scope) {
|
3771
|
+
for (var i = 0, l = arr.length; i < l; i++)
|
3772
|
+
fn.call(scope, arr[i], i);
|
3773
|
+
};
|
3774
|
+
|
3775
|
+
/**
|
3776
|
+
* Array#indexOf (<=IE8)
|
3777
|
+
*
|
3778
|
+
* @parma {Array} arr
|
3779
|
+
* @param {Object} obj to find index of
|
3780
|
+
* @param {Number} start
|
3781
|
+
* @api private
|
3782
|
+
*/
|
3783
|
+
|
3784
|
+
exports.indexOf = function (arr, obj, start) {
|
3785
|
+
for (var i = start || 0, l = arr.length; i < l; i++) {
|
3786
|
+
if (arr[i] === obj)
|
3787
|
+
return i;
|
3788
|
+
}
|
3789
|
+
return -1;
|
3790
|
+
};
|
3791
|
+
|
3792
|
+
/**
|
3793
|
+
* Array#reduce (<=IE8)
|
3794
|
+
*
|
3795
|
+
* @param {Array} array
|
3796
|
+
* @param {Function} fn
|
3797
|
+
* @param {Object} initial value
|
3798
|
+
* @param {Object} scope
|
3799
|
+
* @api private
|
3800
|
+
*/
|
3801
|
+
|
3802
|
+
exports.reduce = function(arr, fn, val, scope) {
|
3803
|
+
var rval = val;
|
3804
|
+
|
3805
|
+
for (var i = 0, l = arr.length; i < l; i++) {
|
3806
|
+
rval = fn.call(scope, rval, arr[i], i, arr);
|
3807
|
+
}
|
3808
|
+
|
3809
|
+
return rval;
|
3810
|
+
};
|
3811
|
+
|
3812
|
+
/**
|
3813
|
+
* Array#filter (<=IE8)
|
3814
|
+
*
|
3815
|
+
* @param {Array} array
|
3816
|
+
* @param {Function} fn
|
3817
|
+
* @param {Object} scope
|
3818
|
+
* @api private
|
3819
|
+
*/
|
3820
|
+
|
3821
|
+
exports.filter = function(arr, fn, scope) {
|
3822
|
+
var ret = [];
|
3823
|
+
|
3824
|
+
for (var i = 0, l = arr.length; i < l; i++) {
|
3825
|
+
var val = arr[i];
|
3826
|
+
if (fn.call(scope, val, i, arr))
|
3827
|
+
ret.push(val);
|
3828
|
+
}
|
3829
|
+
|
3830
|
+
return ret;
|
3831
|
+
};
|
3832
|
+
|
3833
|
+
/**
|
3834
|
+
* Object.keys (<=IE8)
|
3835
|
+
*
|
3836
|
+
* @param {Object} obj
|
3837
|
+
* @return {Array} keys
|
3838
|
+
* @api private
|
3839
|
+
*/
|
3840
|
+
|
3841
|
+
exports.keys = Object.keys || function(obj) {
|
3842
|
+
var keys = []
|
3843
|
+
, has = Object.prototype.hasOwnProperty // for `window` on <=IE8
|
3844
|
+
|
3845
|
+
for (var key in obj) {
|
3846
|
+
if (has.call(obj, key)) {
|
3847
|
+
keys.push(key);
|
3848
|
+
}
|
3849
|
+
}
|
3850
|
+
|
3851
|
+
return keys;
|
3852
|
+
};
|
3853
|
+
|
3854
|
+
/**
|
3855
|
+
* Watch the given `files` for changes
|
3856
|
+
* and invoke `fn(file)` on modification.
|
3857
|
+
*
|
3858
|
+
* @param {Array} files
|
3859
|
+
* @param {Function} fn
|
3860
|
+
* @api private
|
3861
|
+
*/
|
3862
|
+
|
3863
|
+
exports.watch = function(files, fn){
|
3864
|
+
var options = { interval: 100 };
|
3865
|
+
files.forEach(function(file){
|
3866
|
+
debug('file %s', file);
|
3867
|
+
fs.watchFile(file, options, function(curr, prev){
|
3868
|
+
if (prev.mtime < curr.mtime) fn(file);
|
3869
|
+
});
|
3870
|
+
});
|
3871
|
+
};
|
3872
|
+
|
3873
|
+
/**
|
3874
|
+
* Ignored files.
|
3875
|
+
*/
|
3876
|
+
|
3877
|
+
function ignored(path){
|
3878
|
+
return !~ignore.indexOf(path);
|
3879
|
+
}
|
3880
|
+
|
3881
|
+
/**
|
3882
|
+
* Lookup files in the given `dir`.
|
3883
|
+
*
|
3884
|
+
* @return {Array}
|
3885
|
+
* @api private
|
3886
|
+
*/
|
3887
|
+
|
3888
|
+
exports.files = function(dir, ret){
|
3889
|
+
ret = ret || [];
|
3890
|
+
|
3891
|
+
fs.readdirSync(dir)
|
3892
|
+
.filter(ignored)
|
3893
|
+
.forEach(function(path){
|
3894
|
+
path = join(dir, path);
|
3895
|
+
if (fs.statSync(path).isDirectory()) {
|
3896
|
+
exports.files(path, ret);
|
3897
|
+
} else if (path.match(/\.(js|coffee)$/)) {
|
3898
|
+
ret.push(path);
|
3899
|
+
}
|
3900
|
+
});
|
3901
|
+
|
3902
|
+
return ret;
|
3903
|
+
};
|
3904
|
+
|
3905
|
+
/**
|
3906
|
+
* Compute a slug from the given `str`.
|
3907
|
+
*
|
3908
|
+
* @param {String} str
|
3909
|
+
* @return {String}
|
3910
|
+
*/
|
3911
|
+
|
3912
|
+
exports.slug = function(str){
|
3913
|
+
return str
|
3914
|
+
.toLowerCase()
|
3915
|
+
.replace(/ +/g, '-')
|
3916
|
+
.replace(/[^-\w]/g, '');
|
3917
|
+
};
|
3918
|
+
}); // module: utils.js
|
3919
|
+
|
3920
|
+
/**
|
3921
|
+
* Node shims.
|
3922
|
+
*
|
3923
|
+
* These are meant only to allow
|
3924
|
+
* mocha.js to run untouched, not
|
3925
|
+
* to allow running node code in
|
3926
|
+
* the browser.
|
3927
|
+
*/
|
3928
|
+
|
3929
|
+
process = {};
|
3930
|
+
process.exit = function(status){};
|
3931
|
+
process.stdout = {};
|
3932
|
+
global = window;
|
3933
|
+
|
3934
|
+
/**
|
3935
|
+
* next tick implementation.
|
3936
|
+
*/
|
3937
|
+
|
3938
|
+
process.nextTick = (function(){
|
3939
|
+
// postMessage behaves badly on IE8
|
3940
|
+
if (window.ActiveXObject || !window.postMessage) {
|
3941
|
+
return function(fn){ fn() };
|
3942
|
+
}
|
3943
|
+
|
3944
|
+
// based on setZeroTimeout by David Baron
|
3945
|
+
// - http://dbaron.org/log/20100309-faster-timeouts
|
3946
|
+
var timeouts = []
|
3947
|
+
, name = 'mocha-zero-timeout'
|
3948
|
+
|
3949
|
+
return function(fn){
|
3950
|
+
timeouts.push(fn);
|
3951
|
+
window.postMessage(name, '*');
|
3952
|
+
window.addEventListener('message', function(e){
|
3953
|
+
if (e.source == window && e.data == name) {
|
3954
|
+
if (e.stopPropagation) e.stopPropagation();
|
3955
|
+
if (timeouts.length) timeouts.shift()();
|
3956
|
+
}
|
3957
|
+
}, true);
|
3958
|
+
}
|
3959
|
+
})();
|
3960
|
+
|
3961
|
+
/**
|
3962
|
+
* Remove uncaughtException listener.
|
3963
|
+
*/
|
3964
|
+
|
3965
|
+
process.removeListener = function(e){
|
3966
|
+
if ('uncaughtException' == e) {
|
3967
|
+
window.onerror = null;
|
3968
|
+
}
|
3969
|
+
};
|
3970
|
+
|
3971
|
+
/**
|
3972
|
+
* Implements uncaughtException listener.
|
3973
|
+
*/
|
3974
|
+
|
3975
|
+
process.on = function(e, fn){
|
3976
|
+
if ('uncaughtException' == e) {
|
3977
|
+
window.onerror = fn;
|
3978
|
+
}
|
3979
|
+
};
|
3980
|
+
|
3981
|
+
/**
|
3982
|
+
* Expose mocha.
|
3983
|
+
*/
|
3984
|
+
|
3985
|
+
window.mocha = require('mocha');
|
3986
|
+
|
3987
|
+
// boot
|
3988
|
+
;(function(){
|
3989
|
+
var suite = new mocha.Suite('', new mocha.Context)
|
3990
|
+
, utils = mocha.utils
|
3991
|
+
, options = {}
|
3992
|
+
|
3993
|
+
/**
|
3994
|
+
* Highlight the given string of `js`.
|
3995
|
+
*/
|
3996
|
+
|
3997
|
+
function highlight(js) {
|
3998
|
+
return js
|
3999
|
+
.replace(/</g, '<')
|
4000
|
+
.replace(/>/g, '>')
|
4001
|
+
.replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
|
4002
|
+
.replace(/('.*?')/gm, '<span class="string">$1</span>')
|
4003
|
+
.replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
|
4004
|
+
.replace(/(\d+)/gm, '<span class="number">$1</span>')
|
4005
|
+
.replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
|
4006
|
+
.replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
|
4007
|
+
}
|
4008
|
+
|
4009
|
+
/**
|
4010
|
+
* Highlight code contents.
|
4011
|
+
*/
|
4012
|
+
|
4013
|
+
function highlightCode() {
|
4014
|
+
var code = document.getElementsByTagName('code');
|
4015
|
+
for (var i = 0, len = code.length; i < len; ++i) {
|
4016
|
+
code[i].innerHTML = highlight(code[i].innerHTML);
|
4017
|
+
}
|
4018
|
+
}
|
4019
|
+
|
4020
|
+
/**
|
4021
|
+
* Parse the given `qs`.
|
4022
|
+
*/
|
4023
|
+
|
4024
|
+
function parse(qs) {
|
4025
|
+
return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
|
4026
|
+
var i = pair.indexOf('=')
|
4027
|
+
, key = pair.slice(0, i)
|
4028
|
+
, val = pair.slice(++i);
|
4029
|
+
|
4030
|
+
obj[key] = decodeURIComponent(val);
|
4031
|
+
return obj;
|
4032
|
+
}, {});
|
4033
|
+
}
|
4034
|
+
|
4035
|
+
/**
|
4036
|
+
* Setup mocha with the given setting options.
|
4037
|
+
*/
|
4038
|
+
|
4039
|
+
mocha.setup = function(opts){
|
4040
|
+
if ('string' === typeof opts) options.ui = opts;
|
4041
|
+
else options = opts;
|
4042
|
+
|
4043
|
+
ui = mocha.interfaces[options.ui];
|
4044
|
+
if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
|
4045
|
+
if (options.timeout) suite.timeout(options.timeout);
|
4046
|
+
ui(suite);
|
4047
|
+
suite.emit('pre-require', window);
|
4048
|
+
};
|
4049
|
+
|
4050
|
+
/**
|
4051
|
+
* Run mocha, returning the Runner.
|
4052
|
+
*/
|
4053
|
+
|
4054
|
+
mocha.run = function(){
|
4055
|
+
suite.emit('run');
|
4056
|
+
var runner = new mocha.Runner(suite);
|
4057
|
+
var Reporter = options.reporter || mocha.reporters.HTML;
|
4058
|
+
var reporter = new Reporter(runner);
|
4059
|
+
var query = parse(window.location.search || "");
|
4060
|
+
if (query.grep) runner.grep(new RegExp(query.grep));
|
4061
|
+
if (options.ignoreLeaks) runner.ignoreLeaks = true;
|
4062
|
+
if (options.globals) runner.globals(options.globals);
|
4063
|
+
runner.globals(['location']);
|
4064
|
+
runner.on('end', highlightCode);
|
4065
|
+
return runner.run();
|
4066
|
+
};
|
4067
|
+
})();
|
4068
|
+
})();
|