├── History.md ├── Makefile ├── package.json ├── index.js ├── component.json ├── Readme.md └── test ├── mocha ├── tests.html ├── mocha.css └── mocha.js ├── index.html └── before.js /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.1.0 / 2013-02-08 3 | ================== 4 | 5 | * make sure an element has a parent node before attempting to insert before 6 | 7 | 0.0.1 / 2013-02-01 8 | ================== 9 | 10 | * initial 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | build: components index.js 3 | @component build --dev 4 | 5 | components: component.json 6 | @component install --dev 7 | 8 | clean: 9 | rm -fr build components template.js 10 | 11 | .PHONY: clean 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "democracyos-before", 3 | "repository": "https://github.com/DemocracyOS/before", 4 | "description": "standalone before", 5 | "version": "0.1.0", 6 | "keywords": ["before"], 7 | "dependencies": {}, 8 | "license": "MIT" 9 | } 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * insert `b` before `a`. 4 | * 5 | * @param {Element} a 6 | * @param {Element} b 7 | * @return {Element} b 8 | */ 9 | 10 | module.exports = function(a, b){ 11 | if (a.parentNode) { 12 | return a.parentNode.insertBefore(b, a); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "democracyos-before", 3 | "repo": "DemocracyOS/before", 4 | "description": "standalone before", 5 | "version": "0.1.0", 6 | "keywords": ["before"], 7 | "dependencies": {}, 8 | "development": {}, 9 | "license": "MIT", 10 | "scripts": [ 11 | "index.js" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # before 3 | 4 | insert an element before other one 5 | 6 | ## Installation 7 | 8 | $ component install yields/before 9 | 10 | ## API 11 | 12 | ### before(a, b) 13 | 14 | insert `b` before `a`. 15 | 16 | ### Tests 17 | 18 | ```bash 19 | $ git clone https://github.com/yields/before 20 | $ cd before && component install && component build 21 | $ open test/index.html 22 | ``` 23 | 24 | ## License 25 | 26 | MIT 27 | -------------------------------------------------------------------------------- /test/mocha/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mocha 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | before 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/before.js: -------------------------------------------------------------------------------- 1 | 2 | var before = require('before'); 3 | 4 | // assert 5 | 6 | function assert(expr, ms){ 7 | if (expr) return; 8 | throw new Error(ms || 'does not work!'); 9 | } 10 | 11 | describe('before(a, b)', function(){ 12 | it('should insert b before a', function(){ 13 | var ul = document.createElement('ul'); 14 | var a = document.createElement('li'); 15 | var b = document.createElement('li'); 16 | a.innerText = 'a'; 17 | b.innerText = 'b'; 18 | ul.appendChild(a); 19 | before(a, b); 20 | assert(a === b.nextSibling); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/mocha/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | body { 3 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 4 | padding: 60px 50px; 5 | } 6 | 7 | #mocha ul, #mocha li { 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | #mocha ul { 13 | list-style: none; 14 | } 15 | 16 | #mocha h1, #mocha h2 { 17 | margin: 0; 18 | } 19 | 20 | #mocha h1 { 21 | margin-top: 15px; 22 | font-size: 1em; 23 | font-weight: 200; 24 | } 25 | 26 | #mocha h1 a { 27 | text-decoration: none; 28 | color: inherit; 29 | } 30 | 31 | #mocha h1 a:hover { 32 | text-decoration: underline; 33 | } 34 | 35 | #mocha .suite .suite h1 { 36 | margin-top: 0; 37 | font-size: .8em; 38 | } 39 | 40 | #mocha h2 { 41 | font-size: 12px; 42 | font-weight: normal; 43 | cursor: pointer; 44 | } 45 | 46 | #mocha .suite { 47 | margin-left: 15px; 48 | } 49 | 50 | #mocha .test { 51 | margin-left: 15px; 52 | } 53 | 54 | #mocha .test:hover h2::after { 55 | position: relative; 56 | top: 0; 57 | right: -10px; 58 | content: '(view source)'; 59 | font-size: 12px; 60 | font-family: arial; 61 | color: #888; 62 | } 63 | 64 | #mocha .test.pending:hover h2::after { 65 | content: '(pending)'; 66 | font-family: arial; 67 | } 68 | 69 | #mocha .test.pass.medium .duration { 70 | background: #C09853; 71 | } 72 | 73 | #mocha .test.pass.slow .duration { 74 | background: #B94A48; 75 | } 76 | 77 | #mocha .test.pass::before { 78 | content: '✓'; 79 | font-size: 12px; 80 | display: block; 81 | float: left; 82 | margin-right: 5px; 83 | color: #00d6b2; 84 | } 85 | 86 | #mocha .test.pass .duration { 87 | font-size: 9px; 88 | margin-left: 5px; 89 | padding: 2px 5px; 90 | color: white; 91 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 92 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 93 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -webkit-border-radius: 5px; 95 | -moz-border-radius: 5px; 96 | -ms-border-radius: 5px; 97 | -o-border-radius: 5px; 98 | border-radius: 5px; 99 | } 100 | 101 | #mocha .test.pass.fast .duration { 102 | display: none; 103 | } 104 | 105 | #mocha .test.pending { 106 | color: #0b97c4; 107 | } 108 | 109 | #mocha .test.pending::before { 110 | content: '◦'; 111 | color: #0b97c4; 112 | } 113 | 114 | #mocha .test.fail { 115 | color: #c00; 116 | } 117 | 118 | #mocha .test.fail pre { 119 | color: black; 120 | } 121 | 122 | #mocha .test.fail::before { 123 | content: '✖'; 124 | font-size: 12px; 125 | display: block; 126 | float: left; 127 | margin-right: 5px; 128 | color: #c00; 129 | } 130 | 131 | #mocha .test pre.error { 132 | color: #c00; 133 | } 134 | 135 | #mocha .test pre { 136 | display: inline-block; 137 | font: 12px/1.5 monaco, monospace; 138 | margin: 5px; 139 | padding: 15px; 140 | border: 1px solid #eee; 141 | border-bottom-color: #ddd; 142 | -webkit-border-radius: 3px; 143 | -webkit-box-shadow: 0 1px 3px #eee; 144 | } 145 | 146 | #report.pass .test.fail { 147 | display: none; 148 | } 149 | 150 | #report.fail .test.pass { 151 | display: none; 152 | } 153 | 154 | #error { 155 | color: #c00; 156 | font-size: 1.5 em; 157 | font-weight: 100; 158 | letter-spacing: 1px; 159 | } 160 | 161 | #stats { 162 | position: fixed; 163 | top: 15px; 164 | right: 10px; 165 | font-size: 12px; 166 | margin: 0; 167 | color: #888; 168 | } 169 | 170 | #stats .progress { 171 | float: right; 172 | padding-top: 0; 173 | } 174 | 175 | #stats em { 176 | color: black; 177 | } 178 | 179 | #stats a { 180 | text-decoration: none; 181 | color: inherit; 182 | } 183 | 184 | #stats a:hover { 185 | border-bottom: 1px solid #eee; 186 | } 187 | 188 | #stats li { 189 | display: inline-block; 190 | margin: 0 5px; 191 | list-style: none; 192 | padding-top: 11px; 193 | } 194 | 195 | code .comment { color: #ddd } 196 | code .init { color: #2F6FAD } 197 | code .string { color: #5890AD } 198 | code .keyword { color: #8A6343 } 199 | code .number { color: #2F6FAD } 200 | -------------------------------------------------------------------------------- /test/mocha/mocha.js: -------------------------------------------------------------------------------- 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 public 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 or get the context `Runnable` to `runnable`. 411 | * 412 | * @param {Runnable} runnable 413 | * @return {Context} 414 | * @api private 415 | */ 416 | 417 | Context.prototype.runnable = function(runnable){ 418 | if (0 == arguments.length) return this._runnable; 419 | this.test = this._runnable = runnable; 420 | return this; 421 | }; 422 | 423 | /** 424 | * Set test timeout `ms`. 425 | * 426 | * @param {Number} ms 427 | * @return {Context} self 428 | * @api private 429 | */ 430 | 431 | Context.prototype.timeout = function(ms){ 432 | this.runnable().timeout(ms); 433 | return this; 434 | }; 435 | 436 | /** 437 | * Inspect the context void of `._runnable`. 438 | * 439 | * @return {String} 440 | * @api private 441 | */ 442 | 443 | Context.prototype.inspect = function(){ 444 | return JSON.stringify(this, function(key, val){ 445 | if ('_runnable' == key) return; 446 | if ('test' == key) return; 447 | return val; 448 | }, 2); 449 | }; 450 | 451 | }); // module: context.js 452 | 453 | require.register("hook.js", function(module, exports, require){ 454 | 455 | /** 456 | * Module dependencies. 457 | */ 458 | 459 | var Runnable = require('./runnable'); 460 | 461 | /** 462 | * Expose `Hook`. 463 | */ 464 | 465 | module.exports = Hook; 466 | 467 | /** 468 | * Initialize a new `Hook` with the given `title` and callback `fn`. 469 | * 470 | * @param {String} title 471 | * @param {Function} fn 472 | * @api private 473 | */ 474 | 475 | function Hook(title, fn) { 476 | Runnable.call(this, title, fn); 477 | this.type = 'hook'; 478 | } 479 | 480 | /** 481 | * Inherit from `Runnable.prototype`. 482 | */ 483 | 484 | Hook.prototype = new Runnable; 485 | Hook.prototype.constructor = Hook; 486 | 487 | 488 | /** 489 | * Get or set the test `err`. 490 | * 491 | * @param {Error} err 492 | * @return {Error} 493 | * @api public 494 | */ 495 | 496 | Hook.prototype.error = function(err){ 497 | if (0 == arguments.length) { 498 | var err = this._error; 499 | this._error = null; 500 | return err; 501 | } 502 | 503 | this._error = err; 504 | }; 505 | 506 | 507 | }); // module: hook.js 508 | 509 | require.register("interfaces/bdd.js", function(module, exports, require){ 510 | 511 | /** 512 | * Module dependencies. 513 | */ 514 | 515 | var Suite = require('../suite') 516 | , Test = require('../test'); 517 | 518 | /** 519 | * BDD-style interface: 520 | * 521 | * describe('Array', function(){ 522 | * describe('#indexOf()', function(){ 523 | * it('should return -1 when not present', function(){ 524 | * 525 | * }); 526 | * 527 | * it('should return the index when present', function(){ 528 | * 529 | * }); 530 | * }); 531 | * }); 532 | * 533 | */ 534 | 535 | module.exports = function(suite){ 536 | var suites = [suite]; 537 | 538 | suite.on('pre-require', function(context, file, mocha){ 539 | 540 | /** 541 | * Execute before running tests. 542 | */ 543 | 544 | context.before = function(fn){ 545 | suites[0].beforeAll(fn); 546 | }; 547 | 548 | /** 549 | * Execute after running tests. 550 | */ 551 | 552 | context.after = function(fn){ 553 | suites[0].afterAll(fn); 554 | }; 555 | 556 | /** 557 | * Execute before each test case. 558 | */ 559 | 560 | context.beforeEach = function(fn){ 561 | suites[0].beforeEach(fn); 562 | }; 563 | 564 | /** 565 | * Execute after each test case. 566 | */ 567 | 568 | context.afterEach = function(fn){ 569 | suites[0].afterEach(fn); 570 | }; 571 | 572 | /** 573 | * Describe a "suite" with the given `title` 574 | * and callback `fn` containing nested suites 575 | * and/or tests. 576 | */ 577 | 578 | context.describe = context.context = function(title, fn){ 579 | var suite = Suite.create(suites[0], title); 580 | suites.unshift(suite); 581 | fn(); 582 | suites.shift(); 583 | return suite; 584 | }; 585 | 586 | /** 587 | * Pending describe. 588 | */ 589 | 590 | context.xdescribe = 591 | context.xcontext = 592 | context.describe.skip = function(title, fn){ 593 | var suite = Suite.create(suites[0], title); 594 | suite.pending = true; 595 | suites.unshift(suite); 596 | fn(); 597 | suites.shift(); 598 | }; 599 | 600 | /** 601 | * Exclusive suite. 602 | */ 603 | 604 | context.describe.only = function(title, fn){ 605 | var suite = context.describe(title, fn); 606 | mocha.grep(suite.fullTitle()); 607 | }; 608 | 609 | /** 610 | * Describe a specification or test-case 611 | * with the given `title` and callback `fn` 612 | * acting as a thunk. 613 | */ 614 | 615 | context.it = context.specify = function(title, fn){ 616 | var suite = suites[0]; 617 | if (suite.pending) var fn = null; 618 | var test = new Test(title, fn); 619 | suite.addTest(test); 620 | return test; 621 | }; 622 | 623 | /** 624 | * Exclusive test-case. 625 | */ 626 | 627 | context.it.only = function(title, fn){ 628 | var test = context.it(title, fn); 629 | mocha.grep(test.fullTitle()); 630 | }; 631 | 632 | /** 633 | * Pending test case. 634 | */ 635 | 636 | context.xit = 637 | context.xspecify = 638 | context.it.skip = function(title){ 639 | context.it(title); 640 | }; 641 | }); 642 | }; 643 | 644 | }); // module: interfaces/bdd.js 645 | 646 | require.register("interfaces/exports.js", function(module, exports, require){ 647 | 648 | /** 649 | * Module dependencies. 650 | */ 651 | 652 | var Suite = require('../suite') 653 | , Test = require('../test'); 654 | 655 | /** 656 | * TDD-style interface: 657 | * 658 | * exports.Array = { 659 | * '#indexOf()': { 660 | * 'should return -1 when the value is not present': function(){ 661 | * 662 | * }, 663 | * 664 | * 'should return the correct index when the value is present': function(){ 665 | * 666 | * } 667 | * } 668 | * }; 669 | * 670 | */ 671 | 672 | module.exports = function(suite){ 673 | var suites = [suite]; 674 | 675 | suite.on('require', visit); 676 | 677 | function visit(obj) { 678 | var suite; 679 | for (var key in obj) { 680 | if ('function' == typeof obj[key]) { 681 | var fn = obj[key]; 682 | switch (key) { 683 | case 'before': 684 | suites[0].beforeAll(fn); 685 | break; 686 | case 'after': 687 | suites[0].afterAll(fn); 688 | break; 689 | case 'beforeEach': 690 | suites[0].beforeEach(fn); 691 | break; 692 | case 'afterEach': 693 | suites[0].afterEach(fn); 694 | break; 695 | default: 696 | suites[0].addTest(new Test(key, fn)); 697 | } 698 | } else { 699 | var suite = Suite.create(suites[0], key); 700 | suites.unshift(suite); 701 | visit(obj[key]); 702 | suites.shift(); 703 | } 704 | } 705 | } 706 | }; 707 | }); // module: interfaces/exports.js 708 | 709 | require.register("interfaces/index.js", function(module, exports, require){ 710 | 711 | exports.bdd = require('./bdd'); 712 | exports.tdd = require('./tdd'); 713 | exports.qunit = require('./qunit'); 714 | exports.exports = require('./exports'); 715 | 716 | }); // module: interfaces/index.js 717 | 718 | require.register("interfaces/qunit.js", function(module, exports, require){ 719 | 720 | /** 721 | * Module dependencies. 722 | */ 723 | 724 | var Suite = require('../suite') 725 | , Test = require('../test'); 726 | 727 | /** 728 | * QUnit-style interface: 729 | * 730 | * suite('Array'); 731 | * 732 | * test('#length', function(){ 733 | * var arr = [1,2,3]; 734 | * ok(arr.length == 3); 735 | * }); 736 | * 737 | * test('#indexOf()', function(){ 738 | * var arr = [1,2,3]; 739 | * ok(arr.indexOf(1) == 0); 740 | * ok(arr.indexOf(2) == 1); 741 | * ok(arr.indexOf(3) == 2); 742 | * }); 743 | * 744 | * suite('String'); 745 | * 746 | * test('#length', function(){ 747 | * ok('foo'.length == 3); 748 | * }); 749 | * 750 | */ 751 | 752 | module.exports = function(suite){ 753 | var suites = [suite]; 754 | 755 | suite.on('pre-require', function(context){ 756 | 757 | /** 758 | * Execute before running tests. 759 | */ 760 | 761 | context.before = function(fn){ 762 | suites[0].beforeAll(fn); 763 | }; 764 | 765 | /** 766 | * Execute after running tests. 767 | */ 768 | 769 | context.after = function(fn){ 770 | suites[0].afterAll(fn); 771 | }; 772 | 773 | /** 774 | * Execute before each test case. 775 | */ 776 | 777 | context.beforeEach = function(fn){ 778 | suites[0].beforeEach(fn); 779 | }; 780 | 781 | /** 782 | * Execute after each test case. 783 | */ 784 | 785 | context.afterEach = function(fn){ 786 | suites[0].afterEach(fn); 787 | }; 788 | 789 | /** 790 | * Describe a "suite" with the given `title`. 791 | */ 792 | 793 | context.suite = function(title){ 794 | if (suites.length > 1) suites.shift(); 795 | var suite = Suite.create(suites[0], title); 796 | suites.unshift(suite); 797 | }; 798 | 799 | /** 800 | * Describe a specification or test-case 801 | * with the given `title` and callback `fn` 802 | * acting as a thunk. 803 | */ 804 | 805 | context.test = function(title, fn){ 806 | suites[0].addTest(new Test(title, fn)); 807 | }; 808 | }); 809 | }; 810 | 811 | }); // module: interfaces/qunit.js 812 | 813 | require.register("interfaces/tdd.js", function(module, exports, require){ 814 | 815 | /** 816 | * Module dependencies. 817 | */ 818 | 819 | var Suite = require('../suite') 820 | , Test = require('../test'); 821 | 822 | /** 823 | * TDD-style interface: 824 | * 825 | * suite('Array', function(){ 826 | * suite('#indexOf()', function(){ 827 | * suiteSetup(function(){ 828 | * 829 | * }); 830 | * 831 | * test('should return -1 when not present', function(){ 832 | * 833 | * }); 834 | * 835 | * test('should return the index when present', function(){ 836 | * 837 | * }); 838 | * 839 | * suiteTeardown(function(){ 840 | * 841 | * }); 842 | * }); 843 | * }); 844 | * 845 | */ 846 | 847 | module.exports = function(suite){ 848 | var suites = [suite]; 849 | 850 | suite.on('pre-require', function(context, file, mocha){ 851 | 852 | /** 853 | * Execute before each test case. 854 | */ 855 | 856 | context.setup = function(fn){ 857 | suites[0].beforeEach(fn); 858 | }; 859 | 860 | /** 861 | * Execute after each test case. 862 | */ 863 | 864 | context.teardown = function(fn){ 865 | suites[0].afterEach(fn); 866 | }; 867 | 868 | /** 869 | * Execute before the suite. 870 | */ 871 | 872 | context.suiteSetup = function(fn){ 873 | suites[0].beforeAll(fn); 874 | }; 875 | 876 | /** 877 | * Execute after the suite. 878 | */ 879 | 880 | context.suiteTeardown = function(fn){ 881 | suites[0].afterAll(fn); 882 | }; 883 | 884 | /** 885 | * Describe a "suite" with the given `title` 886 | * and callback `fn` containing nested suites 887 | * and/or tests. 888 | */ 889 | 890 | context.suite = function(title, fn){ 891 | var suite = Suite.create(suites[0], title); 892 | suites.unshift(suite); 893 | fn(); 894 | suites.shift(); 895 | return suite; 896 | }; 897 | 898 | /** 899 | * Exclusive test-case. 900 | */ 901 | 902 | context.suite.only = function(title, fn){ 903 | var suite = context.suite(title, fn); 904 | mocha.grep(suite.fullTitle()); 905 | }; 906 | 907 | /** 908 | * Describe a specification or test-case 909 | * with the given `title` and callback `fn` 910 | * acting as a thunk. 911 | */ 912 | 913 | context.test = function(title, fn){ 914 | var test = new Test(title, fn); 915 | suites[0].addTest(test); 916 | return test; 917 | }; 918 | 919 | /** 920 | * Exclusive test-case. 921 | */ 922 | 923 | context.test.only = function(title, fn){ 924 | var test = context.test(title, fn); 925 | mocha.grep(test.fullTitle()); 926 | }; 927 | }); 928 | }; 929 | 930 | }); // module: interfaces/tdd.js 931 | 932 | require.register("mocha.js", function(module, exports, require){ 933 | /*! 934 | * mocha 935 | * Copyright(c) 2011 TJ Holowaychuk 936 | * MIT Licensed 937 | */ 938 | 939 | /** 940 | * Module dependencies. 941 | */ 942 | 943 | var path = require('browser/path'); 944 | 945 | /** 946 | * Expose `Mocha`. 947 | */ 948 | 949 | exports = module.exports = Mocha; 950 | 951 | /** 952 | * Expose internals. 953 | */ 954 | 955 | exports.utils = require('./utils'); 956 | exports.interfaces = require('./interfaces'); 957 | exports.reporters = require('./reporters'); 958 | exports.Runnable = require('./runnable'); 959 | exports.Context = require('./context'); 960 | exports.Runner = require('./runner'); 961 | exports.Suite = require('./suite'); 962 | exports.Hook = require('./hook'); 963 | exports.Test = require('./test'); 964 | 965 | /** 966 | * Return image `name` path. 967 | * 968 | * @param {String} name 969 | * @return {String} 970 | * @api private 971 | */ 972 | 973 | function image(name) { 974 | return __dirname + '/../images/' + name + '.png'; 975 | } 976 | 977 | /** 978 | * Setup mocha with `options`. 979 | * 980 | * Options: 981 | * 982 | * - `ui` name "bdd", "tdd", "exports" etc 983 | * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` 984 | * - `globals` array of accepted globals 985 | * - `timeout` timeout in milliseconds 986 | * - `ignoreLeaks` ignore global leaks 987 | * - `grep` string or regexp to filter tests with 988 | * 989 | * @param {Object} options 990 | * @api public 991 | */ 992 | 993 | function Mocha(options) { 994 | options = options || {}; 995 | this.files = []; 996 | this.options = options; 997 | this.grep(options.grep); 998 | this.suite = new exports.Suite('', new exports.Context); 999 | this.ui(options.ui); 1000 | this.reporter(options.reporter); 1001 | if (options.timeout) this.suite.timeout(options.timeout); 1002 | } 1003 | 1004 | /** 1005 | * Add test `file`. 1006 | * 1007 | * @param {String} file 1008 | * @api public 1009 | */ 1010 | 1011 | Mocha.prototype.addFile = function(file){ 1012 | this.files.push(file); 1013 | return this; 1014 | }; 1015 | 1016 | /** 1017 | * Set reporter to `name`, defaults to "dot". 1018 | * 1019 | * @param {String} name 1020 | * @api public 1021 | */ 1022 | 1023 | Mocha.prototype.reporter = function(name){ 1024 | name = name || 'dot'; 1025 | this._reporter = require('./reporters/' + name); 1026 | if (!this._reporter) throw new Error('invalid reporter "' + name + '"'); 1027 | return this; 1028 | }; 1029 | 1030 | /** 1031 | * Set test UI `name`, defaults to "bdd". 1032 | * 1033 | * @param {String} bdd 1034 | * @api public 1035 | */ 1036 | 1037 | Mocha.prototype.ui = function(name){ 1038 | name = name || 'bdd'; 1039 | this._ui = exports.interfaces[name]; 1040 | if (!this._ui) throw new Error('invalid interface "' + name + '"'); 1041 | this._ui = this._ui(this.suite); 1042 | return this; 1043 | }; 1044 | 1045 | /** 1046 | * Load registered files. 1047 | * 1048 | * @api private 1049 | */ 1050 | 1051 | Mocha.prototype.loadFiles = function(fn){ 1052 | var self = this; 1053 | var suite = this.suite; 1054 | var pending = this.files.length; 1055 | this.files.forEach(function(file){ 1056 | file = path.resolve(file); 1057 | suite.emit('pre-require', global, file, self); 1058 | suite.emit('require', require(file), file, self); 1059 | suite.emit('post-require', global, file, self); 1060 | --pending || (fn && fn()); 1061 | }); 1062 | }; 1063 | 1064 | /** 1065 | * Enable growl support. 1066 | * 1067 | * @api private 1068 | */ 1069 | 1070 | Mocha.prototype._growl = function(runner, reporter) { 1071 | var notify = require('growl'); 1072 | 1073 | runner.on('end', function(){ 1074 | var stats = reporter.stats; 1075 | if (stats.failures) { 1076 | var msg = stats.failures + ' of ' + runner.total + ' tests failed'; 1077 | notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); 1078 | } else { 1079 | notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { 1080 | name: 'mocha' 1081 | , title: 'Passed' 1082 | , image: image('ok') 1083 | }); 1084 | } 1085 | }); 1086 | }; 1087 | 1088 | /** 1089 | * Add regexp to grep for to the options object 1090 | * 1091 | * @param {RegExp} or {String} re 1092 | * @return {Mocha} 1093 | * @api public 1094 | */ 1095 | 1096 | Mocha.prototype.grep = function(re){ 1097 | this.options.grep = 'string' == typeof re 1098 | ? new RegExp(re) 1099 | : re; 1100 | return this; 1101 | }; 1102 | 1103 | /** 1104 | * Invert `.grep()` matches. 1105 | * 1106 | * @return {Mocha} 1107 | * @api public 1108 | */ 1109 | 1110 | Mocha.prototype.invert = function(){ 1111 | this.options.invert = true; 1112 | return this; 1113 | }; 1114 | 1115 | /** 1116 | * Ignore global leaks. 1117 | * 1118 | * @return {Mocha} 1119 | * @api public 1120 | */ 1121 | 1122 | Mocha.prototype.ignoreLeaks = function(){ 1123 | this.options.ignoreLeaks = true; 1124 | return this; 1125 | }; 1126 | 1127 | /** 1128 | * Enable growl support. 1129 | * 1130 | * @return {Mocha} 1131 | * @api public 1132 | */ 1133 | 1134 | Mocha.prototype.growl = function(){ 1135 | this.options.growl = true; 1136 | return this; 1137 | }; 1138 | 1139 | /** 1140 | * Ignore `globals`. 1141 | * 1142 | * @param {Array} globals 1143 | * @return {Mocha} 1144 | * @api public 1145 | */ 1146 | 1147 | Mocha.prototype.globals = function(globals){ 1148 | this.options.globals = globals; 1149 | return this; 1150 | }; 1151 | 1152 | /** 1153 | * Run tests and invoke `fn()` when complete. 1154 | * 1155 | * @param {Function} fn 1156 | * @return {Runner} 1157 | * @api public 1158 | */ 1159 | 1160 | Mocha.prototype.run = function(fn){ 1161 | this.loadFiles(); 1162 | var suite = this.suite; 1163 | var options = this.options; 1164 | var runner = new exports.Runner(suite); 1165 | var reporter = new this._reporter(runner); 1166 | runner.ignoreLeaks = options.ignoreLeaks; 1167 | if (options.grep) runner.grep(options.grep, options.invert); 1168 | if (options.globals) runner.globals(options.globals); 1169 | if (options.growl) this._growl(runner, reporter); 1170 | return runner.run(fn); 1171 | }; 1172 | 1173 | }); // module: mocha.js 1174 | 1175 | require.register("reporters/base.js", function(module, exports, require){ 1176 | 1177 | /** 1178 | * Module dependencies. 1179 | */ 1180 | 1181 | var tty = require('browser/tty') 1182 | , diff = require('browser/diff'); 1183 | 1184 | /** 1185 | * Save timer references to avoid Sinon interfering (see GH-237). 1186 | */ 1187 | 1188 | var Date = global.Date 1189 | , setTimeout = global.setTimeout 1190 | , setInterval = global.setInterval 1191 | , clearTimeout = global.clearTimeout 1192 | , clearInterval = global.clearInterval; 1193 | 1194 | /** 1195 | * Check if both stdio streams are associated with a tty. 1196 | */ 1197 | 1198 | var isatty = tty.isatty(1) && tty.isatty(2); 1199 | 1200 | /** 1201 | * Expose `Base`. 1202 | */ 1203 | 1204 | exports = module.exports = Base; 1205 | 1206 | /** 1207 | * Enable coloring by default. 1208 | */ 1209 | 1210 | exports.useColors = isatty; 1211 | 1212 | /** 1213 | * Default color map. 1214 | */ 1215 | 1216 | exports.colors = { 1217 | 'pass': 90 1218 | , 'fail': 31 1219 | , 'bright pass': 92 1220 | , 'bright fail': 91 1221 | , 'bright yellow': 93 1222 | , 'pending': 36 1223 | , 'suite': 0 1224 | , 'error title': 0 1225 | , 'error message': 31 1226 | , 'error stack': 90 1227 | , 'checkmark': 32 1228 | , 'fast': 90 1229 | , 'medium': 33 1230 | , 'slow': 31 1231 | , 'green': 32 1232 | , 'light': 90 1233 | , 'diff gutter': 90 1234 | , 'diff added': 42 1235 | , 'diff removed': 41 1236 | }; 1237 | 1238 | /** 1239 | * Color `str` with the given `type`, 1240 | * allowing colors to be disabled, 1241 | * as well as user-defined color 1242 | * schemes. 1243 | * 1244 | * @param {String} type 1245 | * @param {String} str 1246 | * @return {String} 1247 | * @api private 1248 | */ 1249 | 1250 | var color = exports.color = function(type, str) { 1251 | if (!exports.useColors) return str; 1252 | return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; 1253 | }; 1254 | 1255 | /** 1256 | * Expose term window size, with some 1257 | * defaults for when stderr is not a tty. 1258 | */ 1259 | 1260 | exports.window = { 1261 | width: isatty 1262 | ? process.stdout.getWindowSize 1263 | ? process.stdout.getWindowSize(1)[0] 1264 | : tty.getWindowSize()[1] 1265 | : 75 1266 | }; 1267 | 1268 | /** 1269 | * Expose some basic cursor interactions 1270 | * that are common among reporters. 1271 | */ 1272 | 1273 | exports.cursor = { 1274 | hide: function(){ 1275 | process.stdout.write('\u001b[?25l'); 1276 | }, 1277 | 1278 | show: function(){ 1279 | process.stdout.write('\u001b[?25h'); 1280 | }, 1281 | 1282 | deleteLine: function(){ 1283 | process.stdout.write('\u001b[2K'); 1284 | }, 1285 | 1286 | beginningOfLine: function(){ 1287 | process.stdout.write('\u001b[0G'); 1288 | }, 1289 | 1290 | CR: function(){ 1291 | exports.cursor.deleteLine(); 1292 | exports.cursor.beginningOfLine(); 1293 | } 1294 | }; 1295 | 1296 | /** 1297 | * A test is considered slow if it 1298 | * exceeds the following value in milliseconds. 1299 | */ 1300 | 1301 | exports.slow = 75; 1302 | 1303 | /** 1304 | * Outut the given `failures` as a list. 1305 | * 1306 | * @param {Array} failures 1307 | * @api public 1308 | */ 1309 | 1310 | exports.list = function(failures){ 1311 | console.error(); 1312 | failures.forEach(function(test, i){ 1313 | // format 1314 | var fmt = color('error title', ' %s) %s:\n') 1315 | + color('error message', ' %s') 1316 | + color('error stack', '\n%s\n'); 1317 | 1318 | // msg 1319 | var err = test.err 1320 | , message = err.message || '' 1321 | , stack = err.stack || message 1322 | , index = stack.indexOf(message) + message.length 1323 | , msg = stack.slice(0, index) 1324 | , actual = err.actual 1325 | , expected = err.expected; 1326 | 1327 | // actual / expected diff 1328 | if ('string' == typeof actual && 'string' == typeof expected) { 1329 | var len = Math.max(actual.length, expected.length); 1330 | 1331 | if (len < 20) msg = errorDiff(err, 'Chars'); 1332 | else msg = errorDiff(err, 'Words'); 1333 | 1334 | // linenos 1335 | var lines = msg.split('\n'); 1336 | if (lines.length > 4) { 1337 | var width = String(lines.length).length; 1338 | msg = lines.map(function(str, i){ 1339 | return pad(++i, width) + ' |' + ' ' + str; 1340 | }).join('\n'); 1341 | } 1342 | 1343 | // legend 1344 | msg = '\n' 1345 | + color('diff removed', 'actual') 1346 | + ' ' 1347 | + color('diff added', 'expected') 1348 | + '\n\n' 1349 | + msg 1350 | + '\n'; 1351 | 1352 | // indent 1353 | msg = msg.replace(/^/gm, ' '); 1354 | 1355 | fmt = color('error title', ' %s) %s:\n%s') 1356 | + color('error stack', '\n%s\n'); 1357 | } 1358 | 1359 | // indent stack trace without msg 1360 | stack = stack.slice(index ? index + 1 : index) 1361 | .replace(/^/gm, ' '); 1362 | 1363 | console.error(fmt, (i + 1), test.fullTitle(), msg, stack); 1364 | }); 1365 | }; 1366 | 1367 | /** 1368 | * Initialize a new `Base` reporter. 1369 | * 1370 | * All other reporters generally 1371 | * inherit from this reporter, providing 1372 | * stats such as test duration, number 1373 | * of tests passed / failed etc. 1374 | * 1375 | * @param {Runner} runner 1376 | * @api public 1377 | */ 1378 | 1379 | function Base(runner) { 1380 | var self = this 1381 | , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } 1382 | , failures = this.failures = []; 1383 | 1384 | if (!runner) return; 1385 | this.runner = runner; 1386 | 1387 | runner.on('start', function(){ 1388 | stats.start = new Date; 1389 | }); 1390 | 1391 | runner.on('suite', function(suite){ 1392 | stats.suites = stats.suites || 0; 1393 | suite.root || stats.suites++; 1394 | }); 1395 | 1396 | runner.on('test end', function(test){ 1397 | stats.tests = stats.tests || 0; 1398 | stats.tests++; 1399 | }); 1400 | 1401 | runner.on('pass', function(test){ 1402 | stats.passes = stats.passes || 0; 1403 | 1404 | var medium = exports.slow / 2; 1405 | test.speed = test.duration > exports.slow 1406 | ? 'slow' 1407 | : test.duration > medium 1408 | ? 'medium' 1409 | : 'fast'; 1410 | 1411 | stats.passes++; 1412 | }); 1413 | 1414 | runner.on('fail', function(test, err){ 1415 | stats.failures = stats.failures || 0; 1416 | stats.failures++; 1417 | test.err = err; 1418 | failures.push(test); 1419 | }); 1420 | 1421 | runner.on('end', function(){ 1422 | stats.end = new Date; 1423 | stats.duration = new Date - stats.start; 1424 | }); 1425 | 1426 | runner.on('pending', function(){ 1427 | stats.pending++; 1428 | }); 1429 | } 1430 | 1431 | /** 1432 | * Output common epilogue used by many of 1433 | * the bundled reporters. 1434 | * 1435 | * @api public 1436 | */ 1437 | 1438 | Base.prototype.epilogue = function(){ 1439 | var stats = this.stats 1440 | , fmt 1441 | , tests; 1442 | 1443 | console.log(); 1444 | 1445 | function pluralize(n) { 1446 | return 1 == n ? 'test' : 'tests'; 1447 | } 1448 | 1449 | // failure 1450 | if (stats.failures) { 1451 | fmt = color('bright fail', ' ✖') 1452 | + color('fail', ' %d of %d %s failed') 1453 | + color('light', ':') 1454 | 1455 | console.error(fmt, 1456 | stats.failures, 1457 | this.runner.total, 1458 | pluralize(this.runner.total)); 1459 | 1460 | Base.list(this.failures); 1461 | console.error(); 1462 | return; 1463 | } 1464 | 1465 | // pass 1466 | fmt = color('bright pass', ' ✔') 1467 | + color('green', ' %d %s complete') 1468 | + color('light', ' (%dms)'); 1469 | 1470 | console.log(fmt, 1471 | stats.tests || 0, 1472 | pluralize(stats.tests), 1473 | stats.duration); 1474 | 1475 | // pending 1476 | if (stats.pending) { 1477 | fmt = color('pending', ' •') 1478 | + color('pending', ' %d %s pending'); 1479 | 1480 | console.log(fmt, stats.pending, pluralize(stats.pending)); 1481 | } 1482 | 1483 | console.log(); 1484 | }; 1485 | 1486 | /** 1487 | * Pad the given `str` to `len`. 1488 | * 1489 | * @param {String} str 1490 | * @param {String} len 1491 | * @return {String} 1492 | * @api private 1493 | */ 1494 | 1495 | function pad(str, len) { 1496 | str = String(str); 1497 | return Array(len - str.length + 1).join(' ') + str; 1498 | } 1499 | 1500 | /** 1501 | * Return a character diff for `err`. 1502 | * 1503 | * @param {Error} err 1504 | * @return {String} 1505 | * @api private 1506 | */ 1507 | 1508 | function errorDiff(err, type) { 1509 | return diff['diff' + type](err.actual, err.expected).map(function(str){ 1510 | if (/^(\n+)$/.test(str.value)) str.value = Array(++RegExp.$1.length).join(''); 1511 | if (str.added) return colorLines('diff added', str.value); 1512 | if (str.removed) return colorLines('diff removed', str.value); 1513 | return str.value; 1514 | }).join(''); 1515 | } 1516 | 1517 | /** 1518 | * Color lines for `str`, using the color `name`. 1519 | * 1520 | * @param {String} name 1521 | * @param {String} str 1522 | * @return {String} 1523 | * @api private 1524 | */ 1525 | 1526 | function colorLines(name, str) { 1527 | return str.split('\n').map(function(str){ 1528 | return color(name, str); 1529 | }).join('\n'); 1530 | } 1531 | 1532 | }); // module: reporters/base.js 1533 | 1534 | require.register("reporters/doc.js", function(module, exports, require){ 1535 | 1536 | /** 1537 | * Module dependencies. 1538 | */ 1539 | 1540 | var Base = require('./base') 1541 | , utils = require('../utils'); 1542 | 1543 | /** 1544 | * Expose `Doc`. 1545 | */ 1546 | 1547 | exports = module.exports = Doc; 1548 | 1549 | /** 1550 | * Initialize a new `Doc` reporter. 1551 | * 1552 | * @param {Runner} runner 1553 | * @api public 1554 | */ 1555 | 1556 | function Doc(runner) { 1557 | Base.call(this, runner); 1558 | 1559 | var self = this 1560 | , stats = this.stats 1561 | , total = runner.total 1562 | , indents = 2; 1563 | 1564 | function indent() { 1565 | return Array(indents).join(' '); 1566 | } 1567 | 1568 | runner.on('suite', function(suite){ 1569 | if (suite.root) return; 1570 | ++indents; 1571 | console.log('%s
', indent()); 1572 | ++indents; 1573 | console.log('%s

%s

', indent(), suite.title); 1574 | console.log('%s
', indent()); 1575 | }); 1576 | 1577 | runner.on('suite end', function(suite){ 1578 | if (suite.root) return; 1579 | console.log('%s
', indent()); 1580 | --indents; 1581 | console.log('%s
', indent()); 1582 | --indents; 1583 | }); 1584 | 1585 | runner.on('pass', function(test){ 1586 | console.log('%s
%s
', indent(), test.title); 1587 | var code = utils.escape(utils.clean(test.fn.toString())); 1588 | console.log('%s
%s
', indent(), code); 1589 | }); 1590 | } 1591 | 1592 | }); // module: reporters/doc.js 1593 | 1594 | require.register("reporters/dot.js", function(module, exports, require){ 1595 | 1596 | /** 1597 | * Module dependencies. 1598 | */ 1599 | 1600 | var Base = require('./base') 1601 | , color = Base.color; 1602 | 1603 | /** 1604 | * Expose `Dot`. 1605 | */ 1606 | 1607 | exports = module.exports = Dot; 1608 | 1609 | /** 1610 | * Initialize a new `Dot` matrix test reporter. 1611 | * 1612 | * @param {Runner} runner 1613 | * @api public 1614 | */ 1615 | 1616 | function Dot(runner) { 1617 | Base.call(this, runner); 1618 | 1619 | var self = this 1620 | , stats = this.stats 1621 | , width = Base.window.width * .75 | 0 1622 | , c = '․' 1623 | , n = 0; 1624 | 1625 | runner.on('start', function(){ 1626 | process.stdout.write('\n '); 1627 | }); 1628 | 1629 | runner.on('pending', function(test){ 1630 | process.stdout.write(color('pending', c)); 1631 | }); 1632 | 1633 | runner.on('pass', function(test){ 1634 | if (++n % width == 0) process.stdout.write('\n '); 1635 | if ('slow' == test.speed) { 1636 | process.stdout.write(color('bright yellow', c)); 1637 | } else { 1638 | process.stdout.write(color(test.speed, c)); 1639 | } 1640 | }); 1641 | 1642 | runner.on('fail', function(test, err){ 1643 | if (++n % width == 0) process.stdout.write('\n '); 1644 | process.stdout.write(color('fail', c)); 1645 | }); 1646 | 1647 | runner.on('end', function(){ 1648 | console.log(); 1649 | self.epilogue(); 1650 | }); 1651 | } 1652 | 1653 | /** 1654 | * Inherit from `Base.prototype`. 1655 | */ 1656 | 1657 | Dot.prototype = new Base; 1658 | Dot.prototype.constructor = Dot; 1659 | 1660 | }); // module: reporters/dot.js 1661 | 1662 | require.register("reporters/html-cov.js", function(module, exports, require){ 1663 | 1664 | /** 1665 | * Module dependencies. 1666 | */ 1667 | 1668 | var JSONCov = require('./json-cov') 1669 | , fs = require('browser/fs'); 1670 | 1671 | /** 1672 | * Expose `HTMLCov`. 1673 | */ 1674 | 1675 | exports = module.exports = HTMLCov; 1676 | 1677 | /** 1678 | * Initialize a new `JsCoverage` reporter. 1679 | * 1680 | * @param {Runner} runner 1681 | * @api public 1682 | */ 1683 | 1684 | function HTMLCov(runner) { 1685 | var jade = require('jade') 1686 | , file = __dirname + '/templates/coverage.jade' 1687 | , str = fs.readFileSync(file, 'utf8') 1688 | , fn = jade.compile(str, { filename: file }) 1689 | , self = this; 1690 | 1691 | JSONCov.call(this, runner, false); 1692 | 1693 | runner.on('end', function(){ 1694 | process.stdout.write(fn({ 1695 | cov: self.cov 1696 | , coverageClass: coverageClass 1697 | })); 1698 | }); 1699 | } 1700 | 1701 | /** 1702 | * Return coverage class for `n`. 1703 | * 1704 | * @return {String} 1705 | * @api private 1706 | */ 1707 | 1708 | function coverageClass(n) { 1709 | if (n >= 75) return 'high'; 1710 | if (n >= 50) return 'medium'; 1711 | if (n >= 25) return 'low'; 1712 | return 'terrible'; 1713 | } 1714 | }); // module: reporters/html-cov.js 1715 | 1716 | require.register("reporters/html.js", function(module, exports, require){ 1717 | 1718 | /** 1719 | * Module dependencies. 1720 | */ 1721 | 1722 | var Base = require('./base') 1723 | , utils = require('../utils') 1724 | , Progress = require('../browser/progress') 1725 | , escape = utils.escape; 1726 | 1727 | /** 1728 | * Save timer references to avoid Sinon interfering (see GH-237). 1729 | */ 1730 | 1731 | var Date = global.Date 1732 | , setTimeout = global.setTimeout 1733 | , setInterval = global.setInterval 1734 | , clearTimeout = global.clearTimeout 1735 | , clearInterval = global.clearInterval; 1736 | 1737 | /** 1738 | * Expose `Doc`. 1739 | */ 1740 | 1741 | exports = module.exports = HTML; 1742 | 1743 | /** 1744 | * Stats template. 1745 | */ 1746 | 1747 | var statsTemplate = ''; 1753 | 1754 | /** 1755 | * Initialize a new `Doc` reporter. 1756 | * 1757 | * @param {Runner} runner 1758 | * @api public 1759 | */ 1760 | 1761 | function HTML(runner) { 1762 | Base.call(this, runner); 1763 | 1764 | var self = this 1765 | , stats = this.stats 1766 | , total = runner.total 1767 | , root = document.getElementById('mocha') 1768 | , stat = fragment(statsTemplate) 1769 | , items = stat.getElementsByTagName('li') 1770 | , passes = items[1].getElementsByTagName('em')[0] 1771 | , passesLink = items[1].getElementsByTagName('a')[0] 1772 | , failures = items[2].getElementsByTagName('em')[0] 1773 | , failuresLink = items[2].getElementsByTagName('a')[0] 1774 | , duration = items[3].getElementsByTagName('em')[0] 1775 | , canvas = stat.getElementsByTagName('canvas')[0] 1776 | , report = fragment('') 1777 | , stack = [report] 1778 | , progress 1779 | , ctx 1780 | 1781 | if (canvas.getContext) { 1782 | var ratio = window.devicePixelRatio || 1; 1783 | canvas.style.width = canvas.width; 1784 | canvas.style.height = canvas.height; 1785 | canvas.width *= ratio; 1786 | canvas.height *= ratio; 1787 | ctx = canvas.getContext('2d'); 1788 | ctx.scale(ratio, ratio); 1789 | progress = new Progress; 1790 | } 1791 | 1792 | if (!root) return error('#mocha div missing, add it to your document'); 1793 | 1794 | // pass toggle 1795 | on(passesLink, 'click', function () { 1796 | var className = /pass/.test(report.className) ? '' : ' pass'; 1797 | report.className = report.className.replace(/fail|pass/g, '') + className; 1798 | }); 1799 | 1800 | // failure toggle 1801 | on(failuresLink, 'click', function () { 1802 | var className = /fail/.test(report.className) ? '' : ' fail'; 1803 | report.className = report.className.replace(/fail|pass/g, '') + className; 1804 | }); 1805 | 1806 | root.appendChild(stat); 1807 | root.appendChild(report); 1808 | 1809 | if (progress) progress.size(40); 1810 | 1811 | runner.on('suite', function(suite){ 1812 | if (suite.root) return; 1813 | 1814 | // suite 1815 | var grep = '^' + encodeURIComponent(utils.escapeRegexp(suite.fullTitle())); 1816 | var url = location.protocol + '//' + location.host + location.pathname + '?grep=' + grep; 1817 | var el = fragment('
  • %s

  • ', url, escape(suite.title)); 1818 | 1819 | // container 1820 | stack[0].appendChild(el); 1821 | stack.unshift(document.createElement('ul')); 1822 | el.appendChild(stack[0]); 1823 | }); 1824 | 1825 | runner.on('suite end', function(suite){ 1826 | if (suite.root) return; 1827 | stack.shift(); 1828 | }); 1829 | 1830 | runner.on('fail', function(test, err){ 1831 | if ('hook' == test.type || err.uncaught) runner.emit('test end', test); 1832 | }); 1833 | 1834 | runner.on('test end', function(test){ 1835 | window.scrollTo(0, document.body.scrollHeight); 1836 | 1837 | // TODO: add to stats 1838 | var percent = stats.tests / total * 100 | 0; 1839 | if (progress) progress.update(percent).draw(ctx); 1840 | 1841 | // update stats 1842 | var ms = new Date - stats.start; 1843 | text(passes, stats.passes); 1844 | text(failures, stats.failures); 1845 | text(duration, (ms / 1000).toFixed(2)); 1846 | 1847 | // test 1848 | if ('passed' == test.state) { 1849 | var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration); 1850 | } else if (test.pending) { 1851 | var el = fragment('
  • %e

  • ', test.title); 1852 | } else { 1853 | var el = fragment('
  • %e

  • ', test.title); 1854 | var str = test.err.stack || test.err.toString(); 1855 | 1856 | // FF / Opera do not add the message 1857 | if (!~str.indexOf(test.err.message)) { 1858 | str = test.err.message + '\n' + str; 1859 | } 1860 | 1861 | // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we 1862 | // check for the result of the stringifying. 1863 | if ('[object Error]' == str) str = test.err.message; 1864 | 1865 | // Safari doesn't give you a stack. Let's at least provide a source line. 1866 | if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { 1867 | str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; 1868 | } 1869 | 1870 | el.appendChild(fragment('
    %e
    ', str)); 1871 | } 1872 | 1873 | // toggle code 1874 | // TODO: defer 1875 | if (!test.pending) { 1876 | var h2 = el.getElementsByTagName('h2')[0]; 1877 | 1878 | on(h2, 'click', function(){ 1879 | pre.style.display = 'none' == pre.style.display 1880 | ? 'inline-block' 1881 | : 'none'; 1882 | }); 1883 | 1884 | var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); 1885 | el.appendChild(pre); 1886 | pre.style.display = 'none'; 1887 | } 1888 | 1889 | stack[0].appendChild(el); 1890 | }); 1891 | } 1892 | 1893 | /** 1894 | * Display error `msg`. 1895 | */ 1896 | 1897 | function error(msg) { 1898 | document.body.appendChild(fragment('
    %s
    ', msg)); 1899 | } 1900 | 1901 | /** 1902 | * Return a DOM fragment from `html`. 1903 | */ 1904 | 1905 | function fragment(html) { 1906 | var args = arguments 1907 | , div = document.createElement('div') 1908 | , i = 1; 1909 | 1910 | div.innerHTML = html.replace(/%([se])/g, function(_, type){ 1911 | switch (type) { 1912 | case 's': return String(args[i++]); 1913 | case 'e': return escape(args[i++]); 1914 | } 1915 | }); 1916 | 1917 | return div.firstChild; 1918 | } 1919 | 1920 | /** 1921 | * Set `el` text to `str`. 1922 | */ 1923 | 1924 | function text(el, str) { 1925 | if (el.textContent) { 1926 | el.textContent = str; 1927 | } else { 1928 | el.innerText = str; 1929 | } 1930 | } 1931 | 1932 | /** 1933 | * Listen on `event` with callback `fn`. 1934 | */ 1935 | 1936 | function on(el, event, fn) { 1937 | if (el.addEventListener) { 1938 | el.addEventListener(event, fn, false); 1939 | } else { 1940 | el.attachEvent('on' + event, fn); 1941 | } 1942 | } 1943 | 1944 | }); // module: reporters/html.js 1945 | 1946 | require.register("reporters/index.js", function(module, exports, require){ 1947 | 1948 | exports.Base = require('./base'); 1949 | exports.Dot = require('./dot'); 1950 | exports.Doc = require('./doc'); 1951 | exports.TAP = require('./tap'); 1952 | exports.JSON = require('./json'); 1953 | exports.HTML = require('./html'); 1954 | exports.List = require('./list'); 1955 | exports.Min = require('./min'); 1956 | exports.Spec = require('./spec'); 1957 | exports.Nyan = require('./nyan'); 1958 | exports.XUnit = require('./xunit'); 1959 | exports.Progress = require('./progress'); 1960 | exports.Landing = require('./landing'); 1961 | exports.JSONCov = require('./json-cov'); 1962 | exports.HTMLCov = require('./html-cov'); 1963 | exports.Markdown = require('./markdown'); 1964 | exports.JSONStream = require('./json-stream'); 1965 | exports.Teamcity = require('./teamcity'); 1966 | 1967 | }); // module: reporters/index.js 1968 | 1969 | require.register("reporters/json-cov.js", function(module, exports, require){ 1970 | 1971 | /** 1972 | * Module dependencies. 1973 | */ 1974 | 1975 | var Base = require('./base'); 1976 | 1977 | /** 1978 | * Expose `JSONCov`. 1979 | */ 1980 | 1981 | exports = module.exports = JSONCov; 1982 | 1983 | /** 1984 | * Initialize a new `JsCoverage` reporter. 1985 | * 1986 | * @param {Runner} runner 1987 | * @param {Boolean} output 1988 | * @api public 1989 | */ 1990 | 1991 | function JSONCov(runner, output) { 1992 | var self = this 1993 | , output = 1 == arguments.length ? true : output; 1994 | 1995 | Base.call(this, runner); 1996 | 1997 | var tests = [] 1998 | , failures = [] 1999 | , passes = []; 2000 | 2001 | runner.on('test end', function(test){ 2002 | tests.push(test); 2003 | }); 2004 | 2005 | runner.on('pass', function(test){ 2006 | passes.push(test); 2007 | }); 2008 | 2009 | runner.on('fail', function(test){ 2010 | failures.push(test); 2011 | }); 2012 | 2013 | runner.on('end', function(){ 2014 | var cov = global._$jscoverage || {}; 2015 | var result = self.cov = map(cov); 2016 | result.stats = self.stats; 2017 | result.tests = tests.map(clean); 2018 | result.failures = failures.map(clean); 2019 | result.passes = passes.map(clean); 2020 | if (!output) return; 2021 | process.stdout.write(JSON.stringify(result, null, 2 )); 2022 | }); 2023 | } 2024 | 2025 | /** 2026 | * Map jscoverage data to a JSON structure 2027 | * suitable for reporting. 2028 | * 2029 | * @param {Object} cov 2030 | * @return {Object} 2031 | * @api private 2032 | */ 2033 | 2034 | function map(cov) { 2035 | var ret = { 2036 | instrumentation: 'node-jscoverage' 2037 | , sloc: 0 2038 | , hits: 0 2039 | , misses: 0 2040 | , coverage: 0 2041 | , files: [] 2042 | }; 2043 | 2044 | for (var filename in cov) { 2045 | var data = coverage(filename, cov[filename]); 2046 | ret.files.push(data); 2047 | ret.hits += data.hits; 2048 | ret.misses += data.misses; 2049 | ret.sloc += data.sloc; 2050 | } 2051 | 2052 | if (ret.sloc > 0) { 2053 | ret.coverage = (ret.hits / ret.sloc) * 100; 2054 | } 2055 | 2056 | return ret; 2057 | }; 2058 | 2059 | /** 2060 | * Map jscoverage data for a single source file 2061 | * to a JSON structure suitable for reporting. 2062 | * 2063 | * @param {String} filename name of the source file 2064 | * @param {Object} data jscoverage coverage data 2065 | * @return {Object} 2066 | * @api private 2067 | */ 2068 | 2069 | function coverage(filename, data) { 2070 | var ret = { 2071 | filename: filename, 2072 | coverage: 0, 2073 | hits: 0, 2074 | misses: 0, 2075 | sloc: 0, 2076 | source: {} 2077 | }; 2078 | 2079 | data.source.forEach(function(line, num){ 2080 | num++; 2081 | 2082 | if (data[num] === 0) { 2083 | ret.misses++; 2084 | ret.sloc++; 2085 | } else if (data[num] !== undefined) { 2086 | ret.hits++; 2087 | ret.sloc++; 2088 | } 2089 | 2090 | ret.source[num] = { 2091 | source: line 2092 | , coverage: data[num] === undefined 2093 | ? '' 2094 | : data[num] 2095 | }; 2096 | }); 2097 | 2098 | ret.coverage = ret.hits / ret.sloc * 100; 2099 | 2100 | return ret; 2101 | } 2102 | 2103 | /** 2104 | * Return a plain-object representation of `test` 2105 | * free of cyclic properties etc. 2106 | * 2107 | * @param {Object} test 2108 | * @return {Object} 2109 | * @api private 2110 | */ 2111 | 2112 | function clean(test) { 2113 | return { 2114 | title: test.title 2115 | , fullTitle: test.fullTitle() 2116 | , duration: test.duration 2117 | } 2118 | } 2119 | 2120 | }); // module: reporters/json-cov.js 2121 | 2122 | require.register("reporters/json-stream.js", function(module, exports, require){ 2123 | 2124 | /** 2125 | * Module dependencies. 2126 | */ 2127 | 2128 | var Base = require('./base') 2129 | , color = Base.color; 2130 | 2131 | /** 2132 | * Expose `List`. 2133 | */ 2134 | 2135 | exports = module.exports = List; 2136 | 2137 | /** 2138 | * Initialize a new `List` test reporter. 2139 | * 2140 | * @param {Runner} runner 2141 | * @api public 2142 | */ 2143 | 2144 | function List(runner) { 2145 | Base.call(this, runner); 2146 | 2147 | var self = this 2148 | , stats = this.stats 2149 | , total = runner.total; 2150 | 2151 | runner.on('start', function(){ 2152 | console.log(JSON.stringify(['start', { total: total }])); 2153 | }); 2154 | 2155 | runner.on('pass', function(test){ 2156 | console.log(JSON.stringify(['pass', clean(test)])); 2157 | }); 2158 | 2159 | runner.on('fail', function(test, err){ 2160 | console.log(JSON.stringify(['fail', clean(test)])); 2161 | }); 2162 | 2163 | runner.on('end', function(){ 2164 | process.stdout.write(JSON.stringify(['end', self.stats])); 2165 | }); 2166 | } 2167 | 2168 | /** 2169 | * Return a plain-object representation of `test` 2170 | * free of cyclic properties etc. 2171 | * 2172 | * @param {Object} test 2173 | * @return {Object} 2174 | * @api private 2175 | */ 2176 | 2177 | function clean(test) { 2178 | return { 2179 | title: test.title 2180 | , fullTitle: test.fullTitle() 2181 | , duration: test.duration 2182 | } 2183 | } 2184 | }); // module: reporters/json-stream.js 2185 | 2186 | require.register("reporters/json.js", function(module, exports, require){ 2187 | 2188 | /** 2189 | * Module dependencies. 2190 | */ 2191 | 2192 | var Base = require('./base') 2193 | , cursor = Base.cursor 2194 | , color = Base.color; 2195 | 2196 | /** 2197 | * Expose `JSON`. 2198 | */ 2199 | 2200 | exports = module.exports = JSONReporter; 2201 | 2202 | /** 2203 | * Initialize a new `JSON` reporter. 2204 | * 2205 | * @param {Runner} runner 2206 | * @api public 2207 | */ 2208 | 2209 | function JSONReporter(runner) { 2210 | var self = this; 2211 | Base.call(this, runner); 2212 | 2213 | var tests = [] 2214 | , failures = [] 2215 | , passes = []; 2216 | 2217 | runner.on('test end', function(test){ 2218 | tests.push(test); 2219 | }); 2220 | 2221 | runner.on('pass', function(test){ 2222 | passes.push(test); 2223 | }); 2224 | 2225 | runner.on('fail', function(test){ 2226 | failures.push(test); 2227 | }); 2228 | 2229 | runner.on('end', function(){ 2230 | var obj = { 2231 | stats: self.stats 2232 | , tests: tests.map(clean) 2233 | , failures: failures.map(clean) 2234 | , passes: passes.map(clean) 2235 | }; 2236 | 2237 | process.stdout.write(JSON.stringify(obj, null, 2)); 2238 | }); 2239 | } 2240 | 2241 | /** 2242 | * Return a plain-object representation of `test` 2243 | * free of cyclic properties etc. 2244 | * 2245 | * @param {Object} test 2246 | * @return {Object} 2247 | * @api private 2248 | */ 2249 | 2250 | function clean(test) { 2251 | return { 2252 | title: test.title 2253 | , fullTitle: test.fullTitle() 2254 | , duration: test.duration 2255 | } 2256 | } 2257 | }); // module: reporters/json.js 2258 | 2259 | require.register("reporters/landing.js", function(module, exports, require){ 2260 | 2261 | /** 2262 | * Module dependencies. 2263 | */ 2264 | 2265 | var Base = require('./base') 2266 | , cursor = Base.cursor 2267 | , color = Base.color; 2268 | 2269 | /** 2270 | * Expose `Landing`. 2271 | */ 2272 | 2273 | exports = module.exports = Landing; 2274 | 2275 | /** 2276 | * Airplane color. 2277 | */ 2278 | 2279 | Base.colors.plane = 0; 2280 | 2281 | /** 2282 | * Airplane crash color. 2283 | */ 2284 | 2285 | Base.colors['plane crash'] = 31; 2286 | 2287 | /** 2288 | * Runway color. 2289 | */ 2290 | 2291 | Base.colors.runway = 90; 2292 | 2293 | /** 2294 | * Initialize a new `Landing` reporter. 2295 | * 2296 | * @param {Runner} runner 2297 | * @api public 2298 | */ 2299 | 2300 | function Landing(runner) { 2301 | Base.call(this, runner); 2302 | 2303 | var self = this 2304 | , stats = this.stats 2305 | , width = Base.window.width * .75 | 0 2306 | , total = runner.total 2307 | , stream = process.stdout 2308 | , plane = color('plane', '✈') 2309 | , crashed = -1 2310 | , n = 0; 2311 | 2312 | function runway() { 2313 | var buf = Array(width).join('-'); 2314 | return ' ' + color('runway', buf); 2315 | } 2316 | 2317 | runner.on('start', function(){ 2318 | stream.write('\n '); 2319 | cursor.hide(); 2320 | }); 2321 | 2322 | runner.on('test end', function(test){ 2323 | // check if the plane crashed 2324 | var col = -1 == crashed 2325 | ? width * ++n / total | 0 2326 | : crashed; 2327 | 2328 | // show the crash 2329 | if ('failed' == test.state) { 2330 | plane = color('plane crash', '✈'); 2331 | crashed = col; 2332 | } 2333 | 2334 | // render landing strip 2335 | stream.write('\u001b[4F\n\n'); 2336 | stream.write(runway()); 2337 | stream.write('\n '); 2338 | stream.write(color('runway', Array(col).join('⋅'))); 2339 | stream.write(plane) 2340 | stream.write(color('runway', Array(width - col).join('⋅') + '\n')); 2341 | stream.write(runway()); 2342 | stream.write('\u001b[0m'); 2343 | }); 2344 | 2345 | runner.on('end', function(){ 2346 | cursor.show(); 2347 | console.log(); 2348 | self.epilogue(); 2349 | }); 2350 | } 2351 | 2352 | /** 2353 | * Inherit from `Base.prototype`. 2354 | */ 2355 | 2356 | Landing.prototype = new Base; 2357 | Landing.prototype.constructor = Landing; 2358 | 2359 | }); // module: reporters/landing.js 2360 | 2361 | require.register("reporters/list.js", function(module, exports, require){ 2362 | 2363 | /** 2364 | * Module dependencies. 2365 | */ 2366 | 2367 | var Base = require('./base') 2368 | , cursor = Base.cursor 2369 | , color = Base.color; 2370 | 2371 | /** 2372 | * Expose `List`. 2373 | */ 2374 | 2375 | exports = module.exports = List; 2376 | 2377 | /** 2378 | * Initialize a new `List` test reporter. 2379 | * 2380 | * @param {Runner} runner 2381 | * @api public 2382 | */ 2383 | 2384 | function List(runner) { 2385 | Base.call(this, runner); 2386 | 2387 | var self = this 2388 | , stats = this.stats 2389 | , n = 0; 2390 | 2391 | runner.on('start', function(){ 2392 | console.log(); 2393 | }); 2394 | 2395 | runner.on('test', function(test){ 2396 | process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); 2397 | }); 2398 | 2399 | runner.on('pending', function(test){ 2400 | var fmt = color('checkmark', ' -') 2401 | + color('pending', ' %s'); 2402 | console.log(fmt, test.fullTitle()); 2403 | }); 2404 | 2405 | runner.on('pass', function(test){ 2406 | var fmt = color('checkmark', ' ✓') 2407 | + color('pass', ' %s: ') 2408 | + color(test.speed, '%dms'); 2409 | cursor.CR(); 2410 | console.log(fmt, test.fullTitle(), test.duration); 2411 | }); 2412 | 2413 | runner.on('fail', function(test, err){ 2414 | cursor.CR(); 2415 | console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); 2416 | }); 2417 | 2418 | runner.on('end', self.epilogue.bind(self)); 2419 | } 2420 | 2421 | /** 2422 | * Inherit from `Base.prototype`. 2423 | */ 2424 | 2425 | List.prototype = new Base; 2426 | List.prototype.constructor = List; 2427 | 2428 | 2429 | }); // module: reporters/list.js 2430 | 2431 | require.register("reporters/markdown.js", function(module, exports, require){ 2432 | /** 2433 | * Module dependencies. 2434 | */ 2435 | 2436 | var Base = require('./base') 2437 | , utils = require('../utils'); 2438 | 2439 | /** 2440 | * Expose `Markdown`. 2441 | */ 2442 | 2443 | exports = module.exports = Markdown; 2444 | 2445 | /** 2446 | * Initialize a new `Markdown` reporter. 2447 | * 2448 | * @param {Runner} runner 2449 | * @api public 2450 | */ 2451 | 2452 | function Markdown(runner) { 2453 | Base.call(this, runner); 2454 | 2455 | var self = this 2456 | , stats = this.stats 2457 | , total = runner.total 2458 | , level = 0 2459 | , buf = ''; 2460 | 2461 | function title(str) { 2462 | return Array(level).join('#') + ' ' + str; 2463 | } 2464 | 2465 | function indent() { 2466 | return Array(level).join(' '); 2467 | } 2468 | 2469 | function mapTOC(suite, obj) { 2470 | var ret = obj; 2471 | obj = obj[suite.title] = obj[suite.title] || { suite: suite }; 2472 | suite.suites.forEach(function(suite){ 2473 | mapTOC(suite, obj); 2474 | }); 2475 | return ret; 2476 | } 2477 | 2478 | function stringifyTOC(obj, level) { 2479 | ++level; 2480 | var buf = ''; 2481 | var link; 2482 | for (var key in obj) { 2483 | if ('suite' == key) continue; 2484 | if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; 2485 | if (key) buf += Array(level).join(' ') + link; 2486 | buf += stringifyTOC(obj[key], level); 2487 | } 2488 | --level; 2489 | return buf; 2490 | } 2491 | 2492 | function generateTOC(suite) { 2493 | var obj = mapTOC(suite, {}); 2494 | return stringifyTOC(obj, 0); 2495 | } 2496 | 2497 | generateTOC(runner.suite); 2498 | 2499 | runner.on('suite', function(suite){ 2500 | ++level; 2501 | var slug = utils.slug(suite.fullTitle()); 2502 | buf += '' + '\n'; 2503 | buf += title(suite.title) + '\n'; 2504 | }); 2505 | 2506 | runner.on('suite end', function(suite){ 2507 | --level; 2508 | }); 2509 | 2510 | runner.on('pass', function(test){ 2511 | var code = utils.clean(test.fn.toString()); 2512 | buf += test.title + '.\n'; 2513 | buf += '\n```js\n'; 2514 | buf += code + '\n'; 2515 | buf += '```\n\n'; 2516 | }); 2517 | 2518 | runner.on('end', function(){ 2519 | console.log('# TOC\n'); 2520 | console.log(generateTOC(runner.suite)); 2521 | console.log(buf); 2522 | }); 2523 | } 2524 | }); // module: reporters/markdown.js 2525 | 2526 | require.register("reporters/min.js", function(module, exports, require){ 2527 | 2528 | /** 2529 | * Module dependencies. 2530 | */ 2531 | 2532 | var Base = require('./base'); 2533 | 2534 | /** 2535 | * Expose `Min`. 2536 | */ 2537 | 2538 | exports = module.exports = Min; 2539 | 2540 | /** 2541 | * Initialize a new `Min` minimal test reporter (best used with --watch). 2542 | * 2543 | * @param {Runner} runner 2544 | * @api public 2545 | */ 2546 | 2547 | function Min(runner) { 2548 | Base.call(this, runner); 2549 | 2550 | runner.on('start', function(){ 2551 | // clear screen 2552 | process.stdout.write('\u001b[2J'); 2553 | // set cursor position 2554 | process.stdout.write('\u001b[1;3H'); 2555 | }); 2556 | 2557 | runner.on('end', this.epilogue.bind(this)); 2558 | } 2559 | 2560 | /** 2561 | * Inherit from `Base.prototype`. 2562 | */ 2563 | 2564 | Min.prototype = new Base; 2565 | Min.prototype.constructor = Min; 2566 | 2567 | }); // module: reporters/min.js 2568 | 2569 | require.register("reporters/nyan.js", function(module, exports, require){ 2570 | 2571 | /** 2572 | * Module dependencies. 2573 | */ 2574 | 2575 | var Base = require('./base') 2576 | , color = Base.color; 2577 | 2578 | /** 2579 | * Expose `Dot`. 2580 | */ 2581 | 2582 | exports = module.exports = NyanCat; 2583 | 2584 | /** 2585 | * Initialize a new `Dot` matrix test reporter. 2586 | * 2587 | * @param {Runner} runner 2588 | * @api public 2589 | */ 2590 | 2591 | function NyanCat(runner) { 2592 | Base.call(this, runner); 2593 | 2594 | var self = this 2595 | , stats = this.stats 2596 | , width = Base.window.width * .75 | 0 2597 | , rainbowColors = this.rainbowColors = self.generateColors() 2598 | , colorIndex = this.colorIndex = 0 2599 | , numerOfLines = this.numberOfLines = 4 2600 | , trajectories = this.trajectories = [[], [], [], []] 2601 | , nyanCatWidth = this.nyanCatWidth = 11 2602 | , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) 2603 | , scoreboardWidth = this.scoreboardWidth = 5 2604 | , tick = this.tick = 0 2605 | , n = 0; 2606 | 2607 | runner.on('start', function(){ 2608 | Base.cursor.hide(); 2609 | self.draw('start'); 2610 | }); 2611 | 2612 | runner.on('pending', function(test){ 2613 | self.draw('pending'); 2614 | }); 2615 | 2616 | runner.on('pass', function(test){ 2617 | self.draw('pass'); 2618 | }); 2619 | 2620 | runner.on('fail', function(test, err){ 2621 | self.draw('fail'); 2622 | }); 2623 | 2624 | runner.on('end', function(){ 2625 | Base.cursor.show(); 2626 | for (var i = 0; i < self.numberOfLines; i++) write('\n'); 2627 | self.epilogue(); 2628 | }); 2629 | } 2630 | 2631 | /** 2632 | * Draw the nyan cat with runner `status`. 2633 | * 2634 | * @param {String} status 2635 | * @api private 2636 | */ 2637 | 2638 | NyanCat.prototype.draw = function(status){ 2639 | this.appendRainbow(); 2640 | this.drawScoreboard(); 2641 | this.drawRainbow(); 2642 | this.drawNyanCat(status); 2643 | this.tick = !this.tick; 2644 | }; 2645 | 2646 | /** 2647 | * Draw the "scoreboard" showing the number 2648 | * of passes, failures and pending tests. 2649 | * 2650 | * @api private 2651 | */ 2652 | 2653 | NyanCat.prototype.drawScoreboard = function(){ 2654 | var stats = this.stats; 2655 | var colors = Base.colors; 2656 | 2657 | function draw(color, n) { 2658 | write(' '); 2659 | write('\u001b[' + color + 'm' + n + '\u001b[0m'); 2660 | write('\n'); 2661 | } 2662 | 2663 | draw(colors.green, stats.passes); 2664 | draw(colors.fail, stats.failures); 2665 | draw(colors.pending, stats.pending); 2666 | write('\n'); 2667 | 2668 | this.cursorUp(this.numberOfLines); 2669 | }; 2670 | 2671 | /** 2672 | * Append the rainbow. 2673 | * 2674 | * @api private 2675 | */ 2676 | 2677 | NyanCat.prototype.appendRainbow = function(){ 2678 | var segment = this.tick ? '_' : '-'; 2679 | var rainbowified = this.rainbowify(segment); 2680 | 2681 | for (var index = 0; index < this.numberOfLines; index++) { 2682 | var trajectory = this.trajectories[index]; 2683 | if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); 2684 | trajectory.push(rainbowified); 2685 | } 2686 | }; 2687 | 2688 | /** 2689 | * Draw the rainbow. 2690 | * 2691 | * @api private 2692 | */ 2693 | 2694 | NyanCat.prototype.drawRainbow = function(){ 2695 | var self = this; 2696 | 2697 | this.trajectories.forEach(function(line, index) { 2698 | write('\u001b[' + self.scoreboardWidth + 'C'); 2699 | write(line.join('')); 2700 | write('\n'); 2701 | }); 2702 | 2703 | this.cursorUp(this.numberOfLines); 2704 | }; 2705 | 2706 | /** 2707 | * Draw the nyan cat with `status`. 2708 | * 2709 | * @param {String} status 2710 | * @api private 2711 | */ 2712 | 2713 | NyanCat.prototype.drawNyanCat = function(status) { 2714 | var self = this; 2715 | var startWidth = this.scoreboardWidth + this.trajectories[0].length; 2716 | 2717 | [0, 1, 2, 3].forEach(function(index) { 2718 | write('\u001b[' + startWidth + 'C'); 2719 | 2720 | switch (index) { 2721 | case 0: 2722 | write('_,------,'); 2723 | write('\n'); 2724 | break; 2725 | case 1: 2726 | var padding = self.tick ? ' ' : ' '; 2727 | write('_|' + padding + '/\\_/\\ '); 2728 | write('\n'); 2729 | break; 2730 | case 2: 2731 | var padding = self.tick ? '_' : '__'; 2732 | var tail = self.tick ? '~' : '^'; 2733 | var face; 2734 | switch (status) { 2735 | case 'pass': 2736 | face = '( ^ .^)'; 2737 | break; 2738 | case 'fail': 2739 | face = '( o .o)'; 2740 | break; 2741 | default: 2742 | face = '( - .-)'; 2743 | } 2744 | write(tail + '|' + padding + face + ' '); 2745 | write('\n'); 2746 | break; 2747 | case 3: 2748 | var padding = self.tick ? ' ' : ' '; 2749 | write(padding + '"" "" '); 2750 | write('\n'); 2751 | break; 2752 | } 2753 | }); 2754 | 2755 | this.cursorUp(this.numberOfLines); 2756 | }; 2757 | 2758 | /** 2759 | * Move cursor up `n`. 2760 | * 2761 | * @param {Number} n 2762 | * @api private 2763 | */ 2764 | 2765 | NyanCat.prototype.cursorUp = function(n) { 2766 | write('\u001b[' + n + 'A'); 2767 | }; 2768 | 2769 | /** 2770 | * Move cursor down `n`. 2771 | * 2772 | * @param {Number} n 2773 | * @api private 2774 | */ 2775 | 2776 | NyanCat.prototype.cursorDown = function(n) { 2777 | write('\u001b[' + n + 'B'); 2778 | }; 2779 | 2780 | /** 2781 | * Generate rainbow colors. 2782 | * 2783 | * @return {Array} 2784 | * @api private 2785 | */ 2786 | 2787 | NyanCat.prototype.generateColors = function(){ 2788 | var colors = []; 2789 | 2790 | for (var i = 0; i < (6 * 7); i++) { 2791 | var pi3 = Math.floor(Math.PI / 3); 2792 | var n = (i * (1.0 / 6)); 2793 | var r = Math.floor(3 * Math.sin(n) + 3); 2794 | var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); 2795 | var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); 2796 | colors.push(36 * r + 6 * g + b + 16); 2797 | } 2798 | 2799 | return colors; 2800 | }; 2801 | 2802 | /** 2803 | * Apply rainbow to the given `str`. 2804 | * 2805 | * @param {String} str 2806 | * @return {String} 2807 | * @api private 2808 | */ 2809 | 2810 | NyanCat.prototype.rainbowify = function(str){ 2811 | var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; 2812 | this.colorIndex += 1; 2813 | return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; 2814 | }; 2815 | 2816 | /** 2817 | * Stdout helper. 2818 | */ 2819 | 2820 | function write(string) { 2821 | process.stdout.write(string); 2822 | } 2823 | 2824 | /** 2825 | * Inherit from `Base.prototype`. 2826 | */ 2827 | 2828 | NyanCat.prototype = new Base; 2829 | NyanCat.prototype.constructor = NyanCat; 2830 | 2831 | 2832 | }); // module: reporters/nyan.js 2833 | 2834 | require.register("reporters/progress.js", function(module, exports, require){ 2835 | 2836 | /** 2837 | * Module dependencies. 2838 | */ 2839 | 2840 | var Base = require('./base') 2841 | , cursor = Base.cursor 2842 | , color = Base.color; 2843 | 2844 | /** 2845 | * Expose `Progress`. 2846 | */ 2847 | 2848 | exports = module.exports = Progress; 2849 | 2850 | /** 2851 | * General progress bar color. 2852 | */ 2853 | 2854 | Base.colors.progress = 90; 2855 | 2856 | /** 2857 | * Initialize a new `Progress` bar test reporter. 2858 | * 2859 | * @param {Runner} runner 2860 | * @param {Object} options 2861 | * @api public 2862 | */ 2863 | 2864 | function Progress(runner, options) { 2865 | Base.call(this, runner); 2866 | 2867 | var self = this 2868 | , options = options || {} 2869 | , stats = this.stats 2870 | , width = Base.window.width * .50 | 0 2871 | , total = runner.total 2872 | , complete = 0 2873 | , max = Math.max; 2874 | 2875 | // default chars 2876 | options.open = options.open || '['; 2877 | options.complete = options.complete || '▬'; 2878 | options.incomplete = options.incomplete || '⋅'; 2879 | options.close = options.close || ']'; 2880 | options.verbose = false; 2881 | 2882 | // tests started 2883 | runner.on('start', function(){ 2884 | console.log(); 2885 | cursor.hide(); 2886 | }); 2887 | 2888 | // tests complete 2889 | runner.on('test end', function(){ 2890 | complete++; 2891 | var incomplete = total - complete 2892 | , percent = complete / total 2893 | , n = width * percent | 0 2894 | , i = width - n; 2895 | 2896 | cursor.CR(); 2897 | process.stdout.write('\u001b[J'); 2898 | process.stdout.write(color('progress', ' ' + options.open)); 2899 | process.stdout.write(Array(n).join(options.complete)); 2900 | process.stdout.write(Array(i).join(options.incomplete)); 2901 | process.stdout.write(color('progress', options.close)); 2902 | if (options.verbose) { 2903 | process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); 2904 | } 2905 | }); 2906 | 2907 | // tests are complete, output some stats 2908 | // and the failures if any 2909 | runner.on('end', function(){ 2910 | cursor.show(); 2911 | console.log(); 2912 | self.epilogue(); 2913 | }); 2914 | } 2915 | 2916 | /** 2917 | * Inherit from `Base.prototype`. 2918 | */ 2919 | 2920 | Progress.prototype = new Base; 2921 | Progress.prototype.constructor = Progress; 2922 | 2923 | 2924 | }); // module: reporters/progress.js 2925 | 2926 | require.register("reporters/spec.js", function(module, exports, require){ 2927 | 2928 | /** 2929 | * Module dependencies. 2930 | */ 2931 | 2932 | var Base = require('./base') 2933 | , cursor = Base.cursor 2934 | , color = Base.color; 2935 | 2936 | /** 2937 | * Expose `Spec`. 2938 | */ 2939 | 2940 | exports = module.exports = Spec; 2941 | 2942 | /** 2943 | * Initialize a new `Spec` test reporter. 2944 | * 2945 | * @param {Runner} runner 2946 | * @api public 2947 | */ 2948 | 2949 | function Spec(runner) { 2950 | Base.call(this, runner); 2951 | 2952 | var self = this 2953 | , stats = this.stats 2954 | , indents = 0 2955 | , n = 0; 2956 | 2957 | function indent() { 2958 | return Array(indents).join(' ') 2959 | } 2960 | 2961 | runner.on('start', function(){ 2962 | console.log(); 2963 | }); 2964 | 2965 | runner.on('suite', function(suite){ 2966 | ++indents; 2967 | console.log(color('suite', '%s%s'), indent(), suite.title); 2968 | }); 2969 | 2970 | runner.on('suite end', function(suite){ 2971 | --indents; 2972 | if (1 == indents) console.log(); 2973 | }); 2974 | 2975 | runner.on('test', function(test){ 2976 | process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': ')); 2977 | }); 2978 | 2979 | runner.on('pending', function(test){ 2980 | var fmt = indent() + color('pending', ' - %s'); 2981 | console.log(fmt, test.title); 2982 | }); 2983 | 2984 | runner.on('pass', function(test){ 2985 | if ('fast' == test.speed) { 2986 | var fmt = indent() 2987 | + color('checkmark', ' ✓') 2988 | + color('pass', ' %s '); 2989 | cursor.CR(); 2990 | console.log(fmt, test.title); 2991 | } else { 2992 | var fmt = indent() 2993 | + color('checkmark', ' ✓') 2994 | + color('pass', ' %s ') 2995 | + color(test.speed, '(%dms)'); 2996 | cursor.CR(); 2997 | console.log(fmt, test.title, test.duration); 2998 | } 2999 | }); 3000 | 3001 | runner.on('fail', function(test, err){ 3002 | cursor.CR(); 3003 | console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); 3004 | }); 3005 | 3006 | runner.on('end', self.epilogue.bind(self)); 3007 | } 3008 | 3009 | /** 3010 | * Inherit from `Base.prototype`. 3011 | */ 3012 | 3013 | Spec.prototype = new Base; 3014 | Spec.prototype.constructor = Spec; 3015 | 3016 | 3017 | }); // module: reporters/spec.js 3018 | 3019 | require.register("reporters/tap.js", function(module, exports, require){ 3020 | 3021 | /** 3022 | * Module dependencies. 3023 | */ 3024 | 3025 | var Base = require('./base') 3026 | , cursor = Base.cursor 3027 | , color = Base.color; 3028 | 3029 | /** 3030 | * Expose `TAP`. 3031 | */ 3032 | 3033 | exports = module.exports = TAP; 3034 | 3035 | /** 3036 | * Initialize a new `TAP` reporter. 3037 | * 3038 | * @param {Runner} runner 3039 | * @api public 3040 | */ 3041 | 3042 | function TAP(runner) { 3043 | Base.call(this, runner); 3044 | 3045 | var self = this 3046 | , stats = this.stats 3047 | , total = runner.total 3048 | , n = 1; 3049 | 3050 | runner.on('start', function(){ 3051 | console.log('%d..%d', 1, total); 3052 | }); 3053 | 3054 | runner.on('test end', function(){ 3055 | ++n; 3056 | }); 3057 | 3058 | runner.on('pending', function(test){ 3059 | console.log('ok %d %s # SKIP -', n, title(test)); 3060 | }); 3061 | 3062 | runner.on('pass', function(test){ 3063 | console.log('ok %d %s', n, title(test)); 3064 | }); 3065 | 3066 | runner.on('fail', function(test, err){ 3067 | console.log('not ok %d %s', n, title(test)); 3068 | console.log(err.stack.replace(/^/gm, ' ')); 3069 | }); 3070 | } 3071 | 3072 | /** 3073 | * Return a TAP-safe title of `test` 3074 | * 3075 | * @param {Object} test 3076 | * @return {String} 3077 | * @api private 3078 | */ 3079 | 3080 | function title(test) { 3081 | return test.fullTitle().replace(/#/g, ''); 3082 | } 3083 | 3084 | }); // module: reporters/tap.js 3085 | 3086 | require.register("reporters/teamcity.js", function(module, exports, require){ 3087 | 3088 | /** 3089 | * Module dependencies. 3090 | */ 3091 | 3092 | var Base = require('./base'); 3093 | 3094 | /** 3095 | * Expose `Teamcity`. 3096 | */ 3097 | 3098 | exports = module.exports = Teamcity; 3099 | 3100 | /** 3101 | * Initialize a new `Teamcity` reporter. 3102 | * 3103 | * @param {Runner} runner 3104 | * @api public 3105 | */ 3106 | 3107 | function Teamcity(runner) { 3108 | Base.call(this, runner); 3109 | var stats = this.stats; 3110 | 3111 | runner.on('start', function() { 3112 | console.log("##teamcity[testSuiteStarted name='mocha.suite']"); 3113 | }); 3114 | 3115 | runner.on('test', function(test) { 3116 | console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']"); 3117 | }); 3118 | 3119 | runner.on('fail', function(test, err) { 3120 | console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']"); 3121 | }); 3122 | 3123 | runner.on('pending', function(test) { 3124 | console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']"); 3125 | }); 3126 | 3127 | runner.on('test end', function(test) { 3128 | console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']"); 3129 | }); 3130 | 3131 | runner.on('end', function() { 3132 | console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']"); 3133 | }); 3134 | } 3135 | 3136 | /** 3137 | * Escape the given `str`. 3138 | */ 3139 | 3140 | function escape(str) { 3141 | return str 3142 | .replace(/\|/g, "||") 3143 | .replace(/\n/g, "|n") 3144 | .replace(/\r/g, "|r") 3145 | .replace(/\[/g, "|[") 3146 | .replace(/\]/g, "|]") 3147 | .replace(/\u0085/g, "|x") 3148 | .replace(/\u2028/g, "|l") 3149 | .replace(/\u2029/g, "|p") 3150 | .replace(/'/g, "|'"); 3151 | } 3152 | 3153 | }); // module: reporters/teamcity.js 3154 | 3155 | require.register("reporters/xunit.js", function(module, exports, require){ 3156 | 3157 | /** 3158 | * Module dependencies. 3159 | */ 3160 | 3161 | var Base = require('./base') 3162 | , utils = require('../utils') 3163 | , escape = utils.escape; 3164 | 3165 | /** 3166 | * Save timer references to avoid Sinon interfering (see GH-237). 3167 | */ 3168 | 3169 | var Date = global.Date 3170 | , setTimeout = global.setTimeout 3171 | , setInterval = global.setInterval 3172 | , clearTimeout = global.clearTimeout 3173 | , clearInterval = global.clearInterval; 3174 | 3175 | /** 3176 | * Expose `XUnit`. 3177 | */ 3178 | 3179 | exports = module.exports = XUnit; 3180 | 3181 | /** 3182 | * Initialize a new `XUnit` reporter. 3183 | * 3184 | * @param {Runner} runner 3185 | * @api public 3186 | */ 3187 | 3188 | function XUnit(runner) { 3189 | Base.call(this, runner); 3190 | var stats = this.stats 3191 | , tests = [] 3192 | , self = this; 3193 | 3194 | runner.on('pass', function(test){ 3195 | tests.push(test); 3196 | }); 3197 | 3198 | runner.on('fail', function(test){ 3199 | tests.push(test); 3200 | }); 3201 | 3202 | runner.on('end', function(){ 3203 | console.log(tag('testsuite', { 3204 | name: 'Mocha Tests' 3205 | , tests: stats.tests 3206 | , failures: stats.failures 3207 | , errors: stats.failures 3208 | , skip: stats.tests - stats.failures - stats.passes 3209 | , timestamp: (new Date).toUTCString() 3210 | , time: stats.duration / 1000 3211 | }, false)); 3212 | 3213 | tests.forEach(test); 3214 | console.log(''); 3215 | }); 3216 | } 3217 | 3218 | /** 3219 | * Inherit from `Base.prototype`. 3220 | */ 3221 | 3222 | XUnit.prototype = new Base; 3223 | XUnit.prototype.constructor = XUnit; 3224 | 3225 | 3226 | /** 3227 | * Output tag for the given `test.` 3228 | */ 3229 | 3230 | function test(test) { 3231 | var attrs = { 3232 | classname: test.parent.fullTitle() 3233 | , name: test.title 3234 | , time: test.duration / 1000 3235 | }; 3236 | 3237 | if ('failed' == test.state) { 3238 | var err = test.err; 3239 | attrs.message = escape(err.message); 3240 | console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); 3241 | } else if (test.pending) { 3242 | console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); 3243 | } else { 3244 | console.log(tag('testcase', attrs, true) ); 3245 | } 3246 | } 3247 | 3248 | /** 3249 | * HTML tag helper. 3250 | */ 3251 | 3252 | function tag(name, attrs, close, content) { 3253 | var end = close ? '/>' : '>' 3254 | , pairs = [] 3255 | , tag; 3256 | 3257 | for (var key in attrs) { 3258 | pairs.push(key + '="' + escape(attrs[key]) + '"'); 3259 | } 3260 | 3261 | tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; 3262 | if (content) tag += content + ''; 3272 | } 3273 | 3274 | }); // module: reporters/xunit.js 3275 | 3276 | require.register("runnable.js", function(module, exports, require){ 3277 | 3278 | /** 3279 | * Module dependencies. 3280 | */ 3281 | 3282 | var EventEmitter = require('browser/events').EventEmitter 3283 | , debug = require('browser/debug')('mocha:runnable'); 3284 | 3285 | /** 3286 | * Save timer references to avoid Sinon interfering (see GH-237). 3287 | */ 3288 | 3289 | var Date = global.Date 3290 | , setTimeout = global.setTimeout 3291 | , setInterval = global.setInterval 3292 | , clearTimeout = global.clearTimeout 3293 | , clearInterval = global.clearInterval; 3294 | 3295 | /** 3296 | * Expose `Runnable`. 3297 | */ 3298 | 3299 | module.exports = Runnable; 3300 | 3301 | /** 3302 | * Initialize a new `Runnable` with the given `title` and callback `fn`. 3303 | * 3304 | * @param {String} title 3305 | * @param {Function} fn 3306 | * @api private 3307 | */ 3308 | 3309 | function Runnable(title, fn) { 3310 | this.title = title; 3311 | this.fn = fn; 3312 | this.async = fn && fn.length; 3313 | this.sync = ! this.async; 3314 | this._timeout = 2000; 3315 | this.timedOut = false; 3316 | } 3317 | 3318 | /** 3319 | * Inherit from `EventEmitter.prototype`. 3320 | */ 3321 | 3322 | Runnable.prototype = new EventEmitter; 3323 | Runnable.prototype.constructor = Runnable; 3324 | 3325 | 3326 | /** 3327 | * Set & get timeout `ms`. 3328 | * 3329 | * @param {Number} ms 3330 | * @return {Runnable|Number} ms or self 3331 | * @api private 3332 | */ 3333 | 3334 | Runnable.prototype.timeout = function(ms){ 3335 | if (0 == arguments.length) return this._timeout; 3336 | debug('timeout %d', ms); 3337 | this._timeout = ms; 3338 | if (this.timer) this.resetTimeout(); 3339 | return this; 3340 | }; 3341 | 3342 | /** 3343 | * Return the full title generated by recursively 3344 | * concatenating the parent's full title. 3345 | * 3346 | * @return {String} 3347 | * @api public 3348 | */ 3349 | 3350 | Runnable.prototype.fullTitle = function(){ 3351 | return this.parent.fullTitle() + ' ' + this.title; 3352 | }; 3353 | 3354 | /** 3355 | * Clear the timeout. 3356 | * 3357 | * @api private 3358 | */ 3359 | 3360 | Runnable.prototype.clearTimeout = function(){ 3361 | clearTimeout(this.timer); 3362 | }; 3363 | 3364 | /** 3365 | * Inspect the runnable void of private properties. 3366 | * 3367 | * @return {String} 3368 | * @api private 3369 | */ 3370 | 3371 | Runnable.prototype.inspect = function(){ 3372 | return JSON.stringify(this, function(key, val){ 3373 | if ('_' == key[0]) return; 3374 | if ('parent' == key) return '#'; 3375 | if ('ctx' == key) return '#'; 3376 | return val; 3377 | }, 2); 3378 | }; 3379 | 3380 | /** 3381 | * Reset the timeout. 3382 | * 3383 | * @api private 3384 | */ 3385 | 3386 | Runnable.prototype.resetTimeout = function(){ 3387 | var self = this 3388 | , ms = this.timeout(); 3389 | 3390 | this.clearTimeout(); 3391 | if (ms) { 3392 | this.timer = setTimeout(function(){ 3393 | self.callback(new Error('timeout of ' + ms + 'ms exceeded')); 3394 | self.timedOut = true; 3395 | }, ms); 3396 | } 3397 | }; 3398 | 3399 | /** 3400 | * Run the test and invoke `fn(err)`. 3401 | * 3402 | * @param {Function} fn 3403 | * @api private 3404 | */ 3405 | 3406 | Runnable.prototype.run = function(fn){ 3407 | var self = this 3408 | , ms = this.timeout() 3409 | , start = new Date 3410 | , ctx = this.ctx 3411 | , finished 3412 | , emitted; 3413 | 3414 | if (ctx) ctx.runnable(this); 3415 | 3416 | // timeout 3417 | if (this.async) { 3418 | if (ms) { 3419 | this.timer = setTimeout(function(){ 3420 | done(new Error('timeout of ' + ms + 'ms exceeded')); 3421 | self.timedOut = true; 3422 | }, ms); 3423 | } 3424 | } 3425 | 3426 | // called multiple times 3427 | function multiple(err) { 3428 | if (emitted) return; 3429 | emitted = true; 3430 | self.emit('error', err || new Error('done() called multiple times')); 3431 | } 3432 | 3433 | // finished 3434 | function done(err) { 3435 | if (self.timedOut) return; 3436 | if (finished) return multiple(err); 3437 | self.clearTimeout(); 3438 | self.duration = new Date - start; 3439 | finished = true; 3440 | fn(err); 3441 | } 3442 | 3443 | // for .resetTimeout() 3444 | this.callback = done; 3445 | 3446 | // async 3447 | if (this.async) { 3448 | try { 3449 | this.fn.call(ctx, function(err){ 3450 | if (err instanceof Error) return done(err); 3451 | if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); 3452 | done(); 3453 | }); 3454 | } catch (err) { 3455 | done(err); 3456 | } 3457 | return; 3458 | } 3459 | 3460 | // sync 3461 | try { 3462 | if (!this.pending) this.fn.call(ctx); 3463 | this.duration = new Date - start; 3464 | fn(); 3465 | } catch (err) { 3466 | fn(err); 3467 | } 3468 | }; 3469 | 3470 | }); // module: runnable.js 3471 | 3472 | require.register("runner.js", function(module, exports, require){ 3473 | 3474 | /** 3475 | * Module dependencies. 3476 | */ 3477 | 3478 | var EventEmitter = require('browser/events').EventEmitter 3479 | , debug = require('browser/debug')('mocha:runner') 3480 | , Test = require('./test') 3481 | , utils = require('./utils') 3482 | , filter = utils.filter 3483 | , keys = utils.keys 3484 | , noop = function(){}; 3485 | 3486 | /** 3487 | * Expose `Runner`. 3488 | */ 3489 | 3490 | module.exports = Runner; 3491 | 3492 | /** 3493 | * Initialize a `Runner` for the given `suite`. 3494 | * 3495 | * Events: 3496 | * 3497 | * - `start` execution started 3498 | * - `end` execution complete 3499 | * - `suite` (suite) test suite execution started 3500 | * - `suite end` (suite) all tests (and sub-suites) have finished 3501 | * - `test` (test) test execution started 3502 | * - `test end` (test) test completed 3503 | * - `hook` (hook) hook execution started 3504 | * - `hook end` (hook) hook complete 3505 | * - `pass` (test) test passed 3506 | * - `fail` (test, err) test failed 3507 | * 3508 | * @api public 3509 | */ 3510 | 3511 | function Runner(suite) { 3512 | var self = this; 3513 | this._globals = []; 3514 | this.suite = suite; 3515 | this.total = suite.total(); 3516 | this.failures = 0; 3517 | this.on('test end', function(test){ self.checkGlobals(test); }); 3518 | this.on('hook end', function(hook){ self.checkGlobals(hook); }); 3519 | this.grep(/.*/); 3520 | this.globals(utils.keys(global).concat(['errno'])); 3521 | } 3522 | 3523 | /** 3524 | * Inherit from `EventEmitter.prototype`. 3525 | */ 3526 | 3527 | Runner.prototype = new EventEmitter; 3528 | Runner.prototype.constructor = Runner; 3529 | 3530 | 3531 | /** 3532 | * Run tests with full titles matching `re`. Updates runner.total 3533 | * with number of tests matched. 3534 | * 3535 | * @param {RegExp} re 3536 | * @param {Boolean} invert 3537 | * @return {Runner} for chaining 3538 | * @api public 3539 | */ 3540 | 3541 | Runner.prototype.grep = function(re, invert){ 3542 | debug('grep %s', re); 3543 | this._grep = re; 3544 | this._invert = invert; 3545 | this.total = this.grepTotal(this.suite); 3546 | return this; 3547 | }; 3548 | 3549 | /** 3550 | * Returns the number of tests matching the grep search for the 3551 | * given suite. 3552 | * 3553 | * @param {Suite} suite 3554 | * @return {Number} 3555 | * @api public 3556 | */ 3557 | 3558 | Runner.prototype.grepTotal = function(suite) { 3559 | var self = this; 3560 | var total = 0; 3561 | 3562 | suite.eachTest(function(test){ 3563 | var match = self._grep.test(test.fullTitle()); 3564 | if (self._invert) match = !match; 3565 | if (match) total++; 3566 | }); 3567 | 3568 | return total; 3569 | }; 3570 | 3571 | /** 3572 | * Allow the given `arr` of globals. 3573 | * 3574 | * @param {Array} arr 3575 | * @return {Runner} for chaining 3576 | * @api public 3577 | */ 3578 | 3579 | Runner.prototype.globals = function(arr){ 3580 | if (0 == arguments.length) return this._globals; 3581 | debug('globals %j', arr); 3582 | utils.forEach(arr, function(arr){ 3583 | this._globals.push(arr); 3584 | }, this); 3585 | return this; 3586 | }; 3587 | 3588 | /** 3589 | * Check for global variable leaks. 3590 | * 3591 | * @api private 3592 | */ 3593 | 3594 | Runner.prototype.checkGlobals = function(test){ 3595 | if (this.ignoreLeaks) return; 3596 | var leaks = filterLeaks(this._globals); 3597 | 3598 | this._globals = this._globals.concat(leaks); 3599 | 3600 | if (leaks.length > 1) { 3601 | this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); 3602 | } else if (leaks.length) { 3603 | this.fail(test, new Error('global leak detected: ' + leaks[0])); 3604 | } 3605 | }; 3606 | 3607 | /** 3608 | * Fail the given `test`. 3609 | * 3610 | * @param {Test} test 3611 | * @param {Error} err 3612 | * @api private 3613 | */ 3614 | 3615 | Runner.prototype.fail = function(test, err){ 3616 | ++this.failures; 3617 | test.state = 'failed'; 3618 | if ('string' == typeof err) { 3619 | err = new Error('the string "' + err + '" was thrown, throw an Error :)'); 3620 | } 3621 | this.emit('fail', test, err); 3622 | }; 3623 | 3624 | /** 3625 | * Fail the given `hook` with `err`. 3626 | * 3627 | * Hook failures (currently) hard-end due 3628 | * to that fact that a failing hook will 3629 | * surely cause subsequent tests to fail, 3630 | * causing jumbled reporting. 3631 | * 3632 | * @param {Hook} hook 3633 | * @param {Error} err 3634 | * @api private 3635 | */ 3636 | 3637 | Runner.prototype.failHook = function(hook, err){ 3638 | this.fail(hook, err); 3639 | this.emit('end'); 3640 | }; 3641 | 3642 | /** 3643 | * Run hook `name` callbacks and then invoke `fn()`. 3644 | * 3645 | * @param {String} name 3646 | * @param {Function} function 3647 | * @api private 3648 | */ 3649 | 3650 | Runner.prototype.hook = function(name, fn){ 3651 | var suite = this.suite 3652 | , hooks = suite['_' + name] 3653 | , ms = suite._timeout 3654 | , self = this 3655 | , timer; 3656 | 3657 | function next(i) { 3658 | var hook = hooks[i]; 3659 | if (!hook) return fn(); 3660 | self.currentRunnable = hook; 3661 | 3662 | self.emit('hook', hook); 3663 | 3664 | hook.on('error', function(err){ 3665 | self.failHook(hook, err); 3666 | }); 3667 | 3668 | hook.run(function(err){ 3669 | hook.removeAllListeners('error'); 3670 | var testError = hook.error(); 3671 | if (testError) self.fail(self.test, testError); 3672 | if (err) return self.failHook(hook, err); 3673 | self.emit('hook end', hook); 3674 | next(++i); 3675 | }); 3676 | } 3677 | 3678 | process.nextTick(function(){ 3679 | next(0); 3680 | }); 3681 | }; 3682 | 3683 | /** 3684 | * Run hook `name` for the given array of `suites` 3685 | * in order, and callback `fn(err)`. 3686 | * 3687 | * @param {String} name 3688 | * @param {Array} suites 3689 | * @param {Function} fn 3690 | * @api private 3691 | */ 3692 | 3693 | Runner.prototype.hooks = function(name, suites, fn){ 3694 | var self = this 3695 | , orig = this.suite; 3696 | 3697 | function next(suite) { 3698 | self.suite = suite; 3699 | 3700 | if (!suite) { 3701 | self.suite = orig; 3702 | return fn(); 3703 | } 3704 | 3705 | self.hook(name, function(err){ 3706 | if (err) { 3707 | self.suite = orig; 3708 | return fn(err); 3709 | } 3710 | 3711 | next(suites.pop()); 3712 | }); 3713 | } 3714 | 3715 | next(suites.pop()); 3716 | }; 3717 | 3718 | /** 3719 | * Run hooks from the top level down. 3720 | * 3721 | * @param {String} name 3722 | * @param {Function} fn 3723 | * @api private 3724 | */ 3725 | 3726 | Runner.prototype.hookUp = function(name, fn){ 3727 | var suites = [this.suite].concat(this.parents()).reverse(); 3728 | this.hooks(name, suites, fn); 3729 | }; 3730 | 3731 | /** 3732 | * Run hooks from the bottom up. 3733 | * 3734 | * @param {String} name 3735 | * @param {Function} fn 3736 | * @api private 3737 | */ 3738 | 3739 | Runner.prototype.hookDown = function(name, fn){ 3740 | var suites = [this.suite].concat(this.parents()); 3741 | this.hooks(name, suites, fn); 3742 | }; 3743 | 3744 | /** 3745 | * Return an array of parent Suites from 3746 | * closest to furthest. 3747 | * 3748 | * @return {Array} 3749 | * @api private 3750 | */ 3751 | 3752 | Runner.prototype.parents = function(){ 3753 | var suite = this.suite 3754 | , suites = []; 3755 | while (suite = suite.parent) suites.push(suite); 3756 | return suites; 3757 | }; 3758 | 3759 | /** 3760 | * Run the current test and callback `fn(err)`. 3761 | * 3762 | * @param {Function} fn 3763 | * @api private 3764 | */ 3765 | 3766 | Runner.prototype.runTest = function(fn){ 3767 | var test = this.test 3768 | , self = this; 3769 | 3770 | try { 3771 | test.on('error', function(err){ 3772 | self.fail(test, err); 3773 | }); 3774 | test.run(fn); 3775 | } catch (err) { 3776 | fn(err); 3777 | } 3778 | }; 3779 | 3780 | /** 3781 | * Run tests in the given `suite` and invoke 3782 | * the callback `fn()` when complete. 3783 | * 3784 | * @param {Suite} suite 3785 | * @param {Function} fn 3786 | * @api private 3787 | */ 3788 | 3789 | Runner.prototype.runTests = function(suite, fn){ 3790 | var self = this 3791 | , tests = suite.tests 3792 | , test; 3793 | 3794 | function next(err) { 3795 | // if we bail after first err 3796 | if (self.failures && suite._bail) return fn(); 3797 | 3798 | // next test 3799 | test = tests.shift(); 3800 | 3801 | // all done 3802 | if (!test) return fn(); 3803 | 3804 | // grep 3805 | var match = self._grep.test(test.fullTitle()); 3806 | if (self._invert) match = !match; 3807 | if (!match) return next(); 3808 | 3809 | // pending 3810 | if (test.pending) { 3811 | self.emit('pending', test); 3812 | self.emit('test end', test); 3813 | return next(); 3814 | } 3815 | 3816 | // execute test and hook(s) 3817 | self.emit('test', self.test = test); 3818 | self.hookDown('beforeEach', function(){ 3819 | self.currentRunnable = self.test; 3820 | self.runTest(function(err){ 3821 | test = self.test; 3822 | 3823 | if (err) { 3824 | self.fail(test, err); 3825 | self.emit('test end', test); 3826 | return self.hookUp('afterEach', next); 3827 | } 3828 | 3829 | test.state = 'passed'; 3830 | self.emit('pass', test); 3831 | self.emit('test end', test); 3832 | self.hookUp('afterEach', next); 3833 | }); 3834 | }); 3835 | } 3836 | 3837 | this.next = next; 3838 | next(); 3839 | }; 3840 | 3841 | /** 3842 | * Run the given `suite` and invoke the 3843 | * callback `fn()` when complete. 3844 | * 3845 | * @param {Suite} suite 3846 | * @param {Function} fn 3847 | * @api private 3848 | */ 3849 | 3850 | Runner.prototype.runSuite = function(suite, fn){ 3851 | var total = this.grepTotal(suite) 3852 | , self = this 3853 | , i = 0; 3854 | 3855 | debug('run suite %s', suite.fullTitle()); 3856 | 3857 | if (!total) return fn(); 3858 | 3859 | this.emit('suite', this.suite = suite); 3860 | 3861 | function next() { 3862 | var curr = suite.suites[i++]; 3863 | if (!curr) return done(); 3864 | self.runSuite(curr, next); 3865 | } 3866 | 3867 | function done() { 3868 | self.suite = suite; 3869 | self.hook('afterAll', function(){ 3870 | self.emit('suite end', suite); 3871 | fn(); 3872 | }); 3873 | } 3874 | 3875 | this.hook('beforeAll', function(){ 3876 | self.runTests(suite, next); 3877 | }); 3878 | }; 3879 | 3880 | /** 3881 | * Handle uncaught exceptions. 3882 | * 3883 | * @param {Error} err 3884 | * @api private 3885 | */ 3886 | 3887 | Runner.prototype.uncaught = function(err){ 3888 | debug('uncaught exception %s', err.message); 3889 | var runnable = this.currentRunnable; 3890 | if (!runnable || 'failed' == runnable.state) return; 3891 | runnable.clearTimeout(); 3892 | err.uncaught = true; 3893 | this.fail(runnable, err); 3894 | 3895 | // recover from test 3896 | if ('test' == runnable.type) { 3897 | this.emit('test end', runnable); 3898 | this.hookUp('afterEach', this.next); 3899 | return; 3900 | } 3901 | 3902 | // bail on hooks 3903 | this.emit('end'); 3904 | }; 3905 | 3906 | /** 3907 | * Run the root suite and invoke `fn(failures)` 3908 | * on completion. 3909 | * 3910 | * @param {Function} fn 3911 | * @return {Runner} for chaining 3912 | * @api public 3913 | */ 3914 | 3915 | Runner.prototype.run = function(fn){ 3916 | var self = this 3917 | , fn = fn || function(){}; 3918 | 3919 | debug('start'); 3920 | 3921 | // uncaught callback 3922 | function uncaught(err) { 3923 | self.uncaught(err); 3924 | } 3925 | 3926 | // callback 3927 | this.on('end', function(){ 3928 | debug('end'); 3929 | process.removeListener('uncaughtException', uncaught); 3930 | fn(self.failures); 3931 | }); 3932 | 3933 | // run suites 3934 | this.emit('start'); 3935 | this.runSuite(this.suite, function(){ 3936 | debug('finished running'); 3937 | self.emit('end'); 3938 | }); 3939 | 3940 | // uncaught exception 3941 | process.on('uncaughtException', uncaught); 3942 | 3943 | return this; 3944 | }; 3945 | 3946 | /** 3947 | * Filter leaks with the given globals flagged as `ok`. 3948 | * 3949 | * @param {Array} ok 3950 | * @return {Array} 3951 | * @api private 3952 | */ 3953 | 3954 | function filterLeaks(ok) { 3955 | return filter(keys(global), function(key){ 3956 | var matched = filter(ok, function(ok){ 3957 | if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); 3958 | return key == ok; 3959 | }); 3960 | return matched.length == 0 && (!global.navigator || 'onerror' !== key); 3961 | }); 3962 | } 3963 | }); // module: runner.js 3964 | 3965 | require.register("suite.js", function(module, exports, require){ 3966 | 3967 | /** 3968 | * Module dependencies. 3969 | */ 3970 | 3971 | var EventEmitter = require('browser/events').EventEmitter 3972 | , debug = require('browser/debug')('mocha:suite') 3973 | , utils = require('./utils') 3974 | , Hook = require('./hook'); 3975 | 3976 | /** 3977 | * Expose `Suite`. 3978 | */ 3979 | 3980 | exports = module.exports = Suite; 3981 | 3982 | /** 3983 | * Create a new `Suite` with the given `title` 3984 | * and parent `Suite`. When a suite with the 3985 | * same title is already present, that suite 3986 | * is returned to provide nicer reporter 3987 | * and more flexible meta-testing. 3988 | * 3989 | * @param {Suite} parent 3990 | * @param {String} title 3991 | * @return {Suite} 3992 | * @api public 3993 | */ 3994 | 3995 | exports.create = function(parent, title){ 3996 | var suite = new Suite(title, parent.ctx); 3997 | suite.parent = parent; 3998 | if (parent.pending) suite.pending = true; 3999 | title = suite.fullTitle(); 4000 | parent.addSuite(suite); 4001 | return suite; 4002 | }; 4003 | 4004 | /** 4005 | * Initialize a new `Suite` with the given 4006 | * `title` and `ctx`. 4007 | * 4008 | * @param {String} title 4009 | * @param {Context} ctx 4010 | * @api private 4011 | */ 4012 | 4013 | function Suite(title, ctx) { 4014 | this.title = title; 4015 | this.ctx = ctx; 4016 | this.suites = []; 4017 | this.tests = []; 4018 | this.pending = false; 4019 | this._beforeEach = []; 4020 | this._beforeAll = []; 4021 | this._afterEach = []; 4022 | this._afterAll = []; 4023 | this.root = !title; 4024 | this._timeout = 2000; 4025 | this._bail = false; 4026 | } 4027 | 4028 | /** 4029 | * Inherit from `EventEmitter.prototype`. 4030 | */ 4031 | 4032 | Suite.prototype = new EventEmitter; 4033 | Suite.prototype.constructor = Suite; 4034 | 4035 | 4036 | /** 4037 | * Return a clone of this `Suite`. 4038 | * 4039 | * @return {Suite} 4040 | * @api private 4041 | */ 4042 | 4043 | Suite.prototype.clone = function(){ 4044 | var suite = new Suite(this.title); 4045 | debug('clone'); 4046 | suite.ctx = this.ctx; 4047 | suite.timeout(this.timeout()); 4048 | suite.bail(this.bail()); 4049 | return suite; 4050 | }; 4051 | 4052 | /** 4053 | * Set timeout `ms` or short-hand such as "2s". 4054 | * 4055 | * @param {Number|String} ms 4056 | * @return {Suite|Number} for chaining 4057 | * @api private 4058 | */ 4059 | 4060 | Suite.prototype.timeout = function(ms){ 4061 | if (0 == arguments.length) return this._timeout; 4062 | if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000; 4063 | debug('timeout %d', ms); 4064 | this._timeout = parseInt(ms, 10); 4065 | return this; 4066 | }; 4067 | 4068 | /** 4069 | * Sets whether to bail after first error. 4070 | * 4071 | * @parma {Boolean} bail 4072 | * @return {Suite|Number} for chaining 4073 | * @api private 4074 | */ 4075 | 4076 | Suite.prototype.bail = function(bail){ 4077 | if (0 == arguments.length) return this._bail; 4078 | debug('bail %s', bail); 4079 | this._bail = bail; 4080 | return this; 4081 | }; 4082 | 4083 | /** 4084 | * Run `fn(test[, done])` before running tests. 4085 | * 4086 | * @param {Function} fn 4087 | * @return {Suite} for chaining 4088 | * @api private 4089 | */ 4090 | 4091 | Suite.prototype.beforeAll = function(fn){ 4092 | if (this.pending) return this; 4093 | var hook = new Hook('"before all" hook', fn); 4094 | hook.parent = this; 4095 | hook.timeout(this.timeout()); 4096 | hook.ctx = this.ctx; 4097 | this._beforeAll.push(hook); 4098 | this.emit('beforeAll', hook); 4099 | return this; 4100 | }; 4101 | 4102 | /** 4103 | * Run `fn(test[, done])` after running tests. 4104 | * 4105 | * @param {Function} fn 4106 | * @return {Suite} for chaining 4107 | * @api private 4108 | */ 4109 | 4110 | Suite.prototype.afterAll = function(fn){ 4111 | if (this.pending) return this; 4112 | var hook = new Hook('"after all" hook', fn); 4113 | hook.parent = this; 4114 | hook.timeout(this.timeout()); 4115 | hook.ctx = this.ctx; 4116 | this._afterAll.push(hook); 4117 | this.emit('afterAll', hook); 4118 | return this; 4119 | }; 4120 | 4121 | /** 4122 | * Run `fn(test[, done])` before each test case. 4123 | * 4124 | * @param {Function} fn 4125 | * @return {Suite} for chaining 4126 | * @api private 4127 | */ 4128 | 4129 | Suite.prototype.beforeEach = function(fn){ 4130 | if (this.pending) return this; 4131 | var hook = new Hook('"before each" hook', fn); 4132 | hook.parent = this; 4133 | hook.timeout(this.timeout()); 4134 | hook.ctx = this.ctx; 4135 | this._beforeEach.push(hook); 4136 | this.emit('beforeEach', hook); 4137 | return this; 4138 | }; 4139 | 4140 | /** 4141 | * Run `fn(test[, done])` after each test case. 4142 | * 4143 | * @param {Function} fn 4144 | * @return {Suite} for chaining 4145 | * @api private 4146 | */ 4147 | 4148 | Suite.prototype.afterEach = function(fn){ 4149 | if (this.pending) return this; 4150 | var hook = new Hook('"after each" hook', fn); 4151 | hook.parent = this; 4152 | hook.timeout(this.timeout()); 4153 | hook.ctx = this.ctx; 4154 | this._afterEach.push(hook); 4155 | this.emit('afterEach', hook); 4156 | return this; 4157 | }; 4158 | 4159 | /** 4160 | * Add a test `suite`. 4161 | * 4162 | * @param {Suite} suite 4163 | * @return {Suite} for chaining 4164 | * @api private 4165 | */ 4166 | 4167 | Suite.prototype.addSuite = function(suite){ 4168 | suite.parent = this; 4169 | suite.timeout(this.timeout()); 4170 | suite.bail(this.bail()); 4171 | this.suites.push(suite); 4172 | this.emit('suite', suite); 4173 | return this; 4174 | }; 4175 | 4176 | /** 4177 | * Add a `test` to this suite. 4178 | * 4179 | * @param {Test} test 4180 | * @return {Suite} for chaining 4181 | * @api private 4182 | */ 4183 | 4184 | Suite.prototype.addTest = function(test){ 4185 | test.parent = this; 4186 | test.timeout(this.timeout()); 4187 | test.ctx = this.ctx; 4188 | this.tests.push(test); 4189 | this.emit('test', test); 4190 | return this; 4191 | }; 4192 | 4193 | /** 4194 | * Return the full title generated by recursively 4195 | * concatenating the parent's full title. 4196 | * 4197 | * @return {String} 4198 | * @api public 4199 | */ 4200 | 4201 | Suite.prototype.fullTitle = function(){ 4202 | if (this.parent) { 4203 | var full = this.parent.fullTitle(); 4204 | if (full) return full + ' ' + this.title; 4205 | } 4206 | return this.title; 4207 | }; 4208 | 4209 | /** 4210 | * Return the total number of tests. 4211 | * 4212 | * @return {Number} 4213 | * @api public 4214 | */ 4215 | 4216 | Suite.prototype.total = function(){ 4217 | return utils.reduce(this.suites, function(sum, suite){ 4218 | return sum + suite.total(); 4219 | }, 0) + this.tests.length; 4220 | }; 4221 | 4222 | /** 4223 | * Iterates through each suite recursively to find 4224 | * all tests. Applies a function in the format 4225 | * `fn(test)`. 4226 | * 4227 | * @param {Function} fn 4228 | * @return {Suite} 4229 | * @api private 4230 | */ 4231 | 4232 | Suite.prototype.eachTest = function(fn){ 4233 | utils.forEach(this.tests, fn); 4234 | utils.forEach(this.suites, function(suite){ 4235 | suite.eachTest(fn); 4236 | }); 4237 | return this; 4238 | }; 4239 | 4240 | }); // module: suite.js 4241 | 4242 | require.register("test.js", function(module, exports, require){ 4243 | 4244 | /** 4245 | * Module dependencies. 4246 | */ 4247 | 4248 | var Runnable = require('./runnable'); 4249 | 4250 | /** 4251 | * Expose `Test`. 4252 | */ 4253 | 4254 | module.exports = Test; 4255 | 4256 | /** 4257 | * Initialize a new `Test` with the given `title` and callback `fn`. 4258 | * 4259 | * @param {String} title 4260 | * @param {Function} fn 4261 | * @api private 4262 | */ 4263 | 4264 | function Test(title, fn) { 4265 | Runnable.call(this, title, fn); 4266 | this.pending = !fn; 4267 | this.type = 'test'; 4268 | } 4269 | 4270 | /** 4271 | * Inherit from `Runnable.prototype`. 4272 | */ 4273 | 4274 | Test.prototype = new Runnable; 4275 | Test.prototype.constructor = Test; 4276 | 4277 | 4278 | }); // module: test.js 4279 | 4280 | require.register("utils.js", function(module, exports, require){ 4281 | 4282 | /** 4283 | * Module dependencies. 4284 | */ 4285 | 4286 | var fs = require('browser/fs') 4287 | , path = require('browser/path') 4288 | , join = path.join 4289 | , debug = require('browser/debug')('mocha:watch'); 4290 | 4291 | /** 4292 | * Ignored directories. 4293 | */ 4294 | 4295 | var ignore = ['node_modules', '.git']; 4296 | 4297 | /** 4298 | * Escape special characters in the given string of html. 4299 | * 4300 | * @param {String} html 4301 | * @return {String} 4302 | * @api private 4303 | */ 4304 | 4305 | exports.escape = function(html) { 4306 | return String(html) 4307 | .replace(/&/g, '&') 4308 | .replace(/"/g, '"') 4309 | .replace(//g, '>'); 4311 | }; 4312 | 4313 | /** 4314 | * Array#forEach (<=IE8) 4315 | * 4316 | * @param {Array} array 4317 | * @param {Function} fn 4318 | * @param {Object} scope 4319 | * @api private 4320 | */ 4321 | 4322 | exports.forEach = function(arr, fn, scope) { 4323 | for (var i = 0, l = arr.length; i < l; i++) 4324 | fn.call(scope, arr[i], i); 4325 | }; 4326 | 4327 | /** 4328 | * Array#indexOf (<=IE8) 4329 | * 4330 | * @parma {Array} arr 4331 | * @param {Object} obj to find index of 4332 | * @param {Number} start 4333 | * @api private 4334 | */ 4335 | 4336 | exports.indexOf = function (arr, obj, start) { 4337 | for (var i = start || 0, l = arr.length; i < l; i++) { 4338 | if (arr[i] === obj) 4339 | return i; 4340 | } 4341 | return -1; 4342 | }; 4343 | 4344 | /** 4345 | * Array#reduce (<=IE8) 4346 | * 4347 | * @param {Array} array 4348 | * @param {Function} fn 4349 | * @param {Object} initial value 4350 | * @param {Object} scope 4351 | * @api private 4352 | */ 4353 | 4354 | exports.reduce = function(arr, fn, val, scope) { 4355 | var rval = val; 4356 | 4357 | for (var i = 0, l = arr.length; i < l; i++) { 4358 | rval = fn.call(scope, rval, arr[i], i, arr); 4359 | } 4360 | 4361 | return rval; 4362 | }; 4363 | 4364 | /** 4365 | * Array#filter (<=IE8) 4366 | * 4367 | * @param {Array} array 4368 | * @param {Function} fn 4369 | * @param {Object} scope 4370 | * @api private 4371 | */ 4372 | 4373 | exports.filter = function(arr, fn, scope) { 4374 | var ret = []; 4375 | 4376 | for (var i = 0, l = arr.length; i < l; i++) { 4377 | var val = arr[i]; 4378 | if (fn.call(scope, val, i, arr)) 4379 | ret.push(val); 4380 | } 4381 | 4382 | return ret; 4383 | }; 4384 | 4385 | /** 4386 | * Object.keys (<=IE8) 4387 | * 4388 | * @param {Object} obj 4389 | * @return {Array} keys 4390 | * @api private 4391 | */ 4392 | 4393 | exports.keys = Object.keys || function(obj) { 4394 | var keys = [] 4395 | , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 4396 | 4397 | for (var key in obj) { 4398 | if (has.call(obj, key)) { 4399 | keys.push(key); 4400 | } 4401 | } 4402 | 4403 | return keys; 4404 | }; 4405 | 4406 | /** 4407 | * Watch the given `files` for changes 4408 | * and invoke `fn(file)` on modification. 4409 | * 4410 | * @param {Array} files 4411 | * @param {Function} fn 4412 | * @api private 4413 | */ 4414 | 4415 | exports.watch = function(files, fn){ 4416 | var options = { interval: 100 }; 4417 | files.forEach(function(file){ 4418 | debug('file %s', file); 4419 | fs.watchFile(file, options, function(curr, prev){ 4420 | if (prev.mtime < curr.mtime) fn(file); 4421 | }); 4422 | }); 4423 | }; 4424 | 4425 | /** 4426 | * Ignored files. 4427 | */ 4428 | 4429 | function ignored(path){ 4430 | return !~ignore.indexOf(path); 4431 | } 4432 | 4433 | /** 4434 | * Lookup files in the given `dir`. 4435 | * 4436 | * @return {Array} 4437 | * @api private 4438 | */ 4439 | 4440 | exports.files = function(dir, ret){ 4441 | ret = ret || []; 4442 | 4443 | fs.readdirSync(dir) 4444 | .filter(ignored) 4445 | .forEach(function(path){ 4446 | path = join(dir, path); 4447 | if (fs.statSync(path).isDirectory()) { 4448 | exports.files(path, ret); 4449 | } else if (path.match(/\.(js|coffee)$/)) { 4450 | ret.push(path); 4451 | } 4452 | }); 4453 | 4454 | return ret; 4455 | }; 4456 | 4457 | /** 4458 | * Compute a slug from the given `str`. 4459 | * 4460 | * @param {String} str 4461 | * @return {String} 4462 | * @api private 4463 | */ 4464 | 4465 | exports.slug = function(str){ 4466 | return str 4467 | .toLowerCase() 4468 | .replace(/ +/g, '-') 4469 | .replace(/[^-\w]/g, ''); 4470 | }; 4471 | 4472 | /** 4473 | * Strip the function definition from `str`, 4474 | * and re-indent for pre whitespace. 4475 | */ 4476 | 4477 | exports.clean = function(str) { 4478 | str = str 4479 | .replace(/^function *\(.*\) *{/, '') 4480 | .replace(/\s+\}$/, ''); 4481 | 4482 | var spaces = str.match(/^\n?( *)/)[1].length 4483 | , re = new RegExp('^ {' + spaces + '}', 'gm'); 4484 | 4485 | str = str.replace(re, ''); 4486 | 4487 | return exports.trim(str); 4488 | }; 4489 | 4490 | /** 4491 | * Escape regular expression characters in `str`. 4492 | * 4493 | * @param {String} str 4494 | * @return {String} 4495 | * @api private 4496 | */ 4497 | 4498 | exports.escapeRegexp = function(str){ 4499 | return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); 4500 | }; 4501 | 4502 | /** 4503 | * Trim the given `str`. 4504 | * 4505 | * @param {String} str 4506 | * @return {String} 4507 | * @api private 4508 | */ 4509 | 4510 | exports.trim = function(str){ 4511 | return str.replace(/^\s+|\s+$/g, ''); 4512 | }; 4513 | }); // module: utils.js 4514 | /** 4515 | * Node shims. 4516 | * 4517 | * These are meant only to allow 4518 | * mocha.js to run untouched, not 4519 | * to allow running node code in 4520 | * the browser. 4521 | */ 4522 | 4523 | process = {}; 4524 | process.exit = function(status){}; 4525 | process.stdout = {}; 4526 | global = window; 4527 | 4528 | /** 4529 | * next tick implementation. 4530 | */ 4531 | 4532 | process.nextTick = (function(){ 4533 | // postMessage behaves badly on IE8 4534 | if (window.ActiveXObject || !window.postMessage) { 4535 | return function(fn){ fn() }; 4536 | } 4537 | 4538 | // based on setZeroTimeout by David Baron 4539 | // - http://dbaron.org/log/20100309-faster-timeouts 4540 | var timeouts = [] 4541 | , name = 'mocha-zero-timeout' 4542 | 4543 | window.addEventListener('message', function(e){ 4544 | if (e.source == window && e.data == name) { 4545 | if (e.stopPropagation) e.stopPropagation(); 4546 | if (timeouts.length) timeouts.shift()(); 4547 | } 4548 | }, true); 4549 | 4550 | return function(fn){ 4551 | timeouts.push(fn); 4552 | window.postMessage(name, '*'); 4553 | } 4554 | })(); 4555 | 4556 | /** 4557 | * Remove uncaughtException listener. 4558 | */ 4559 | 4560 | process.removeListener = function(e){ 4561 | if ('uncaughtException' == e) { 4562 | window.onerror = null; 4563 | } 4564 | }; 4565 | 4566 | /** 4567 | * Implements uncaughtException listener. 4568 | */ 4569 | 4570 | process.on = function(e, fn){ 4571 | if ('uncaughtException' == e) { 4572 | window.onerror = fn; 4573 | } 4574 | }; 4575 | 4576 | /** 4577 | * Expose mocha. 4578 | */ 4579 | 4580 | window.mocha = require('mocha'); 4581 | 4582 | // boot 4583 | ;(function(){ 4584 | var utils = mocha.utils 4585 | , options = {} 4586 | 4587 | // TODO: use new Mocha here... not mocha.grep etc 4588 | 4589 | mocha.suite = new mocha.Suite('', new mocha.Context()); 4590 | 4591 | /** 4592 | * Highlight the given string of `js`. 4593 | */ 4594 | 4595 | function highlight(js) { 4596 | return js 4597 | .replace(//g, '>') 4599 | .replace(/\/\/(.*)/gm, '//$1') 4600 | .replace(/('.*?')/gm, '$1') 4601 | .replace(/(\d+\.\d+)/gm, '$1') 4602 | .replace(/(\d+)/gm, '$1') 4603 | .replace(/\bnew *(\w+)/gm, 'new $1') 4604 | .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') 4605 | } 4606 | 4607 | /** 4608 | * Highlight code contents. 4609 | */ 4610 | 4611 | function highlightCode() { 4612 | var code = document.getElementsByTagName('code'); 4613 | for (var i = 0, len = code.length; i < len; ++i) { 4614 | code[i].innerHTML = highlight(code[i].innerHTML); 4615 | } 4616 | } 4617 | 4618 | /** 4619 | * Parse the given `qs`. 4620 | */ 4621 | 4622 | function parse(qs) { 4623 | return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){ 4624 | var i = pair.indexOf('=') 4625 | , key = pair.slice(0, i) 4626 | , val = pair.slice(++i); 4627 | 4628 | obj[key] = decodeURIComponent(val); 4629 | return obj; 4630 | }, {}); 4631 | } 4632 | 4633 | /** 4634 | * Grep. 4635 | */ 4636 | 4637 | mocha.grep = function(str){ 4638 | options.grep = new RegExp(utils.escapeRegexp(str)); 4639 | }; 4640 | 4641 | /** 4642 | * Setup mocha with the given setting options. 4643 | */ 4644 | 4645 | mocha.setup = function(opts){ 4646 | if ('string' === typeof opts) options.ui = opts; 4647 | else options = opts; 4648 | 4649 | ui = mocha.interfaces[options.ui]; 4650 | if (!ui) throw new Error('invalid mocha interface "' + ui + '"'); 4651 | if (options.timeout) mocha.suite.timeout(options.timeout); 4652 | ui(mocha.suite); 4653 | mocha.suite.emit('pre-require', window, null, mocha); 4654 | }; 4655 | 4656 | /** 4657 | * Run mocha, returning the Runner. 4658 | */ 4659 | 4660 | mocha.run = function(fn){ 4661 | mocha.suite.emit('run'); 4662 | var runner = new mocha.Runner(mocha.suite); 4663 | var Reporter = options.reporter || mocha.reporters.HTML; 4664 | var reporter = new Reporter(runner); 4665 | var query = parse(window.location.search || ""); 4666 | if (query.grep) runner.grep(new RegExp(query.grep)); 4667 | if (options.grep) runner.grep(options.grep); 4668 | if (options.ignoreLeaks) runner.ignoreLeaks = true; 4669 | if (options.globals) runner.globals(options.globals); 4670 | runner.globals(['location']); 4671 | runner.on('end', highlightCode); 4672 | return runner.run(fn); 4673 | }; 4674 | })(); 4675 | })(); --------------------------------------------------------------------------------