| OLD | NEW |
| (Empty) |
| 1 ;(function(){ | |
| 2 | |
| 3 // CommonJS require() | |
| 4 | |
| 5 function require(p){ | |
| 6 var path = require.resolve(p) | |
| 7 , mod = require.modules[path]; | |
| 8 if (!mod) throw new Error('failed to require "' + p + '"'); | |
| 9 if (!mod.exports) { | |
| 10 mod.exports = {}; | |
| 11 mod.call(mod.exports, mod, mod.exports, require.relative(path)); | |
| 12 } | |
| 13 return mod.exports; | |
| 14 } | |
| 15 | |
| 16 require.modules = {}; | |
| 17 | |
| 18 require.resolve = function (path){ | |
| 19 var orig = path | |
| 20 , reg = path + '.js' | |
| 21 , index = path + '/index.js'; | |
| 22 return require.modules[reg] && reg | |
| 23 || require.modules[index] && index | |
| 24 || orig; | |
| 25 }; | |
| 26 | |
| 27 require.register = function (path, fn){ | |
| 28 require.modules[path] = fn; | |
| 29 }; | |
| 30 | |
| 31 require.relative = function (parent) { | |
| 32 return function(p){ | |
| 33 if ('.' != p.charAt(0)) return require(p); | |
| 34 | |
| 35 var path = parent.split('/') | |
| 36 , segs = p.split('/'); | |
| 37 path.pop(); | |
| 38 | |
| 39 for (var i = 0; i < segs.length; i++) { | |
| 40 var seg = segs[i]; | |
| 41 if ('..' == seg) path.pop(); | |
| 42 else if ('.' != seg) path.push(seg); | |
| 43 } | |
| 44 | |
| 45 return require(path.join('/')); | |
| 46 }; | |
| 47 }; | |
| 48 | |
| 49 | |
| 50 require.register("browser/debug.js", function(module, exports, require){ | |
| 51 | |
| 52 module.exports = function(type){ | |
| 53 return function(){ | |
| 54 } | |
| 55 }; | |
| 56 | |
| 57 }); // module: browser/debug.js | |
| 58 | |
| 59 require.register("browser/diff.js", function(module, exports, require){ | |
| 60 /* See LICENSE file for terms of use */ | |
| 61 | |
| 62 /* | |
| 63 * Text diff implementation. | |
| 64 * | |
| 65 * This library supports the following APIS: | |
| 66 * JsDiff.diffChars: Character by character diff | |
| 67 * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace | |
| 68 * JsDiff.diffLines: Line based diff | |
| 69 * | |
| 70 * JsDiff.diffCss: Diff targeted at CSS content | |
| 71 * | |
| 72 * These methods are based on the implementation proposed in | |
| 73 * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). | |
| 74 * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 | |
| 75 */ | |
| 76 var JsDiff = (function() { | |
| 77 /*jshint maxparams: 5*/ | |
| 78 function clonePath(path) { | |
| 79 return { newPos: path.newPos, components: path.components.slice(0) }; | |
| 80 } | |
| 81 function removeEmpty(array) { | |
| 82 var ret = []; | |
| 83 for (var i = 0; i < array.length; i++) { | |
| 84 if (array[i]) { | |
| 85 ret.push(array[i]); | |
| 86 } | |
| 87 } | |
| 88 return ret; | |
| 89 } | |
| 90 function escapeHTML(s) { | |
| 91 var n = s; | |
| 92 n = n.replace(/&/g, '&'); | |
| 93 n = n.replace(/</g, '<'); | |
| 94 n = n.replace(/>/g, '>'); | |
| 95 n = n.replace(/"/g, '"'); | |
| 96 | |
| 97 return n; | |
| 98 } | |
| 99 | |
| 100 var Diff = function(ignoreWhitespace) { | |
| 101 this.ignoreWhitespace = ignoreWhitespace; | |
| 102 }; | |
| 103 Diff.prototype = { | |
| 104 diff: function(oldString, newString) { | |
| 105 // Handle the identity case (this is due to unrolling editLength == 0 | |
| 106 if (newString === oldString) { | |
| 107 return [{ value: newString }]; | |
| 108 } | |
| 109 if (!newString) { | |
| 110 return [{ value: oldString, removed: true }]; | |
| 111 } | |
| 112 if (!oldString) { | |
| 113 return [{ value: newString, added: true }]; | |
| 114 } | |
| 115 | |
| 116 newString = this.tokenize(newString); | |
| 117 oldString = this.tokenize(oldString); | |
| 118 | |
| 119 var newLen = newString.length, oldLen = oldString.length; | |
| 120 var maxEditLength = newLen + oldLen; | |
| 121 var bestPath = [{ newPos: -1, components: [] }]; | |
| 122 | |
| 123 // Seed editLength = 0 | |
| 124 var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); | |
| 125 if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { | |
| 126 return bestPath[0].components; | |
| 127 } | |
| 128 | |
| 129 for (var editLength = 1; editLength <= maxEditLength; editLength++) { | |
| 130 for (var diagonalPath = -1*editLength; diagonalPath <= editLength; dia
gonalPath+=2) { | |
| 131 var basePath; | |
| 132 var addPath = bestPath[diagonalPath-1], | |
| 133 removePath = bestPath[diagonalPath+1]; | |
| 134 oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; | |
| 135 if (addPath) { | |
| 136 // No one else is going to attempt to use this value, clear it | |
| 137 bestPath[diagonalPath-1] = undefined; | |
| 138 } | |
| 139 | |
| 140 var canAdd = addPath && addPath.newPos+1 < newLen; | |
| 141 var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; | |
| 142 if (!canAdd && !canRemove) { | |
| 143 bestPath[diagonalPath] = undefined; | |
| 144 continue; | |
| 145 } | |
| 146 | |
| 147 // Select the diagonal that we want to branch from. We select the pr
ior | |
| 148 // path whose position in the new string is the farthest from the or
igin | |
| 149 // and does not pass the bounds of the diff graph | |
| 150 if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { | |
| 151 basePath = clonePath(removePath); | |
| 152 this.pushComponent(basePath.components, oldString[oldPos], undefin
ed, true); | |
| 153 } else { | |
| 154 basePath = clonePath(addPath); | |
| 155 basePath.newPos++; | |
| 156 this.pushComponent(basePath.components, newString[basePath.newPos]
, true, undefined); | |
| 157 } | |
| 158 | |
| 159 var oldPos = this.extractCommon(basePath, newString, oldString, diag
onalPath); | |
| 160 | |
| 161 if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { | |
| 162 return basePath.components; | |
| 163 } else { | |
| 164 bestPath[diagonalPath] = basePath; | |
| 165 } | |
| 166 } | |
| 167 } | |
| 168 }, | |
| 169 | |
| 170 pushComponent: function(components, value, added, removed) { | |
| 171 var last = components[components.length-1]; | |
| 172 if (last && last.added === added && last.removed === removed) { | |
| 173 // We need to clone here as the component clone operation is just | |
| 174 // as shallow array clone | |
| 175 components[components.length-1] = | |
| 176 {value: this.join(last.value, value), added: added, removed: removed
}; | |
| 177 } else { | |
| 178 components.push({value: value, added: added, removed: removed }); | |
| 179 } | |
| 180 }, | |
| 181 extractCommon: function(basePath, newString, oldString, diagonalPath) { | |
| 182 var newLen = newString.length, | |
| 183 oldLen = oldString.length, | |
| 184 newPos = basePath.newPos, | |
| 185 oldPos = newPos - diagonalPath; | |
| 186 while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[n
ewPos+1], oldString[oldPos+1])) { | |
| 187 newPos++; | |
| 188 oldPos++; | |
| 189 | |
| 190 this.pushComponent(basePath.components, newString[newPos], undefined,
undefined); | |
| 191 } | |
| 192 basePath.newPos = newPos; | |
| 193 return oldPos; | |
| 194 }, | |
| 195 | |
| 196 equals: function(left, right) { | |
| 197 var reWhitespace = /\S/; | |
| 198 if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.t
est(right)) { | |
| 199 return true; | |
| 200 } else { | |
| 201 return left === right; | |
| 202 } | |
| 203 }, | |
| 204 join: function(left, right) { | |
| 205 return left + right; | |
| 206 }, | |
| 207 tokenize: function(value) { | |
| 208 return value; | |
| 209 } | |
| 210 }; | |
| 211 | |
| 212 var CharDiff = new Diff(); | |
| 213 | |
| 214 var WordDiff = new Diff(true); | |
| 215 var WordWithSpaceDiff = new Diff(); | |
| 216 WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { | |
| 217 return removeEmpty(value.split(/(\s+|\b)/)); | |
| 218 }; | |
| 219 | |
| 220 var CssDiff = new Diff(true); | |
| 221 CssDiff.tokenize = function(value) { | |
| 222 return removeEmpty(value.split(/([{}:;,]|\s+)/)); | |
| 223 }; | |
| 224 | |
| 225 var LineDiff = new Diff(); | |
| 226 LineDiff.tokenize = function(value) { | |
| 227 return value.split(/^/m); | |
| 228 }; | |
| 229 | |
| 230 return { | |
| 231 Diff: Diff, | |
| 232 | |
| 233 diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr);
}, | |
| 234 diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr);
}, | |
| 235 diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff
(oldStr, newStr); }, | |
| 236 diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr);
}, | |
| 237 | |
| 238 diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, | |
| 239 | |
| 240 createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { | |
| 241 var ret = []; | |
| 242 | |
| 243 ret.push('Index: ' + fileName); | |
| 244 ret.push('================================================================
==='); | |
| 245 ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t'
+ oldHeader)); | |
| 246 ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t'
+ newHeader)); | |
| 247 | |
| 248 var diff = LineDiff.diff(oldStr, newStr); | |
| 249 if (!diff[diff.length-1].value) { | |
| 250 diff.pop(); // Remove trailing newline add | |
| 251 } | |
| 252 diff.push({value: '', lines: []}); // Append an empty value to make clea
nup easier | |
| 253 | |
| 254 function contextLines(lines) { | |
| 255 return lines.map(function(entry) { return ' ' + entry; }); | |
| 256 } | |
| 257 function eofNL(curRange, i, current) { | |
| 258 var last = diff[diff.length-2], | |
| 259 isLast = i === diff.length-2, | |
| 260 isLastOfType = i === diff.length-3 && (current.added !== last.added
|| current.removed !== last.removed); | |
| 261 | |
| 262 // Figure out if this is the last line for the given file and missing NL | |
| 263 if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { | |
| 264 curRange.push('\\ No newline at end of file'); | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 var oldRangeStart = 0, newRangeStart = 0, curRange = [], | |
| 269 oldLine = 1, newLine = 1; | |
| 270 for (var i = 0; i < diff.length; i++) { | |
| 271 var current = diff[i], | |
| 272 lines = current.lines || current.value.replace(/\n$/, '').split('\n'
); | |
| 273 current.lines = lines; | |
| 274 | |
| 275 if (current.added || current.removed) { | |
| 276 if (!oldRangeStart) { | |
| 277 var prev = diff[i-1]; | |
| 278 oldRangeStart = oldLine; | |
| 279 newRangeStart = newLine; | |
| 280 | |
| 281 if (prev) { | |
| 282 curRange = contextLines(prev.lines.slice(-4)); | |
| 283 oldRangeStart -= curRange.length; | |
| 284 newRangeStart -= curRange.length; | |
| 285 } | |
| 286 } | |
| 287 curRange.push.apply(curRange, lines.map(function(entry) { return (curr
ent.added?'+':'-') + entry; })); | |
| 288 eofNL(curRange, i, current); | |
| 289 | |
| 290 if (current.added) { | |
| 291 newLine += lines.length; | |
| 292 } else { | |
| 293 oldLine += lines.length; | |
| 294 } | |
| 295 } else { | |
| 296 if (oldRangeStart) { | |
| 297 // Close out any changes that have been output (or join overlapping) | |
| 298 if (lines.length <= 8 && i < diff.length-2) { | |
| 299 // Overlapping | |
| 300 curRange.push.apply(curRange, contextLines(lines)); | |
| 301 } else { | |
| 302 // end the range and output | |
| 303 var contextSize = Math.min(lines.length, 4); | |
| 304 ret.push( | |
| 305 '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextS
ize) | |
| 306 + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextS
ize) | |
| 307 + ' @@'); | |
| 308 ret.push.apply(ret, curRange); | |
| 309 ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); | |
| 310 if (lines.length <= 4) { | |
| 311 eofNL(ret, i, current); | |
| 312 } | |
| 313 | |
| 314 oldRangeStart = 0; newRangeStart = 0; curRange = []; | |
| 315 } | |
| 316 } | |
| 317 oldLine += lines.length; | |
| 318 newLine += lines.length; | |
| 319 } | |
| 320 } | |
| 321 | |
| 322 return ret.join('\n') + '\n'; | |
| 323 }, | |
| 324 | |
| 325 applyPatch: function(oldStr, uniDiff) { | |
| 326 var diffstr = uniDiff.split('\n'); | |
| 327 var diff = []; | |
| 328 var remEOFNL = false, | |
| 329 addEOFNL = false; | |
| 330 | |
| 331 for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { | |
| 332 if(diffstr[i][0] === '@') { | |
| 333 var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); | |
| 334 diff.unshift({ | |
| 335 start:meh[3], | |
| 336 oldlength:meh[2], | |
| 337 oldlines:[], | |
| 338 newlength:meh[4], | |
| 339 newlines:[] | |
| 340 }); | |
| 341 } else if(diffstr[i][0] === '+') { | |
| 342 diff[0].newlines.push(diffstr[i].substr(1)); | |
| 343 } else if(diffstr[i][0] === '-') { | |
| 344 diff[0].oldlines.push(diffstr[i].substr(1)); | |
| 345 } else if(diffstr[i][0] === ' ') { | |
| 346 diff[0].newlines.push(diffstr[i].substr(1)); | |
| 347 diff[0].oldlines.push(diffstr[i].substr(1)); | |
| 348 } else if(diffstr[i][0] === '\\') { | |
| 349 if (diffstr[i-1][0] === '+') { | |
| 350 remEOFNL = true; | |
| 351 } else if(diffstr[i-1][0] === '-') { | |
| 352 addEOFNL = true; | |
| 353 } | |
| 354 } | |
| 355 } | |
| 356 | |
| 357 var str = oldStr.split('\n'); | |
| 358 for (var i = diff.length - 1; i >= 0; i--) { | |
| 359 var d = diff[i]; | |
| 360 for (var j = 0; j < d.oldlength; j++) { | |
| 361 if(str[d.start-1+j] !== d.oldlines[j]) { | |
| 362 return false; | |
| 363 } | |
| 364 } | |
| 365 Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newli
nes)); | |
| 366 } | |
| 367 | |
| 368 if (remEOFNL) { | |
| 369 while (!str[str.length-1]) { | |
| 370 str.pop(); | |
| 371 } | |
| 372 } else if (addEOFNL) { | |
| 373 str.push(''); | |
| 374 } | |
| 375 return str.join('\n'); | |
| 376 }, | |
| 377 | |
| 378 convertChangesToXML: function(changes){ | |
| 379 var ret = []; | |
| 380 for ( var i = 0; i < changes.length; i++) { | |
| 381 var change = changes[i]; | |
| 382 if (change.added) { | |
| 383 ret.push('<ins>'); | |
| 384 } else if (change.removed) { | |
| 385 ret.push('<del>'); | |
| 386 } | |
| 387 | |
| 388 ret.push(escapeHTML(change.value)); | |
| 389 | |
| 390 if (change.added) { | |
| 391 ret.push('</ins>'); | |
| 392 } else if (change.removed) { | |
| 393 ret.push('</del>'); | |
| 394 } | |
| 395 } | |
| 396 return ret.join(''); | |
| 397 }, | |
| 398 | |
| 399 // See: http://code.google.com/p/google-diff-match-patch/wiki/API | |
| 400 convertChangesToDMP: function(changes){ | |
| 401 var ret = [], change; | |
| 402 for ( var i = 0; i < changes.length; i++) { | |
| 403 change = changes[i]; | |
| 404 ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); | |
| 405 } | |
| 406 return ret; | |
| 407 } | |
| 408 }; | |
| 409 })(); | |
| 410 | |
| 411 if (typeof module !== 'undefined') { | |
| 412 module.exports = JsDiff; | |
| 413 } | |
| 414 | |
| 415 }); // module: browser/diff.js | |
| 416 | |
| 417 require.register("browser/events.js", function(module, exports, require){ | |
| 418 | |
| 419 /** | |
| 420 * Module exports. | |
| 421 */ | |
| 422 | |
| 423 exports.EventEmitter = EventEmitter; | |
| 424 | |
| 425 /** | |
| 426 * Check if `obj` is an array. | |
| 427 */ | |
| 428 | |
| 429 function isArray(obj) { | |
| 430 return '[object Array]' == {}.toString.call(obj); | |
| 431 } | |
| 432 | |
| 433 /** | |
| 434 * Event emitter constructor. | |
| 435 * | |
| 436 * @api public | |
| 437 */ | |
| 438 | |
| 439 function EventEmitter(){}; | |
| 440 | |
| 441 /** | |
| 442 * Adds a listener. | |
| 443 * | |
| 444 * @api public | |
| 445 */ | |
| 446 | |
| 447 EventEmitter.prototype.on = function (name, fn) { | |
| 448 if (!this.$events) { | |
| 449 this.$events = {}; | |
| 450 } | |
| 451 | |
| 452 if (!this.$events[name]) { | |
| 453 this.$events[name] = fn; | |
| 454 } else if (isArray(this.$events[name])) { | |
| 455 this.$events[name].push(fn); | |
| 456 } else { | |
| 457 this.$events[name] = [this.$events[name], fn]; | |
| 458 } | |
| 459 | |
| 460 return this; | |
| 461 }; | |
| 462 | |
| 463 EventEmitter.prototype.addListener = EventEmitter.prototype.on; | |
| 464 | |
| 465 /** | |
| 466 * Adds a volatile listener. | |
| 467 * | |
| 468 * @api public | |
| 469 */ | |
| 470 | |
| 471 EventEmitter.prototype.once = function (name, fn) { | |
| 472 var self = this; | |
| 473 | |
| 474 function on () { | |
| 475 self.removeListener(name, on); | |
| 476 fn.apply(this, arguments); | |
| 477 }; | |
| 478 | |
| 479 on.listener = fn; | |
| 480 this.on(name, on); | |
| 481 | |
| 482 return this; | |
| 483 }; | |
| 484 | |
| 485 /** | |
| 486 * Removes a listener. | |
| 487 * | |
| 488 * @api public | |
| 489 */ | |
| 490 | |
| 491 EventEmitter.prototype.removeListener = function (name, fn) { | |
| 492 if (this.$events && this.$events[name]) { | |
| 493 var list = this.$events[name]; | |
| 494 | |
| 495 if (isArray(list)) { | |
| 496 var pos = -1; | |
| 497 | |
| 498 for (var i = 0, l = list.length; i < l; i++) { | |
| 499 if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { | |
| 500 pos = i; | |
| 501 break; | |
| 502 } | |
| 503 } | |
| 504 | |
| 505 if (pos < 0) { | |
| 506 return this; | |
| 507 } | |
| 508 | |
| 509 list.splice(pos, 1); | |
| 510 | |
| 511 if (!list.length) { | |
| 512 delete this.$events[name]; | |
| 513 } | |
| 514 } else if (list === fn || (list.listener && list.listener === fn)) { | |
| 515 delete this.$events[name]; | |
| 516 } | |
| 517 } | |
| 518 | |
| 519 return this; | |
| 520 }; | |
| 521 | |
| 522 /** | |
| 523 * Removes all listeners for an event. | |
| 524 * | |
| 525 * @api public | |
| 526 */ | |
| 527 | |
| 528 EventEmitter.prototype.removeAllListeners = function (name) { | |
| 529 if (name === undefined) { | |
| 530 this.$events = {}; | |
| 531 return this; | |
| 532 } | |
| 533 | |
| 534 if (this.$events && this.$events[name]) { | |
| 535 this.$events[name] = null; | |
| 536 } | |
| 537 | |
| 538 return this; | |
| 539 }; | |
| 540 | |
| 541 /** | |
| 542 * Gets all listeners for a certain event. | |
| 543 * | |
| 544 * @api public | |
| 545 */ | |
| 546 | |
| 547 EventEmitter.prototype.listeners = function (name) { | |
| 548 if (!this.$events) { | |
| 549 this.$events = {}; | |
| 550 } | |
| 551 | |
| 552 if (!this.$events[name]) { | |
| 553 this.$events[name] = []; | |
| 554 } | |
| 555 | |
| 556 if (!isArray(this.$events[name])) { | |
| 557 this.$events[name] = [this.$events[name]]; | |
| 558 } | |
| 559 | |
| 560 return this.$events[name]; | |
| 561 }; | |
| 562 | |
| 563 /** | |
| 564 * Emits an event. | |
| 565 * | |
| 566 * @api public | |
| 567 */ | |
| 568 | |
| 569 EventEmitter.prototype.emit = function (name) { | |
| 570 if (!this.$events) { | |
| 571 return false; | |
| 572 } | |
| 573 | |
| 574 var handler = this.$events[name]; | |
| 575 | |
| 576 if (!handler) { | |
| 577 return false; | |
| 578 } | |
| 579 | |
| 580 var args = [].slice.call(arguments, 1); | |
| 581 | |
| 582 if ('function' == typeof handler) { | |
| 583 handler.apply(this, args); | |
| 584 } else if (isArray(handler)) { | |
| 585 var listeners = handler.slice(); | |
| 586 | |
| 587 for (var i = 0, l = listeners.length; i < l; i++) { | |
| 588 listeners[i].apply(this, args); | |
| 589 } | |
| 590 } else { | |
| 591 return false; | |
| 592 } | |
| 593 | |
| 594 return true; | |
| 595 }; | |
| 596 }); // module: browser/events.js | |
| 597 | |
| 598 require.register("browser/fs.js", function(module, exports, require){ | |
| 599 | |
| 600 }); // module: browser/fs.js | |
| 601 | |
| 602 require.register("browser/path.js", function(module, exports, require){ | |
| 603 | |
| 604 }); // module: browser/path.js | |
| 605 | |
| 606 require.register("browser/progress.js", function(module, exports, require){ | |
| 607 /** | |
| 608 * Expose `Progress`. | |
| 609 */ | |
| 610 | |
| 611 module.exports = Progress; | |
| 612 | |
| 613 /** | |
| 614 * Initialize a new `Progress` indicator. | |
| 615 */ | |
| 616 | |
| 617 function Progress() { | |
| 618 this.percent = 0; | |
| 619 this.size(0); | |
| 620 this.fontSize(11); | |
| 621 this.font('helvetica, arial, sans-serif'); | |
| 622 } | |
| 623 | |
| 624 /** | |
| 625 * Set progress size to `n`. | |
| 626 * | |
| 627 * @param {Number} n | |
| 628 * @return {Progress} for chaining | |
| 629 * @api public | |
| 630 */ | |
| 631 | |
| 632 Progress.prototype.size = function(n){ | |
| 633 this._size = n; | |
| 634 return this; | |
| 635 }; | |
| 636 | |
| 637 /** | |
| 638 * Set text to `str`. | |
| 639 * | |
| 640 * @param {String} str | |
| 641 * @return {Progress} for chaining | |
| 642 * @api public | |
| 643 */ | |
| 644 | |
| 645 Progress.prototype.text = function(str){ | |
| 646 this._text = str; | |
| 647 return this; | |
| 648 }; | |
| 649 | |
| 650 /** | |
| 651 * Set font size to `n`. | |
| 652 * | |
| 653 * @param {Number} n | |
| 654 * @return {Progress} for chaining | |
| 655 * @api public | |
| 656 */ | |
| 657 | |
| 658 Progress.prototype.fontSize = function(n){ | |
| 659 this._fontSize = n; | |
| 660 return this; | |
| 661 }; | |
| 662 | |
| 663 /** | |
| 664 * Set font `family`. | |
| 665 * | |
| 666 * @param {String} family | |
| 667 * @return {Progress} for chaining | |
| 668 */ | |
| 669 | |
| 670 Progress.prototype.font = function(family){ | |
| 671 this._font = family; | |
| 672 return this; | |
| 673 }; | |
| 674 | |
| 675 /** | |
| 676 * Update percentage to `n`. | |
| 677 * | |
| 678 * @param {Number} n | |
| 679 * @return {Progress} for chaining | |
| 680 */ | |
| 681 | |
| 682 Progress.prototype.update = function(n){ | |
| 683 this.percent = n; | |
| 684 return this; | |
| 685 }; | |
| 686 | |
| 687 /** | |
| 688 * Draw on `ctx`. | |
| 689 * | |
| 690 * @param {CanvasRenderingContext2d} ctx | |
| 691 * @return {Progress} for chaining | |
| 692 */ | |
| 693 | |
| 694 Progress.prototype.draw = function(ctx){ | |
| 695 try { | |
| 696 var percent = Math.min(this.percent, 100) | |
| 697 , size = this._size | |
| 698 , half = size / 2 | |
| 699 , x = half | |
| 700 , y = half | |
| 701 , rad = half - 1 | |
| 702 , fontSize = this._fontSize; | |
| 703 | |
| 704 ctx.font = fontSize + 'px ' + this._font; | |
| 705 | |
| 706 var angle = Math.PI * 2 * (percent / 100); | |
| 707 ctx.clearRect(0, 0, size, size); | |
| 708 | |
| 709 // outer circle | |
| 710 ctx.strokeStyle = '#9f9f9f'; | |
| 711 ctx.beginPath(); | |
| 712 ctx.arc(x, y, rad, 0, angle, false); | |
| 713 ctx.stroke(); | |
| 714 | |
| 715 // inner circle | |
| 716 ctx.strokeStyle = '#eee'; | |
| 717 ctx.beginPath(); | |
| 718 ctx.arc(x, y, rad - 1, 0, angle, true); | |
| 719 ctx.stroke(); | |
| 720 | |
| 721 // text | |
| 722 var text = this._text || (percent | 0) + '%' | |
| 723 , w = ctx.measureText(text).width; | |
| 724 | |
| 725 ctx.fillText( | |
| 726 text | |
| 727 , x - w / 2 + 1 | |
| 728 , y + fontSize / 2 - 1); | |
| 729 } catch (ex) {} //don't fail if we can't render progress | |
| 730 return this; | |
| 731 }; | |
| 732 | |
| 733 }); // module: browser/progress.js | |
| 734 | |
| 735 require.register("browser/tty.js", function(module, exports, require){ | |
| 736 | |
| 737 exports.isatty = function(){ | |
| 738 return true; | |
| 739 }; | |
| 740 | |
| 741 exports.getWindowSize = function(){ | |
| 742 if ('innerHeight' in global) { | |
| 743 return [global.innerHeight, global.innerWidth]; | |
| 744 } else { | |
| 745 // In a Web Worker, the DOM Window is not available. | |
| 746 return [640, 480]; | |
| 747 } | |
| 748 }; | |
| 749 | |
| 750 }); // module: browser/tty.js | |
| 751 | |
| 752 require.register("context.js", function(module, exports, require){ | |
| 753 | |
| 754 /** | |
| 755 * Expose `Context`. | |
| 756 */ | |
| 757 | |
| 758 module.exports = Context; | |
| 759 | |
| 760 /** | |
| 761 * Initialize a new `Context`. | |
| 762 * | |
| 763 * @api private | |
| 764 */ | |
| 765 | |
| 766 function Context(){} | |
| 767 | |
| 768 /** | |
| 769 * Set or get the context `Runnable` to `runnable`. | |
| 770 * | |
| 771 * @param {Runnable} runnable | |
| 772 * @return {Context} | |
| 773 * @api private | |
| 774 */ | |
| 775 | |
| 776 Context.prototype.runnable = function(runnable){ | |
| 777 if (0 == arguments.length) return this._runnable; | |
| 778 this.test = this._runnable = runnable; | |
| 779 return this; | |
| 780 }; | |
| 781 | |
| 782 /** | |
| 783 * Set test timeout `ms`. | |
| 784 * | |
| 785 * @param {Number} ms | |
| 786 * @return {Context} self | |
| 787 * @api private | |
| 788 */ | |
| 789 | |
| 790 Context.prototype.timeout = function(ms){ | |
| 791 this.runnable().timeout(ms); | |
| 792 return this; | |
| 793 }; | |
| 794 | |
| 795 /** | |
| 796 * Set test slowness threshold `ms`. | |
| 797 * | |
| 798 * @param {Number} ms | |
| 799 * @return {Context} self | |
| 800 * @api private | |
| 801 */ | |
| 802 | |
| 803 Context.prototype.slow = function(ms){ | |
| 804 this.runnable().slow(ms); | |
| 805 return this; | |
| 806 }; | |
| 807 | |
| 808 /** | |
| 809 * Inspect the context void of `._runnable`. | |
| 810 * | |
| 811 * @return {String} | |
| 812 * @api private | |
| 813 */ | |
| 814 | |
| 815 Context.prototype.inspect = function(){ | |
| 816 return JSON.stringify(this, function(key, val){ | |
| 817 if ('_runnable' == key) return; | |
| 818 if ('test' == key) return; | |
| 819 return val; | |
| 820 }, 2); | |
| 821 }; | |
| 822 | |
| 823 }); // module: context.js | |
| 824 | |
| 825 require.register("hook.js", function(module, exports, require){ | |
| 826 | |
| 827 /** | |
| 828 * Module dependencies. | |
| 829 */ | |
| 830 | |
| 831 var Runnable = require('./runnable'); | |
| 832 | |
| 833 /** | |
| 834 * Expose `Hook`. | |
| 835 */ | |
| 836 | |
| 837 module.exports = Hook; | |
| 838 | |
| 839 /** | |
| 840 * Initialize a new `Hook` with the given `title` and callback `fn`. | |
| 841 * | |
| 842 * @param {String} title | |
| 843 * @param {Function} fn | |
| 844 * @api private | |
| 845 */ | |
| 846 | |
| 847 function Hook(title, fn) { | |
| 848 Runnable.call(this, title, fn); | |
| 849 this.type = 'hook'; | |
| 850 } | |
| 851 | |
| 852 /** | |
| 853 * Inherit from `Runnable.prototype`. | |
| 854 */ | |
| 855 | |
| 856 function F(){}; | |
| 857 F.prototype = Runnable.prototype; | |
| 858 Hook.prototype = new F; | |
| 859 Hook.prototype.constructor = Hook; | |
| 860 | |
| 861 | |
| 862 /** | |
| 863 * Get or set the test `err`. | |
| 864 * | |
| 865 * @param {Error} err | |
| 866 * @return {Error} | |
| 867 * @api public | |
| 868 */ | |
| 869 | |
| 870 Hook.prototype.error = function(err){ | |
| 871 if (0 == arguments.length) { | |
| 872 var err = this._error; | |
| 873 this._error = null; | |
| 874 return err; | |
| 875 } | |
| 876 | |
| 877 this._error = err; | |
| 878 }; | |
| 879 | |
| 880 }); // module: hook.js | |
| 881 | |
| 882 require.register("interfaces/bdd.js", function(module, exports, require){ | |
| 883 | |
| 884 /** | |
| 885 * Module dependencies. | |
| 886 */ | |
| 887 | |
| 888 var Suite = require('../suite') | |
| 889 , Test = require('../test') | |
| 890 , utils = require('../utils'); | |
| 891 | |
| 892 /** | |
| 893 * BDD-style interface: | |
| 894 * | |
| 895 * describe('Array', function(){ | |
| 896 * describe('#indexOf()', function(){ | |
| 897 * it('should return -1 when not present', function(){ | |
| 898 * | |
| 899 * }); | |
| 900 * | |
| 901 * it('should return the index when present', function(){ | |
| 902 * | |
| 903 * }); | |
| 904 * }); | |
| 905 * }); | |
| 906 * | |
| 907 */ | |
| 908 | |
| 909 module.exports = function(suite){ | |
| 910 var suites = [suite]; | |
| 911 | |
| 912 suite.on('pre-require', function(context, file, mocha){ | |
| 913 | |
| 914 /** | |
| 915 * Execute before running tests. | |
| 916 */ | |
| 917 | |
| 918 context.before = function(name, fn){ | |
| 919 suites[0].beforeAll(name, fn); | |
| 920 }; | |
| 921 | |
| 922 /** | |
| 923 * Execute after running tests. | |
| 924 */ | |
| 925 | |
| 926 context.after = function(name, fn){ | |
| 927 suites[0].afterAll(name, fn); | |
| 928 }; | |
| 929 | |
| 930 /** | |
| 931 * Execute before each test case. | |
| 932 */ | |
| 933 | |
| 934 context.beforeEach = function(name, fn){ | |
| 935 suites[0].beforeEach(name, fn); | |
| 936 }; | |
| 937 | |
| 938 /** | |
| 939 * Execute after each test case. | |
| 940 */ | |
| 941 | |
| 942 context.afterEach = function(name, fn){ | |
| 943 suites[0].afterEach(name, fn); | |
| 944 }; | |
| 945 | |
| 946 /** | |
| 947 * Describe a "suite" with the given `title` | |
| 948 * and callback `fn` containing nested suites | |
| 949 * and/or tests. | |
| 950 */ | |
| 951 | |
| 952 context.describe = context.context = function(title, fn){ | |
| 953 var suite = Suite.create(suites[0], title); | |
| 954 suites.unshift(suite); | |
| 955 fn.call(suite); | |
| 956 suites.shift(); | |
| 957 return suite; | |
| 958 }; | |
| 959 | |
| 960 /** | |
| 961 * Pending describe. | |
| 962 */ | |
| 963 | |
| 964 context.xdescribe = | |
| 965 context.xcontext = | |
| 966 context.describe.skip = function(title, fn){ | |
| 967 var suite = Suite.create(suites[0], title); | |
| 968 suite.pending = true; | |
| 969 suites.unshift(suite); | |
| 970 fn.call(suite); | |
| 971 suites.shift(); | |
| 972 }; | |
| 973 | |
| 974 /** | |
| 975 * Exclusive suite. | |
| 976 */ | |
| 977 | |
| 978 context.describe.only = function(title, fn){ | |
| 979 var suite = context.describe(title, fn); | |
| 980 mocha.grep(suite.fullTitle()); | |
| 981 return suite; | |
| 982 }; | |
| 983 | |
| 984 /** | |
| 985 * Describe a specification or test-case | |
| 986 * with the given `title` and callback `fn` | |
| 987 * acting as a thunk. | |
| 988 */ | |
| 989 | |
| 990 context.it = context.specify = function(title, fn){ | |
| 991 var suite = suites[0]; | |
| 992 if (suite.pending) var fn = null; | |
| 993 var test = new Test(title, fn); | |
| 994 suite.addTest(test); | |
| 995 return test; | |
| 996 }; | |
| 997 | |
| 998 /** | |
| 999 * Exclusive test-case. | |
| 1000 */ | |
| 1001 | |
| 1002 context.it.only = function(title, fn){ | |
| 1003 var test = context.it(title, fn); | |
| 1004 var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; | |
| 1005 mocha.grep(new RegExp(reString)); | |
| 1006 return test; | |
| 1007 }; | |
| 1008 | |
| 1009 /** | |
| 1010 * Pending test case. | |
| 1011 */ | |
| 1012 | |
| 1013 context.xit = | |
| 1014 context.xspecify = | |
| 1015 context.it.skip = function(title){ | |
| 1016 context.it(title); | |
| 1017 }; | |
| 1018 }); | |
| 1019 }; | |
| 1020 | |
| 1021 }); // module: interfaces/bdd.js | |
| 1022 | |
| 1023 require.register("interfaces/exports.js", function(module, exports, require){ | |
| 1024 | |
| 1025 /** | |
| 1026 * Module dependencies. | |
| 1027 */ | |
| 1028 | |
| 1029 var Suite = require('../suite') | |
| 1030 , Test = require('../test'); | |
| 1031 | |
| 1032 /** | |
| 1033 * TDD-style interface: | |
| 1034 * | |
| 1035 * exports.Array = { | |
| 1036 * '#indexOf()': { | |
| 1037 * 'should return -1 when the value is not present': function(){ | |
| 1038 * | |
| 1039 * }, | |
| 1040 * | |
| 1041 * 'should return the correct index when the value is present': function
(){ | |
| 1042 * | |
| 1043 * } | |
| 1044 * } | |
| 1045 * }; | |
| 1046 * | |
| 1047 */ | |
| 1048 | |
| 1049 module.exports = function(suite){ | |
| 1050 var suites = [suite]; | |
| 1051 | |
| 1052 suite.on('require', visit); | |
| 1053 | |
| 1054 function visit(obj) { | |
| 1055 var suite; | |
| 1056 for (var key in obj) { | |
| 1057 if ('function' == typeof obj[key]) { | |
| 1058 var fn = obj[key]; | |
| 1059 switch (key) { | |
| 1060 case 'before': | |
| 1061 suites[0].beforeAll(fn); | |
| 1062 break; | |
| 1063 case 'after': | |
| 1064 suites[0].afterAll(fn); | |
| 1065 break; | |
| 1066 case 'beforeEach': | |
| 1067 suites[0].beforeEach(fn); | |
| 1068 break; | |
| 1069 case 'afterEach': | |
| 1070 suites[0].afterEach(fn); | |
| 1071 break; | |
| 1072 default: | |
| 1073 suites[0].addTest(new Test(key, fn)); | |
| 1074 } | |
| 1075 } else { | |
| 1076 var suite = Suite.create(suites[0], key); | |
| 1077 suites.unshift(suite); | |
| 1078 visit(obj[key]); | |
| 1079 suites.shift(); | |
| 1080 } | |
| 1081 } | |
| 1082 } | |
| 1083 }; | |
| 1084 | |
| 1085 }); // module: interfaces/exports.js | |
| 1086 | |
| 1087 require.register("interfaces/index.js", function(module, exports, require){ | |
| 1088 | |
| 1089 exports.bdd = require('./bdd'); | |
| 1090 exports.tdd = require('./tdd'); | |
| 1091 exports.qunit = require('./qunit'); | |
| 1092 exports.exports = require('./exports'); | |
| 1093 | |
| 1094 }); // module: interfaces/index.js | |
| 1095 | |
| 1096 require.register("interfaces/qunit.js", function(module, exports, require){ | |
| 1097 | |
| 1098 /** | |
| 1099 * Module dependencies. | |
| 1100 */ | |
| 1101 | |
| 1102 var Suite = require('../suite') | |
| 1103 , Test = require('../test') | |
| 1104 , utils = require('../utils'); | |
| 1105 | |
| 1106 /** | |
| 1107 * QUnit-style interface: | |
| 1108 * | |
| 1109 * suite('Array'); | |
| 1110 * | |
| 1111 * test('#length', function(){ | |
| 1112 * var arr = [1,2,3]; | |
| 1113 * ok(arr.length == 3); | |
| 1114 * }); | |
| 1115 * | |
| 1116 * test('#indexOf()', function(){ | |
| 1117 * var arr = [1,2,3]; | |
| 1118 * ok(arr.indexOf(1) == 0); | |
| 1119 * ok(arr.indexOf(2) == 1); | |
| 1120 * ok(arr.indexOf(3) == 2); | |
| 1121 * }); | |
| 1122 * | |
| 1123 * suite('String'); | |
| 1124 * | |
| 1125 * test('#length', function(){ | |
| 1126 * ok('foo'.length == 3); | |
| 1127 * }); | |
| 1128 * | |
| 1129 */ | |
| 1130 | |
| 1131 module.exports = function(suite){ | |
| 1132 var suites = [suite]; | |
| 1133 | |
| 1134 suite.on('pre-require', function(context, file, mocha){ | |
| 1135 | |
| 1136 /** | |
| 1137 * Execute before running tests. | |
| 1138 */ | |
| 1139 | |
| 1140 context.before = function(name, fn){ | |
| 1141 suites[0].beforeAll(name, fn); | |
| 1142 }; | |
| 1143 | |
| 1144 /** | |
| 1145 * Execute after running tests. | |
| 1146 */ | |
| 1147 | |
| 1148 context.after = function(name, fn){ | |
| 1149 suites[0].afterAll(name, fn); | |
| 1150 }; | |
| 1151 | |
| 1152 /** | |
| 1153 * Execute before each test case. | |
| 1154 */ | |
| 1155 | |
| 1156 context.beforeEach = function(name, fn){ | |
| 1157 suites[0].beforeEach(name, fn); | |
| 1158 }; | |
| 1159 | |
| 1160 /** | |
| 1161 * Execute after each test case. | |
| 1162 */ | |
| 1163 | |
| 1164 context.afterEach = function(name, fn){ | |
| 1165 suites[0].afterEach(name, fn); | |
| 1166 }; | |
| 1167 | |
| 1168 /** | |
| 1169 * Describe a "suite" with the given `title`. | |
| 1170 */ | |
| 1171 | |
| 1172 context.suite = function(title){ | |
| 1173 if (suites.length > 1) suites.shift(); | |
| 1174 var suite = Suite.create(suites[0], title); | |
| 1175 suites.unshift(suite); | |
| 1176 return suite; | |
| 1177 }; | |
| 1178 | |
| 1179 /** | |
| 1180 * Exclusive test-case. | |
| 1181 */ | |
| 1182 | |
| 1183 context.suite.only = function(title, fn){ | |
| 1184 var suite = context.suite(title, fn); | |
| 1185 mocha.grep(suite.fullTitle()); | |
| 1186 }; | |
| 1187 | |
| 1188 /** | |
| 1189 * Describe a specification or test-case | |
| 1190 * with the given `title` and callback `fn` | |
| 1191 * acting as a thunk. | |
| 1192 */ | |
| 1193 | |
| 1194 context.test = function(title, fn){ | |
| 1195 var test = new Test(title, fn); | |
| 1196 suites[0].addTest(test); | |
| 1197 return test; | |
| 1198 }; | |
| 1199 | |
| 1200 /** | |
| 1201 * Exclusive test-case. | |
| 1202 */ | |
| 1203 | |
| 1204 context.test.only = function(title, fn){ | |
| 1205 var test = context.test(title, fn); | |
| 1206 var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; | |
| 1207 mocha.grep(new RegExp(reString)); | |
| 1208 }; | |
| 1209 | |
| 1210 /** | |
| 1211 * Pending test case. | |
| 1212 */ | |
| 1213 | |
| 1214 context.test.skip = function(title){ | |
| 1215 context.test(title); | |
| 1216 }; | |
| 1217 }); | |
| 1218 }; | |
| 1219 | |
| 1220 }); // module: interfaces/qunit.js | |
| 1221 | |
| 1222 require.register("interfaces/tdd.js", function(module, exports, require){ | |
| 1223 | |
| 1224 /** | |
| 1225 * Module dependencies. | |
| 1226 */ | |
| 1227 | |
| 1228 var Suite = require('../suite') | |
| 1229 , Test = require('../test') | |
| 1230 , utils = require('../utils');; | |
| 1231 | |
| 1232 /** | |
| 1233 * TDD-style interface: | |
| 1234 * | |
| 1235 * suite('Array', function(){ | |
| 1236 * suite('#indexOf()', function(){ | |
| 1237 * suiteSetup(function(){ | |
| 1238 * | |
| 1239 * }); | |
| 1240 * | |
| 1241 * test('should return -1 when not present', function(){ | |
| 1242 * | |
| 1243 * }); | |
| 1244 * | |
| 1245 * test('should return the index when present', function(){ | |
| 1246 * | |
| 1247 * }); | |
| 1248 * | |
| 1249 * suiteTeardown(function(){ | |
| 1250 * | |
| 1251 * }); | |
| 1252 * }); | |
| 1253 * }); | |
| 1254 * | |
| 1255 */ | |
| 1256 | |
| 1257 module.exports = function(suite){ | |
| 1258 var suites = [suite]; | |
| 1259 | |
| 1260 suite.on('pre-require', function(context, file, mocha){ | |
| 1261 | |
| 1262 /** | |
| 1263 * Execute before each test case. | |
| 1264 */ | |
| 1265 | |
| 1266 context.setup = function(name, fn){ | |
| 1267 suites[0].beforeEach(name, fn); | |
| 1268 }; | |
| 1269 | |
| 1270 /** | |
| 1271 * Execute after each test case. | |
| 1272 */ | |
| 1273 | |
| 1274 context.teardown = function(name, fn){ | |
| 1275 suites[0].afterEach(name, fn); | |
| 1276 }; | |
| 1277 | |
| 1278 /** | |
| 1279 * Execute before the suite. | |
| 1280 */ | |
| 1281 | |
| 1282 context.suiteSetup = function(name, fn){ | |
| 1283 suites[0].beforeAll(name, fn); | |
| 1284 }; | |
| 1285 | |
| 1286 /** | |
| 1287 * Execute after the suite. | |
| 1288 */ | |
| 1289 | |
| 1290 context.suiteTeardown = function(name, fn){ | |
| 1291 suites[0].afterAll(name, fn); | |
| 1292 }; | |
| 1293 | |
| 1294 /** | |
| 1295 * Describe a "suite" with the given `title` | |
| 1296 * and callback `fn` containing nested suites | |
| 1297 * and/or tests. | |
| 1298 */ | |
| 1299 | |
| 1300 context.suite = function(title, fn){ | |
| 1301 var suite = Suite.create(suites[0], title); | |
| 1302 suites.unshift(suite); | |
| 1303 fn.call(suite); | |
| 1304 suites.shift(); | |
| 1305 return suite; | |
| 1306 }; | |
| 1307 | |
| 1308 /** | |
| 1309 * Pending suite. | |
| 1310 */ | |
| 1311 context.suite.skip = function(title, fn) { | |
| 1312 var suite = Suite.create(suites[0], title); | |
| 1313 suite.pending = true; | |
| 1314 suites.unshift(suite); | |
| 1315 fn.call(suite); | |
| 1316 suites.shift(); | |
| 1317 }; | |
| 1318 | |
| 1319 /** | |
| 1320 * Exclusive test-case. | |
| 1321 */ | |
| 1322 | |
| 1323 context.suite.only = function(title, fn){ | |
| 1324 var suite = context.suite(title, fn); | |
| 1325 mocha.grep(suite.fullTitle()); | |
| 1326 }; | |
| 1327 | |
| 1328 /** | |
| 1329 * Describe a specification or test-case | |
| 1330 * with the given `title` and callback `fn` | |
| 1331 * acting as a thunk. | |
| 1332 */ | |
| 1333 | |
| 1334 context.test = function(title, fn){ | |
| 1335 var suite = suites[0]; | |
| 1336 if (suite.pending) var fn = null; | |
| 1337 var test = new Test(title, fn); | |
| 1338 suite.addTest(test); | |
| 1339 return test; | |
| 1340 }; | |
| 1341 | |
| 1342 /** | |
| 1343 * Exclusive test-case. | |
| 1344 */ | |
| 1345 | |
| 1346 context.test.only = function(title, fn){ | |
| 1347 var test = context.test(title, fn); | |
| 1348 var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; | |
| 1349 mocha.grep(new RegExp(reString)); | |
| 1350 }; | |
| 1351 | |
| 1352 /** | |
| 1353 * Pending test case. | |
| 1354 */ | |
| 1355 | |
| 1356 context.test.skip = function(title){ | |
| 1357 context.test(title); | |
| 1358 }; | |
| 1359 }); | |
| 1360 }; | |
| 1361 | |
| 1362 }); // module: interfaces/tdd.js | |
| 1363 | |
| 1364 require.register("mocha.js", function(module, exports, require){ | |
| 1365 /*! | |
| 1366 * mocha | |
| 1367 * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca> | |
| 1368 * MIT Licensed | |
| 1369 */ | |
| 1370 | |
| 1371 /** | |
| 1372 * Module dependencies. | |
| 1373 */ | |
| 1374 | |
| 1375 var path = require('browser/path') | |
| 1376 , utils = require('./utils'); | |
| 1377 | |
| 1378 /** | |
| 1379 * Expose `Mocha`. | |
| 1380 */ | |
| 1381 | |
| 1382 exports = module.exports = Mocha; | |
| 1383 | |
| 1384 /** | |
| 1385 * Expose internals. | |
| 1386 */ | |
| 1387 | |
| 1388 exports.utils = utils; | |
| 1389 exports.interfaces = require('./interfaces'); | |
| 1390 exports.reporters = require('./reporters'); | |
| 1391 exports.Runnable = require('./runnable'); | |
| 1392 exports.Context = require('./context'); | |
| 1393 exports.Runner = require('./runner'); | |
| 1394 exports.Suite = require('./suite'); | |
| 1395 exports.Hook = require('./hook'); | |
| 1396 exports.Test = require('./test'); | |
| 1397 | |
| 1398 /** | |
| 1399 * Return image `name` path. | |
| 1400 * | |
| 1401 * @param {String} name | |
| 1402 * @return {String} | |
| 1403 * @api private | |
| 1404 */ | |
| 1405 | |
| 1406 function image(name) { | |
| 1407 return __dirname + '/../images/' + name + '.png'; | |
| 1408 } | |
| 1409 | |
| 1410 /** | |
| 1411 * Setup mocha with `options`. | |
| 1412 * | |
| 1413 * Options: | |
| 1414 * | |
| 1415 * - `ui` name "bdd", "tdd", "exports" etc | |
| 1416 * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` | |
| 1417 * - `globals` array of accepted globals | |
| 1418 * - `timeout` timeout in milliseconds | |
| 1419 * - `bail` bail on the first test failure | |
| 1420 * - `slow` milliseconds to wait before considering a test slow | |
| 1421 * - `ignoreLeaks` ignore global leaks | |
| 1422 * - `grep` string or regexp to filter tests with | |
| 1423 * | |
| 1424 * @param {Object} options | |
| 1425 * @api public | |
| 1426 */ | |
| 1427 | |
| 1428 function Mocha(options) { | |
| 1429 options = options || {}; | |
| 1430 this.files = []; | |
| 1431 this.options = options; | |
| 1432 this.grep(options.grep); | |
| 1433 this.suite = new exports.Suite('', new exports.Context); | |
| 1434 this.ui(options.ui); | |
| 1435 this.bail(options.bail); | |
| 1436 this.reporter(options.reporter); | |
| 1437 if (null != options.timeout) this.timeout(options.timeout); | |
| 1438 this.useColors(options.useColors) | |
| 1439 if (options.slow) this.slow(options.slow); | |
| 1440 | |
| 1441 this.suite.on('pre-require', function (context) { | |
| 1442 exports.afterEach = context.afterEach || context.teardown; | |
| 1443 exports.after = context.after || context.suiteTeardown; | |
| 1444 exports.beforeEach = context.beforeEach || context.setup; | |
| 1445 exports.before = context.before || context.suiteSetup; | |
| 1446 exports.describe = context.describe || context.suite; | |
| 1447 exports.it = context.it || context.test; | |
| 1448 exports.setup = context.setup || context.beforeEach; | |
| 1449 exports.suiteSetup = context.suiteSetup || context.before; | |
| 1450 exports.suiteTeardown = context.suiteTeardown || context.after; | |
| 1451 exports.suite = context.suite || context.describe; | |
| 1452 exports.teardown = context.teardown || context.afterEach; | |
| 1453 exports.test = context.test || context.it; | |
| 1454 }); | |
| 1455 } | |
| 1456 | |
| 1457 /** | |
| 1458 * Enable or disable bailing on the first failure. | |
| 1459 * | |
| 1460 * @param {Boolean} [bail] | |
| 1461 * @api public | |
| 1462 */ | |
| 1463 | |
| 1464 Mocha.prototype.bail = function(bail){ | |
| 1465 if (0 == arguments.length) bail = true; | |
| 1466 this.suite.bail(bail); | |
| 1467 return this; | |
| 1468 }; | |
| 1469 | |
| 1470 /** | |
| 1471 * Add test `file`. | |
| 1472 * | |
| 1473 * @param {String} file | |
| 1474 * @api public | |
| 1475 */ | |
| 1476 | |
| 1477 Mocha.prototype.addFile = function(file){ | |
| 1478 this.files.push(file); | |
| 1479 return this; | |
| 1480 }; | |
| 1481 | |
| 1482 /** | |
| 1483 * Set reporter to `reporter`, defaults to "dot". | |
| 1484 * | |
| 1485 * @param {String|Function} reporter name or constructor | |
| 1486 * @api public | |
| 1487 */ | |
| 1488 | |
| 1489 Mocha.prototype.reporter = function(reporter){ | |
| 1490 if ('function' == typeof reporter) { | |
| 1491 this._reporter = reporter; | |
| 1492 } else { | |
| 1493 reporter = reporter || 'dot'; | |
| 1494 var _reporter; | |
| 1495 try { _reporter = require('./reporters/' + reporter); } catch (err) {}; | |
| 1496 if (!_reporter) try { _reporter = require(reporter); } catch (err) {}; | |
| 1497 if (!_reporter && reporter === 'teamcity') | |
| 1498 console.warn('The Teamcity reporter was moved to a package named ' + | |
| 1499 'mocha-teamcity-reporter ' + | |
| 1500 '(https://npmjs.org/package/mocha-teamcity-reporter).'); | |
| 1501 if (!_reporter) throw new Error('invalid reporter "' + reporter + '"'); | |
| 1502 this._reporter = _reporter; | |
| 1503 } | |
| 1504 return this; | |
| 1505 }; | |
| 1506 | |
| 1507 /** | |
| 1508 * Set test UI `name`, defaults to "bdd". | |
| 1509 * | |
| 1510 * @param {String} bdd | |
| 1511 * @api public | |
| 1512 */ | |
| 1513 | |
| 1514 Mocha.prototype.ui = function(name){ | |
| 1515 name = name || 'bdd'; | |
| 1516 this._ui = exports.interfaces[name]; | |
| 1517 if (!this._ui) try { this._ui = require(name); } catch (err) {}; | |
| 1518 if (!this._ui) throw new Error('invalid interface "' + name + '"'); | |
| 1519 this._ui = this._ui(this.suite); | |
| 1520 return this; | |
| 1521 }; | |
| 1522 | |
| 1523 /** | |
| 1524 * Load registered files. | |
| 1525 * | |
| 1526 * @api private | |
| 1527 */ | |
| 1528 | |
| 1529 Mocha.prototype.loadFiles = function(fn){ | |
| 1530 var self = this; | |
| 1531 var suite = this.suite; | |
| 1532 var pending = this.files.length; | |
| 1533 this.files.forEach(function(file){ | |
| 1534 file = path.resolve(file); | |
| 1535 suite.emit('pre-require', global, file, self); | |
| 1536 suite.emit('require', require(file), file, self); | |
| 1537 suite.emit('post-require', global, file, self); | |
| 1538 --pending || (fn && fn()); | |
| 1539 }); | |
| 1540 }; | |
| 1541 | |
| 1542 /** | |
| 1543 * Enable growl support. | |
| 1544 * | |
| 1545 * @api private | |
| 1546 */ | |
| 1547 | |
| 1548 Mocha.prototype._growl = function(runner, reporter) { | |
| 1549 var notify = require('growl'); | |
| 1550 | |
| 1551 runner.on('end', function(){ | |
| 1552 var stats = reporter.stats; | |
| 1553 if (stats.failures) { | |
| 1554 var msg = stats.failures + ' of ' + runner.total + ' tests failed'; | |
| 1555 notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); | |
| 1556 } else { | |
| 1557 notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { | |
| 1558 name: 'mocha' | |
| 1559 , title: 'Passed' | |
| 1560 , image: image('ok') | |
| 1561 }); | |
| 1562 } | |
| 1563 }); | |
| 1564 }; | |
| 1565 | |
| 1566 /** | |
| 1567 * Add regexp to grep, if `re` is a string it is escaped. | |
| 1568 * | |
| 1569 * @param {RegExp|String} re | |
| 1570 * @return {Mocha} | |
| 1571 * @api public | |
| 1572 */ | |
| 1573 | |
| 1574 Mocha.prototype.grep = function(re){ | |
| 1575 this.options.grep = 'string' == typeof re | |
| 1576 ? new RegExp(utils.escapeRegexp(re)) | |
| 1577 : re; | |
| 1578 return this; | |
| 1579 }; | |
| 1580 | |
| 1581 /** | |
| 1582 * Invert `.grep()` matches. | |
| 1583 * | |
| 1584 * @return {Mocha} | |
| 1585 * @api public | |
| 1586 */ | |
| 1587 | |
| 1588 Mocha.prototype.invert = function(){ | |
| 1589 this.options.invert = true; | |
| 1590 return this; | |
| 1591 }; | |
| 1592 | |
| 1593 /** | |
| 1594 * Ignore global leaks. | |
| 1595 * | |
| 1596 * @param {Boolean} ignore | |
| 1597 * @return {Mocha} | |
| 1598 * @api public | |
| 1599 */ | |
| 1600 | |
| 1601 Mocha.prototype.ignoreLeaks = function(ignore){ | |
| 1602 this.options.ignoreLeaks = !!ignore; | |
| 1603 return this; | |
| 1604 }; | |
| 1605 | |
| 1606 /** | |
| 1607 * Enable global leak checking. | |
| 1608 * | |
| 1609 * @return {Mocha} | |
| 1610 * @api public | |
| 1611 */ | |
| 1612 | |
| 1613 Mocha.prototype.checkLeaks = function(){ | |
| 1614 this.options.ignoreLeaks = false; | |
| 1615 return this; | |
| 1616 }; | |
| 1617 | |
| 1618 /** | |
| 1619 * Enable growl support. | |
| 1620 * | |
| 1621 * @return {Mocha} | |
| 1622 * @api public | |
| 1623 */ | |
| 1624 | |
| 1625 Mocha.prototype.growl = function(){ | |
| 1626 this.options.growl = true; | |
| 1627 return this; | |
| 1628 }; | |
| 1629 | |
| 1630 /** | |
| 1631 * Ignore `globals` array or string. | |
| 1632 * | |
| 1633 * @param {Array|String} globals | |
| 1634 * @return {Mocha} | |
| 1635 * @api public | |
| 1636 */ | |
| 1637 | |
| 1638 Mocha.prototype.globals = function(globals){ | |
| 1639 this.options.globals = (this.options.globals || []).concat(globals); | |
| 1640 return this; | |
| 1641 }; | |
| 1642 | |
| 1643 /** | |
| 1644 * Emit color output. | |
| 1645 * | |
| 1646 * @param {Boolean} colors | |
| 1647 * @return {Mocha} | |
| 1648 * @api public | |
| 1649 */ | |
| 1650 | |
| 1651 Mocha.prototype.useColors = function(colors){ | |
| 1652 this.options.useColors = arguments.length && colors != undefined | |
| 1653 ? colors | |
| 1654 : true; | |
| 1655 return this; | |
| 1656 }; | |
| 1657 | |
| 1658 /** | |
| 1659 * Use inline diffs rather than +/-. | |
| 1660 * | |
| 1661 * @param {Boolean} inlineDiffs | |
| 1662 * @return {Mocha} | |
| 1663 * @api public | |
| 1664 */ | |
| 1665 | |
| 1666 Mocha.prototype.useInlineDiffs = function(inlineDiffs) { | |
| 1667 this.options.useInlineDiffs = arguments.length && inlineDiffs != undefined | |
| 1668 ? inlineDiffs | |
| 1669 : false; | |
| 1670 return this; | |
| 1671 }; | |
| 1672 | |
| 1673 /** | |
| 1674 * Set the timeout in milliseconds. | |
| 1675 * | |
| 1676 * @param {Number} timeout | |
| 1677 * @return {Mocha} | |
| 1678 * @api public | |
| 1679 */ | |
| 1680 | |
| 1681 Mocha.prototype.timeout = function(timeout){ | |
| 1682 this.suite.timeout(timeout); | |
| 1683 return this; | |
| 1684 }; | |
| 1685 | |
| 1686 /** | |
| 1687 * Set slowness threshold in milliseconds. | |
| 1688 * | |
| 1689 * @param {Number} slow | |
| 1690 * @return {Mocha} | |
| 1691 * @api public | |
| 1692 */ | |
| 1693 | |
| 1694 Mocha.prototype.slow = function(slow){ | |
| 1695 this.suite.slow(slow); | |
| 1696 return this; | |
| 1697 }; | |
| 1698 | |
| 1699 /** | |
| 1700 * Makes all tests async (accepting a callback) | |
| 1701 * | |
| 1702 * @return {Mocha} | |
| 1703 * @api public | |
| 1704 */ | |
| 1705 | |
| 1706 Mocha.prototype.asyncOnly = function(){ | |
| 1707 this.options.asyncOnly = true; | |
| 1708 return this; | |
| 1709 }; | |
| 1710 | |
| 1711 /** | |
| 1712 * Run tests and invoke `fn()` when complete. | |
| 1713 * | |
| 1714 * @param {Function} fn | |
| 1715 * @return {Runner} | |
| 1716 * @api public | |
| 1717 */ | |
| 1718 | |
| 1719 Mocha.prototype.run = function(fn){ | |
| 1720 if (this.files.length) this.loadFiles(); | |
| 1721 var suite = this.suite; | |
| 1722 var options = this.options; | |
| 1723 options.files = this.files; | |
| 1724 var runner = new exports.Runner(suite); | |
| 1725 var reporter = new this._reporter(runner, options); | |
| 1726 runner.ignoreLeaks = false !== options.ignoreLeaks; | |
| 1727 runner.asyncOnly = options.asyncOnly; | |
| 1728 if (options.grep) runner.grep(options.grep, options.invert); | |
| 1729 if (options.globals) runner.globals(options.globals); | |
| 1730 if (options.growl) this._growl(runner, reporter); | |
| 1731 exports.reporters.Base.useColors = options.useColors; | |
| 1732 exports.reporters.Base.inlineDiffs = options.useInlineDiffs; | |
| 1733 return runner.run(fn); | |
| 1734 }; | |
| 1735 | |
| 1736 }); // module: mocha.js | |
| 1737 | |
| 1738 require.register("ms.js", function(module, exports, require){ | |
| 1739 /** | |
| 1740 * Helpers. | |
| 1741 */ | |
| 1742 | |
| 1743 var s = 1000; | |
| 1744 var m = s * 60; | |
| 1745 var h = m * 60; | |
| 1746 var d = h * 24; | |
| 1747 var y = d * 365.25; | |
| 1748 | |
| 1749 /** | |
| 1750 * Parse or format the given `val`. | |
| 1751 * | |
| 1752 * Options: | |
| 1753 * | |
| 1754 * - `long` verbose formatting [false] | |
| 1755 * | |
| 1756 * @param {String|Number} val | |
| 1757 * @param {Object} options | |
| 1758 * @return {String|Number} | |
| 1759 * @api public | |
| 1760 */ | |
| 1761 | |
| 1762 module.exports = function(val, options){ | |
| 1763 options = options || {}; | |
| 1764 if ('string' == typeof val) return parse(val); | |
| 1765 return options.long ? longFormat(val) : shortFormat(val); | |
| 1766 }; | |
| 1767 | |
| 1768 /** | |
| 1769 * Parse the given `str` and return milliseconds. | |
| 1770 * | |
| 1771 * @param {String} str | |
| 1772 * @return {Number} | |
| 1773 * @api private | |
| 1774 */ | |
| 1775 | |
| 1776 function parse(str) { | |
| 1777 var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|yea
rs?|y)?$/i.exec(str); | |
| 1778 if (!match) return; | |
| 1779 var n = parseFloat(match[1]); | |
| 1780 var type = (match[2] || 'ms').toLowerCase(); | |
| 1781 switch (type) { | |
| 1782 case 'years': | |
| 1783 case 'year': | |
| 1784 case 'y': | |
| 1785 return n * y; | |
| 1786 case 'days': | |
| 1787 case 'day': | |
| 1788 case 'd': | |
| 1789 return n * d; | |
| 1790 case 'hours': | |
| 1791 case 'hour': | |
| 1792 case 'h': | |
| 1793 return n * h; | |
| 1794 case 'minutes': | |
| 1795 case 'minute': | |
| 1796 case 'm': | |
| 1797 return n * m; | |
| 1798 case 'seconds': | |
| 1799 case 'second': | |
| 1800 case 's': | |
| 1801 return n * s; | |
| 1802 case 'ms': | |
| 1803 return n; | |
| 1804 } | |
| 1805 } | |
| 1806 | |
| 1807 /** | |
| 1808 * Short format for `ms`. | |
| 1809 * | |
| 1810 * @param {Number} ms | |
| 1811 * @return {String} | |
| 1812 * @api private | |
| 1813 */ | |
| 1814 | |
| 1815 function shortFormat(ms) { | |
| 1816 if (ms >= d) return Math.round(ms / d) + 'd'; | |
| 1817 if (ms >= h) return Math.round(ms / h) + 'h'; | |
| 1818 if (ms >= m) return Math.round(ms / m) + 'm'; | |
| 1819 if (ms >= s) return Math.round(ms / s) + 's'; | |
| 1820 return ms + 'ms'; | |
| 1821 } | |
| 1822 | |
| 1823 /** | |
| 1824 * Long format for `ms`. | |
| 1825 * | |
| 1826 * @param {Number} ms | |
| 1827 * @return {String} | |
| 1828 * @api private | |
| 1829 */ | |
| 1830 | |
| 1831 function longFormat(ms) { | |
| 1832 return plural(ms, d, 'day') | |
| 1833 || plural(ms, h, 'hour') | |
| 1834 || plural(ms, m, 'minute') | |
| 1835 || plural(ms, s, 'second') | |
| 1836 || ms + ' ms'; | |
| 1837 } | |
| 1838 | |
| 1839 /** | |
| 1840 * Pluralization helper. | |
| 1841 */ | |
| 1842 | |
| 1843 function plural(ms, n, name) { | |
| 1844 if (ms < n) return; | |
| 1845 if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; | |
| 1846 return Math.ceil(ms / n) + ' ' + name + 's'; | |
| 1847 } | |
| 1848 | |
| 1849 }); // module: ms.js | |
| 1850 | |
| 1851 require.register("reporters/base.js", function(module, exports, require){ | |
| 1852 | |
| 1853 /** | |
| 1854 * Module dependencies. | |
| 1855 */ | |
| 1856 | |
| 1857 var tty = require('browser/tty') | |
| 1858 , diff = require('browser/diff') | |
| 1859 , ms = require('../ms') | |
| 1860 , utils = require('../utils'); | |
| 1861 | |
| 1862 /** | |
| 1863 * Save timer references to avoid Sinon interfering (see GH-237). | |
| 1864 */ | |
| 1865 | |
| 1866 var Date = global.Date | |
| 1867 , setTimeout = global.setTimeout | |
| 1868 , setInterval = global.setInterval | |
| 1869 , clearTimeout = global.clearTimeout | |
| 1870 , clearInterval = global.clearInterval; | |
| 1871 | |
| 1872 /** | |
| 1873 * Check if both stdio streams are associated with a tty. | |
| 1874 */ | |
| 1875 | |
| 1876 var isatty = tty.isatty(1) && tty.isatty(2); | |
| 1877 | |
| 1878 /** | |
| 1879 * Expose `Base`. | |
| 1880 */ | |
| 1881 | |
| 1882 exports = module.exports = Base; | |
| 1883 | |
| 1884 /** | |
| 1885 * Enable coloring by default. | |
| 1886 */ | |
| 1887 | |
| 1888 exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined); | |
| 1889 | |
| 1890 /** | |
| 1891 * Inline diffs instead of +/- | |
| 1892 */ | |
| 1893 | |
| 1894 exports.inlineDiffs = false; | |
| 1895 | |
| 1896 /** | |
| 1897 * Default color map. | |
| 1898 */ | |
| 1899 | |
| 1900 exports.colors = { | |
| 1901 'pass': 90 | |
| 1902 , 'fail': 31 | |
| 1903 , 'bright pass': 92 | |
| 1904 , 'bright fail': 91 | |
| 1905 , 'bright yellow': 93 | |
| 1906 , 'pending': 36 | |
| 1907 , 'suite': 0 | |
| 1908 , 'error title': 0 | |
| 1909 , 'error message': 31 | |
| 1910 , 'error stack': 90 | |
| 1911 , 'checkmark': 32 | |
| 1912 , 'fast': 90 | |
| 1913 , 'medium': 33 | |
| 1914 , 'slow': 31 | |
| 1915 , 'green': 32 | |
| 1916 , 'light': 90 | |
| 1917 , 'diff gutter': 90 | |
| 1918 , 'diff added': 42 | |
| 1919 , 'diff removed': 41 | |
| 1920 }; | |
| 1921 | |
| 1922 /** | |
| 1923 * Default symbol map. | |
| 1924 */ | |
| 1925 | |
| 1926 exports.symbols = { | |
| 1927 ok: '✓', | |
| 1928 err: '✖', | |
| 1929 dot: '․' | |
| 1930 }; | |
| 1931 | |
| 1932 // With node.js on Windows: use symbols available in terminal default fonts | |
| 1933 if ('win32' == process.platform) { | |
| 1934 exports.symbols.ok = '\u221A'; | |
| 1935 exports.symbols.err = '\u00D7'; | |
| 1936 exports.symbols.dot = '.'; | |
| 1937 } | |
| 1938 | |
| 1939 /** | |
| 1940 * Color `str` with the given `type`, | |
| 1941 * allowing colors to be disabled, | |
| 1942 * as well as user-defined color | |
| 1943 * schemes. | |
| 1944 * | |
| 1945 * @param {String} type | |
| 1946 * @param {String} str | |
| 1947 * @return {String} | |
| 1948 * @api private | |
| 1949 */ | |
| 1950 | |
| 1951 var color = exports.color = function(type, str) { | |
| 1952 if (!exports.useColors) return str; | |
| 1953 return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; | |
| 1954 }; | |
| 1955 | |
| 1956 /** | |
| 1957 * Expose term window size, with some | |
| 1958 * defaults for when stderr is not a tty. | |
| 1959 */ | |
| 1960 | |
| 1961 exports.window = { | |
| 1962 width: isatty | |
| 1963 ? process.stdout.getWindowSize | |
| 1964 ? process.stdout.getWindowSize(1)[0] | |
| 1965 : tty.getWindowSize()[1] | |
| 1966 : 75 | |
| 1967 }; | |
| 1968 | |
| 1969 /** | |
| 1970 * Expose some basic cursor interactions | |
| 1971 * that are common among reporters. | |
| 1972 */ | |
| 1973 | |
| 1974 exports.cursor = { | |
| 1975 hide: function(){ | |
| 1976 isatty && process.stdout.write('\u001b[?25l'); | |
| 1977 }, | |
| 1978 | |
| 1979 show: function(){ | |
| 1980 isatty && process.stdout.write('\u001b[?25h'); | |
| 1981 }, | |
| 1982 | |
| 1983 deleteLine: function(){ | |
| 1984 isatty && process.stdout.write('\u001b[2K'); | |
| 1985 }, | |
| 1986 | |
| 1987 beginningOfLine: function(){ | |
| 1988 isatty && process.stdout.write('\u001b[0G'); | |
| 1989 }, | |
| 1990 | |
| 1991 CR: function(){ | |
| 1992 if (isatty) { | |
| 1993 exports.cursor.deleteLine(); | |
| 1994 exports.cursor.beginningOfLine(); | |
| 1995 } else { | |
| 1996 process.stdout.write('\r'); | |
| 1997 } | |
| 1998 } | |
| 1999 }; | |
| 2000 | |
| 2001 /** | |
| 2002 * Outut the given `failures` as a list. | |
| 2003 * | |
| 2004 * @param {Array} failures | |
| 2005 * @api public | |
| 2006 */ | |
| 2007 | |
| 2008 exports.list = function(failures){ | |
| 2009 console.error(); | |
| 2010 failures.forEach(function(test, i){ | |
| 2011 // format | |
| 2012 var fmt = color('error title', ' %s) %s:\n') | |
| 2013 + color('error message', ' %s') | |
| 2014 + color('error stack', '\n%s\n'); | |
| 2015 | |
| 2016 // msg | |
| 2017 var err = test.err | |
| 2018 , message = err.message || '' | |
| 2019 , stack = err.stack || message | |
| 2020 , index = stack.indexOf(message) + message.length | |
| 2021 , msg = stack.slice(0, index) | |
| 2022 , actual = err.actual | |
| 2023 , expected = err.expected | |
| 2024 , escape = true; | |
| 2025 | |
| 2026 // uncaught | |
| 2027 if (err.uncaught) { | |
| 2028 msg = 'Uncaught ' + msg; | |
| 2029 } | |
| 2030 | |
| 2031 // explicitly show diff | |
| 2032 if (err.showDiff && sameType(actual, expected)) { | |
| 2033 escape = false; | |
| 2034 err.actual = actual = stringify(canonicalize(actual)); | |
| 2035 err.expected = expected = stringify(canonicalize(expected)); | |
| 2036 } | |
| 2037 | |
| 2038 // actual / expected diff | |
| 2039 if ('string' == typeof actual && 'string' == typeof expected) { | |
| 2040 fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n
'); | |
| 2041 var match = message.match(/^([^:]+): expected/); | |
| 2042 msg = '\n ' + color('error message', match ? match[1] : msg); | |
| 2043 | |
| 2044 if (exports.inlineDiffs) { | |
| 2045 msg += inlineDiff(err, escape); | |
| 2046 } else { | |
| 2047 msg += unifiedDiff(err, escape); | |
| 2048 } | |
| 2049 } | |
| 2050 | |
| 2051 // indent stack trace without msg | |
| 2052 stack = stack.slice(index ? index + 1 : index) | |
| 2053 .replace(/^/gm, ' '); | |
| 2054 | |
| 2055 console.error(fmt, (i + 1), test.fullTitle(), msg, stack); | |
| 2056 }); | |
| 2057 }; | |
| 2058 | |
| 2059 /** | |
| 2060 * Initialize a new `Base` reporter. | |
| 2061 * | |
| 2062 * All other reporters generally | |
| 2063 * inherit from this reporter, providing | |
| 2064 * stats such as test duration, number | |
| 2065 * of tests passed / failed etc. | |
| 2066 * | |
| 2067 * @param {Runner} runner | |
| 2068 * @api public | |
| 2069 */ | |
| 2070 | |
| 2071 function Base(runner) { | |
| 2072 var self = this | |
| 2073 , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failure
s: 0 } | |
| 2074 , failures = this.failures = []; | |
| 2075 | |
| 2076 if (!runner) return; | |
| 2077 this.runner = runner; | |
| 2078 | |
| 2079 runner.stats = stats; | |
| 2080 | |
| 2081 runner.on('start', function(){ | |
| 2082 stats.start = new Date; | |
| 2083 }); | |
| 2084 | |
| 2085 runner.on('suite', function(suite){ | |
| 2086 stats.suites = stats.suites || 0; | |
| 2087 suite.root || stats.suites++; | |
| 2088 }); | |
| 2089 | |
| 2090 runner.on('test end', function(test){ | |
| 2091 stats.tests = stats.tests || 0; | |
| 2092 stats.tests++; | |
| 2093 }); | |
| 2094 | |
| 2095 runner.on('pass', function(test){ | |
| 2096 stats.passes = stats.passes || 0; | |
| 2097 | |
| 2098 var medium = test.slow() / 2; | |
| 2099 test.speed = test.duration > test.slow() | |
| 2100 ? 'slow' | |
| 2101 : test.duration > medium | |
| 2102 ? 'medium' | |
| 2103 : 'fast'; | |
| 2104 | |
| 2105 stats.passes++; | |
| 2106 }); | |
| 2107 | |
| 2108 runner.on('fail', function(test, err){ | |
| 2109 stats.failures = stats.failures || 0; | |
| 2110 stats.failures++; | |
| 2111 test.err = err; | |
| 2112 failures.push(test); | |
| 2113 }); | |
| 2114 | |
| 2115 runner.on('end', function(){ | |
| 2116 stats.end = new Date; | |
| 2117 stats.duration = new Date - stats.start; | |
| 2118 }); | |
| 2119 | |
| 2120 runner.on('pending', function(){ | |
| 2121 stats.pending++; | |
| 2122 }); | |
| 2123 } | |
| 2124 | |
| 2125 /** | |
| 2126 * Output common epilogue used by many of | |
| 2127 * the bundled reporters. | |
| 2128 * | |
| 2129 * @api public | |
| 2130 */ | |
| 2131 | |
| 2132 Base.prototype.epilogue = function(){ | |
| 2133 var stats = this.stats; | |
| 2134 var tests; | |
| 2135 var fmt; | |
| 2136 | |
| 2137 console.log(); | |
| 2138 | |
| 2139 // passes | |
| 2140 fmt = color('bright pass', ' ') | |
| 2141 + color('green', ' %d passing') | |
| 2142 + color('light', ' (%s)'); | |
| 2143 | |
| 2144 console.log(fmt, | |
| 2145 stats.passes || 0, | |
| 2146 ms(stats.duration)); | |
| 2147 | |
| 2148 // pending | |
| 2149 if (stats.pending) { | |
| 2150 fmt = color('pending', ' ') | |
| 2151 + color('pending', ' %d pending'); | |
| 2152 | |
| 2153 console.log(fmt, stats.pending); | |
| 2154 } | |
| 2155 | |
| 2156 // failures | |
| 2157 if (stats.failures) { | |
| 2158 fmt = color('fail', ' %d failing'); | |
| 2159 | |
| 2160 console.error(fmt, | |
| 2161 stats.failures); | |
| 2162 | |
| 2163 Base.list(this.failures); | |
| 2164 console.error(); | |
| 2165 } | |
| 2166 | |
| 2167 console.log(); | |
| 2168 }; | |
| 2169 | |
| 2170 /** | |
| 2171 * Pad the given `str` to `len`. | |
| 2172 * | |
| 2173 * @param {String} str | |
| 2174 * @param {String} len | |
| 2175 * @return {String} | |
| 2176 * @api private | |
| 2177 */ | |
| 2178 | |
| 2179 function pad(str, len) { | |
| 2180 str = String(str); | |
| 2181 return Array(len - str.length + 1).join(' ') + str; | |
| 2182 } | |
| 2183 | |
| 2184 | |
| 2185 /** | |
| 2186 * Returns an inline diff between 2 strings with coloured ANSI output | |
| 2187 * | |
| 2188 * @param {Error} Error with actual/expected | |
| 2189 * @return {String} Diff | |
| 2190 * @api private | |
| 2191 */ | |
| 2192 | |
| 2193 function inlineDiff(err, escape) { | |
| 2194 var msg = errorDiff(err, 'WordsWithSpace', escape); | |
| 2195 | |
| 2196 // linenos | |
| 2197 var lines = msg.split('\n'); | |
| 2198 if (lines.length > 4) { | |
| 2199 var width = String(lines.length).length; | |
| 2200 msg = lines.map(function(str, i){ | |
| 2201 return pad(++i, width) + ' |' + ' ' + str; | |
| 2202 }).join('\n'); | |
| 2203 } | |
| 2204 | |
| 2205 // legend | |
| 2206 msg = '\n' | |
| 2207 + color('diff removed', 'actual') | |
| 2208 + ' ' | |
| 2209 + color('diff added', 'expected') | |
| 2210 + '\n\n' | |
| 2211 + msg | |
| 2212 + '\n'; | |
| 2213 | |
| 2214 // indent | |
| 2215 msg = msg.replace(/^/gm, ' '); | |
| 2216 return msg; | |
| 2217 } | |
| 2218 | |
| 2219 /** | |
| 2220 * Returns a unified diff between 2 strings | |
| 2221 * | |
| 2222 * @param {Error} Error with actual/expected | |
| 2223 * @return {String} Diff | |
| 2224 * @api private | |
| 2225 */ | |
| 2226 | |
| 2227 function unifiedDiff(err, escape) { | |
| 2228 var indent = ' '; | |
| 2229 function cleanUp(line) { | |
| 2230 if (escape) { | |
| 2231 line = escapeInvisibles(line); | |
| 2232 } | |
| 2233 if (line[0] === '+') return indent + colorLines('diff added', line); | |
| 2234 if (line[0] === '-') return indent + colorLines('diff removed', line); | |
| 2235 if (line.match(/\@\@/)) return null; | |
| 2236 if (line.match(/\\ No newline/)) return null; | |
| 2237 else return indent + line; | |
| 2238 } | |
| 2239 function notBlank(line) { | |
| 2240 return line != null; | |
| 2241 } | |
| 2242 msg = diff.createPatch('string', err.actual, err.expected); | |
| 2243 var lines = msg.split('\n').splice(4); | |
| 2244 return '\n ' | |
| 2245 + colorLines('diff added', '+ expected') + ' ' | |
| 2246 + colorLines('diff removed', '- actual') | |
| 2247 + '\n\n' | |
| 2248 + lines.map(cleanUp).filter(notBlank).join('\n'); | |
| 2249 } | |
| 2250 | |
| 2251 /** | |
| 2252 * Return a character diff for `err`. | |
| 2253 * | |
| 2254 * @param {Error} err | |
| 2255 * @return {String} | |
| 2256 * @api private | |
| 2257 */ | |
| 2258 | |
| 2259 function errorDiff(err, type, escape) { | |
| 2260 var actual = escape ? escapeInvisibles(err.actual) : err.actual; | |
| 2261 var expected = escape ? escapeInvisibles(err.expected) : err.expected; | |
| 2262 return diff['diff' + type](actual, expected).map(function(str){ | |
| 2263 if (str.added) return colorLines('diff added', str.value); | |
| 2264 if (str.removed) return colorLines('diff removed', str.value); | |
| 2265 return str.value; | |
| 2266 }).join(''); | |
| 2267 } | |
| 2268 | |
| 2269 /** | |
| 2270 * Returns a string with all invisible characters in plain text | |
| 2271 * | |
| 2272 * @param {String} line | |
| 2273 * @return {String} | |
| 2274 * @api private | |
| 2275 */ | |
| 2276 function escapeInvisibles(line) { | |
| 2277 return line.replace(/\t/g, '<tab>') | |
| 2278 .replace(/\r/g, '<CR>') | |
| 2279 .replace(/\n/g, '<LF>\n'); | |
| 2280 } | |
| 2281 | |
| 2282 /** | |
| 2283 * Color lines for `str`, using the color `name`. | |
| 2284 * | |
| 2285 * @param {String} name | |
| 2286 * @param {String} str | |
| 2287 * @return {String} | |
| 2288 * @api private | |
| 2289 */ | |
| 2290 | |
| 2291 function colorLines(name, str) { | |
| 2292 return str.split('\n').map(function(str){ | |
| 2293 return color(name, str); | |
| 2294 }).join('\n'); | |
| 2295 } | |
| 2296 | |
| 2297 /** | |
| 2298 * Stringify `obj`. | |
| 2299 * | |
| 2300 * @param {Object} obj | |
| 2301 * @return {String} | |
| 2302 * @api private | |
| 2303 */ | |
| 2304 | |
| 2305 function stringify(obj) { | |
| 2306 if (obj instanceof RegExp) return obj.toString(); | |
| 2307 return JSON.stringify(obj, null, 2); | |
| 2308 } | |
| 2309 | |
| 2310 /** | |
| 2311 * Return a new object that has the keys in sorted order. | |
| 2312 * @param {Object} obj | |
| 2313 * @return {Object} | |
| 2314 * @api private | |
| 2315 */ | |
| 2316 | |
| 2317 function canonicalize(obj, stack) { | |
| 2318 stack = stack || []; | |
| 2319 | |
| 2320 if (utils.indexOf(stack, obj) !== -1) return obj; | |
| 2321 | |
| 2322 var canonicalizedObj; | |
| 2323 | |
| 2324 if ('[object Array]' == {}.toString.call(obj)) { | |
| 2325 stack.push(obj); | |
| 2326 canonicalizedObj = utils.map(obj, function(item) { | |
| 2327 return canonicalize(item, stack); | |
| 2328 }); | |
| 2329 stack.pop(); | |
| 2330 } else if (typeof obj === 'object' && obj !== null) { | |
| 2331 stack.push(obj); | |
| 2332 canonicalizedObj = {}; | |
| 2333 utils.forEach(utils.keys(obj).sort(), function(key) { | |
| 2334 canonicalizedObj[key] = canonicalize(obj[key], stack); | |
| 2335 }); | |
| 2336 stack.pop(); | |
| 2337 } else { | |
| 2338 canonicalizedObj = obj; | |
| 2339 } | |
| 2340 | |
| 2341 return canonicalizedObj; | |
| 2342 } | |
| 2343 | |
| 2344 /** | |
| 2345 * Check that a / b have the same type. | |
| 2346 * | |
| 2347 * @param {Object} a | |
| 2348 * @param {Object} b | |
| 2349 * @return {Boolean} | |
| 2350 * @api private | |
| 2351 */ | |
| 2352 | |
| 2353 function sameType(a, b) { | |
| 2354 a = Object.prototype.toString.call(a); | |
| 2355 b = Object.prototype.toString.call(b); | |
| 2356 return a == b; | |
| 2357 } | |
| 2358 | |
| 2359 | |
| 2360 }); // module: reporters/base.js | |
| 2361 | |
| 2362 require.register("reporters/doc.js", function(module, exports, require){ | |
| 2363 | |
| 2364 /** | |
| 2365 * Module dependencies. | |
| 2366 */ | |
| 2367 | |
| 2368 var Base = require('./base') | |
| 2369 , utils = require('../utils'); | |
| 2370 | |
| 2371 /** | |
| 2372 * Expose `Doc`. | |
| 2373 */ | |
| 2374 | |
| 2375 exports = module.exports = Doc; | |
| 2376 | |
| 2377 /** | |
| 2378 * Initialize a new `Doc` reporter. | |
| 2379 * | |
| 2380 * @param {Runner} runner | |
| 2381 * @api public | |
| 2382 */ | |
| 2383 | |
| 2384 function Doc(runner) { | |
| 2385 Base.call(this, runner); | |
| 2386 | |
| 2387 var self = this | |
| 2388 , stats = this.stats | |
| 2389 , total = runner.total | |
| 2390 , indents = 2; | |
| 2391 | |
| 2392 function indent() { | |
| 2393 return Array(indents).join(' '); | |
| 2394 } | |
| 2395 | |
| 2396 runner.on('suite', function(suite){ | |
| 2397 if (suite.root) return; | |
| 2398 ++indents; | |
| 2399 console.log('%s<section class="suite">', indent()); | |
| 2400 ++indents; | |
| 2401 console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title)); | |
| 2402 console.log('%s<dl>', indent()); | |
| 2403 }); | |
| 2404 | |
| 2405 runner.on('suite end', function(suite){ | |
| 2406 if (suite.root) return; | |
| 2407 console.log('%s</dl>', indent()); | |
| 2408 --indents; | |
| 2409 console.log('%s</section>', indent()); | |
| 2410 --indents; | |
| 2411 }); | |
| 2412 | |
| 2413 runner.on('pass', function(test){ | |
| 2414 console.log('%s <dt>%s</dt>', indent(), utils.escape(test.title)); | |
| 2415 var code = utils.escape(utils.clean(test.fn.toString())); | |
| 2416 console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code); | |
| 2417 }); | |
| 2418 } | |
| 2419 | |
| 2420 }); // module: reporters/doc.js | |
| 2421 | |
| 2422 require.register("reporters/dot.js", function(module, exports, require){ | |
| 2423 | |
| 2424 /** | |
| 2425 * Module dependencies. | |
| 2426 */ | |
| 2427 | |
| 2428 var Base = require('./base') | |
| 2429 , color = Base.color; | |
| 2430 | |
| 2431 /** | |
| 2432 * Expose `Dot`. | |
| 2433 */ | |
| 2434 | |
| 2435 exports = module.exports = Dot; | |
| 2436 | |
| 2437 /** | |
| 2438 * Initialize a new `Dot` matrix test reporter. | |
| 2439 * | |
| 2440 * @param {Runner} runner | |
| 2441 * @api public | |
| 2442 */ | |
| 2443 | |
| 2444 function Dot(runner) { | |
| 2445 Base.call(this, runner); | |
| 2446 | |
| 2447 var self = this | |
| 2448 , stats = this.stats | |
| 2449 , width = Base.window.width * .75 | 0 | |
| 2450 , n = 0; | |
| 2451 | |
| 2452 runner.on('start', function(){ | |
| 2453 process.stdout.write('\n '); | |
| 2454 }); | |
| 2455 | |
| 2456 runner.on('pending', function(test){ | |
| 2457 process.stdout.write(color('pending', Base.symbols.dot)); | |
| 2458 }); | |
| 2459 | |
| 2460 runner.on('pass', function(test){ | |
| 2461 if (++n % width == 0) process.stdout.write('\n '); | |
| 2462 if ('slow' == test.speed) { | |
| 2463 process.stdout.write(color('bright yellow', Base.symbols.dot)); | |
| 2464 } else { | |
| 2465 process.stdout.write(color(test.speed, Base.symbols.dot)); | |
| 2466 } | |
| 2467 }); | |
| 2468 | |
| 2469 runner.on('fail', function(test, err){ | |
| 2470 if (++n % width == 0) process.stdout.write('\n '); | |
| 2471 process.stdout.write(color('fail', Base.symbols.dot)); | |
| 2472 }); | |
| 2473 | |
| 2474 runner.on('end', function(){ | |
| 2475 console.log(); | |
| 2476 self.epilogue(); | |
| 2477 }); | |
| 2478 } | |
| 2479 | |
| 2480 /** | |
| 2481 * Inherit from `Base.prototype`. | |
| 2482 */ | |
| 2483 | |
| 2484 function F(){}; | |
| 2485 F.prototype = Base.prototype; | |
| 2486 Dot.prototype = new F; | |
| 2487 Dot.prototype.constructor = Dot; | |
| 2488 | |
| 2489 }); // module: reporters/dot.js | |
| 2490 | |
| 2491 require.register("reporters/html-cov.js", function(module, exports, require){ | |
| 2492 | |
| 2493 /** | |
| 2494 * Module dependencies. | |
| 2495 */ | |
| 2496 | |
| 2497 var JSONCov = require('./json-cov') | |
| 2498 , fs = require('browser/fs'); | |
| 2499 | |
| 2500 /** | |
| 2501 * Expose `HTMLCov`. | |
| 2502 */ | |
| 2503 | |
| 2504 exports = module.exports = HTMLCov; | |
| 2505 | |
| 2506 /** | |
| 2507 * Initialize a new `JsCoverage` reporter. | |
| 2508 * | |
| 2509 * @param {Runner} runner | |
| 2510 * @api public | |
| 2511 */ | |
| 2512 | |
| 2513 function HTMLCov(runner) { | |
| 2514 var jade = require('jade') | |
| 2515 , file = __dirname + '/templates/coverage.jade' | |
| 2516 , str = fs.readFileSync(file, 'utf8') | |
| 2517 , fn = jade.compile(str, { filename: file }) | |
| 2518 , self = this; | |
| 2519 | |
| 2520 JSONCov.call(this, runner, false); | |
| 2521 | |
| 2522 runner.on('end', function(){ | |
| 2523 process.stdout.write(fn({ | |
| 2524 cov: self.cov | |
| 2525 , coverageClass: coverageClass | |
| 2526 })); | |
| 2527 }); | |
| 2528 } | |
| 2529 | |
| 2530 /** | |
| 2531 * Return coverage class for `n`. | |
| 2532 * | |
| 2533 * @return {String} | |
| 2534 * @api private | |
| 2535 */ | |
| 2536 | |
| 2537 function coverageClass(n) { | |
| 2538 if (n >= 75) return 'high'; | |
| 2539 if (n >= 50) return 'medium'; | |
| 2540 if (n >= 25) return 'low'; | |
| 2541 return 'terrible'; | |
| 2542 } | |
| 2543 }); // module: reporters/html-cov.js | |
| 2544 | |
| 2545 require.register("reporters/html.js", function(module, exports, require){ | |
| 2546 | |
| 2547 /** | |
| 2548 * Module dependencies. | |
| 2549 */ | |
| 2550 | |
| 2551 var Base = require('./base') | |
| 2552 , utils = require('../utils') | |
| 2553 , Progress = require('../browser/progress') | |
| 2554 , escape = utils.escape; | |
| 2555 | |
| 2556 /** | |
| 2557 * Save timer references to avoid Sinon interfering (see GH-237). | |
| 2558 */ | |
| 2559 | |
| 2560 var Date = global.Date | |
| 2561 , setTimeout = global.setTimeout | |
| 2562 , setInterval = global.setInterval | |
| 2563 , clearTimeout = global.clearTimeout | |
| 2564 , clearInterval = global.clearInterval; | |
| 2565 | |
| 2566 /** | |
| 2567 * Expose `HTML`. | |
| 2568 */ | |
| 2569 | |
| 2570 exports = module.exports = HTML; | |
| 2571 | |
| 2572 /** | |
| 2573 * Stats template. | |
| 2574 */ | |
| 2575 | |
| 2576 var statsTemplate = '<ul id="mocha-stats">' | |
| 2577 + '<li class="progress"><canvas width="40" height="40"></canvas></li>' | |
| 2578 + '<li class="passes"><a href="#">passes:</a> <em>0</em></li>' | |
| 2579 + '<li class="failures"><a href="#">failures:</a> <em>0</em></li>' | |
| 2580 + '<li class="duration">duration: <em>0</em>s</li>' | |
| 2581 + '</ul>'; | |
| 2582 | |
| 2583 /** | |
| 2584 * Initialize a new `HTML` reporter. | |
| 2585 * | |
| 2586 * @param {Runner} runner | |
| 2587 * @api public | |
| 2588 */ | |
| 2589 | |
| 2590 function HTML(runner) { | |
| 2591 Base.call(this, runner); | |
| 2592 | |
| 2593 var self = this | |
| 2594 , stats = this.stats | |
| 2595 , total = runner.total | |
| 2596 , stat = fragment(statsTemplate) | |
| 2597 , items = stat.getElementsByTagName('li') | |
| 2598 , passes = items[1].getElementsByTagName('em')[0] | |
| 2599 , passesLink = items[1].getElementsByTagName('a')[0] | |
| 2600 , failures = items[2].getElementsByTagName('em')[0] | |
| 2601 , failuresLink = items[2].getElementsByTagName('a')[0] | |
| 2602 , duration = items[3].getElementsByTagName('em')[0] | |
| 2603 , canvas = stat.getElementsByTagName('canvas')[0] | |
| 2604 , report = fragment('<ul id="mocha-report"></ul>') | |
| 2605 , stack = [report] | |
| 2606 , progress | |
| 2607 , ctx | |
| 2608 , root = document.getElementById('mocha'); | |
| 2609 | |
| 2610 if (canvas.getContext) { | |
| 2611 var ratio = window.devicePixelRatio || 1; | |
| 2612 canvas.style.width = canvas.width; | |
| 2613 canvas.style.height = canvas.height; | |
| 2614 canvas.width *= ratio; | |
| 2615 canvas.height *= ratio; | |
| 2616 ctx = canvas.getContext('2d'); | |
| 2617 ctx.scale(ratio, ratio); | |
| 2618 progress = new Progress; | |
| 2619 } | |
| 2620 | |
| 2621 if (!root) return error('#mocha div missing, add it to your document'); | |
| 2622 | |
| 2623 // pass toggle | |
| 2624 on(passesLink, 'click', function(){ | |
| 2625 unhide(); | |
| 2626 var name = /pass/.test(report.className) ? '' : ' pass'; | |
| 2627 report.className = report.className.replace(/fail|pass/g, '') + name; | |
| 2628 if (report.className.trim()) hideSuitesWithout('test pass'); | |
| 2629 }); | |
| 2630 | |
| 2631 // failure toggle | |
| 2632 on(failuresLink, 'click', function(){ | |
| 2633 unhide(); | |
| 2634 var name = /fail/.test(report.className) ? '' : ' fail'; | |
| 2635 report.className = report.className.replace(/fail|pass/g, '') + name; | |
| 2636 if (report.className.trim()) hideSuitesWithout('test fail'); | |
| 2637 }); | |
| 2638 | |
| 2639 root.appendChild(stat); | |
| 2640 root.appendChild(report); | |
| 2641 | |
| 2642 if (progress) progress.size(40); | |
| 2643 | |
| 2644 runner.on('suite', function(suite){ | |
| 2645 if (suite.root) return; | |
| 2646 | |
| 2647 // suite | |
| 2648 var url = self.suiteURL(suite); | |
| 2649 var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url
, escape(suite.title)); | |
| 2650 | |
| 2651 // container | |
| 2652 stack[0].appendChild(el); | |
| 2653 stack.unshift(document.createElement('ul')); | |
| 2654 el.appendChild(stack[0]); | |
| 2655 }); | |
| 2656 | |
| 2657 runner.on('suite end', function(suite){ | |
| 2658 if (suite.root) return; | |
| 2659 stack.shift(); | |
| 2660 }); | |
| 2661 | |
| 2662 runner.on('fail', function(test, err){ | |
| 2663 if ('hook' == test.type) runner.emit('test end', test); | |
| 2664 }); | |
| 2665 | |
| 2666 runner.on('test end', function(test){ | |
| 2667 // TODO: add to stats | |
| 2668 var percent = stats.tests / this.total * 100 | 0; | |
| 2669 if (progress) progress.update(percent).draw(ctx); | |
| 2670 | |
| 2671 // update stats | |
| 2672 var ms = new Date - stats.start; | |
| 2673 text(passes, stats.passes); | |
| 2674 text(failures, stats.failures); | |
| 2675 text(duration, (ms / 1000).toFixed(2)); | |
| 2676 | |
| 2677 // test | |
| 2678 if ('passed' == test.state) { | |
| 2679 var url = self.testURL(test); | |
| 2680 var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%
ems</span> <a href="%s" class="replay">‣</a></h2></li>', test.speed, test.title,
test.duration, url); | |
| 2681 } else if (test.pending) { | |
| 2682 var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.t
itle); | |
| 2683 } else { | |
| 2684 var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="
replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle())); | |
| 2685 var str = test.err.stack || test.err.toString(); | |
| 2686 | |
| 2687 // FF / Opera do not add the message | |
| 2688 if (!~str.indexOf(test.err.message)) { | |
| 2689 str = test.err.message + '\n' + str; | |
| 2690 } | |
| 2691 | |
| 2692 // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we | |
| 2693 // check for the result of the stringifying. | |
| 2694 if ('[object Error]' == str) str = test.err.message; | |
| 2695 | |
| 2696 // Safari doesn't give you a stack. Let's at least provide a source line. | |
| 2697 if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined)
{ | |
| 2698 str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; | |
| 2699 } | |
| 2700 | |
| 2701 el.appendChild(fragment('<pre class="error">%e</pre>', str)); | |
| 2702 } | |
| 2703 | |
| 2704 // toggle code | |
| 2705 // TODO: defer | |
| 2706 if (!test.pending) { | |
| 2707 var h2 = el.getElementsByTagName('h2')[0]; | |
| 2708 | |
| 2709 on(h2, 'click', function(){ | |
| 2710 pre.style.display = 'none' == pre.style.display | |
| 2711 ? 'block' | |
| 2712 : 'none'; | |
| 2713 }); | |
| 2714 | |
| 2715 var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toStr
ing())); | |
| 2716 el.appendChild(pre); | |
| 2717 pre.style.display = 'none'; | |
| 2718 } | |
| 2719 | |
| 2720 // Don't call .appendChild if #mocha-report was already .shift()'ed off the
stack. | |
| 2721 if (stack[0]) stack[0].appendChild(el); | |
| 2722 }); | |
| 2723 } | |
| 2724 | |
| 2725 /** | |
| 2726 * Provide suite URL | |
| 2727 * | |
| 2728 * @param {Object} [suite] | |
| 2729 */ | |
| 2730 | |
| 2731 HTML.prototype.suiteURL = function(suite){ | |
| 2732 return '?grep=' + encodeURIComponent(suite.fullTitle()); | |
| 2733 }; | |
| 2734 | |
| 2735 /** | |
| 2736 * Provide test URL | |
| 2737 * | |
| 2738 * @param {Object} [test] | |
| 2739 */ | |
| 2740 | |
| 2741 HTML.prototype.testURL = function(test){ | |
| 2742 return '?grep=' + encodeURIComponent(test.fullTitle()); | |
| 2743 }; | |
| 2744 | |
| 2745 /** | |
| 2746 * Display error `msg`. | |
| 2747 */ | |
| 2748 | |
| 2749 function error(msg) { | |
| 2750 document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg)); | |
| 2751 } | |
| 2752 | |
| 2753 /** | |
| 2754 * Return a DOM fragment from `html`. | |
| 2755 */ | |
| 2756 | |
| 2757 function fragment(html) { | |
| 2758 var args = arguments | |
| 2759 , div = document.createElement('div') | |
| 2760 , i = 1; | |
| 2761 | |
| 2762 div.innerHTML = html.replace(/%([se])/g, function(_, type){ | |
| 2763 switch (type) { | |
| 2764 case 's': return String(args[i++]); | |
| 2765 case 'e': return escape(args[i++]); | |
| 2766 } | |
| 2767 }); | |
| 2768 | |
| 2769 return div.firstChild; | |
| 2770 } | |
| 2771 | |
| 2772 /** | |
| 2773 * Check for suites that do not have elements | |
| 2774 * with `classname`, and hide them. | |
| 2775 */ | |
| 2776 | |
| 2777 function hideSuitesWithout(classname) { | |
| 2778 var suites = document.getElementsByClassName('suite'); | |
| 2779 for (var i = 0; i < suites.length; i++) { | |
| 2780 var els = suites[i].getElementsByClassName(classname); | |
| 2781 if (0 == els.length) suites[i].className += ' hidden'; | |
| 2782 } | |
| 2783 } | |
| 2784 | |
| 2785 /** | |
| 2786 * Unhide .hidden suites. | |
| 2787 */ | |
| 2788 | |
| 2789 function unhide() { | |
| 2790 var els = document.getElementsByClassName('suite hidden'); | |
| 2791 for (var i = 0; i < els.length; ++i) { | |
| 2792 els[i].className = els[i].className.replace('suite hidden', 'suite'); | |
| 2793 } | |
| 2794 } | |
| 2795 | |
| 2796 /** | |
| 2797 * Set `el` text to `str`. | |
| 2798 */ | |
| 2799 | |
| 2800 function text(el, str) { | |
| 2801 if (el.textContent) { | |
| 2802 el.textContent = str; | |
| 2803 } else { | |
| 2804 el.innerText = str; | |
| 2805 } | |
| 2806 } | |
| 2807 | |
| 2808 /** | |
| 2809 * Listen on `event` with callback `fn`. | |
| 2810 */ | |
| 2811 | |
| 2812 function on(el, event, fn) { | |
| 2813 if (el.addEventListener) { | |
| 2814 el.addEventListener(event, fn, false); | |
| 2815 } else { | |
| 2816 el.attachEvent('on' + event, fn); | |
| 2817 } | |
| 2818 } | |
| 2819 | |
| 2820 }); // module: reporters/html.js | |
| 2821 | |
| 2822 require.register("reporters/index.js", function(module, exports, require){ | |
| 2823 | |
| 2824 exports.Base = require('./base'); | |
| 2825 exports.Dot = require('./dot'); | |
| 2826 exports.Doc = require('./doc'); | |
| 2827 exports.TAP = require('./tap'); | |
| 2828 exports.JSON = require('./json'); | |
| 2829 exports.HTML = require('./html'); | |
| 2830 exports.List = require('./list'); | |
| 2831 exports.Min = require('./min'); | |
| 2832 exports.Spec = require('./spec'); | |
| 2833 exports.Nyan = require('./nyan'); | |
| 2834 exports.XUnit = require('./xunit'); | |
| 2835 exports.Markdown = require('./markdown'); | |
| 2836 exports.Progress = require('./progress'); | |
| 2837 exports.Landing = require('./landing'); | |
| 2838 exports.JSONCov = require('./json-cov'); | |
| 2839 exports.HTMLCov = require('./html-cov'); | |
| 2840 exports.JSONStream = require('./json-stream'); | |
| 2841 | |
| 2842 }); // module: reporters/index.js | |
| 2843 | |
| 2844 require.register("reporters/json-cov.js", function(module, exports, require){ | |
| 2845 | |
| 2846 /** | |
| 2847 * Module dependencies. | |
| 2848 */ | |
| 2849 | |
| 2850 var Base = require('./base'); | |
| 2851 | |
| 2852 /** | |
| 2853 * Expose `JSONCov`. | |
| 2854 */ | |
| 2855 | |
| 2856 exports = module.exports = JSONCov; | |
| 2857 | |
| 2858 /** | |
| 2859 * Initialize a new `JsCoverage` reporter. | |
| 2860 * | |
| 2861 * @param {Runner} runner | |
| 2862 * @param {Boolean} output | |
| 2863 * @api public | |
| 2864 */ | |
| 2865 | |
| 2866 function JSONCov(runner, output) { | |
| 2867 var self = this | |
| 2868 , output = 1 == arguments.length ? true : output; | |
| 2869 | |
| 2870 Base.call(this, runner); | |
| 2871 | |
| 2872 var tests = [] | |
| 2873 , failures = [] | |
| 2874 , passes = []; | |
| 2875 | |
| 2876 runner.on('test end', function(test){ | |
| 2877 tests.push(test); | |
| 2878 }); | |
| 2879 | |
| 2880 runner.on('pass', function(test){ | |
| 2881 passes.push(test); | |
| 2882 }); | |
| 2883 | |
| 2884 runner.on('fail', function(test){ | |
| 2885 failures.push(test); | |
| 2886 }); | |
| 2887 | |
| 2888 runner.on('end', function(){ | |
| 2889 var cov = global._$jscoverage || {}; | |
| 2890 var result = self.cov = map(cov); | |
| 2891 result.stats = self.stats; | |
| 2892 result.tests = tests.map(clean); | |
| 2893 result.failures = failures.map(clean); | |
| 2894 result.passes = passes.map(clean); | |
| 2895 if (!output) return; | |
| 2896 process.stdout.write(JSON.stringify(result, null, 2 )); | |
| 2897 }); | |
| 2898 } | |
| 2899 | |
| 2900 /** | |
| 2901 * Map jscoverage data to a JSON structure | |
| 2902 * suitable for reporting. | |
| 2903 * | |
| 2904 * @param {Object} cov | |
| 2905 * @return {Object} | |
| 2906 * @api private | |
| 2907 */ | |
| 2908 | |
| 2909 function map(cov) { | |
| 2910 var ret = { | |
| 2911 instrumentation: 'node-jscoverage' | |
| 2912 , sloc: 0 | |
| 2913 , hits: 0 | |
| 2914 , misses: 0 | |
| 2915 , coverage: 0 | |
| 2916 , files: [] | |
| 2917 }; | |
| 2918 | |
| 2919 for (var filename in cov) { | |
| 2920 var data = coverage(filename, cov[filename]); | |
| 2921 ret.files.push(data); | |
| 2922 ret.hits += data.hits; | |
| 2923 ret.misses += data.misses; | |
| 2924 ret.sloc += data.sloc; | |
| 2925 } | |
| 2926 | |
| 2927 ret.files.sort(function(a, b) { | |
| 2928 return a.filename.localeCompare(b.filename); | |
| 2929 }); | |
| 2930 | |
| 2931 if (ret.sloc > 0) { | |
| 2932 ret.coverage = (ret.hits / ret.sloc) * 100; | |
| 2933 } | |
| 2934 | |
| 2935 return ret; | |
| 2936 }; | |
| 2937 | |
| 2938 /** | |
| 2939 * Map jscoverage data for a single source file | |
| 2940 * to a JSON structure suitable for reporting. | |
| 2941 * | |
| 2942 * @param {String} filename name of the source file | |
| 2943 * @param {Object} data jscoverage coverage data | |
| 2944 * @return {Object} | |
| 2945 * @api private | |
| 2946 */ | |
| 2947 | |
| 2948 function coverage(filename, data) { | |
| 2949 var ret = { | |
| 2950 filename: filename, | |
| 2951 coverage: 0, | |
| 2952 hits: 0, | |
| 2953 misses: 0, | |
| 2954 sloc: 0, | |
| 2955 source: {} | |
| 2956 }; | |
| 2957 | |
| 2958 data.source.forEach(function(line, num){ | |
| 2959 num++; | |
| 2960 | |
| 2961 if (data[num] === 0) { | |
| 2962 ret.misses++; | |
| 2963 ret.sloc++; | |
| 2964 } else if (data[num] !== undefined) { | |
| 2965 ret.hits++; | |
| 2966 ret.sloc++; | |
| 2967 } | |
| 2968 | |
| 2969 ret.source[num] = { | |
| 2970 source: line | |
| 2971 , coverage: data[num] === undefined | |
| 2972 ? '' | |
| 2973 : data[num] | |
| 2974 }; | |
| 2975 }); | |
| 2976 | |
| 2977 ret.coverage = ret.hits / ret.sloc * 100; | |
| 2978 | |
| 2979 return ret; | |
| 2980 } | |
| 2981 | |
| 2982 /** | |
| 2983 * Return a plain-object representation of `test` | |
| 2984 * free of cyclic properties etc. | |
| 2985 * | |
| 2986 * @param {Object} test | |
| 2987 * @return {Object} | |
| 2988 * @api private | |
| 2989 */ | |
| 2990 | |
| 2991 function clean(test) { | |
| 2992 return { | |
| 2993 title: test.title | |
| 2994 , fullTitle: test.fullTitle() | |
| 2995 , duration: test.duration | |
| 2996 } | |
| 2997 } | |
| 2998 | |
| 2999 }); // module: reporters/json-cov.js | |
| 3000 | |
| 3001 require.register("reporters/json-stream.js", function(module, exports, require){ | |
| 3002 | |
| 3003 /** | |
| 3004 * Module dependencies. | |
| 3005 */ | |
| 3006 | |
| 3007 var Base = require('./base') | |
| 3008 , color = Base.color; | |
| 3009 | |
| 3010 /** | |
| 3011 * Expose `List`. | |
| 3012 */ | |
| 3013 | |
| 3014 exports = module.exports = List; | |
| 3015 | |
| 3016 /** | |
| 3017 * Initialize a new `List` test reporter. | |
| 3018 * | |
| 3019 * @param {Runner} runner | |
| 3020 * @api public | |
| 3021 */ | |
| 3022 | |
| 3023 function List(runner) { | |
| 3024 Base.call(this, runner); | |
| 3025 | |
| 3026 var self = this | |
| 3027 , stats = this.stats | |
| 3028 , total = runner.total; | |
| 3029 | |
| 3030 runner.on('start', function(){ | |
| 3031 console.log(JSON.stringify(['start', { total: total }])); | |
| 3032 }); | |
| 3033 | |
| 3034 runner.on('pass', function(test){ | |
| 3035 console.log(JSON.stringify(['pass', clean(test)])); | |
| 3036 }); | |
| 3037 | |
| 3038 runner.on('fail', function(test, err){ | |
| 3039 console.log(JSON.stringify(['fail', clean(test)])); | |
| 3040 }); | |
| 3041 | |
| 3042 runner.on('end', function(){ | |
| 3043 process.stdout.write(JSON.stringify(['end', self.stats])); | |
| 3044 }); | |
| 3045 } | |
| 3046 | |
| 3047 /** | |
| 3048 * Return a plain-object representation of `test` | |
| 3049 * free of cyclic properties etc. | |
| 3050 * | |
| 3051 * @param {Object} test | |
| 3052 * @return {Object} | |
| 3053 * @api private | |
| 3054 */ | |
| 3055 | |
| 3056 function clean(test) { | |
| 3057 return { | |
| 3058 title: test.title | |
| 3059 , fullTitle: test.fullTitle() | |
| 3060 , duration: test.duration | |
| 3061 } | |
| 3062 } | |
| 3063 }); // module: reporters/json-stream.js | |
| 3064 | |
| 3065 require.register("reporters/json.js", function(module, exports, require){ | |
| 3066 | |
| 3067 /** | |
| 3068 * Module dependencies. | |
| 3069 */ | |
| 3070 | |
| 3071 var Base = require('./base') | |
| 3072 , cursor = Base.cursor | |
| 3073 , color = Base.color; | |
| 3074 | |
| 3075 /** | |
| 3076 * Expose `JSON`. | |
| 3077 */ | |
| 3078 | |
| 3079 exports = module.exports = JSONReporter; | |
| 3080 | |
| 3081 /** | |
| 3082 * Initialize a new `JSON` reporter. | |
| 3083 * | |
| 3084 * @param {Runner} runner | |
| 3085 * @api public | |
| 3086 */ | |
| 3087 | |
| 3088 function JSONReporter(runner) { | |
| 3089 var self = this; | |
| 3090 Base.call(this, runner); | |
| 3091 | |
| 3092 var tests = [] | |
| 3093 , failures = [] | |
| 3094 , passes = []; | |
| 3095 | |
| 3096 runner.on('test end', function(test){ | |
| 3097 tests.push(test); | |
| 3098 }); | |
| 3099 | |
| 3100 runner.on('pass', function(test){ | |
| 3101 passes.push(test); | |
| 3102 }); | |
| 3103 | |
| 3104 runner.on('fail', function(test){ | |
| 3105 failures.push(test); | |
| 3106 }); | |
| 3107 | |
| 3108 runner.on('end', function(){ | |
| 3109 var obj = { | |
| 3110 stats: self.stats | |
| 3111 , tests: tests.map(clean) | |
| 3112 , failures: failures.map(clean) | |
| 3113 , passes: passes.map(clean) | |
| 3114 }; | |
| 3115 | |
| 3116 process.stdout.write(JSON.stringify(obj, null, 2)); | |
| 3117 }); | |
| 3118 } | |
| 3119 | |
| 3120 /** | |
| 3121 * Return a plain-object representation of `test` | |
| 3122 * free of cyclic properties etc. | |
| 3123 * | |
| 3124 * @param {Object} test | |
| 3125 * @return {Object} | |
| 3126 * @api private | |
| 3127 */ | |
| 3128 | |
| 3129 function clean(test) { | |
| 3130 return { | |
| 3131 title: test.title | |
| 3132 , fullTitle: test.fullTitle() | |
| 3133 , duration: test.duration | |
| 3134 } | |
| 3135 } | |
| 3136 }); // module: reporters/json.js | |
| 3137 | |
| 3138 require.register("reporters/landing.js", function(module, exports, require){ | |
| 3139 | |
| 3140 /** | |
| 3141 * Module dependencies. | |
| 3142 */ | |
| 3143 | |
| 3144 var Base = require('./base') | |
| 3145 , cursor = Base.cursor | |
| 3146 , color = Base.color; | |
| 3147 | |
| 3148 /** | |
| 3149 * Expose `Landing`. | |
| 3150 */ | |
| 3151 | |
| 3152 exports = module.exports = Landing; | |
| 3153 | |
| 3154 /** | |
| 3155 * Airplane color. | |
| 3156 */ | |
| 3157 | |
| 3158 Base.colors.plane = 0; | |
| 3159 | |
| 3160 /** | |
| 3161 * Airplane crash color. | |
| 3162 */ | |
| 3163 | |
| 3164 Base.colors['plane crash'] = 31; | |
| 3165 | |
| 3166 /** | |
| 3167 * Runway color. | |
| 3168 */ | |
| 3169 | |
| 3170 Base.colors.runway = 90; | |
| 3171 | |
| 3172 /** | |
| 3173 * Initialize a new `Landing` reporter. | |
| 3174 * | |
| 3175 * @param {Runner} runner | |
| 3176 * @api public | |
| 3177 */ | |
| 3178 | |
| 3179 function Landing(runner) { | |
| 3180 Base.call(this, runner); | |
| 3181 | |
| 3182 var self = this | |
| 3183 , stats = this.stats | |
| 3184 , width = Base.window.width * .75 | 0 | |
| 3185 , total = runner.total | |
| 3186 , stream = process.stdout | |
| 3187 , plane = color('plane', '✈') | |
| 3188 , crashed = -1 | |
| 3189 , n = 0; | |
| 3190 | |
| 3191 function runway() { | |
| 3192 var buf = Array(width).join('-'); | |
| 3193 return ' ' + color('runway', buf); | |
| 3194 } | |
| 3195 | |
| 3196 runner.on('start', function(){ | |
| 3197 stream.write('\n '); | |
| 3198 cursor.hide(); | |
| 3199 }); | |
| 3200 | |
| 3201 runner.on('test end', function(test){ | |
| 3202 // check if the plane crashed | |
| 3203 var col = -1 == crashed | |
| 3204 ? width * ++n / total | 0 | |
| 3205 : crashed; | |
| 3206 | |
| 3207 // show the crash | |
| 3208 if ('failed' == test.state) { | |
| 3209 plane = color('plane crash', '✈'); | |
| 3210 crashed = col; | |
| 3211 } | |
| 3212 | |
| 3213 // render landing strip | |
| 3214 stream.write('\u001b[4F\n\n'); | |
| 3215 stream.write(runway()); | |
| 3216 stream.write('\n '); | |
| 3217 stream.write(color('runway', Array(col).join('â‹…'))); | |
| 3218 stream.write(plane) | |
| 3219 stream.write(color('runway', Array(width - col).join('â‹…') + '\n')); | |
| 3220 stream.write(runway()); | |
| 3221 stream.write('\u001b[0m'); | |
| 3222 }); | |
| 3223 | |
| 3224 runner.on('end', function(){ | |
| 3225 cursor.show(); | |
| 3226 console.log(); | |
| 3227 self.epilogue(); | |
| 3228 }); | |
| 3229 } | |
| 3230 | |
| 3231 /** | |
| 3232 * Inherit from `Base.prototype`. | |
| 3233 */ | |
| 3234 | |
| 3235 function F(){}; | |
| 3236 F.prototype = Base.prototype; | |
| 3237 Landing.prototype = new F; | |
| 3238 Landing.prototype.constructor = Landing; | |
| 3239 | |
| 3240 }); // module: reporters/landing.js | |
| 3241 | |
| 3242 require.register("reporters/list.js", function(module, exports, require){ | |
| 3243 | |
| 3244 /** | |
| 3245 * Module dependencies. | |
| 3246 */ | |
| 3247 | |
| 3248 var Base = require('./base') | |
| 3249 , cursor = Base.cursor | |
| 3250 , color = Base.color; | |
| 3251 | |
| 3252 /** | |
| 3253 * Expose `List`. | |
| 3254 */ | |
| 3255 | |
| 3256 exports = module.exports = List; | |
| 3257 | |
| 3258 /** | |
| 3259 * Initialize a new `List` test reporter. | |
| 3260 * | |
| 3261 * @param {Runner} runner | |
| 3262 * @api public | |
| 3263 */ | |
| 3264 | |
| 3265 function List(runner) { | |
| 3266 Base.call(this, runner); | |
| 3267 | |
| 3268 var self = this | |
| 3269 , stats = this.stats | |
| 3270 , n = 0; | |
| 3271 | |
| 3272 runner.on('start', function(){ | |
| 3273 console.log(); | |
| 3274 }); | |
| 3275 | |
| 3276 runner.on('test', function(test){ | |
| 3277 process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); | |
| 3278 }); | |
| 3279 | |
| 3280 runner.on('pending', function(test){ | |
| 3281 var fmt = color('checkmark', ' -') | |
| 3282 + color('pending', ' %s'); | |
| 3283 console.log(fmt, test.fullTitle()); | |
| 3284 }); | |
| 3285 | |
| 3286 runner.on('pass', function(test){ | |
| 3287 var fmt = color('checkmark', ' '+Base.symbols.dot) | |
| 3288 + color('pass', ' %s: ') | |
| 3289 + color(test.speed, '%dms'); | |
| 3290 cursor.CR(); | |
| 3291 console.log(fmt, test.fullTitle(), test.duration); | |
| 3292 }); | |
| 3293 | |
| 3294 runner.on('fail', function(test, err){ | |
| 3295 cursor.CR(); | |
| 3296 console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); | |
| 3297 }); | |
| 3298 | |
| 3299 runner.on('end', self.epilogue.bind(self)); | |
| 3300 } | |
| 3301 | |
| 3302 /** | |
| 3303 * Inherit from `Base.prototype`. | |
| 3304 */ | |
| 3305 | |
| 3306 function F(){}; | |
| 3307 F.prototype = Base.prototype; | |
| 3308 List.prototype = new F; | |
| 3309 List.prototype.constructor = List; | |
| 3310 | |
| 3311 | |
| 3312 }); // module: reporters/list.js | |
| 3313 | |
| 3314 require.register("reporters/markdown.js", function(module, exports, require){ | |
| 3315 /** | |
| 3316 * Module dependencies. | |
| 3317 */ | |
| 3318 | |
| 3319 var Base = require('./base') | |
| 3320 , utils = require('../utils'); | |
| 3321 | |
| 3322 /** | |
| 3323 * Expose `Markdown`. | |
| 3324 */ | |
| 3325 | |
| 3326 exports = module.exports = Markdown; | |
| 3327 | |
| 3328 /** | |
| 3329 * Initialize a new `Markdown` reporter. | |
| 3330 * | |
| 3331 * @param {Runner} runner | |
| 3332 * @api public | |
| 3333 */ | |
| 3334 | |
| 3335 function Markdown(runner) { | |
| 3336 Base.call(this, runner); | |
| 3337 | |
| 3338 var self = this | |
| 3339 , stats = this.stats | |
| 3340 , level = 0 | |
| 3341 , buf = ''; | |
| 3342 | |
| 3343 function title(str) { | |
| 3344 return Array(level).join('#') + ' ' + str; | |
| 3345 } | |
| 3346 | |
| 3347 function indent() { | |
| 3348 return Array(level).join(' '); | |
| 3349 } | |
| 3350 | |
| 3351 function mapTOC(suite, obj) { | |
| 3352 var ret = obj; | |
| 3353 obj = obj[suite.title] = obj[suite.title] || { suite: suite }; | |
| 3354 suite.suites.forEach(function(suite){ | |
| 3355 mapTOC(suite, obj); | |
| 3356 }); | |
| 3357 return ret; | |
| 3358 } | |
| 3359 | |
| 3360 function stringifyTOC(obj, level) { | |
| 3361 ++level; | |
| 3362 var buf = ''; | |
| 3363 var link; | |
| 3364 for (var key in obj) { | |
| 3365 if ('suite' == key) continue; | |
| 3366 if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle
()) + ')\n'; | |
| 3367 if (key) buf += Array(level).join(' ') + link; | |
| 3368 buf += stringifyTOC(obj[key], level); | |
| 3369 } | |
| 3370 --level; | |
| 3371 return buf; | |
| 3372 } | |
| 3373 | |
| 3374 function generateTOC(suite) { | |
| 3375 var obj = mapTOC(suite, {}); | |
| 3376 return stringifyTOC(obj, 0); | |
| 3377 } | |
| 3378 | |
| 3379 generateTOC(runner.suite); | |
| 3380 | |
| 3381 runner.on('suite', function(suite){ | |
| 3382 ++level; | |
| 3383 var slug = utils.slug(suite.fullTitle()); | |
| 3384 buf += '<a name="' + slug + '"></a>' + '\n'; | |
| 3385 buf += title(suite.title) + '\n'; | |
| 3386 }); | |
| 3387 | |
| 3388 runner.on('suite end', function(suite){ | |
| 3389 --level; | |
| 3390 }); | |
| 3391 | |
| 3392 runner.on('pass', function(test){ | |
| 3393 var code = utils.clean(test.fn.toString()); | |
| 3394 buf += test.title + '.\n'; | |
| 3395 buf += '\n```js\n'; | |
| 3396 buf += code + '\n'; | |
| 3397 buf += '```\n\n'; | |
| 3398 }); | |
| 3399 | |
| 3400 runner.on('end', function(){ | |
| 3401 process.stdout.write('# TOC\n'); | |
| 3402 process.stdout.write(generateTOC(runner.suite)); | |
| 3403 process.stdout.write(buf); | |
| 3404 }); | |
| 3405 } | |
| 3406 }); // module: reporters/markdown.js | |
| 3407 | |
| 3408 require.register("reporters/min.js", function(module, exports, require){ | |
| 3409 | |
| 3410 /** | |
| 3411 * Module dependencies. | |
| 3412 */ | |
| 3413 | |
| 3414 var Base = require('./base'); | |
| 3415 | |
| 3416 /** | |
| 3417 * Expose `Min`. | |
| 3418 */ | |
| 3419 | |
| 3420 exports = module.exports = Min; | |
| 3421 | |
| 3422 /** | |
| 3423 * Initialize a new `Min` minimal test reporter (best used with --watch). | |
| 3424 * | |
| 3425 * @param {Runner} runner | |
| 3426 * @api public | |
| 3427 */ | |
| 3428 | |
| 3429 function Min(runner) { | |
| 3430 Base.call(this, runner); | |
| 3431 | |
| 3432 runner.on('start', function(){ | |
| 3433 // clear screen | |
| 3434 process.stdout.write('\u001b[2J'); | |
| 3435 // set cursor position | |
| 3436 process.stdout.write('\u001b[1;3H'); | |
| 3437 }); | |
| 3438 | |
| 3439 runner.on('end', this.epilogue.bind(this)); | |
| 3440 } | |
| 3441 | |
| 3442 /** | |
| 3443 * Inherit from `Base.prototype`. | |
| 3444 */ | |
| 3445 | |
| 3446 function F(){}; | |
| 3447 F.prototype = Base.prototype; | |
| 3448 Min.prototype = new F; | |
| 3449 Min.prototype.constructor = Min; | |
| 3450 | |
| 3451 | |
| 3452 }); // module: reporters/min.js | |
| 3453 | |
| 3454 require.register("reporters/nyan.js", function(module, exports, require){ | |
| 3455 /** | |
| 3456 * Module dependencies. | |
| 3457 */ | |
| 3458 | |
| 3459 var Base = require('./base') | |
| 3460 , color = Base.color; | |
| 3461 | |
| 3462 /** | |
| 3463 * Expose `Dot`. | |
| 3464 */ | |
| 3465 | |
| 3466 exports = module.exports = NyanCat; | |
| 3467 | |
| 3468 /** | |
| 3469 * Initialize a new `Dot` matrix test reporter. | |
| 3470 * | |
| 3471 * @param {Runner} runner | |
| 3472 * @api public | |
| 3473 */ | |
| 3474 | |
| 3475 function NyanCat(runner) { | |
| 3476 Base.call(this, runner); | |
| 3477 var self = this | |
| 3478 , stats = this.stats | |
| 3479 , width = Base.window.width * .75 | 0 | |
| 3480 , rainbowColors = this.rainbowColors = self.generateColors() | |
| 3481 , colorIndex = this.colorIndex = 0 | |
| 3482 , numerOfLines = this.numberOfLines = 4 | |
| 3483 , trajectories = this.trajectories = [[], [], [], []] | |
| 3484 , nyanCatWidth = this.nyanCatWidth = 11 | |
| 3485 , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) | |
| 3486 , scoreboardWidth = this.scoreboardWidth = 5 | |
| 3487 , tick = this.tick = 0 | |
| 3488 , n = 0; | |
| 3489 | |
| 3490 runner.on('start', function(){ | |
| 3491 Base.cursor.hide(); | |
| 3492 self.draw(); | |
| 3493 }); | |
| 3494 | |
| 3495 runner.on('pending', function(test){ | |
| 3496 self.draw(); | |
| 3497 }); | |
| 3498 | |
| 3499 runner.on('pass', function(test){ | |
| 3500 self.draw(); | |
| 3501 }); | |
| 3502 | |
| 3503 runner.on('fail', function(test, err){ | |
| 3504 self.draw(); | |
| 3505 }); | |
| 3506 | |
| 3507 runner.on('end', function(){ | |
| 3508 Base.cursor.show(); | |
| 3509 for (var i = 0; i < self.numberOfLines; i++) write('\n'); | |
| 3510 self.epilogue(); | |
| 3511 }); | |
| 3512 } | |
| 3513 | |
| 3514 /** | |
| 3515 * Draw the nyan cat | |
| 3516 * | |
| 3517 * @api private | |
| 3518 */ | |
| 3519 | |
| 3520 NyanCat.prototype.draw = function(){ | |
| 3521 this.appendRainbow(); | |
| 3522 this.drawScoreboard(); | |
| 3523 this.drawRainbow(); | |
| 3524 this.drawNyanCat(); | |
| 3525 this.tick = !this.tick; | |
| 3526 }; | |
| 3527 | |
| 3528 /** | |
| 3529 * Draw the "scoreboard" showing the number | |
| 3530 * of passes, failures and pending tests. | |
| 3531 * | |
| 3532 * @api private | |
| 3533 */ | |
| 3534 | |
| 3535 NyanCat.prototype.drawScoreboard = function(){ | |
| 3536 var stats = this.stats; | |
| 3537 var colors = Base.colors; | |
| 3538 | |
| 3539 function draw(color, n) { | |
| 3540 write(' '); | |
| 3541 write('\u001b[' + color + 'm' + n + '\u001b[0m'); | |
| 3542 write('\n'); | |
| 3543 } | |
| 3544 | |
| 3545 draw(colors.green, stats.passes); | |
| 3546 draw(colors.fail, stats.failures); | |
| 3547 draw(colors.pending, stats.pending); | |
| 3548 write('\n'); | |
| 3549 | |
| 3550 this.cursorUp(this.numberOfLines); | |
| 3551 }; | |
| 3552 | |
| 3553 /** | |
| 3554 * Append the rainbow. | |
| 3555 * | |
| 3556 * @api private | |
| 3557 */ | |
| 3558 | |
| 3559 NyanCat.prototype.appendRainbow = function(){ | |
| 3560 var segment = this.tick ? '_' : '-'; | |
| 3561 var rainbowified = this.rainbowify(segment); | |
| 3562 | |
| 3563 for (var index = 0; index < this.numberOfLines; index++) { | |
| 3564 var trajectory = this.trajectories[index]; | |
| 3565 if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); | |
| 3566 trajectory.push(rainbowified); | |
| 3567 } | |
| 3568 }; | |
| 3569 | |
| 3570 /** | |
| 3571 * Draw the rainbow. | |
| 3572 * | |
| 3573 * @api private | |
| 3574 */ | |
| 3575 | |
| 3576 NyanCat.prototype.drawRainbow = function(){ | |
| 3577 var self = this; | |
| 3578 | |
| 3579 this.trajectories.forEach(function(line, index) { | |
| 3580 write('\u001b[' + self.scoreboardWidth + 'C'); | |
| 3581 write(line.join('')); | |
| 3582 write('\n'); | |
| 3583 }); | |
| 3584 | |
| 3585 this.cursorUp(this.numberOfLines); | |
| 3586 }; | |
| 3587 | |
| 3588 /** | |
| 3589 * Draw the nyan cat | |
| 3590 * | |
| 3591 * @api private | |
| 3592 */ | |
| 3593 | |
| 3594 NyanCat.prototype.drawNyanCat = function() { | |
| 3595 var self = this; | |
| 3596 var startWidth = this.scoreboardWidth + this.trajectories[0].length; | |
| 3597 var color = '\u001b[' + startWidth + 'C'; | |
| 3598 var padding = ''; | |
| 3599 | |
| 3600 write(color); | |
| 3601 write('_,------,'); | |
| 3602 write('\n'); | |
| 3603 | |
| 3604 write(color); | |
| 3605 padding = self.tick ? ' ' : ' '; | |
| 3606 write('_|' + padding + '/\\_/\\ '); | |
| 3607 write('\n'); | |
| 3608 | |
| 3609 write(color); | |
| 3610 padding = self.tick ? '_' : '__'; | |
| 3611 var tail = self.tick ? '~' : '^'; | |
| 3612 var face; | |
| 3613 write(tail + '|' + padding + this.face() + ' '); | |
| 3614 write('\n'); | |
| 3615 | |
| 3616 write(color); | |
| 3617 padding = self.tick ? ' ' : ' '; | |
| 3618 write(padding + '"" "" '); | |
| 3619 write('\n'); | |
| 3620 | |
| 3621 this.cursorUp(this.numberOfLines); | |
| 3622 }; | |
| 3623 | |
| 3624 /** | |
| 3625 * Draw nyan cat face. | |
| 3626 * | |
| 3627 * @return {String} | |
| 3628 * @api private | |
| 3629 */ | |
| 3630 | |
| 3631 NyanCat.prototype.face = function() { | |
| 3632 var stats = this.stats; | |
| 3633 if (stats.failures) { | |
| 3634 return '( x .x)'; | |
| 3635 } else if (stats.pending) { | |
| 3636 return '( o .o)'; | |
| 3637 } else if(stats.passes) { | |
| 3638 return '( ^ .^)'; | |
| 3639 } else { | |
| 3640 return '( - .-)'; | |
| 3641 } | |
| 3642 } | |
| 3643 | |
| 3644 /** | |
| 3645 * Move cursor up `n`. | |
| 3646 * | |
| 3647 * @param {Number} n | |
| 3648 * @api private | |
| 3649 */ | |
| 3650 | |
| 3651 NyanCat.prototype.cursorUp = function(n) { | |
| 3652 write('\u001b[' + n + 'A'); | |
| 3653 }; | |
| 3654 | |
| 3655 /** | |
| 3656 * Move cursor down `n`. | |
| 3657 * | |
| 3658 * @param {Number} n | |
| 3659 * @api private | |
| 3660 */ | |
| 3661 | |
| 3662 NyanCat.prototype.cursorDown = function(n) { | |
| 3663 write('\u001b[' + n + 'B'); | |
| 3664 }; | |
| 3665 | |
| 3666 /** | |
| 3667 * Generate rainbow colors. | |
| 3668 * | |
| 3669 * @return {Array} | |
| 3670 * @api private | |
| 3671 */ | |
| 3672 | |
| 3673 NyanCat.prototype.generateColors = function(){ | |
| 3674 var colors = []; | |
| 3675 | |
| 3676 for (var i = 0; i < (6 * 7); i++) { | |
| 3677 var pi3 = Math.floor(Math.PI / 3); | |
| 3678 var n = (i * (1.0 / 6)); | |
| 3679 var r = Math.floor(3 * Math.sin(n) + 3); | |
| 3680 var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); | |
| 3681 var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); | |
| 3682 colors.push(36 * r + 6 * g + b + 16); | |
| 3683 } | |
| 3684 | |
| 3685 return colors; | |
| 3686 }; | |
| 3687 | |
| 3688 /** | |
| 3689 * Apply rainbow to the given `str`. | |
| 3690 * | |
| 3691 * @param {String} str | |
| 3692 * @return {String} | |
| 3693 * @api private | |
| 3694 */ | |
| 3695 | |
| 3696 NyanCat.prototype.rainbowify = function(str){ | |
| 3697 var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; | |
| 3698 this.colorIndex += 1; | |
| 3699 return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; | |
| 3700 }; | |
| 3701 | |
| 3702 /** | |
| 3703 * Stdout helper. | |
| 3704 */ | |
| 3705 | |
| 3706 function write(string) { | |
| 3707 process.stdout.write(string); | |
| 3708 } | |
| 3709 | |
| 3710 /** | |
| 3711 * Inherit from `Base.prototype`. | |
| 3712 */ | |
| 3713 | |
| 3714 function F(){}; | |
| 3715 F.prototype = Base.prototype; | |
| 3716 NyanCat.prototype = new F; | |
| 3717 NyanCat.prototype.constructor = NyanCat; | |
| 3718 | |
| 3719 | |
| 3720 }); // module: reporters/nyan.js | |
| 3721 | |
| 3722 require.register("reporters/progress.js", function(module, exports, require){ | |
| 3723 | |
| 3724 /** | |
| 3725 * Module dependencies. | |
| 3726 */ | |
| 3727 | |
| 3728 var Base = require('./base') | |
| 3729 , cursor = Base.cursor | |
| 3730 , color = Base.color; | |
| 3731 | |
| 3732 /** | |
| 3733 * Expose `Progress`. | |
| 3734 */ | |
| 3735 | |
| 3736 exports = module.exports = Progress; | |
| 3737 | |
| 3738 /** | |
| 3739 * General progress bar color. | |
| 3740 */ | |
| 3741 | |
| 3742 Base.colors.progress = 90; | |
| 3743 | |
| 3744 /** | |
| 3745 * Initialize a new `Progress` bar test reporter. | |
| 3746 * | |
| 3747 * @param {Runner} runner | |
| 3748 * @param {Object} options | |
| 3749 * @api public | |
| 3750 */ | |
| 3751 | |
| 3752 function Progress(runner, options) { | |
| 3753 Base.call(this, runner); | |
| 3754 | |
| 3755 var self = this | |
| 3756 , options = options || {} | |
| 3757 , stats = this.stats | |
| 3758 , width = Base.window.width * .50 | 0 | |
| 3759 , total = runner.total | |
| 3760 , complete = 0 | |
| 3761 , max = Math.max; | |
| 3762 | |
| 3763 // default chars | |
| 3764 options.open = options.open || '['; | |
| 3765 options.complete = options.complete || 'â–¬'; | |
| 3766 options.incomplete = options.incomplete || Base.symbols.dot; | |
| 3767 options.close = options.close || ']'; | |
| 3768 options.verbose = false; | |
| 3769 | |
| 3770 // tests started | |
| 3771 runner.on('start', function(){ | |
| 3772 console.log(); | |
| 3773 cursor.hide(); | |
| 3774 }); | |
| 3775 | |
| 3776 // tests complete | |
| 3777 runner.on('test end', function(){ | |
| 3778 complete++; | |
| 3779 var incomplete = total - complete | |
| 3780 , percent = complete / total | |
| 3781 , n = width * percent | 0 | |
| 3782 , i = width - n; | |
| 3783 | |
| 3784 cursor.CR(); | |
| 3785 process.stdout.write('\u001b[J'); | |
| 3786 process.stdout.write(color('progress', ' ' + options.open)); | |
| 3787 process.stdout.write(Array(n).join(options.complete)); | |
| 3788 process.stdout.write(Array(i).join(options.incomplete)); | |
| 3789 process.stdout.write(color('progress', options.close)); | |
| 3790 if (options.verbose) { | |
| 3791 process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); | |
| 3792 } | |
| 3793 }); | |
| 3794 | |
| 3795 // tests are complete, output some stats | |
| 3796 // and the failures if any | |
| 3797 runner.on('end', function(){ | |
| 3798 cursor.show(); | |
| 3799 console.log(); | |
| 3800 self.epilogue(); | |
| 3801 }); | |
| 3802 } | |
| 3803 | |
| 3804 /** | |
| 3805 * Inherit from `Base.prototype`. | |
| 3806 */ | |
| 3807 | |
| 3808 function F(){}; | |
| 3809 F.prototype = Base.prototype; | |
| 3810 Progress.prototype = new F; | |
| 3811 Progress.prototype.constructor = Progress; | |
| 3812 | |
| 3813 | |
| 3814 }); // module: reporters/progress.js | |
| 3815 | |
| 3816 require.register("reporters/spec.js", function(module, exports, require){ | |
| 3817 | |
| 3818 /** | |
| 3819 * Module dependencies. | |
| 3820 */ | |
| 3821 | |
| 3822 var Base = require('./base') | |
| 3823 , cursor = Base.cursor | |
| 3824 , color = Base.color; | |
| 3825 | |
| 3826 /** | |
| 3827 * Expose `Spec`. | |
| 3828 */ | |
| 3829 | |
| 3830 exports = module.exports = Spec; | |
| 3831 | |
| 3832 /** | |
| 3833 * Initialize a new `Spec` test reporter. | |
| 3834 * | |
| 3835 * @param {Runner} runner | |
| 3836 * @api public | |
| 3837 */ | |
| 3838 | |
| 3839 function Spec(runner) { | |
| 3840 Base.call(this, runner); | |
| 3841 | |
| 3842 var self = this | |
| 3843 , stats = this.stats | |
| 3844 , indents = 0 | |
| 3845 , n = 0; | |
| 3846 | |
| 3847 function indent() { | |
| 3848 return Array(indents).join(' ') | |
| 3849 } | |
| 3850 | |
| 3851 runner.on('start', function(){ | |
| 3852 console.log(); | |
| 3853 }); | |
| 3854 | |
| 3855 runner.on('suite', function(suite){ | |
| 3856 ++indents; | |
| 3857 console.log(color('suite', '%s%s'), indent(), suite.title); | |
| 3858 }); | |
| 3859 | |
| 3860 runner.on('suite end', function(suite){ | |
| 3861 --indents; | |
| 3862 if (1 == indents) console.log(); | |
| 3863 }); | |
| 3864 | |
| 3865 runner.on('pending', function(test){ | |
| 3866 var fmt = indent() + color('pending', ' - %s'); | |
| 3867 console.log(fmt, test.title); | |
| 3868 }); | |
| 3869 | |
| 3870 runner.on('pass', function(test){ | |
| 3871 if ('fast' == test.speed) { | |
| 3872 var fmt = indent() | |
| 3873 + color('checkmark', ' ' + Base.symbols.ok) | |
| 3874 + color('pass', ' %s '); | |
| 3875 cursor.CR(); | |
| 3876 console.log(fmt, test.title); | |
| 3877 } else { | |
| 3878 var fmt = indent() | |
| 3879 + color('checkmark', ' ' + Base.symbols.ok) | |
| 3880 + color('pass', ' %s ') | |
| 3881 + color(test.speed, '(%dms)'); | |
| 3882 cursor.CR(); | |
| 3883 console.log(fmt, test.title, test.duration); | |
| 3884 } | |
| 3885 }); | |
| 3886 | |
| 3887 runner.on('fail', function(test, err){ | |
| 3888 cursor.CR(); | |
| 3889 console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); | |
| 3890 }); | |
| 3891 | |
| 3892 runner.on('end', self.epilogue.bind(self)); | |
| 3893 } | |
| 3894 | |
| 3895 /** | |
| 3896 * Inherit from `Base.prototype`. | |
| 3897 */ | |
| 3898 | |
| 3899 function F(){}; | |
| 3900 F.prototype = Base.prototype; | |
| 3901 Spec.prototype = new F; | |
| 3902 Spec.prototype.constructor = Spec; | |
| 3903 | |
| 3904 | |
| 3905 }); // module: reporters/spec.js | |
| 3906 | |
| 3907 require.register("reporters/tap.js", function(module, exports, require){ | |
| 3908 | |
| 3909 /** | |
| 3910 * Module dependencies. | |
| 3911 */ | |
| 3912 | |
| 3913 var Base = require('./base') | |
| 3914 , cursor = Base.cursor | |
| 3915 , color = Base.color; | |
| 3916 | |
| 3917 /** | |
| 3918 * Expose `TAP`. | |
| 3919 */ | |
| 3920 | |
| 3921 exports = module.exports = TAP; | |
| 3922 | |
| 3923 /** | |
| 3924 * Initialize a new `TAP` reporter. | |
| 3925 * | |
| 3926 * @param {Runner} runner | |
| 3927 * @api public | |
| 3928 */ | |
| 3929 | |
| 3930 function TAP(runner) { | |
| 3931 Base.call(this, runner); | |
| 3932 | |
| 3933 var self = this | |
| 3934 , stats = this.stats | |
| 3935 , n = 1 | |
| 3936 , passes = 0 | |
| 3937 , failures = 0; | |
| 3938 | |
| 3939 runner.on('start', function(){ | |
| 3940 var total = runner.grepTotal(runner.suite); | |
| 3941 console.log('%d..%d', 1, total); | |
| 3942 }); | |
| 3943 | |
| 3944 runner.on('test end', function(){ | |
| 3945 ++n; | |
| 3946 }); | |
| 3947 | |
| 3948 runner.on('pending', function(test){ | |
| 3949 console.log('ok %d %s # SKIP -', n, title(test)); | |
| 3950 }); | |
| 3951 | |
| 3952 runner.on('pass', function(test){ | |
| 3953 passes++; | |
| 3954 console.log('ok %d %s', n, title(test)); | |
| 3955 }); | |
| 3956 | |
| 3957 runner.on('fail', function(test, err){ | |
| 3958 failures++; | |
| 3959 console.log('not ok %d %s', n, title(test)); | |
| 3960 if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); | |
| 3961 }); | |
| 3962 | |
| 3963 runner.on('end', function(){ | |
| 3964 console.log('# tests ' + (passes + failures)); | |
| 3965 console.log('# pass ' + passes); | |
| 3966 console.log('# fail ' + failures); | |
| 3967 }); | |
| 3968 } | |
| 3969 | |
| 3970 /** | |
| 3971 * Return a TAP-safe title of `test` | |
| 3972 * | |
| 3973 * @param {Object} test | |
| 3974 * @return {String} | |
| 3975 * @api private | |
| 3976 */ | |
| 3977 | |
| 3978 function title(test) { | |
| 3979 return test.fullTitle().replace(/#/g, ''); | |
| 3980 } | |
| 3981 | |
| 3982 }); // module: reporters/tap.js | |
| 3983 | |
| 3984 require.register("reporters/xunit.js", function(module, exports, require){ | |
| 3985 | |
| 3986 /** | |
| 3987 * Module dependencies. | |
| 3988 */ | |
| 3989 | |
| 3990 var Base = require('./base') | |
| 3991 , utils = require('../utils') | |
| 3992 , escape = utils.escape; | |
| 3993 | |
| 3994 /** | |
| 3995 * Save timer references to avoid Sinon interfering (see GH-237). | |
| 3996 */ | |
| 3997 | |
| 3998 var Date = global.Date | |
| 3999 , setTimeout = global.setTimeout | |
| 4000 , setInterval = global.setInterval | |
| 4001 , clearTimeout = global.clearTimeout | |
| 4002 , clearInterval = global.clearInterval; | |
| 4003 | |
| 4004 /** | |
| 4005 * Expose `XUnit`. | |
| 4006 */ | |
| 4007 | |
| 4008 exports = module.exports = XUnit; | |
| 4009 | |
| 4010 /** | |
| 4011 * Initialize a new `XUnit` reporter. | |
| 4012 * | |
| 4013 * @param {Runner} runner | |
| 4014 * @api public | |
| 4015 */ | |
| 4016 | |
| 4017 function XUnit(runner) { | |
| 4018 Base.call(this, runner); | |
| 4019 var stats = this.stats | |
| 4020 , tests = [] | |
| 4021 , self = this; | |
| 4022 | |
| 4023 runner.on('pending', function(test){ | |
| 4024 tests.push(test); | |
| 4025 }); | |
| 4026 | |
| 4027 runner.on('pass', function(test){ | |
| 4028 tests.push(test); | |
| 4029 }); | |
| 4030 | |
| 4031 runner.on('fail', function(test){ | |
| 4032 tests.push(test); | |
| 4033 }); | |
| 4034 | |
| 4035 runner.on('end', function(){ | |
| 4036 console.log(tag('testsuite', { | |
| 4037 name: 'Mocha Tests' | |
| 4038 , tests: stats.tests | |
| 4039 , failures: stats.failures | |
| 4040 , errors: stats.failures | |
| 4041 , skipped: stats.tests - stats.failures - stats.passes | |
| 4042 , timestamp: (new Date).toUTCString() | |
| 4043 , time: (stats.duration / 1000) || 0 | |
| 4044 }, false)); | |
| 4045 | |
| 4046 tests.forEach(test); | |
| 4047 console.log('</testsuite>'); | |
| 4048 }); | |
| 4049 } | |
| 4050 | |
| 4051 /** | |
| 4052 * Inherit from `Base.prototype`. | |
| 4053 */ | |
| 4054 | |
| 4055 function F(){}; | |
| 4056 F.prototype = Base.prototype; | |
| 4057 XUnit.prototype = new F; | |
| 4058 XUnit.prototype.constructor = XUnit; | |
| 4059 | |
| 4060 | |
| 4061 /** | |
| 4062 * Output tag for the given `test.` | |
| 4063 */ | |
| 4064 | |
| 4065 function test(test) { | |
| 4066 var attrs = { | |
| 4067 classname: test.parent.fullTitle() | |
| 4068 , name: test.title | |
| 4069 , time: (test.duration / 1000) || 0 | |
| 4070 }; | |
| 4071 | |
| 4072 if ('failed' == test.state) { | |
| 4073 var err = test.err; | |
| 4074 attrs.message = escape(err.message); | |
| 4075 console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata
(err.stack)))); | |
| 4076 } else if (test.pending) { | |
| 4077 console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); | |
| 4078 } else { | |
| 4079 console.log(tag('testcase', attrs, true) ); | |
| 4080 } | |
| 4081 } | |
| 4082 | |
| 4083 /** | |
| 4084 * HTML tag helper. | |
| 4085 */ | |
| 4086 | |
| 4087 function tag(name, attrs, close, content) { | |
| 4088 var end = close ? '/>' : '>' | |
| 4089 , pairs = [] | |
| 4090 , tag; | |
| 4091 | |
| 4092 for (var key in attrs) { | |
| 4093 pairs.push(key + '="' + escape(attrs[key]) + '"'); | |
| 4094 } | |
| 4095 | |
| 4096 tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; | |
| 4097 if (content) tag += content + '</' + name + end; | |
| 4098 return tag; | |
| 4099 } | |
| 4100 | |
| 4101 /** | |
| 4102 * Return cdata escaped CDATA `str`. | |
| 4103 */ | |
| 4104 | |
| 4105 function cdata(str) { | |
| 4106 return '<![CDATA[' + escape(str) + ']]>'; | |
| 4107 } | |
| 4108 | |
| 4109 }); // module: reporters/xunit.js | |
| 4110 | |
| 4111 require.register("runnable.js", function(module, exports, require){ | |
| 4112 | |
| 4113 /** | |
| 4114 * Module dependencies. | |
| 4115 */ | |
| 4116 | |
| 4117 var EventEmitter = require('browser/events').EventEmitter | |
| 4118 , debug = require('browser/debug')('mocha:runnable') | |
| 4119 , milliseconds = require('./ms'); | |
| 4120 | |
| 4121 /** | |
| 4122 * Save timer references to avoid Sinon interfering (see GH-237). | |
| 4123 */ | |
| 4124 | |
| 4125 var Date = global.Date | |
| 4126 , setTimeout = global.setTimeout | |
| 4127 , setInterval = global.setInterval | |
| 4128 , clearTimeout = global.clearTimeout | |
| 4129 , clearInterval = global.clearInterval; | |
| 4130 | |
| 4131 /** | |
| 4132 * Object#toString(). | |
| 4133 */ | |
| 4134 | |
| 4135 var toString = Object.prototype.toString; | |
| 4136 | |
| 4137 /** | |
| 4138 * Expose `Runnable`. | |
| 4139 */ | |
| 4140 | |
| 4141 module.exports = Runnable; | |
| 4142 | |
| 4143 /** | |
| 4144 * Initialize a new `Runnable` with the given `title` and callback `fn`. | |
| 4145 * | |
| 4146 * @param {String} title | |
| 4147 * @param {Function} fn | |
| 4148 * @api private | |
| 4149 */ | |
| 4150 | |
| 4151 function Runnable(title, fn) { | |
| 4152 this.title = title; | |
| 4153 this.fn = fn; | |
| 4154 this.async = fn && fn.length; | |
| 4155 this.sync = ! this.async; | |
| 4156 this._timeout = 2000; | |
| 4157 this._slow = 75; | |
| 4158 this.timedOut = false; | |
| 4159 } | |
| 4160 | |
| 4161 /** | |
| 4162 * Inherit from `EventEmitter.prototype`. | |
| 4163 */ | |
| 4164 | |
| 4165 function F(){}; | |
| 4166 F.prototype = EventEmitter.prototype; | |
| 4167 Runnable.prototype = new F; | |
| 4168 Runnable.prototype.constructor = Runnable; | |
| 4169 | |
| 4170 | |
| 4171 /** | |
| 4172 * Set & get timeout `ms`. | |
| 4173 * | |
| 4174 * @param {Number|String} ms | |
| 4175 * @return {Runnable|Number} ms or self | |
| 4176 * @api private | |
| 4177 */ | |
| 4178 | |
| 4179 Runnable.prototype.timeout = function(ms){ | |
| 4180 if (0 == arguments.length) return this._timeout; | |
| 4181 if ('string' == typeof ms) ms = milliseconds(ms); | |
| 4182 debug('timeout %d', ms); | |
| 4183 this._timeout = ms; | |
| 4184 if (this.timer) this.resetTimeout(); | |
| 4185 return this; | |
| 4186 }; | |
| 4187 | |
| 4188 /** | |
| 4189 * Set & get slow `ms`. | |
| 4190 * | |
| 4191 * @param {Number|String} ms | |
| 4192 * @return {Runnable|Number} ms or self | |
| 4193 * @api private | |
| 4194 */ | |
| 4195 | |
| 4196 Runnable.prototype.slow = function(ms){ | |
| 4197 if (0 === arguments.length) return this._slow; | |
| 4198 if ('string' == typeof ms) ms = milliseconds(ms); | |
| 4199 debug('timeout %d', ms); | |
| 4200 this._slow = ms; | |
| 4201 return this; | |
| 4202 }; | |
| 4203 | |
| 4204 /** | |
| 4205 * Return the full title generated by recursively | |
| 4206 * concatenating the parent's full title. | |
| 4207 * | |
| 4208 * @return {String} | |
| 4209 * @api public | |
| 4210 */ | |
| 4211 | |
| 4212 Runnable.prototype.fullTitle = function(){ | |
| 4213 return this.parent.fullTitle() + ' ' + this.title; | |
| 4214 }; | |
| 4215 | |
| 4216 /** | |
| 4217 * Clear the timeout. | |
| 4218 * | |
| 4219 * @api private | |
| 4220 */ | |
| 4221 | |
| 4222 Runnable.prototype.clearTimeout = function(){ | |
| 4223 clearTimeout(this.timer); | |
| 4224 }; | |
| 4225 | |
| 4226 /** | |
| 4227 * Inspect the runnable void of private properties. | |
| 4228 * | |
| 4229 * @return {String} | |
| 4230 * @api private | |
| 4231 */ | |
| 4232 | |
| 4233 Runnable.prototype.inspect = function(){ | |
| 4234 return JSON.stringify(this, function(key, val){ | |
| 4235 if ('_' == key[0]) return; | |
| 4236 if ('parent' == key) return '#<Suite>'; | |
| 4237 if ('ctx' == key) return '#<Context>'; | |
| 4238 return val; | |
| 4239 }, 2); | |
| 4240 }; | |
| 4241 | |
| 4242 /** | |
| 4243 * Reset the timeout. | |
| 4244 * | |
| 4245 * @api private | |
| 4246 */ | |
| 4247 | |
| 4248 Runnable.prototype.resetTimeout = function(){ | |
| 4249 var self = this; | |
| 4250 var ms = this.timeout() || 1e9; | |
| 4251 | |
| 4252 this.clearTimeout(); | |
| 4253 this.timer = setTimeout(function(){ | |
| 4254 self.callback(new Error('timeout of ' + ms + 'ms exceeded')); | |
| 4255 self.timedOut = true; | |
| 4256 }, ms); | |
| 4257 }; | |
| 4258 | |
| 4259 /** | |
| 4260 * Whitelist these globals for this test run | |
| 4261 * | |
| 4262 * @api private | |
| 4263 */ | |
| 4264 Runnable.prototype.globals = function(arr){ | |
| 4265 var self = this; | |
| 4266 this._allowedGlobals = arr; | |
| 4267 }; | |
| 4268 | |
| 4269 /** | |
| 4270 * Run the test and invoke `fn(err)`. | |
| 4271 * | |
| 4272 * @param {Function} fn | |
| 4273 * @api private | |
| 4274 */ | |
| 4275 | |
| 4276 Runnable.prototype.run = function(fn){ | |
| 4277 var self = this | |
| 4278 , ms = this.timeout() | |
| 4279 , start = new Date | |
| 4280 , ctx = this.ctx | |
| 4281 , finished | |
| 4282 , emitted; | |
| 4283 | |
| 4284 if (ctx) ctx.runnable(this); | |
| 4285 | |
| 4286 // called multiple times | |
| 4287 function multiple(err) { | |
| 4288 if (emitted) return; | |
| 4289 emitted = true; | |
| 4290 self.emit('error', err || new Error('done() called multiple times')); | |
| 4291 } | |
| 4292 | |
| 4293 // finished | |
| 4294 function done(err) { | |
| 4295 if (self.timedOut) return; | |
| 4296 if (finished) return multiple(err); | |
| 4297 self.clearTimeout(); | |
| 4298 self.duration = new Date - start; | |
| 4299 finished = true; | |
| 4300 fn(err); | |
| 4301 } | |
| 4302 | |
| 4303 // for .resetTimeout() | |
| 4304 this.callback = done; | |
| 4305 | |
| 4306 // explicit async with `done` argument | |
| 4307 if (this.async) { | |
| 4308 this.resetTimeout(); | |
| 4309 | |
| 4310 try { | |
| 4311 this.fn.call(ctx, function(err){ | |
| 4312 if (err instanceof Error || toString.call(err) === "[object Error]") ret
urn done(err); | |
| 4313 if (null != err) return done(new Error('done() invoked with non-Error: '
+ err)); | |
| 4314 done(); | |
| 4315 }); | |
| 4316 } catch (err) { | |
| 4317 done(err); | |
| 4318 } | |
| 4319 return; | |
| 4320 } | |
| 4321 | |
| 4322 if (this.asyncOnly) { | |
| 4323 return done(new Error('--async-only option in use without declaring `done()`
')); | |
| 4324 } | |
| 4325 | |
| 4326 // sync or promise-returning | |
| 4327 try { | |
| 4328 if (this.pending) { | |
| 4329 done(); | |
| 4330 } else { | |
| 4331 callFn(this.fn); | |
| 4332 } | |
| 4333 } catch (err) { | |
| 4334 done(err); | |
| 4335 } | |
| 4336 | |
| 4337 function callFn(fn) { | |
| 4338 var result = fn.call(ctx); | |
| 4339 if (result && typeof result.then === 'function') { | |
| 4340 self.resetTimeout(); | |
| 4341 result.then(function(){ done() }, done); | |
| 4342 } else { | |
| 4343 done(); | |
| 4344 } | |
| 4345 } | |
| 4346 }; | |
| 4347 | |
| 4348 }); // module: runnable.js | |
| 4349 | |
| 4350 require.register("runner.js", function(module, exports, require){ | |
| 4351 /** | |
| 4352 * Module dependencies. | |
| 4353 */ | |
| 4354 | |
| 4355 var EventEmitter = require('browser/events').EventEmitter | |
| 4356 , debug = require('browser/debug')('mocha:runner') | |
| 4357 , Test = require('./test') | |
| 4358 , utils = require('./utils') | |
| 4359 , filter = utils.filter | |
| 4360 , keys = utils.keys; | |
| 4361 | |
| 4362 /** | |
| 4363 * Non-enumerable globals. | |
| 4364 */ | |
| 4365 | |
| 4366 var globals = [ | |
| 4367 'setTimeout', | |
| 4368 'clearTimeout', | |
| 4369 'setInterval', | |
| 4370 'clearInterval', | |
| 4371 'XMLHttpRequest', | |
| 4372 'Date' | |
| 4373 ]; | |
| 4374 | |
| 4375 /** | |
| 4376 * Expose `Runner`. | |
| 4377 */ | |
| 4378 | |
| 4379 module.exports = Runner; | |
| 4380 | |
| 4381 /** | |
| 4382 * Initialize a `Runner` for the given `suite`. | |
| 4383 * | |
| 4384 * Events: | |
| 4385 * | |
| 4386 * - `start` execution started | |
| 4387 * - `end` execution complete | |
| 4388 * - `suite` (suite) test suite execution started | |
| 4389 * - `suite end` (suite) all tests (and sub-suites) have finished | |
| 4390 * - `test` (test) test execution started | |
| 4391 * - `test end` (test) test completed | |
| 4392 * - `hook` (hook) hook execution started | |
| 4393 * - `hook end` (hook) hook complete | |
| 4394 * - `pass` (test) test passed | |
| 4395 * - `fail` (test, err) test failed | |
| 4396 * - `pending` (test) test pending | |
| 4397 * | |
| 4398 * @api public | |
| 4399 */ | |
| 4400 | |
| 4401 function Runner(suite) { | |
| 4402 var self = this; | |
| 4403 this._globals = []; | |
| 4404 this._abort = false; | |
| 4405 this.suite = suite; | |
| 4406 this.total = suite.total(); | |
| 4407 this.failures = 0; | |
| 4408 this.on('test end', function(test){ self.checkGlobals(test); }); | |
| 4409 this.on('hook end', function(hook){ self.checkGlobals(hook); }); | |
| 4410 this.grep(/.*/); | |
| 4411 this.globals(this.globalProps().concat(extraGlobals())); | |
| 4412 } | |
| 4413 | |
| 4414 /** | |
| 4415 * Wrapper for setImmediate, process.nextTick, or browser polyfill. | |
| 4416 * | |
| 4417 * @param {Function} fn | |
| 4418 * @api private | |
| 4419 */ | |
| 4420 | |
| 4421 Runner.immediately = global.setImmediate || process.nextTick; | |
| 4422 | |
| 4423 /** | |
| 4424 * Inherit from `EventEmitter.prototype`. | |
| 4425 */ | |
| 4426 | |
| 4427 function F(){}; | |
| 4428 F.prototype = EventEmitter.prototype; | |
| 4429 Runner.prototype = new F; | |
| 4430 Runner.prototype.constructor = Runner; | |
| 4431 | |
| 4432 | |
| 4433 /** | |
| 4434 * Run tests with full titles matching `re`. Updates runner.total | |
| 4435 * with number of tests matched. | |
| 4436 * | |
| 4437 * @param {RegExp} re | |
| 4438 * @param {Boolean} invert | |
| 4439 * @return {Runner} for chaining | |
| 4440 * @api public | |
| 4441 */ | |
| 4442 | |
| 4443 Runner.prototype.grep = function(re, invert){ | |
| 4444 debug('grep %s', re); | |
| 4445 this._grep = re; | |
| 4446 this._invert = invert; | |
| 4447 this.total = this.grepTotal(this.suite); | |
| 4448 return this; | |
| 4449 }; | |
| 4450 | |
| 4451 /** | |
| 4452 * Returns the number of tests matching the grep search for the | |
| 4453 * given suite. | |
| 4454 * | |
| 4455 * @param {Suite} suite | |
| 4456 * @return {Number} | |
| 4457 * @api public | |
| 4458 */ | |
| 4459 | |
| 4460 Runner.prototype.grepTotal = function(suite) { | |
| 4461 var self = this; | |
| 4462 var total = 0; | |
| 4463 | |
| 4464 suite.eachTest(function(test){ | |
| 4465 var match = self._grep.test(test.fullTitle()); | |
| 4466 if (self._invert) match = !match; | |
| 4467 if (match) total++; | |
| 4468 }); | |
| 4469 | |
| 4470 return total; | |
| 4471 }; | |
| 4472 | |
| 4473 /** | |
| 4474 * Return a list of global properties. | |
| 4475 * | |
| 4476 * @return {Array} | |
| 4477 * @api private | |
| 4478 */ | |
| 4479 | |
| 4480 Runner.prototype.globalProps = function() { | |
| 4481 var props = utils.keys(global); | |
| 4482 | |
| 4483 // non-enumerables | |
| 4484 for (var i = 0; i < globals.length; ++i) { | |
| 4485 if (~utils.indexOf(props, globals[i])) continue; | |
| 4486 props.push(globals[i]); | |
| 4487 } | |
| 4488 | |
| 4489 return props; | |
| 4490 }; | |
| 4491 | |
| 4492 /** | |
| 4493 * Allow the given `arr` of globals. | |
| 4494 * | |
| 4495 * @param {Array} arr | |
| 4496 * @return {Runner} for chaining | |
| 4497 * @api public | |
| 4498 */ | |
| 4499 | |
| 4500 Runner.prototype.globals = function(arr){ | |
| 4501 if (0 == arguments.length) return this._globals; | |
| 4502 debug('globals %j', arr); | |
| 4503 this._globals = this._globals.concat(arr); | |
| 4504 return this; | |
| 4505 }; | |
| 4506 | |
| 4507 /** | |
| 4508 * Check for global variable leaks. | |
| 4509 * | |
| 4510 * @api private | |
| 4511 */ | |
| 4512 | |
| 4513 Runner.prototype.checkGlobals = function(test){ | |
| 4514 if (this.ignoreLeaks) return; | |
| 4515 var ok = this._globals; | |
| 4516 | |
| 4517 var globals = this.globalProps(); | |
| 4518 var isNode = process.kill; | |
| 4519 var leaks; | |
| 4520 | |
| 4521 if (test) { | |
| 4522 ok = ok.concat(test._allowedGlobals || []); | |
| 4523 } | |
| 4524 | |
| 4525 if(this.prevGlobalsLength == globals.length) return; | |
| 4526 this.prevGlobalsLength = globals.length; | |
| 4527 | |
| 4528 leaks = filterLeaks(ok, globals); | |
| 4529 this._globals = this._globals.concat(leaks); | |
| 4530 | |
| 4531 if (leaks.length > 1) { | |
| 4532 this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')
); | |
| 4533 } else if (leaks.length) { | |
| 4534 this.fail(test, new Error('global leak detected: ' + leaks[0])); | |
| 4535 } | |
| 4536 }; | |
| 4537 | |
| 4538 /** | |
| 4539 * Fail the given `test`. | |
| 4540 * | |
| 4541 * @param {Test} test | |
| 4542 * @param {Error} err | |
| 4543 * @api private | |
| 4544 */ | |
| 4545 | |
| 4546 Runner.prototype.fail = function(test, err){ | |
| 4547 ++this.failures; | |
| 4548 test.state = 'failed'; | |
| 4549 | |
| 4550 if ('string' == typeof err) { | |
| 4551 err = new Error('the string "' + err + '" was thrown, throw an Error :)'); | |
| 4552 } | |
| 4553 | |
| 4554 this.emit('fail', test, err); | |
| 4555 }; | |
| 4556 | |
| 4557 /** | |
| 4558 * Fail the given `hook` with `err`. | |
| 4559 * | |
| 4560 * Hook failures work in the following pattern: | |
| 4561 * - If bail, then exit | |
| 4562 * - Failed `before` hook skips all tests in a suite and subsuites, | |
| 4563 * but jumps to corresponding `after` hook | |
| 4564 * - Failed `before each` hook skips remaining tests in a | |
| 4565 * suite and jumps to corresponding `after each` hook, | |
| 4566 * which is run only once | |
| 4567 * - Failed `after` hook does not alter | |
| 4568 * execution order | |
| 4569 * - Failed `after each` hook skips remaining tests in a | |
| 4570 * suite and subsuites, but executes other `after each` | |
| 4571 * hooks | |
| 4572 * | |
| 4573 * @param {Hook} hook | |
| 4574 * @param {Error} err | |
| 4575 * @api private | |
| 4576 */ | |
| 4577 | |
| 4578 Runner.prototype.failHook = function(hook, err){ | |
| 4579 this.fail(hook, err); | |
| 4580 if (this.suite.bail()) { | |
| 4581 this.emit('end'); | |
| 4582 } | |
| 4583 }; | |
| 4584 | |
| 4585 /** | |
| 4586 * Run hook `name` callbacks and then invoke `fn()`. | |
| 4587 * | |
| 4588 * @param {String} name | |
| 4589 * @param {Function} function | |
| 4590 * @api private | |
| 4591 */ | |
| 4592 | |
| 4593 Runner.prototype.hook = function(name, fn){ | |
| 4594 var suite = this.suite | |
| 4595 , hooks = suite['_' + name] | |
| 4596 , self = this | |
| 4597 , timer; | |
| 4598 | |
| 4599 function next(i) { | |
| 4600 var hook = hooks[i]; | |
| 4601 if (!hook) return fn(); | |
| 4602 if (self.failures && suite.bail()) return fn(); | |
| 4603 self.currentRunnable = hook; | |
| 4604 | |
| 4605 hook.ctx.currentTest = self.test; | |
| 4606 | |
| 4607 self.emit('hook', hook); | |
| 4608 | |
| 4609 hook.on('error', function(err){ | |
| 4610 self.failHook(hook, err); | |
| 4611 }); | |
| 4612 | |
| 4613 hook.run(function(err){ | |
| 4614 hook.removeAllListeners('error'); | |
| 4615 var testError = hook.error(); | |
| 4616 if (testError) self.fail(self.test, testError); | |
| 4617 if (err) { | |
| 4618 self.failHook(hook, err); | |
| 4619 | |
| 4620 // stop executing hooks, notify callee of hook err | |
| 4621 return fn(err); | |
| 4622 } | |
| 4623 self.emit('hook end', hook); | |
| 4624 delete hook.ctx.currentTest; | |
| 4625 next(++i); | |
| 4626 }); | |
| 4627 } | |
| 4628 | |
| 4629 Runner.immediately(function(){ | |
| 4630 next(0); | |
| 4631 }); | |
| 4632 }; | |
| 4633 | |
| 4634 /** | |
| 4635 * Run hook `name` for the given array of `suites` | |
| 4636 * in order, and callback `fn(err, errSuite)`. | |
| 4637 * | |
| 4638 * @param {String} name | |
| 4639 * @param {Array} suites | |
| 4640 * @param {Function} fn | |
| 4641 * @api private | |
| 4642 */ | |
| 4643 | |
| 4644 Runner.prototype.hooks = function(name, suites, fn){ | |
| 4645 var self = this | |
| 4646 , orig = this.suite; | |
| 4647 | |
| 4648 function next(suite) { | |
| 4649 self.suite = suite; | |
| 4650 | |
| 4651 if (!suite) { | |
| 4652 self.suite = orig; | |
| 4653 return fn(); | |
| 4654 } | |
| 4655 | |
| 4656 self.hook(name, function(err){ | |
| 4657 if (err) { | |
| 4658 var errSuite = self.suite; | |
| 4659 self.suite = orig; | |
| 4660 return fn(err, errSuite); | |
| 4661 } | |
| 4662 | |
| 4663 next(suites.pop()); | |
| 4664 }); | |
| 4665 } | |
| 4666 | |
| 4667 next(suites.pop()); | |
| 4668 }; | |
| 4669 | |
| 4670 /** | |
| 4671 * Run hooks from the top level down. | |
| 4672 * | |
| 4673 * @param {String} name | |
| 4674 * @param {Function} fn | |
| 4675 * @api private | |
| 4676 */ | |
| 4677 | |
| 4678 Runner.prototype.hookUp = function(name, fn){ | |
| 4679 var suites = [this.suite].concat(this.parents()).reverse(); | |
| 4680 this.hooks(name, suites, fn); | |
| 4681 }; | |
| 4682 | |
| 4683 /** | |
| 4684 * Run hooks from the bottom up. | |
| 4685 * | |
| 4686 * @param {String} name | |
| 4687 * @param {Function} fn | |
| 4688 * @api private | |
| 4689 */ | |
| 4690 | |
| 4691 Runner.prototype.hookDown = function(name, fn){ | |
| 4692 var suites = [this.suite].concat(this.parents()); | |
| 4693 this.hooks(name, suites, fn); | |
| 4694 }; | |
| 4695 | |
| 4696 /** | |
| 4697 * Return an array of parent Suites from | |
| 4698 * closest to furthest. | |
| 4699 * | |
| 4700 * @return {Array} | |
| 4701 * @api private | |
| 4702 */ | |
| 4703 | |
| 4704 Runner.prototype.parents = function(){ | |
| 4705 var suite = this.suite | |
| 4706 , suites = []; | |
| 4707 while (suite = suite.parent) suites.push(suite); | |
| 4708 return suites; | |
| 4709 }; | |
| 4710 | |
| 4711 /** | |
| 4712 * Run the current test and callback `fn(err)`. | |
| 4713 * | |
| 4714 * @param {Function} fn | |
| 4715 * @api private | |
| 4716 */ | |
| 4717 | |
| 4718 Runner.prototype.runTest = function(fn){ | |
| 4719 var test = this.test | |
| 4720 , self = this; | |
| 4721 | |
| 4722 if (this.asyncOnly) test.asyncOnly = true; | |
| 4723 | |
| 4724 try { | |
| 4725 test.on('error', function(err){ | |
| 4726 self.fail(test, err); | |
| 4727 }); | |
| 4728 test.run(fn); | |
| 4729 } catch (err) { | |
| 4730 fn(err); | |
| 4731 } | |
| 4732 }; | |
| 4733 | |
| 4734 /** | |
| 4735 * Run tests in the given `suite` and invoke | |
| 4736 * the callback `fn()` when complete. | |
| 4737 * | |
| 4738 * @param {Suite} suite | |
| 4739 * @param {Function} fn | |
| 4740 * @api private | |
| 4741 */ | |
| 4742 | |
| 4743 Runner.prototype.runTests = function(suite, fn){ | |
| 4744 var self = this | |
| 4745 , tests = suite.tests.slice() | |
| 4746 , test; | |
| 4747 | |
| 4748 | |
| 4749 function hookErr(err, errSuite, after) { | |
| 4750 // before/after Each hook for errSuite failed: | |
| 4751 var orig = self.suite; | |
| 4752 | |
| 4753 // for failed 'after each' hook start from errSuite parent, | |
| 4754 // otherwise start from errSuite itself | |
| 4755 self.suite = after ? errSuite.parent : errSuite; | |
| 4756 | |
| 4757 if (self.suite) { | |
| 4758 // call hookUp afterEach | |
| 4759 self.hookUp('afterEach', function(err2, errSuite2) { | |
| 4760 self.suite = orig; | |
| 4761 // some hooks may fail even now | |
| 4762 if (err2) return hookErr(err2, errSuite2, true); | |
| 4763 // report error suite | |
| 4764 fn(errSuite); | |
| 4765 }); | |
| 4766 } else { | |
| 4767 // there is no need calling other 'after each' hooks | |
| 4768 self.suite = orig; | |
| 4769 fn(errSuite); | |
| 4770 } | |
| 4771 } | |
| 4772 | |
| 4773 function next(err, errSuite) { | |
| 4774 // if we bail after first err | |
| 4775 if (self.failures && suite._bail) return fn(); | |
| 4776 | |
| 4777 if (self._abort) return fn(); | |
| 4778 | |
| 4779 if (err) return hookErr(err, errSuite, true); | |
| 4780 | |
| 4781 // next test | |
| 4782 test = tests.shift(); | |
| 4783 | |
| 4784 // all done | |
| 4785 if (!test) return fn(); | |
| 4786 | |
| 4787 // grep | |
| 4788 var match = self._grep.test(test.fullTitle()); | |
| 4789 if (self._invert) match = !match; | |
| 4790 if (!match) return next(); | |
| 4791 | |
| 4792 // pending | |
| 4793 if (test.pending) { | |
| 4794 self.emit('pending', test); | |
| 4795 self.emit('test end', test); | |
| 4796 return next(); | |
| 4797 } | |
| 4798 | |
| 4799 // execute test and hook(s) | |
| 4800 self.emit('test', self.test = test); | |
| 4801 self.hookDown('beforeEach', function(err, errSuite){ | |
| 4802 | |
| 4803 if (err) return hookErr(err, errSuite, false); | |
| 4804 | |
| 4805 self.currentRunnable = self.test; | |
| 4806 self.runTest(function(err){ | |
| 4807 test = self.test; | |
| 4808 | |
| 4809 if (err) { | |
| 4810 self.fail(test, err); | |
| 4811 self.emit('test end', test); | |
| 4812 return self.hookUp('afterEach', next); | |
| 4813 } | |
| 4814 | |
| 4815 test.state = 'passed'; | |
| 4816 self.emit('pass', test); | |
| 4817 self.emit('test end', test); | |
| 4818 self.hookUp('afterEach', next); | |
| 4819 }); | |
| 4820 }); | |
| 4821 } | |
| 4822 | |
| 4823 this.next = next; | |
| 4824 next(); | |
| 4825 }; | |
| 4826 | |
| 4827 /** | |
| 4828 * Run the given `suite` and invoke the | |
| 4829 * callback `fn()` when complete. | |
| 4830 * | |
| 4831 * @param {Suite} suite | |
| 4832 * @param {Function} fn | |
| 4833 * @api private | |
| 4834 */ | |
| 4835 | |
| 4836 Runner.prototype.runSuite = function(suite, fn){ | |
| 4837 var total = this.grepTotal(suite) | |
| 4838 , self = this | |
| 4839 , i = 0; | |
| 4840 | |
| 4841 debug('run suite %s', suite.fullTitle()); | |
| 4842 | |
| 4843 if (!total) return fn(); | |
| 4844 | |
| 4845 this.emit('suite', this.suite = suite); | |
| 4846 | |
| 4847 function next(errSuite) { | |
| 4848 if (errSuite) { | |
| 4849 // current suite failed on a hook from errSuite | |
| 4850 if (errSuite == suite) { | |
| 4851 // if errSuite is current suite | |
| 4852 // continue to the next sibling suite | |
| 4853 return done(); | |
| 4854 } else { | |
| 4855 // errSuite is among the parents of current suite | |
| 4856 // stop execution of errSuite and all sub-suites | |
| 4857 return done(errSuite); | |
| 4858 } | |
| 4859 } | |
| 4860 | |
| 4861 if (self._abort) return done(); | |
| 4862 | |
| 4863 var curr = suite.suites[i++]; | |
| 4864 if (!curr) return done(); | |
| 4865 self.runSuite(curr, next); | |
| 4866 } | |
| 4867 | |
| 4868 function done(errSuite) { | |
| 4869 self.suite = suite; | |
| 4870 self.hook('afterAll', function(){ | |
| 4871 self.emit('suite end', suite); | |
| 4872 fn(errSuite); | |
| 4873 }); | |
| 4874 } | |
| 4875 | |
| 4876 this.hook('beforeAll', function(err){ | |
| 4877 if (err) return done(); | |
| 4878 self.runTests(suite, next); | |
| 4879 }); | |
| 4880 }; | |
| 4881 | |
| 4882 /** | |
| 4883 * Handle uncaught exceptions. | |
| 4884 * | |
| 4885 * @param {Error} err | |
| 4886 * @api private | |
| 4887 */ | |
| 4888 | |
| 4889 Runner.prototype.uncaught = function(err){ | |
| 4890 debug('uncaught exception %s', err.message); | |
| 4891 var runnable = this.currentRunnable; | |
| 4892 if (!runnable || 'failed' == runnable.state) return; | |
| 4893 runnable.clearTimeout(); | |
| 4894 err.uncaught = true; | |
| 4895 this.fail(runnable, err); | |
| 4896 | |
| 4897 // recover from test | |
| 4898 if ('test' == runnable.type) { | |
| 4899 this.emit('test end', runnable); | |
| 4900 this.hookUp('afterEach', this.next); | |
| 4901 return; | |
| 4902 } | |
| 4903 | |
| 4904 // bail on hooks | |
| 4905 this.emit('end'); | |
| 4906 }; | |
| 4907 | |
| 4908 /** | |
| 4909 * Run the root suite and invoke `fn(failures)` | |
| 4910 * on completion. | |
| 4911 * | |
| 4912 * @param {Function} fn | |
| 4913 * @return {Runner} for chaining | |
| 4914 * @api public | |
| 4915 */ | |
| 4916 | |
| 4917 Runner.prototype.run = function(fn){ | |
| 4918 var self = this | |
| 4919 , fn = fn || function(){}; | |
| 4920 | |
| 4921 function uncaught(err){ | |
| 4922 self.uncaught(err); | |
| 4923 } | |
| 4924 | |
| 4925 debug('start'); | |
| 4926 | |
| 4927 // callback | |
| 4928 this.on('end', function(){ | |
| 4929 debug('end'); | |
| 4930 process.removeListener('uncaughtException', uncaught); | |
| 4931 fn(self.failures); | |
| 4932 }); | |
| 4933 | |
| 4934 // run suites | |
| 4935 this.emit('start'); | |
| 4936 this.runSuite(this.suite, function(){ | |
| 4937 debug('finished running'); | |
| 4938 self.emit('end'); | |
| 4939 }); | |
| 4940 | |
| 4941 // uncaught exception | |
| 4942 process.on('uncaughtException', uncaught); | |
| 4943 | |
| 4944 return this; | |
| 4945 }; | |
| 4946 | |
| 4947 /** | |
| 4948 * Cleanly abort execution | |
| 4949 * | |
| 4950 * @return {Runner} for chaining | |
| 4951 * @api public | |
| 4952 */ | |
| 4953 Runner.prototype.abort = function(){ | |
| 4954 debug('aborting'); | |
| 4955 this._abort = true; | |
| 4956 } | |
| 4957 | |
| 4958 /** | |
| 4959 * Filter leaks with the given globals flagged as `ok`. | |
| 4960 * | |
| 4961 * @param {Array} ok | |
| 4962 * @param {Array} globals | |
| 4963 * @return {Array} | |
| 4964 * @api private | |
| 4965 */ | |
| 4966 | |
| 4967 function filterLeaks(ok, globals) { | |
| 4968 return filter(globals, function(key){ | |
| 4969 // Firefox and Chrome exposes iframes as index inside the window object | |
| 4970 if (/^d+/.test(key)) return false; | |
| 4971 | |
| 4972 // in firefox | |
| 4973 // if runner runs in an iframe, this iframe's window.getInterface method not
init at first | |
| 4974 // it is assigned in some seconds | |
| 4975 if (global.navigator && /^getInterface/.test(key)) return false; | |
| 4976 | |
| 4977 // an iframe could be approached by window[iframeIndex] | |
| 4978 // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak | |
| 4979 if (global.navigator && /^\d+/.test(key)) return false; | |
| 4980 | |
| 4981 // Opera and IE expose global variables for HTML element IDs (issue #243) | |
| 4982 if (/^mocha-/.test(key)) return false; | |
| 4983 | |
| 4984 var matched = filter(ok, function(ok){ | |
| 4985 if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); | |
| 4986 return key == ok; | |
| 4987 }); | |
| 4988 return matched.length == 0 && (!global.navigator || 'onerror' !== key); | |
| 4989 }); | |
| 4990 } | |
| 4991 | |
| 4992 /** | |
| 4993 * Array of globals dependent on the environment. | |
| 4994 * | |
| 4995 * @return {Array} | |
| 4996 * @api private | |
| 4997 */ | |
| 4998 | |
| 4999 function extraGlobals() { | |
| 5000 if (typeof(process) === 'object' && | |
| 5001 typeof(process.version) === 'string') { | |
| 5002 | |
| 5003 var nodeVersion = process.version.split('.').reduce(function(a, v) { | |
| 5004 return a << 8 | v; | |
| 5005 }); | |
| 5006 | |
| 5007 // 'errno' was renamed to process._errno in v0.9.11. | |
| 5008 | |
| 5009 if (nodeVersion < 0x00090B) { | |
| 5010 return ['errno']; | |
| 5011 } | |
| 5012 } | |
| 5013 | |
| 5014 return []; | |
| 5015 } | |
| 5016 | |
| 5017 }); // module: runner.js | |
| 5018 | |
| 5019 require.register("suite.js", function(module, exports, require){ | |
| 5020 | |
| 5021 /** | |
| 5022 * Module dependencies. | |
| 5023 */ | |
| 5024 | |
| 5025 var EventEmitter = require('browser/events').EventEmitter | |
| 5026 , debug = require('browser/debug')('mocha:suite') | |
| 5027 , milliseconds = require('./ms') | |
| 5028 , utils = require('./utils') | |
| 5029 , Hook = require('./hook'); | |
| 5030 | |
| 5031 /** | |
| 5032 * Expose `Suite`. | |
| 5033 */ | |
| 5034 | |
| 5035 exports = module.exports = Suite; | |
| 5036 | |
| 5037 /** | |
| 5038 * Create a new `Suite` with the given `title` | |
| 5039 * and parent `Suite`. When a suite with the | |
| 5040 * same title is already present, that suite | |
| 5041 * is returned to provide nicer reporter | |
| 5042 * and more flexible meta-testing. | |
| 5043 * | |
| 5044 * @param {Suite} parent | |
| 5045 * @param {String} title | |
| 5046 * @return {Suite} | |
| 5047 * @api public | |
| 5048 */ | |
| 5049 | |
| 5050 exports.create = function(parent, title){ | |
| 5051 var suite = new Suite(title, parent.ctx); | |
| 5052 suite.parent = parent; | |
| 5053 if (parent.pending) suite.pending = true; | |
| 5054 title = suite.fullTitle(); | |
| 5055 parent.addSuite(suite); | |
| 5056 return suite; | |
| 5057 }; | |
| 5058 | |
| 5059 /** | |
| 5060 * Initialize a new `Suite` with the given | |
| 5061 * `title` and `ctx`. | |
| 5062 * | |
| 5063 * @param {String} title | |
| 5064 * @param {Context} ctx | |
| 5065 * @api private | |
| 5066 */ | |
| 5067 | |
| 5068 function Suite(title, parentContext) { | |
| 5069 this.title = title; | |
| 5070 var context = function () {}; | |
| 5071 context.prototype = parentContext; | |
| 5072 this.ctx = new context(); | |
| 5073 this.suites = []; | |
| 5074 this.tests = []; | |
| 5075 this.pending = false; | |
| 5076 this._beforeEach = []; | |
| 5077 this._beforeAll = []; | |
| 5078 this._afterEach = []; | |
| 5079 this._afterAll = []; | |
| 5080 this.root = !title; | |
| 5081 this._timeout = 2000; | |
| 5082 this._slow = 75; | |
| 5083 this._bail = false; | |
| 5084 } | |
| 5085 | |
| 5086 /** | |
| 5087 * Inherit from `EventEmitter.prototype`. | |
| 5088 */ | |
| 5089 | |
| 5090 function F(){}; | |
| 5091 F.prototype = EventEmitter.prototype; | |
| 5092 Suite.prototype = new F; | |
| 5093 Suite.prototype.constructor = Suite; | |
| 5094 | |
| 5095 | |
| 5096 /** | |
| 5097 * Return a clone of this `Suite`. | |
| 5098 * | |
| 5099 * @return {Suite} | |
| 5100 * @api private | |
| 5101 */ | |
| 5102 | |
| 5103 Suite.prototype.clone = function(){ | |
| 5104 var suite = new Suite(this.title); | |
| 5105 debug('clone'); | |
| 5106 suite.ctx = this.ctx; | |
| 5107 suite.timeout(this.timeout()); | |
| 5108 suite.slow(this.slow()); | |
| 5109 suite.bail(this.bail()); | |
| 5110 return suite; | |
| 5111 }; | |
| 5112 | |
| 5113 /** | |
| 5114 * Set timeout `ms` or short-hand such as "2s". | |
| 5115 * | |
| 5116 * @param {Number|String} ms | |
| 5117 * @return {Suite|Number} for chaining | |
| 5118 * @api private | |
| 5119 */ | |
| 5120 | |
| 5121 Suite.prototype.timeout = function(ms){ | |
| 5122 if (0 == arguments.length) return this._timeout; | |
| 5123 if ('string' == typeof ms) ms = milliseconds(ms); | |
| 5124 debug('timeout %d', ms); | |
| 5125 this._timeout = parseInt(ms, 10); | |
| 5126 return this; | |
| 5127 }; | |
| 5128 | |
| 5129 /** | |
| 5130 * Set slow `ms` or short-hand such as "2s". | |
| 5131 * | |
| 5132 * @param {Number|String} ms | |
| 5133 * @return {Suite|Number} for chaining | |
| 5134 * @api private | |
| 5135 */ | |
| 5136 | |
| 5137 Suite.prototype.slow = function(ms){ | |
| 5138 if (0 === arguments.length) return this._slow; | |
| 5139 if ('string' == typeof ms) ms = milliseconds(ms); | |
| 5140 debug('slow %d', ms); | |
| 5141 this._slow = ms; | |
| 5142 return this; | |
| 5143 }; | |
| 5144 | |
| 5145 /** | |
| 5146 * Sets whether to bail after first error. | |
| 5147 * | |
| 5148 * @parma {Boolean} bail | |
| 5149 * @return {Suite|Number} for chaining | |
| 5150 * @api private | |
| 5151 */ | |
| 5152 | |
| 5153 Suite.prototype.bail = function(bail){ | |
| 5154 if (0 == arguments.length) return this._bail; | |
| 5155 debug('bail %s', bail); | |
| 5156 this._bail = bail; | |
| 5157 return this; | |
| 5158 }; | |
| 5159 | |
| 5160 /** | |
| 5161 * Run `fn(test[, done])` before running tests. | |
| 5162 * | |
| 5163 * @param {Function} fn | |
| 5164 * @return {Suite} for chaining | |
| 5165 * @api private | |
| 5166 */ | |
| 5167 | |
| 5168 Suite.prototype.beforeAll = function(title, fn){ | |
| 5169 if (this.pending) return this; | |
| 5170 if ('function' === typeof title) { | |
| 5171 fn = title; | |
| 5172 title = fn.name; | |
| 5173 } | |
| 5174 title = '"before all" hook' + (title ? ': ' + title : ''); | |
| 5175 | |
| 5176 var hook = new Hook(title, fn); | |
| 5177 hook.parent = this; | |
| 5178 hook.timeout(this.timeout()); | |
| 5179 hook.slow(this.slow()); | |
| 5180 hook.ctx = this.ctx; | |
| 5181 this._beforeAll.push(hook); | |
| 5182 this.emit('beforeAll', hook); | |
| 5183 return this; | |
| 5184 }; | |
| 5185 | |
| 5186 /** | |
| 5187 * Run `fn(test[, done])` after running tests. | |
| 5188 * | |
| 5189 * @param {Function} fn | |
| 5190 * @return {Suite} for chaining | |
| 5191 * @api private | |
| 5192 */ | |
| 5193 | |
| 5194 Suite.prototype.afterAll = function(title, fn){ | |
| 5195 if (this.pending) return this; | |
| 5196 if ('function' === typeof title) { | |
| 5197 fn = title; | |
| 5198 title = fn.name; | |
| 5199 } | |
| 5200 title = '"after all" hook' + (title ? ': ' + title : ''); | |
| 5201 | |
| 5202 var hook = new Hook(title, fn); | |
| 5203 hook.parent = this; | |
| 5204 hook.timeout(this.timeout()); | |
| 5205 hook.slow(this.slow()); | |
| 5206 hook.ctx = this.ctx; | |
| 5207 this._afterAll.push(hook); | |
| 5208 this.emit('afterAll', hook); | |
| 5209 return this; | |
| 5210 }; | |
| 5211 | |
| 5212 /** | |
| 5213 * Run `fn(test[, done])` before each test case. | |
| 5214 * | |
| 5215 * @param {Function} fn | |
| 5216 * @return {Suite} for chaining | |
| 5217 * @api private | |
| 5218 */ | |
| 5219 | |
| 5220 Suite.prototype.beforeEach = function(title, fn){ | |
| 5221 if (this.pending) return this; | |
| 5222 if ('function' === typeof title) { | |
| 5223 fn = title; | |
| 5224 title = fn.name; | |
| 5225 } | |
| 5226 title = '"before each" hook' + (title ? ': ' + title : ''); | |
| 5227 | |
| 5228 var hook = new Hook(title, fn); | |
| 5229 hook.parent = this; | |
| 5230 hook.timeout(this.timeout()); | |
| 5231 hook.slow(this.slow()); | |
| 5232 hook.ctx = this.ctx; | |
| 5233 this._beforeEach.push(hook); | |
| 5234 this.emit('beforeEach', hook); | |
| 5235 return this; | |
| 5236 }; | |
| 5237 | |
| 5238 /** | |
| 5239 * Run `fn(test[, done])` after each test case. | |
| 5240 * | |
| 5241 * @param {Function} fn | |
| 5242 * @return {Suite} for chaining | |
| 5243 * @api private | |
| 5244 */ | |
| 5245 | |
| 5246 Suite.prototype.afterEach = function(title, fn){ | |
| 5247 if (this.pending) return this; | |
| 5248 if ('function' === typeof title) { | |
| 5249 fn = title; | |
| 5250 title = fn.name; | |
| 5251 } | |
| 5252 title = '"after each" hook' + (title ? ': ' + title : ''); | |
| 5253 | |
| 5254 var hook = new Hook(title, fn); | |
| 5255 hook.parent = this; | |
| 5256 hook.timeout(this.timeout()); | |
| 5257 hook.slow(this.slow()); | |
| 5258 hook.ctx = this.ctx; | |
| 5259 this._afterEach.push(hook); | |
| 5260 this.emit('afterEach', hook); | |
| 5261 return this; | |
| 5262 }; | |
| 5263 | |
| 5264 /** | |
| 5265 * Add a test `suite`. | |
| 5266 * | |
| 5267 * @param {Suite} suite | |
| 5268 * @return {Suite} for chaining | |
| 5269 * @api private | |
| 5270 */ | |
| 5271 | |
| 5272 Suite.prototype.addSuite = function(suite){ | |
| 5273 suite.parent = this; | |
| 5274 suite.timeout(this.timeout()); | |
| 5275 suite.slow(this.slow()); | |
| 5276 suite.bail(this.bail()); | |
| 5277 this.suites.push(suite); | |
| 5278 this.emit('suite', suite); | |
| 5279 return this; | |
| 5280 }; | |
| 5281 | |
| 5282 /** | |
| 5283 * Add a `test` to this suite. | |
| 5284 * | |
| 5285 * @param {Test} test | |
| 5286 * @return {Suite} for chaining | |
| 5287 * @api private | |
| 5288 */ | |
| 5289 | |
| 5290 Suite.prototype.addTest = function(test){ | |
| 5291 test.parent = this; | |
| 5292 test.timeout(this.timeout()); | |
| 5293 test.slow(this.slow()); | |
| 5294 test.ctx = this.ctx; | |
| 5295 this.tests.push(test); | |
| 5296 this.emit('test', test); | |
| 5297 return this; | |
| 5298 }; | |
| 5299 | |
| 5300 /** | |
| 5301 * Return the full title generated by recursively | |
| 5302 * concatenating the parent's full title. | |
| 5303 * | |
| 5304 * @return {String} | |
| 5305 * @api public | |
| 5306 */ | |
| 5307 | |
| 5308 Suite.prototype.fullTitle = function(){ | |
| 5309 if (this.parent) { | |
| 5310 var full = this.parent.fullTitle(); | |
| 5311 if (full) return full + ' ' + this.title; | |
| 5312 } | |
| 5313 return this.title; | |
| 5314 }; | |
| 5315 | |
| 5316 /** | |
| 5317 * Return the total number of tests. | |
| 5318 * | |
| 5319 * @return {Number} | |
| 5320 * @api public | |
| 5321 */ | |
| 5322 | |
| 5323 Suite.prototype.total = function(){ | |
| 5324 return utils.reduce(this.suites, function(sum, suite){ | |
| 5325 return sum + suite.total(); | |
| 5326 }, 0) + this.tests.length; | |
| 5327 }; | |
| 5328 | |
| 5329 /** | |
| 5330 * Iterates through each suite recursively to find | |
| 5331 * all tests. Applies a function in the format | |
| 5332 * `fn(test)`. | |
| 5333 * | |
| 5334 * @param {Function} fn | |
| 5335 * @return {Suite} | |
| 5336 * @api private | |
| 5337 */ | |
| 5338 | |
| 5339 Suite.prototype.eachTest = function(fn){ | |
| 5340 utils.forEach(this.tests, fn); | |
| 5341 utils.forEach(this.suites, function(suite){ | |
| 5342 suite.eachTest(fn); | |
| 5343 }); | |
| 5344 return this; | |
| 5345 }; | |
| 5346 | |
| 5347 }); // module: suite.js | |
| 5348 | |
| 5349 require.register("test.js", function(module, exports, require){ | |
| 5350 | |
| 5351 /** | |
| 5352 * Module dependencies. | |
| 5353 */ | |
| 5354 | |
| 5355 var Runnable = require('./runnable'); | |
| 5356 | |
| 5357 /** | |
| 5358 * Expose `Test`. | |
| 5359 */ | |
| 5360 | |
| 5361 module.exports = Test; | |
| 5362 | |
| 5363 /** | |
| 5364 * Initialize a new `Test` with the given `title` and callback `fn`. | |
| 5365 * | |
| 5366 * @param {String} title | |
| 5367 * @param {Function} fn | |
| 5368 * @api private | |
| 5369 */ | |
| 5370 | |
| 5371 function Test(title, fn) { | |
| 5372 Runnable.call(this, title, fn); | |
| 5373 this.pending = !fn; | |
| 5374 this.type = 'test'; | |
| 5375 } | |
| 5376 | |
| 5377 /** | |
| 5378 * Inherit from `Runnable.prototype`. | |
| 5379 */ | |
| 5380 | |
| 5381 function F(){}; | |
| 5382 F.prototype = Runnable.prototype; | |
| 5383 Test.prototype = new F; | |
| 5384 Test.prototype.constructor = Test; | |
| 5385 | |
| 5386 | |
| 5387 }); // module: test.js | |
| 5388 | |
| 5389 require.register("utils.js", function(module, exports, require){ | |
| 5390 /** | |
| 5391 * Module dependencies. | |
| 5392 */ | |
| 5393 | |
| 5394 var fs = require('browser/fs') | |
| 5395 , path = require('browser/path') | |
| 5396 , join = path.join | |
| 5397 , debug = require('browser/debug')('mocha:watch'); | |
| 5398 | |
| 5399 /** | |
| 5400 * Ignored directories. | |
| 5401 */ | |
| 5402 | |
| 5403 var ignore = ['node_modules', '.git']; | |
| 5404 | |
| 5405 /** | |
| 5406 * Escape special characters in the given string of html. | |
| 5407 * | |
| 5408 * @param {String} html | |
| 5409 * @return {String} | |
| 5410 * @api private | |
| 5411 */ | |
| 5412 | |
| 5413 exports.escape = function(html){ | |
| 5414 return String(html) | |
| 5415 .replace(/&/g, '&') | |
| 5416 .replace(/"/g, '"') | |
| 5417 .replace(/</g, '<') | |
| 5418 .replace(/>/g, '>'); | |
| 5419 }; | |
| 5420 | |
| 5421 /** | |
| 5422 * Array#forEach (<=IE8) | |
| 5423 * | |
| 5424 * @param {Array} array | |
| 5425 * @param {Function} fn | |
| 5426 * @param {Object} scope | |
| 5427 * @api private | |
| 5428 */ | |
| 5429 | |
| 5430 exports.forEach = function(arr, fn, scope){ | |
| 5431 for (var i = 0, l = arr.length; i < l; i++) | |
| 5432 fn.call(scope, arr[i], i); | |
| 5433 }; | |
| 5434 | |
| 5435 /** | |
| 5436 * Array#map (<=IE8) | |
| 5437 * | |
| 5438 * @param {Array} array | |
| 5439 * @param {Function} fn | |
| 5440 * @param {Object} scope | |
| 5441 * @api private | |
| 5442 */ | |
| 5443 | |
| 5444 exports.map = function(arr, fn, scope){ | |
| 5445 var result = []; | |
| 5446 for (var i = 0, l = arr.length; i < l; i++) | |
| 5447 result.push(fn.call(scope, arr[i], i)); | |
| 5448 return result; | |
| 5449 }; | |
| 5450 | |
| 5451 /** | |
| 5452 * Array#indexOf (<=IE8) | |
| 5453 * | |
| 5454 * @parma {Array} arr | |
| 5455 * @param {Object} obj to find index of | |
| 5456 * @param {Number} start | |
| 5457 * @api private | |
| 5458 */ | |
| 5459 | |
| 5460 exports.indexOf = function(arr, obj, start){ | |
| 5461 for (var i = start || 0, l = arr.length; i < l; i++) { | |
| 5462 if (arr[i] === obj) | |
| 5463 return i; | |
| 5464 } | |
| 5465 return -1; | |
| 5466 }; | |
| 5467 | |
| 5468 /** | |
| 5469 * Array#reduce (<=IE8) | |
| 5470 * | |
| 5471 * @param {Array} array | |
| 5472 * @param {Function} fn | |
| 5473 * @param {Object} initial value | |
| 5474 * @api private | |
| 5475 */ | |
| 5476 | |
| 5477 exports.reduce = function(arr, fn, val){ | |
| 5478 var rval = val; | |
| 5479 | |
| 5480 for (var i = 0, l = arr.length; i < l; i++) { | |
| 5481 rval = fn(rval, arr[i], i, arr); | |
| 5482 } | |
| 5483 | |
| 5484 return rval; | |
| 5485 }; | |
| 5486 | |
| 5487 /** | |
| 5488 * Array#filter (<=IE8) | |
| 5489 * | |
| 5490 * @param {Array} array | |
| 5491 * @param {Function} fn | |
| 5492 * @api private | |
| 5493 */ | |
| 5494 | |
| 5495 exports.filter = function(arr, fn){ | |
| 5496 var ret = []; | |
| 5497 | |
| 5498 for (var i = 0, l = arr.length; i < l; i++) { | |
| 5499 var val = arr[i]; | |
| 5500 if (fn(val, i, arr)) ret.push(val); | |
| 5501 } | |
| 5502 | |
| 5503 return ret; | |
| 5504 }; | |
| 5505 | |
| 5506 /** | |
| 5507 * Object.keys (<=IE8) | |
| 5508 * | |
| 5509 * @param {Object} obj | |
| 5510 * @return {Array} keys | |
| 5511 * @api private | |
| 5512 */ | |
| 5513 | |
| 5514 exports.keys = Object.keys || function(obj) { | |
| 5515 var keys = [] | |
| 5516 , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 | |
| 5517 | |
| 5518 for (var key in obj) { | |
| 5519 if (has.call(obj, key)) { | |
| 5520 keys.push(key); | |
| 5521 } | |
| 5522 } | |
| 5523 | |
| 5524 return keys; | |
| 5525 }; | |
| 5526 | |
| 5527 /** | |
| 5528 * Watch the given `files` for changes | |
| 5529 * and invoke `fn(file)` on modification. | |
| 5530 * | |
| 5531 * @param {Array} files | |
| 5532 * @param {Function} fn | |
| 5533 * @api private | |
| 5534 */ | |
| 5535 | |
| 5536 exports.watch = function(files, fn){ | |
| 5537 var options = { interval: 100 }; | |
| 5538 files.forEach(function(file){ | |
| 5539 debug('file %s', file); | |
| 5540 fs.watchFile(file, options, function(curr, prev){ | |
| 5541 if (prev.mtime < curr.mtime) fn(file); | |
| 5542 }); | |
| 5543 }); | |
| 5544 }; | |
| 5545 | |
| 5546 /** | |
| 5547 * Ignored files. | |
| 5548 */ | |
| 5549 | |
| 5550 function ignored(path){ | |
| 5551 return !~ignore.indexOf(path); | |
| 5552 } | |
| 5553 | |
| 5554 /** | |
| 5555 * Lookup files in the given `dir`. | |
| 5556 * | |
| 5557 * @return {Array} | |
| 5558 * @api private | |
| 5559 */ | |
| 5560 | |
| 5561 exports.files = function(dir, ret){ | |
| 5562 ret = ret || []; | |
| 5563 | |
| 5564 fs.readdirSync(dir) | |
| 5565 .filter(ignored) | |
| 5566 .forEach(function(path){ | |
| 5567 path = join(dir, path); | |
| 5568 if (fs.statSync(path).isDirectory()) { | |
| 5569 exports.files(path, ret); | |
| 5570 } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) { | |
| 5571 ret.push(path); | |
| 5572 } | |
| 5573 }); | |
| 5574 | |
| 5575 return ret; | |
| 5576 }; | |
| 5577 | |
| 5578 /** | |
| 5579 * Compute a slug from the given `str`. | |
| 5580 * | |
| 5581 * @param {String} str | |
| 5582 * @return {String} | |
| 5583 * @api private | |
| 5584 */ | |
| 5585 | |
| 5586 exports.slug = function(str){ | |
| 5587 return str | |
| 5588 .toLowerCase() | |
| 5589 .replace(/ +/g, '-') | |
| 5590 .replace(/[^-\w]/g, ''); | |
| 5591 }; | |
| 5592 | |
| 5593 /** | |
| 5594 * Strip the function definition from `str`, | |
| 5595 * and re-indent for pre whitespace. | |
| 5596 */ | |
| 5597 | |
| 5598 exports.clean = function(str) { | |
| 5599 str = str | |
| 5600 .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '') | |
| 5601 .replace(/^function *\(.*\) *{/, '') | |
| 5602 .replace(/\s+\}$/, ''); | |
| 5603 | |
| 5604 var spaces = str.match(/^\n?( *)/)[1].length | |
| 5605 , tabs = str.match(/^\n?(\t*)/)[1].length | |
| 5606 , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces
) + '}', 'gm'); | |
| 5607 | |
| 5608 str = str.replace(re, ''); | |
| 5609 | |
| 5610 return exports.trim(str); | |
| 5611 }; | |
| 5612 | |
| 5613 /** | |
| 5614 * Escape regular expression characters in `str`. | |
| 5615 * | |
| 5616 * @param {String} str | |
| 5617 * @return {String} | |
| 5618 * @api private | |
| 5619 */ | |
| 5620 | |
| 5621 exports.escapeRegexp = function(str){ | |
| 5622 return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); | |
| 5623 }; | |
| 5624 | |
| 5625 /** | |
| 5626 * Trim the given `str`. | |
| 5627 * | |
| 5628 * @param {String} str | |
| 5629 * @return {String} | |
| 5630 * @api private | |
| 5631 */ | |
| 5632 | |
| 5633 exports.trim = function(str){ | |
| 5634 return str.replace(/^\s+|\s+$/g, ''); | |
| 5635 }; | |
| 5636 | |
| 5637 /** | |
| 5638 * Parse the given `qs`. | |
| 5639 * | |
| 5640 * @param {String} qs | |
| 5641 * @return {Object} | |
| 5642 * @api private | |
| 5643 */ | |
| 5644 | |
| 5645 exports.parseQuery = function(qs){ | |
| 5646 return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ | |
| 5647 var i = pair.indexOf('=') | |
| 5648 , key = pair.slice(0, i) | |
| 5649 , val = pair.slice(++i); | |
| 5650 | |
| 5651 obj[key] = decodeURIComponent(val); | |
| 5652 return obj; | |
| 5653 }, {}); | |
| 5654 }; | |
| 5655 | |
| 5656 /** | |
| 5657 * Highlight the given string of `js`. | |
| 5658 * | |
| 5659 * @param {String} js | |
| 5660 * @return {String} | |
| 5661 * @api private | |
| 5662 */ | |
| 5663 | |
| 5664 function highlight(js) { | |
| 5665 return js | |
| 5666 .replace(/</g, '<') | |
| 5667 .replace(/>/g, '>') | |
| 5668 .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>') | |
| 5669 .replace(/('.*?')/gm, '<span class="string">$1</span>') | |
| 5670 .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>') | |
| 5671 .replace(/(\d+)/gm, '<span class="number">$1</span>') | |
| 5672 .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="in
it">$1</span>') | |
| 5673 .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyw
ord">$1</span>') | |
| 5674 } | |
| 5675 | |
| 5676 /** | |
| 5677 * Highlight the contents of tag `name`. | |
| 5678 * | |
| 5679 * @param {String} name | |
| 5680 * @api private | |
| 5681 */ | |
| 5682 | |
| 5683 exports.highlightTags = function(name) { | |
| 5684 var code = document.getElementsByTagName(name); | |
| 5685 for (var i = 0, len = code.length; i < len; ++i) { | |
| 5686 code[i].innerHTML = highlight(code[i].innerHTML); | |
| 5687 } | |
| 5688 }; | |
| 5689 | |
| 5690 }); // module: utils.js | |
| 5691 // The global object is "self" in Web Workers. | |
| 5692 global = (function() { return this; })(); | |
| 5693 | |
| 5694 /** | |
| 5695 * Save timer references to avoid Sinon interfering (see GH-237). | |
| 5696 */ | |
| 5697 | |
| 5698 var Date = global.Date; | |
| 5699 var setTimeout = global.setTimeout; | |
| 5700 var setInterval = global.setInterval; | |
| 5701 var clearTimeout = global.clearTimeout; | |
| 5702 var clearInterval = global.clearInterval; | |
| 5703 | |
| 5704 /** | |
| 5705 * Node shims. | |
| 5706 * | |
| 5707 * These are meant only to allow | |
| 5708 * mocha.js to run untouched, not | |
| 5709 * to allow running node code in | |
| 5710 * the browser. | |
| 5711 */ | |
| 5712 | |
| 5713 var process = {}; | |
| 5714 process.exit = function(status){}; | |
| 5715 process.stdout = {}; | |
| 5716 | |
| 5717 var uncaughtExceptionHandlers = []; | |
| 5718 | |
| 5719 /** | |
| 5720 * Remove uncaughtException listener. | |
| 5721 */ | |
| 5722 | |
| 5723 process.removeListener = function(e, fn){ | |
| 5724 if ('uncaughtException' == e) { | |
| 5725 global.onerror = function() {}; | |
| 5726 var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); | |
| 5727 if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } | |
| 5728 } | |
| 5729 }; | |
| 5730 | |
| 5731 /** | |
| 5732 * Implements uncaughtException listener. | |
| 5733 */ | |
| 5734 | |
| 5735 process.on = function(e, fn){ | |
| 5736 if ('uncaughtException' == e) { | |
| 5737 global.onerror = function(err, url, line){ | |
| 5738 fn(new Error(err + ' (' + url + ':' + line + ')')); | |
| 5739 return true; | |
| 5740 }; | |
| 5741 uncaughtExceptionHandlers.push(fn); | |
| 5742 } | |
| 5743 }; | |
| 5744 | |
| 5745 /** | |
| 5746 * Expose mocha. | |
| 5747 */ | |
| 5748 | |
| 5749 var Mocha = global.Mocha = require('mocha'), | |
| 5750 mocha = global.mocha = new Mocha({ reporter: 'html' }); | |
| 5751 | |
| 5752 // The BDD UI is registered by default, but no UI will be functional in the | |
| 5753 // browser without an explicit call to the overridden `mocha.ui` (see below). | |
| 5754 // Ensure that this default UI does not expose its methods to the global scope. | |
| 5755 mocha.suite.removeAllListeners('pre-require'); | |
| 5756 | |
| 5757 var immediateQueue = [] | |
| 5758 , immediateTimeout; | |
| 5759 | |
| 5760 function timeslice() { | |
| 5761 var immediateStart = new Date().getTime(); | |
| 5762 while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100)
{ | |
| 5763 immediateQueue.shift()(); | |
| 5764 } | |
| 5765 if (immediateQueue.length) { | |
| 5766 immediateTimeout = setTimeout(timeslice, 0); | |
| 5767 } else { | |
| 5768 immediateTimeout = null; | |
| 5769 } | |
| 5770 } | |
| 5771 | |
| 5772 /** | |
| 5773 * High-performance override of Runner.immediately. | |
| 5774 */ | |
| 5775 | |
| 5776 Mocha.Runner.immediately = function(callback) { | |
| 5777 immediateQueue.push(callback); | |
| 5778 if (!immediateTimeout) { | |
| 5779 immediateTimeout = setTimeout(timeslice, 0); | |
| 5780 } | |
| 5781 }; | |
| 5782 | |
| 5783 /** | |
| 5784 * Function to allow assertion libraries to throw errors directly into mocha. | |
| 5785 * This is useful when running tests in a browser because window.onerror will | |
| 5786 * only receive the 'message' attribute of the Error. | |
| 5787 */ | |
| 5788 mocha.throwError = function(err) { | |
| 5789 Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { | |
| 5790 fn(err); | |
| 5791 }); | |
| 5792 throw err; | |
| 5793 }; | |
| 5794 | |
| 5795 /** | |
| 5796 * Override ui to ensure that the ui functions are initialized. | |
| 5797 * Normally this would happen in Mocha.prototype.loadFiles. | |
| 5798 */ | |
| 5799 | |
| 5800 mocha.ui = function(ui){ | |
| 5801 Mocha.prototype.ui.call(this, ui); | |
| 5802 this.suite.emit('pre-require', global, null, this); | |
| 5803 return this; | |
| 5804 }; | |
| 5805 | |
| 5806 /** | |
| 5807 * Setup mocha with the given setting options. | |
| 5808 */ | |
| 5809 | |
| 5810 mocha.setup = function(opts){ | |
| 5811 if ('string' == typeof opts) opts = { ui: opts }; | |
| 5812 for (var opt in opts) this[opt](opts[opt]); | |
| 5813 return this; | |
| 5814 }; | |
| 5815 | |
| 5816 /** | |
| 5817 * Run mocha, returning the Runner. | |
| 5818 */ | |
| 5819 | |
| 5820 mocha.run = function(fn){ | |
| 5821 var options = mocha.options; | |
| 5822 mocha.globals('location'); | |
| 5823 | |
| 5824 var query = Mocha.utils.parseQuery(global.location.search || ''); | |
| 5825 if (query.grep) mocha.grep(query.grep); | |
| 5826 if (query.invert) mocha.invert(); | |
| 5827 | |
| 5828 return Mocha.prototype.run.call(mocha, function(){ | |
| 5829 // The DOM Document is not available in Web Workers. | |
| 5830 if (global.document) { | |
| 5831 Mocha.utils.highlightTags('code'); | |
| 5832 } | |
| 5833 if (fn) fn(); | |
| 5834 }); | |
| 5835 }; | |
| 5836 | |
| 5837 /** | |
| 5838 * Expose the process shim. | |
| 5839 */ | |
| 5840 | |
| 5841 Mocha.process = process; | |
| 5842 })(); | |
| OLD | NEW |