├── .gitignore ├── history.md ├── Makefile ├── .jshintrc ├── package.json ├── component.json ├── test ├── index.html ├── normalize.js └── mocha │ ├── mocha.css │ └── mocha.js ├── readme.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | components 2 | build 3 | -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | # 0.0.1 2 | 3 | Inital release -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | build: components index.js 3 | @component build --dev 4 | 5 | components: component.json 6 | @component install --dev 7 | 8 | clean: 9 | rm -fr build components template.js 10 | 11 | .PHONY: clean 12 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "require": false, 4 | "exports": true, 5 | "module": true 6 | }, 7 | "browser": true, 8 | "indent": 2, 9 | "laxbreak": true, 10 | "expr": true, 11 | "white": true 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "democracyos-normalize", 3 | "repo": "github.com/DemocracyOS/normalize", 4 | "description": "Normalize events", 5 | "version": "0.0.3", 6 | "keywords": [], 7 | "dependencies": {}, 8 | "license": "MIT", 9 | "main": "index.js", 10 | "scripts": [ 11 | "index.js" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "normalize", 3 | "repo": "stephenmathieson/normalize", 4 | "description": "Normalize events", 5 | "version": "0.0.1", 6 | "keywords": [], 7 | "dependencies": {}, 8 | "development": { 9 | "component/event": "*" 10 | }, 11 | "license": "MIT", 12 | "main": "index.js", 13 | "scripts": [ 14 | "index.js" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | normalize() 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | foo 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # normalize 3 | 4 | Normalize events 5 | 6 | ## Installation 7 | 8 | Install with [component(1)](http://component.io): 9 | 10 | $ component install stephenmathieson/normalize 11 | 12 | ## API 13 | 14 | ### `normalize(fn)` 15 | 16 | Normalize the event provided to `fn`. Will fallback to `window.event` if no event is provided to `fn`. 17 | 18 | ### `normalize(event)` 19 | 20 | Normalize the given `event`. Will fallback to `window.event`. 21 | 22 | ## Added Properties and Methods 23 | 24 | `normalize` will provide you access to the following properties and methods of an `Event`: 25 | 26 | - target 27 | - which 28 | - preventDefault() 29 | - stopPropagation() 30 | 31 | ## Examples 32 | 33 | ```js 34 | var ev = require('event'); 35 | var normalize = require('normalize'); 36 | 37 | var foo = document.getElementById('foo'); 38 | 39 | ev.bind(foo, 'click', normalize(function (e) { 40 | // ... 41 | })); 42 | 43 | ev.bind(foo, 'mouseover', function (e) { 44 | e = normalize(e); 45 | // ... 46 | }); 47 | ``` 48 | 49 | ## License 50 | 51 | MIT 52 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Normalize the events provided to `fn` 4 | * 5 | * @api public 6 | * @param {Function|Event} fn 7 | * @return {Function|Event} 8 | */ 9 | 10 | exports = module.exports = function (fn) { 11 | // handle functions which are passed an event 12 | if (typeof fn === 'function') { 13 | return function (event) { 14 | event = exports.normalize(event); 15 | fn.call(this, event); 16 | }; 17 | } 18 | 19 | // just normalize the event 20 | return exports.normalize(fn); 21 | }; 22 | 23 | /** 24 | * Normalize the given `event` 25 | * 26 | * @api private 27 | * @param {Event} event 28 | * @return {Event} 29 | */ 30 | 31 | exports.normalize = function (event) { 32 | event = event || window.event; 33 | 34 | event.target = event.target || event.srcElement; 35 | 36 | event.which = event.which || event.keyCode || event.charCode; 37 | 38 | event.preventDefault = event.preventDefault || function () { 39 | this.returnValue = false; 40 | }; 41 | 42 | event.stopPropagation = event.stopPropagation || function () { 43 | this.cancelBubble = true; 44 | }; 45 | 46 | return event; 47 | }; 48 | -------------------------------------------------------------------------------- /test/normalize.js: -------------------------------------------------------------------------------- 1 | describe('normalize', function () { 2 | var normalize = require('normalize'), 3 | ev = require('event'); 4 | 5 | var div = document.getElementById('div'), 6 | anchor = document.getElementById('anchor'); 7 | 8 | function assertEqual(actual, expected, msg) { 9 | if (actual != expected) { 10 | throw new Error(actual + ' != ' + expected); 11 | } 12 | } 13 | 14 | function fire(element, type, augment) { 15 | augment = augment || {}; 16 | 17 | var e = document.createEvent 18 | ? document.createEvent('HTMLEvents') 19 | : document.createEventObject(); 20 | 21 | for (var a in augment) { 22 | if (a === 'which') { 23 | e.keyCode = augment[a]; 24 | } 25 | e[a] = augment[a]; 26 | } 27 | 28 | if (e.initEvent) { 29 | e.initEvent(type, true, true); 30 | } 31 | 32 | element.dispatchEvent 33 | ? element.dispatchEvent(e) 34 | : element.fireEvent('on' + type, e); 35 | } 36 | 37 | describe('normalize(fn)', function () { 38 | it('should work', function (done) { 39 | var fn = ev.bind(div, 'click', normalize(function (e) { 40 | assertEqual(e.target, div, 'e.target should be #div'); 41 | ev.unbind(div, 'click', fn); 42 | done(); 43 | })); 44 | fire(div, 'click'); 45 | }); 46 | }); 47 | 48 | describe('normalize(e)', function () { 49 | it('should add ".target"', function (done) { 50 | var fn = ev.bind(div, 'click', function (e) { 51 | e = normalize(e); 52 | assertEqual(e.target, div, 'e.target should be #div'); 53 | ev.unbind(div, 'click', fn); 54 | done(); 55 | }); 56 | fire(div, 'click'); 57 | }); 58 | 59 | it('should add ".which" to keyboard events', function (done) { 60 | var fn = ev.bind(anchor, 'keydown', function (e) { 61 | e = normalize(e); 62 | assertEqual(e.which, 13); 63 | ev.unbind(anchor, 'keydown', fn); 64 | done(); 65 | }); 66 | fire(anchor, 'keydown', { which: 13 }); 67 | }); 68 | 69 | it('should add ".preventDefault()"', function (done) { 70 | var fn = ev.bind(div, 'click', function (e) { 71 | e = normalize(e); 72 | assertEqual(typeof e.preventDefault, 'function'); 73 | ev.unbind(div, 'click', fn); 74 | done(); 75 | }); 76 | fire(div, 'click'); 77 | }); 78 | 79 | describe('e.preventDefault', function () { 80 | it('should work', function (done) { 81 | location.hash = '#bananas'; 82 | 83 | var fn = ev.bind(anchor, 'click', function (e) { 84 | ev.unbind(anchor, 'click', fn); 85 | 86 | normalize(e).preventDefault(); 87 | 88 | setTimeout(function () { 89 | assertEqual(location.hash, '#bananas'); 90 | done(); 91 | }, 0); 92 | }); 93 | 94 | fire(anchor, 'click'); 95 | }); 96 | }); 97 | 98 | it('should add ".stopPropagation()"', function (done) { 99 | var fn = ev.bind(div, 'click', function (e) { 100 | e = normalize(e); 101 | assertEqual(typeof e.stopPropagation, 'function'); 102 | e.stopPropagation(); 103 | ev.unbind(div, 'click', fn); 104 | done(); 105 | }); 106 | fire(div, 'click'); 107 | }); 108 | 109 | describe('e.stopPropagation', function () { 110 | it('should work', function (done) { 111 | 112 | ev.bind(div, 'click', function (e) { 113 | throw new Error('stopPropagation didn\'t stop propagation'); 114 | }); 115 | 116 | var fn = ev.bind(anchor, 'click', function (e) { 117 | ev.unbind(anchor, 'click', fn); 118 | 119 | normalize(e).stopPropagation(); 120 | // the click will bubble to the div within 10ms, even in old ie 121 | setTimeout(function () { 122 | done(); 123 | }, 10); 124 | }); 125 | 126 | fire(anchor, 'click'); 127 | }); 128 | }); 129 | }); 130 | }); 131 | -------------------------------------------------------------------------------- /test/mocha/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, #mocha li { 13 | margin: 0; 14 | padding: 0; 15 | } 16 | 17 | #mocha ul { 18 | list-style: none; 19 | } 20 | 21 | #mocha h1, #mocha h2 { 22 | margin: 0; 23 | } 24 | 25 | #mocha h1 { 26 | margin-top: 15px; 27 | font-size: 1em; 28 | font-weight: 200; 29 | } 30 | 31 | #mocha h1 a { 32 | text-decoration: none; 33 | color: inherit; 34 | } 35 | 36 | #mocha h1 a:hover { 37 | text-decoration: underline; 38 | } 39 | 40 | #mocha .suite .suite h1 { 41 | margin-top: 0; 42 | font-size: .8em; 43 | } 44 | 45 | #mocha .hidden { 46 | display: none; 47 | } 48 | 49 | #mocha h2 { 50 | font-size: 12px; 51 | font-weight: normal; 52 | cursor: pointer; 53 | } 54 | 55 | #mocha .suite { 56 | margin-left: 15px; 57 | } 58 | 59 | #mocha .test { 60 | margin-left: 15px; 61 | overflow: hidden; 62 | } 63 | 64 | #mocha .test.pending:hover h2::after { 65 | content: '(pending)'; 66 | font-family: arial, sans-serif; 67 | } 68 | 69 | #mocha .test.pass.medium .duration { 70 | background: #C09853; 71 | } 72 | 73 | #mocha .test.pass.slow .duration { 74 | background: #B94A48; 75 | } 76 | 77 | #mocha .test.pass::before { 78 | content: '✓'; 79 | font-size: 12px; 80 | display: block; 81 | float: left; 82 | margin-right: 5px; 83 | color: #00d6b2; 84 | } 85 | 86 | #mocha .test.pass .duration { 87 | font-size: 9px; 88 | margin-left: 5px; 89 | padding: 2px 5px; 90 | color: white; 91 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 92 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 93 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -webkit-border-radius: 5px; 95 | -moz-border-radius: 5px; 96 | -ms-border-radius: 5px; 97 | -o-border-radius: 5px; 98 | border-radius: 5px; 99 | } 100 | 101 | #mocha .test.pass.fast .duration { 102 | display: none; 103 | } 104 | 105 | #mocha .test.pending { 106 | color: #0b97c4; 107 | } 108 | 109 | #mocha .test.pending::before { 110 | content: '◦'; 111 | color: #0b97c4; 112 | } 113 | 114 | #mocha .test.fail { 115 | color: #c00; 116 | } 117 | 118 | #mocha .test.fail pre { 119 | color: black; 120 | } 121 | 122 | #mocha .test.fail::before { 123 | content: '✖'; 124 | font-size: 12px; 125 | display: block; 126 | float: left; 127 | margin-right: 5px; 128 | color: #c00; 129 | } 130 | 131 | #mocha .test pre.error { 132 | color: #c00; 133 | max-height: 300px; 134 | overflow: auto; 135 | } 136 | 137 | #mocha .test pre { 138 | display: block; 139 | float: left; 140 | clear: left; 141 | font: 12px/1.5 monaco, monospace; 142 | margin: 5px; 143 | padding: 15px; 144 | border: 1px solid #eee; 145 | border-bottom-color: #ddd; 146 | -webkit-border-radius: 3px; 147 | -webkit-box-shadow: 0 1px 3px #eee; 148 | -moz-border-radius: 3px; 149 | -moz-box-shadow: 0 1px 3px #eee; 150 | } 151 | 152 | #mocha .test h2 { 153 | position: relative; 154 | } 155 | 156 | #mocha .test a.replay { 157 | position: absolute; 158 | top: 3px; 159 | right: 0; 160 | text-decoration: none; 161 | vertical-align: middle; 162 | display: block; 163 | width: 15px; 164 | height: 15px; 165 | line-height: 15px; 166 | text-align: center; 167 | background: #eee; 168 | font-size: 15px; 169 | -moz-border-radius: 15px; 170 | border-radius: 15px; 171 | -webkit-transition: opacity 200ms; 172 | -moz-transition: opacity 200ms; 173 | transition: opacity 200ms; 174 | opacity: 0.3; 175 | color: #888; 176 | } 177 | 178 | #mocha .test:hover a.replay { 179 | opacity: 1; 180 | } 181 | 182 | #mocha-report.pass .test.fail { 183 | display: none; 184 | } 185 | 186 | #mocha-report.fail .test.pass { 187 | display: none; 188 | } 189 | 190 | #mocha-error { 191 | color: #c00; 192 | font-size: 1.5em; 193 | font-weight: 100; 194 | letter-spacing: 1px; 195 | } 196 | 197 | #mocha-stats { 198 | position: fixed; 199 | top: 15px; 200 | right: 10px; 201 | font-size: 12px; 202 | margin: 0; 203 | color: #888; 204 | z-index: 1; 205 | } 206 | 207 | #mocha-stats .progress { 208 | float: right; 209 | padding-top: 0; 210 | } 211 | 212 | #mocha-stats em { 213 | color: black; 214 | } 215 | 216 | #mocha-stats a { 217 | text-decoration: none; 218 | color: inherit; 219 | } 220 | 221 | #mocha-stats a:hover { 222 | border-bottom: 1px solid #eee; 223 | } 224 | 225 | #mocha-stats li { 226 | display: inline-block; 227 | margin: 0 5px; 228 | list-style: none; 229 | padding-top: 11px; 230 | } 231 | 232 | #mocha-stats canvas { 233 | width: 40px; 234 | height: 40px; 235 | } 236 | 237 | #mocha code .comment { color: #ddd } 238 | #mocha code .init { color: #2F6FAD } 239 | #mocha code .string { color: #5890AD } 240 | #mocha code .keyword { color: #8A6343 } 241 | #mocha code .number { color: #2F6FAD } 242 | 243 | @media screen and (max-device-width: 480px) { 244 | #mocha { 245 | margin: 60px 0px; 246 | } 247 | 248 | #mocha #stats { 249 | position: absolute; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /test/mocha/mocha.js: -------------------------------------------------------------------------------- 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.txt for terms of usage */ 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 | function clonePath(path) { 78 | return { newPos: path.newPos, components: path.components.slice(0) }; 79 | } 80 | function removeEmpty(array) { 81 | var ret = []; 82 | for (var i = 0; i < array.length; i++) { 83 | if (array[i]) { 84 | ret.push(array[i]); 85 | } 86 | } 87 | return ret; 88 | } 89 | function escapeHTML(s) { 90 | var n = s; 91 | n = n.replace(/&/g, "&"); 92 | n = n.replace(//g, ">"); 94 | n = n.replace(/"/g, """); 95 | 96 | return n; 97 | } 98 | 99 | 100 | var fbDiff = function(ignoreWhitespace) { 101 | this.ignoreWhitespace = ignoreWhitespace; 102 | }; 103 | fbDiff.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; diagonalPath+=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 prior 148 | // path whose position in the new string is the farthest from the origin 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], undefined, 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, diagonalPath); 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[newPos+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.test(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 fbDiff(); 213 | 214 | var WordDiff = new fbDiff(true); 215 | WordDiff.tokenize = function(value) { 216 | return removeEmpty(value.split(/(\s+|\b)/)); 217 | }; 218 | 219 | var CssDiff = new fbDiff(true); 220 | CssDiff.tokenize = function(value) { 221 | return removeEmpty(value.split(/([{}:;,]|\s+)/)); 222 | }; 223 | 224 | var LineDiff = new fbDiff(); 225 | LineDiff.tokenize = function(value) { 226 | return value.split(/^/m); 227 | }; 228 | 229 | return { 230 | diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, 231 | diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, 232 | diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, 233 | 234 | diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, 235 | 236 | createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { 237 | var ret = []; 238 | 239 | ret.push("Index: " + fileName); 240 | ret.push("==================================================================="); 241 | ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader)); 242 | ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader)); 243 | 244 | var diff = LineDiff.diff(oldStr, newStr); 245 | if (!diff[diff.length-1].value) { 246 | diff.pop(); // Remove trailing newline add 247 | } 248 | diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier 249 | 250 | function contextLines(lines) { 251 | return lines.map(function(entry) { return ' ' + entry; }); 252 | } 253 | function eofNL(curRange, i, current) { 254 | var last = diff[diff.length-2], 255 | isLast = i === diff.length-2, 256 | isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed); 257 | 258 | // Figure out if this is the last line for the given file and missing NL 259 | if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { 260 | curRange.push('\\ No newline at end of file'); 261 | } 262 | } 263 | 264 | var oldRangeStart = 0, newRangeStart = 0, curRange = [], 265 | oldLine = 1, newLine = 1; 266 | for (var i = 0; i < diff.length; i++) { 267 | var current = diff[i], 268 | lines = current.lines || current.value.replace(/\n$/, "").split("\n"); 269 | current.lines = lines; 270 | 271 | if (current.added || current.removed) { 272 | if (!oldRangeStart) { 273 | var prev = diff[i-1]; 274 | oldRangeStart = oldLine; 275 | newRangeStart = newLine; 276 | 277 | if (prev) { 278 | curRange = contextLines(prev.lines.slice(-4)); 279 | oldRangeStart -= curRange.length; 280 | newRangeStart -= curRange.length; 281 | } 282 | } 283 | curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; })); 284 | eofNL(curRange, i, current); 285 | 286 | if (current.added) { 287 | newLine += lines.length; 288 | } else { 289 | oldLine += lines.length; 290 | } 291 | } else { 292 | if (oldRangeStart) { 293 | // Close out any changes that have been output (or join overlapping) 294 | if (lines.length <= 8 && i < diff.length-2) { 295 | // Overlapping 296 | curRange.push.apply(curRange, contextLines(lines)); 297 | } else { 298 | // end the range and output 299 | var contextSize = Math.min(lines.length, 4); 300 | ret.push( 301 | "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize) 302 | + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize) 303 | + " @@"); 304 | ret.push.apply(ret, curRange); 305 | ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); 306 | if (lines.length <= 4) { 307 | eofNL(ret, i, current); 308 | } 309 | 310 | oldRangeStart = 0; newRangeStart = 0; curRange = []; 311 | } 312 | } 313 | oldLine += lines.length; 314 | newLine += lines.length; 315 | } 316 | } 317 | 318 | return ret.join('\n') + '\n'; 319 | }, 320 | 321 | convertChangesToXML: function(changes){ 322 | var ret = []; 323 | for ( var i = 0; i < changes.length; i++) { 324 | var change = changes[i]; 325 | if (change.added) { 326 | ret.push(""); 327 | } else if (change.removed) { 328 | ret.push(""); 329 | } 330 | 331 | ret.push(escapeHTML(change.value)); 332 | 333 | if (change.added) { 334 | ret.push(""); 335 | } else if (change.removed) { 336 | ret.push(""); 337 | } 338 | } 339 | return ret.join(""); 340 | } 341 | }; 342 | })(); 343 | 344 | if (typeof module !== "undefined") { 345 | module.exports = JsDiff; 346 | } 347 | 348 | }); // module: browser/diff.js 349 | 350 | require.register("browser/events.js", function(module, exports, require){ 351 | 352 | /** 353 | * Module exports. 354 | */ 355 | 356 | exports.EventEmitter = EventEmitter; 357 | 358 | /** 359 | * Check if `obj` is an array. 360 | */ 361 | 362 | function isArray(obj) { 363 | return '[object Array]' == {}.toString.call(obj); 364 | } 365 | 366 | /** 367 | * Event emitter constructor. 368 | * 369 | * @api public 370 | */ 371 | 372 | function EventEmitter(){}; 373 | 374 | /** 375 | * Adds a listener. 376 | * 377 | * @api public 378 | */ 379 | 380 | EventEmitter.prototype.on = function (name, fn) { 381 | if (!this.$events) { 382 | this.$events = {}; 383 | } 384 | 385 | if (!this.$events[name]) { 386 | this.$events[name] = fn; 387 | } else if (isArray(this.$events[name])) { 388 | this.$events[name].push(fn); 389 | } else { 390 | this.$events[name] = [this.$events[name], fn]; 391 | } 392 | 393 | return this; 394 | }; 395 | 396 | EventEmitter.prototype.addListener = EventEmitter.prototype.on; 397 | 398 | /** 399 | * Adds a volatile listener. 400 | * 401 | * @api public 402 | */ 403 | 404 | EventEmitter.prototype.once = function (name, fn) { 405 | var self = this; 406 | 407 | function on () { 408 | self.removeListener(name, on); 409 | fn.apply(this, arguments); 410 | }; 411 | 412 | on.listener = fn; 413 | this.on(name, on); 414 | 415 | return this; 416 | }; 417 | 418 | /** 419 | * Removes a listener. 420 | * 421 | * @api public 422 | */ 423 | 424 | EventEmitter.prototype.removeListener = function (name, fn) { 425 | if (this.$events && this.$events[name]) { 426 | var list = this.$events[name]; 427 | 428 | if (isArray(list)) { 429 | var pos = -1; 430 | 431 | for (var i = 0, l = list.length; i < l; i++) { 432 | if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { 433 | pos = i; 434 | break; 435 | } 436 | } 437 | 438 | if (pos < 0) { 439 | return this; 440 | } 441 | 442 | list.splice(pos, 1); 443 | 444 | if (!list.length) { 445 | delete this.$events[name]; 446 | } 447 | } else if (list === fn || (list.listener && list.listener === fn)) { 448 | delete this.$events[name]; 449 | } 450 | } 451 | 452 | return this; 453 | }; 454 | 455 | /** 456 | * Removes all listeners for an event. 457 | * 458 | * @api public 459 | */ 460 | 461 | EventEmitter.prototype.removeAllListeners = function (name) { 462 | if (name === undefined) { 463 | this.$events = {}; 464 | return this; 465 | } 466 | 467 | if (this.$events && this.$events[name]) { 468 | this.$events[name] = null; 469 | } 470 | 471 | return this; 472 | }; 473 | 474 | /** 475 | * Gets all listeners for a certain event. 476 | * 477 | * @api public 478 | */ 479 | 480 | EventEmitter.prototype.listeners = function (name) { 481 | if (!this.$events) { 482 | this.$events = {}; 483 | } 484 | 485 | if (!this.$events[name]) { 486 | this.$events[name] = []; 487 | } 488 | 489 | if (!isArray(this.$events[name])) { 490 | this.$events[name] = [this.$events[name]]; 491 | } 492 | 493 | return this.$events[name]; 494 | }; 495 | 496 | /** 497 | * Emits an event. 498 | * 499 | * @api public 500 | */ 501 | 502 | EventEmitter.prototype.emit = function (name) { 503 | if (!this.$events) { 504 | return false; 505 | } 506 | 507 | var handler = this.$events[name]; 508 | 509 | if (!handler) { 510 | return false; 511 | } 512 | 513 | var args = [].slice.call(arguments, 1); 514 | 515 | if ('function' == typeof handler) { 516 | handler.apply(this, args); 517 | } else if (isArray(handler)) { 518 | var listeners = handler.slice(); 519 | 520 | for (var i = 0, l = listeners.length; i < l; i++) { 521 | listeners[i].apply(this, args); 522 | } 523 | } else { 524 | return false; 525 | } 526 | 527 | return true; 528 | }; 529 | }); // module: browser/events.js 530 | 531 | require.register("browser/fs.js", function(module, exports, require){ 532 | 533 | }); // module: browser/fs.js 534 | 535 | require.register("browser/path.js", function(module, exports, require){ 536 | 537 | }); // module: browser/path.js 538 | 539 | require.register("browser/progress.js", function(module, exports, require){ 540 | 541 | /** 542 | * Expose `Progress`. 543 | */ 544 | 545 | module.exports = Progress; 546 | 547 | /** 548 | * Initialize a new `Progress` indicator. 549 | */ 550 | 551 | function Progress() { 552 | this.percent = 0; 553 | this.size(0); 554 | this.fontSize(11); 555 | this.font('helvetica, arial, sans-serif'); 556 | } 557 | 558 | /** 559 | * Set progress size to `n`. 560 | * 561 | * @param {Number} n 562 | * @return {Progress} for chaining 563 | * @api public 564 | */ 565 | 566 | Progress.prototype.size = function(n){ 567 | this._size = n; 568 | return this; 569 | }; 570 | 571 | /** 572 | * Set text to `str`. 573 | * 574 | * @param {String} str 575 | * @return {Progress} for chaining 576 | * @api public 577 | */ 578 | 579 | Progress.prototype.text = function(str){ 580 | this._text = str; 581 | return this; 582 | }; 583 | 584 | /** 585 | * Set font size to `n`. 586 | * 587 | * @param {Number} n 588 | * @return {Progress} for chaining 589 | * @api public 590 | */ 591 | 592 | Progress.prototype.fontSize = function(n){ 593 | this._fontSize = n; 594 | return this; 595 | }; 596 | 597 | /** 598 | * Set font `family`. 599 | * 600 | * @param {String} family 601 | * @return {Progress} for chaining 602 | */ 603 | 604 | Progress.prototype.font = function(family){ 605 | this._font = family; 606 | return this; 607 | }; 608 | 609 | /** 610 | * Update percentage to `n`. 611 | * 612 | * @param {Number} n 613 | * @return {Progress} for chaining 614 | */ 615 | 616 | Progress.prototype.update = function(n){ 617 | this.percent = n; 618 | return this; 619 | }; 620 | 621 | /** 622 | * Draw on `ctx`. 623 | * 624 | * @param {CanvasRenderingContext2d} ctx 625 | * @return {Progress} for chaining 626 | */ 627 | 628 | Progress.prototype.draw = function(ctx){ 629 | var percent = Math.min(this.percent, 100) 630 | , size = this._size 631 | , half = size / 2 632 | , x = half 633 | , y = half 634 | , rad = half - 1 635 | , fontSize = this._fontSize; 636 | 637 | ctx.font = fontSize + 'px ' + this._font; 638 | 639 | var angle = Math.PI * 2 * (percent / 100); 640 | ctx.clearRect(0, 0, size, size); 641 | 642 | // outer circle 643 | ctx.strokeStyle = '#9f9f9f'; 644 | ctx.beginPath(); 645 | ctx.arc(x, y, rad, 0, angle, false); 646 | ctx.stroke(); 647 | 648 | // inner circle 649 | ctx.strokeStyle = '#eee'; 650 | ctx.beginPath(); 651 | ctx.arc(x, y, rad - 1, 0, angle, true); 652 | ctx.stroke(); 653 | 654 | // text 655 | var text = this._text || (percent | 0) + '%' 656 | , w = ctx.measureText(text).width; 657 | 658 | ctx.fillText( 659 | text 660 | , x - w / 2 + 1 661 | , y + fontSize / 2 - 1); 662 | 663 | return this; 664 | }; 665 | 666 | }); // module: browser/progress.js 667 | 668 | require.register("browser/tty.js", function(module, exports, require){ 669 | 670 | exports.isatty = function(){ 671 | return true; 672 | }; 673 | 674 | exports.getWindowSize = function(){ 675 | if ('innerHeight' in global) { 676 | return [global.innerHeight, global.innerWidth]; 677 | } else { 678 | // In a Web Worker, the DOM Window is not available. 679 | return [640, 480]; 680 | } 681 | }; 682 | 683 | }); // module: browser/tty.js 684 | 685 | require.register("context.js", function(module, exports, require){ 686 | 687 | /** 688 | * Expose `Context`. 689 | */ 690 | 691 | module.exports = Context; 692 | 693 | /** 694 | * Initialize a new `Context`. 695 | * 696 | * @api private 697 | */ 698 | 699 | function Context(){} 700 | 701 | /** 702 | * Set or get the context `Runnable` to `runnable`. 703 | * 704 | * @param {Runnable} runnable 705 | * @return {Context} 706 | * @api private 707 | */ 708 | 709 | Context.prototype.runnable = function(runnable){ 710 | if (0 == arguments.length) return this._runnable; 711 | this.test = this._runnable = runnable; 712 | return this; 713 | }; 714 | 715 | /** 716 | * Set test timeout `ms`. 717 | * 718 | * @param {Number} ms 719 | * @return {Context} self 720 | * @api private 721 | */ 722 | 723 | Context.prototype.timeout = function(ms){ 724 | this.runnable().timeout(ms); 725 | return this; 726 | }; 727 | 728 | /** 729 | * Set test slowness threshold `ms`. 730 | * 731 | * @param {Number} ms 732 | * @return {Context} self 733 | * @api private 734 | */ 735 | 736 | Context.prototype.slow = function(ms){ 737 | this.runnable().slow(ms); 738 | return this; 739 | }; 740 | 741 | /** 742 | * Inspect the context void of `._runnable`. 743 | * 744 | * @return {String} 745 | * @api private 746 | */ 747 | 748 | Context.prototype.inspect = function(){ 749 | return JSON.stringify(this, function(key, val){ 750 | if ('_runnable' == key) return; 751 | if ('test' == key) return; 752 | return val; 753 | }, 2); 754 | }; 755 | 756 | }); // module: context.js 757 | 758 | require.register("hook.js", function(module, exports, require){ 759 | 760 | /** 761 | * Module dependencies. 762 | */ 763 | 764 | var Runnable = require('./runnable'); 765 | 766 | /** 767 | * Expose `Hook`. 768 | */ 769 | 770 | module.exports = Hook; 771 | 772 | /** 773 | * Initialize a new `Hook` with the given `title` and callback `fn`. 774 | * 775 | * @param {String} title 776 | * @param {Function} fn 777 | * @api private 778 | */ 779 | 780 | function Hook(title, fn) { 781 | Runnable.call(this, title, fn); 782 | this.type = 'hook'; 783 | } 784 | 785 | /** 786 | * Inherit from `Runnable.prototype`. 787 | */ 788 | 789 | function F(){}; 790 | F.prototype = Runnable.prototype; 791 | Hook.prototype = new F; 792 | Hook.prototype.constructor = Hook; 793 | 794 | 795 | /** 796 | * Get or set the test `err`. 797 | * 798 | * @param {Error} err 799 | * @return {Error} 800 | * @api public 801 | */ 802 | 803 | Hook.prototype.error = function(err){ 804 | if (0 == arguments.length) { 805 | var err = this._error; 806 | this._error = null; 807 | return err; 808 | } 809 | 810 | this._error = err; 811 | }; 812 | 813 | }); // module: hook.js 814 | 815 | require.register("interfaces/bdd.js", function(module, exports, require){ 816 | 817 | /** 818 | * Module dependencies. 819 | */ 820 | 821 | var Suite = require('../suite') 822 | , Test = require('../test'); 823 | 824 | /** 825 | * BDD-style interface: 826 | * 827 | * describe('Array', function(){ 828 | * describe('#indexOf()', function(){ 829 | * it('should return -1 when not present', function(){ 830 | * 831 | * }); 832 | * 833 | * it('should return the index when present', function(){ 834 | * 835 | * }); 836 | * }); 837 | * }); 838 | * 839 | */ 840 | 841 | module.exports = function(suite){ 842 | var suites = [suite]; 843 | 844 | suite.on('pre-require', function(context, file, mocha){ 845 | 846 | /** 847 | * Execute before running tests. 848 | */ 849 | 850 | context.before = function(fn){ 851 | suites[0].beforeAll(fn); 852 | }; 853 | 854 | /** 855 | * Execute after running tests. 856 | */ 857 | 858 | context.after = function(fn){ 859 | suites[0].afterAll(fn); 860 | }; 861 | 862 | /** 863 | * Execute before each test case. 864 | */ 865 | 866 | context.beforeEach = function(fn){ 867 | suites[0].beforeEach(fn); 868 | }; 869 | 870 | /** 871 | * Execute after each test case. 872 | */ 873 | 874 | context.afterEach = function(fn){ 875 | suites[0].afterEach(fn); 876 | }; 877 | 878 | /** 879 | * Describe a "suite" with the given `title` 880 | * and callback `fn` containing nested suites 881 | * and/or tests. 882 | */ 883 | 884 | context.describe = context.context = function(title, fn){ 885 | var suite = Suite.create(suites[0], title); 886 | suites.unshift(suite); 887 | fn.call(suite); 888 | suites.shift(); 889 | return suite; 890 | }; 891 | 892 | /** 893 | * Pending describe. 894 | */ 895 | 896 | context.xdescribe = 897 | context.xcontext = 898 | context.describe.skip = function(title, fn){ 899 | var suite = Suite.create(suites[0], title); 900 | suite.pending = true; 901 | suites.unshift(suite); 902 | fn.call(suite); 903 | suites.shift(); 904 | }; 905 | 906 | /** 907 | * Exclusive suite. 908 | */ 909 | 910 | context.describe.only = function(title, fn){ 911 | var suite = context.describe(title, fn); 912 | mocha.grep(suite.fullTitle()); 913 | }; 914 | 915 | /** 916 | * Describe a specification or test-case 917 | * with the given `title` and callback `fn` 918 | * acting as a thunk. 919 | */ 920 | 921 | context.it = context.specify = function(title, fn){ 922 | var suite = suites[0]; 923 | if (suite.pending) var fn = null; 924 | var test = new Test(title, fn); 925 | suite.addTest(test); 926 | return test; 927 | }; 928 | 929 | /** 930 | * Exclusive test-case. 931 | */ 932 | 933 | context.it.only = function(title, fn){ 934 | var test = context.it(title, fn); 935 | mocha.grep(test.fullTitle()); 936 | }; 937 | 938 | /** 939 | * Pending test case. 940 | */ 941 | 942 | context.xit = 943 | context.xspecify = 944 | context.it.skip = function(title){ 945 | context.it(title); 946 | }; 947 | }); 948 | }; 949 | 950 | }); // module: interfaces/bdd.js 951 | 952 | require.register("interfaces/exports.js", function(module, exports, require){ 953 | 954 | /** 955 | * Module dependencies. 956 | */ 957 | 958 | var Suite = require('../suite') 959 | , Test = require('../test'); 960 | 961 | /** 962 | * TDD-style interface: 963 | * 964 | * exports.Array = { 965 | * '#indexOf()': { 966 | * 'should return -1 when the value is not present': function(){ 967 | * 968 | * }, 969 | * 970 | * 'should return the correct index when the value is present': function(){ 971 | * 972 | * } 973 | * } 974 | * }; 975 | * 976 | */ 977 | 978 | module.exports = function(suite){ 979 | var suites = [suite]; 980 | 981 | suite.on('require', visit); 982 | 983 | function visit(obj) { 984 | var suite; 985 | for (var key in obj) { 986 | if ('function' == typeof obj[key]) { 987 | var fn = obj[key]; 988 | switch (key) { 989 | case 'before': 990 | suites[0].beforeAll(fn); 991 | break; 992 | case 'after': 993 | suites[0].afterAll(fn); 994 | break; 995 | case 'beforeEach': 996 | suites[0].beforeEach(fn); 997 | break; 998 | case 'afterEach': 999 | suites[0].afterEach(fn); 1000 | break; 1001 | default: 1002 | suites[0].addTest(new Test(key, fn)); 1003 | } 1004 | } else { 1005 | var suite = Suite.create(suites[0], key); 1006 | suites.unshift(suite); 1007 | visit(obj[key]); 1008 | suites.shift(); 1009 | } 1010 | } 1011 | } 1012 | }; 1013 | 1014 | }); // module: interfaces/exports.js 1015 | 1016 | require.register("interfaces/index.js", function(module, exports, require){ 1017 | 1018 | exports.bdd = require('./bdd'); 1019 | exports.tdd = require('./tdd'); 1020 | exports.qunit = require('./qunit'); 1021 | exports.exports = require('./exports'); 1022 | 1023 | }); // module: interfaces/index.js 1024 | 1025 | require.register("interfaces/qunit.js", function(module, exports, require){ 1026 | 1027 | /** 1028 | * Module dependencies. 1029 | */ 1030 | 1031 | var Suite = require('../suite') 1032 | , Test = require('../test'); 1033 | 1034 | /** 1035 | * QUnit-style interface: 1036 | * 1037 | * suite('Array'); 1038 | * 1039 | * test('#length', function(){ 1040 | * var arr = [1,2,3]; 1041 | * ok(arr.length == 3); 1042 | * }); 1043 | * 1044 | * test('#indexOf()', function(){ 1045 | * var arr = [1,2,3]; 1046 | * ok(arr.indexOf(1) == 0); 1047 | * ok(arr.indexOf(2) == 1); 1048 | * ok(arr.indexOf(3) == 2); 1049 | * }); 1050 | * 1051 | * suite('String'); 1052 | * 1053 | * test('#length', function(){ 1054 | * ok('foo'.length == 3); 1055 | * }); 1056 | * 1057 | */ 1058 | 1059 | module.exports = function(suite){ 1060 | var suites = [suite]; 1061 | 1062 | suite.on('pre-require', function(context, file, mocha){ 1063 | 1064 | /** 1065 | * Execute before running tests. 1066 | */ 1067 | 1068 | context.before = function(fn){ 1069 | suites[0].beforeAll(fn); 1070 | }; 1071 | 1072 | /** 1073 | * Execute after running tests. 1074 | */ 1075 | 1076 | context.after = function(fn){ 1077 | suites[0].afterAll(fn); 1078 | }; 1079 | 1080 | /** 1081 | * Execute before each test case. 1082 | */ 1083 | 1084 | context.beforeEach = function(fn){ 1085 | suites[0].beforeEach(fn); 1086 | }; 1087 | 1088 | /** 1089 | * Execute after each test case. 1090 | */ 1091 | 1092 | context.afterEach = function(fn){ 1093 | suites[0].afterEach(fn); 1094 | }; 1095 | 1096 | /** 1097 | * Describe a "suite" with the given `title`. 1098 | */ 1099 | 1100 | context.suite = function(title){ 1101 | if (suites.length > 1) suites.shift(); 1102 | var suite = Suite.create(suites[0], title); 1103 | suites.unshift(suite); 1104 | return suite; 1105 | }; 1106 | 1107 | /** 1108 | * Exclusive test-case. 1109 | */ 1110 | 1111 | context.suite.only = function(title, fn){ 1112 | var suite = context.suite(title, fn); 1113 | mocha.grep(suite.fullTitle()); 1114 | }; 1115 | 1116 | /** 1117 | * Describe a specification or test-case 1118 | * with the given `title` and callback `fn` 1119 | * acting as a thunk. 1120 | */ 1121 | 1122 | context.test = function(title, fn){ 1123 | var test = new Test(title, fn); 1124 | suites[0].addTest(test); 1125 | return test; 1126 | }; 1127 | 1128 | /** 1129 | * Exclusive test-case. 1130 | */ 1131 | 1132 | context.test.only = function(title, fn){ 1133 | var test = context.test(title, fn); 1134 | mocha.grep(test.fullTitle()); 1135 | }; 1136 | 1137 | /** 1138 | * Pending test case. 1139 | */ 1140 | 1141 | context.test.skip = function(title){ 1142 | context.test(title); 1143 | }; 1144 | }); 1145 | }; 1146 | 1147 | }); // module: interfaces/qunit.js 1148 | 1149 | require.register("interfaces/tdd.js", function(module, exports, require){ 1150 | 1151 | /** 1152 | * Module dependencies. 1153 | */ 1154 | 1155 | var Suite = require('../suite') 1156 | , Test = require('../test'); 1157 | 1158 | /** 1159 | * TDD-style interface: 1160 | * 1161 | * suite('Array', function(){ 1162 | * suite('#indexOf()', function(){ 1163 | * suiteSetup(function(){ 1164 | * 1165 | * }); 1166 | * 1167 | * test('should return -1 when not present', function(){ 1168 | * 1169 | * }); 1170 | * 1171 | * test('should return the index when present', function(){ 1172 | * 1173 | * }); 1174 | * 1175 | * suiteTeardown(function(){ 1176 | * 1177 | * }); 1178 | * }); 1179 | * }); 1180 | * 1181 | */ 1182 | 1183 | module.exports = function(suite){ 1184 | var suites = [suite]; 1185 | 1186 | suite.on('pre-require', function(context, file, mocha){ 1187 | 1188 | /** 1189 | * Execute before each test case. 1190 | */ 1191 | 1192 | context.setup = function(fn){ 1193 | suites[0].beforeEach(fn); 1194 | }; 1195 | 1196 | /** 1197 | * Execute after each test case. 1198 | */ 1199 | 1200 | context.teardown = function(fn){ 1201 | suites[0].afterEach(fn); 1202 | }; 1203 | 1204 | /** 1205 | * Execute before the suite. 1206 | */ 1207 | 1208 | context.suiteSetup = function(fn){ 1209 | suites[0].beforeAll(fn); 1210 | }; 1211 | 1212 | /** 1213 | * Execute after the suite. 1214 | */ 1215 | 1216 | context.suiteTeardown = function(fn){ 1217 | suites[0].afterAll(fn); 1218 | }; 1219 | 1220 | /** 1221 | * Describe a "suite" with the given `title` 1222 | * and callback `fn` containing nested suites 1223 | * and/or tests. 1224 | */ 1225 | 1226 | context.suite = function(title, fn){ 1227 | var suite = Suite.create(suites[0], title); 1228 | suites.unshift(suite); 1229 | fn.call(suite); 1230 | suites.shift(); 1231 | return suite; 1232 | }; 1233 | 1234 | /** 1235 | * Pending suite. 1236 | */ 1237 | context.suite.skip = function(title, fn) { 1238 | var suite = Suite.create(suites[0], title); 1239 | suite.pending = true; 1240 | suites.unshift(suite); 1241 | fn.call(suite); 1242 | suites.shift(); 1243 | }; 1244 | 1245 | /** 1246 | * Exclusive test-case. 1247 | */ 1248 | 1249 | context.suite.only = function(title, fn){ 1250 | var suite = context.suite(title, fn); 1251 | mocha.grep(suite.fullTitle()); 1252 | }; 1253 | 1254 | /** 1255 | * Describe a specification or test-case 1256 | * with the given `title` and callback `fn` 1257 | * acting as a thunk. 1258 | */ 1259 | 1260 | context.test = function(title, fn){ 1261 | var suite = suites[0]; 1262 | if (suite.pending) var fn = null; 1263 | var test = new Test(title, fn); 1264 | suite.addTest(test); 1265 | return test; 1266 | }; 1267 | 1268 | /** 1269 | * Exclusive test-case. 1270 | */ 1271 | 1272 | context.test.only = function(title, fn){ 1273 | var test = context.test(title, fn); 1274 | mocha.grep(test.fullTitle()); 1275 | }; 1276 | 1277 | /** 1278 | * Pending test case. 1279 | */ 1280 | 1281 | context.test.skip = function(title){ 1282 | context.test(title); 1283 | }; 1284 | }); 1285 | }; 1286 | 1287 | }); // module: interfaces/tdd.js 1288 | 1289 | require.register("mocha.js", function(module, exports, require){ 1290 | /*! 1291 | * mocha 1292 | * Copyright(c) 2011 TJ Holowaychuk 1293 | * MIT Licensed 1294 | */ 1295 | 1296 | /** 1297 | * Module dependencies. 1298 | */ 1299 | 1300 | var path = require('browser/path') 1301 | , utils = require('./utils'); 1302 | 1303 | /** 1304 | * Expose `Mocha`. 1305 | */ 1306 | 1307 | exports = module.exports = Mocha; 1308 | 1309 | /** 1310 | * Expose internals. 1311 | */ 1312 | 1313 | exports.utils = utils; 1314 | exports.interfaces = require('./interfaces'); 1315 | exports.reporters = require('./reporters'); 1316 | exports.Runnable = require('./runnable'); 1317 | exports.Context = require('./context'); 1318 | exports.Runner = require('./runner'); 1319 | exports.Suite = require('./suite'); 1320 | exports.Hook = require('./hook'); 1321 | exports.Test = require('./test'); 1322 | 1323 | /** 1324 | * Return image `name` path. 1325 | * 1326 | * @param {String} name 1327 | * @return {String} 1328 | * @api private 1329 | */ 1330 | 1331 | function image(name) { 1332 | return __dirname + '/../images/' + name + '.png'; 1333 | } 1334 | 1335 | /** 1336 | * Setup mocha with `options`. 1337 | * 1338 | * Options: 1339 | * 1340 | * - `ui` name "bdd", "tdd", "exports" etc 1341 | * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` 1342 | * - `globals` array of accepted globals 1343 | * - `timeout` timeout in milliseconds 1344 | * - `bail` bail on the first test failure 1345 | * - `slow` milliseconds to wait before considering a test slow 1346 | * - `ignoreLeaks` ignore global leaks 1347 | * - `grep` string or regexp to filter tests with 1348 | * 1349 | * @param {Object} options 1350 | * @api public 1351 | */ 1352 | 1353 | function Mocha(options) { 1354 | options = options || {}; 1355 | this.files = []; 1356 | this.options = options; 1357 | this.grep(options.grep); 1358 | this.suite = new exports.Suite('', new exports.Context); 1359 | this.ui(options.ui); 1360 | this.bail(options.bail); 1361 | this.reporter(options.reporter); 1362 | if (options.timeout) this.timeout(options.timeout); 1363 | if (options.slow) this.slow(options.slow); 1364 | } 1365 | 1366 | /** 1367 | * Enable or disable bailing on the first failure. 1368 | * 1369 | * @param {Boolean} [bail] 1370 | * @api public 1371 | */ 1372 | 1373 | Mocha.prototype.bail = function(bail){ 1374 | if (0 == arguments.length) bail = true; 1375 | this.suite.bail(bail); 1376 | return this; 1377 | }; 1378 | 1379 | /** 1380 | * Add test `file`. 1381 | * 1382 | * @param {String} file 1383 | * @api public 1384 | */ 1385 | 1386 | Mocha.prototype.addFile = function(file){ 1387 | this.files.push(file); 1388 | return this; 1389 | }; 1390 | 1391 | /** 1392 | * Set reporter to `reporter`, defaults to "dot". 1393 | * 1394 | * @param {String|Function} reporter name or constructor 1395 | * @api public 1396 | */ 1397 | 1398 | Mocha.prototype.reporter = function(reporter){ 1399 | if ('function' == typeof reporter) { 1400 | this._reporter = reporter; 1401 | } else { 1402 | reporter = reporter || 'dot'; 1403 | try { 1404 | this._reporter = require('./reporters/' + reporter); 1405 | } catch (err) { 1406 | this._reporter = require(reporter); 1407 | } 1408 | if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"'); 1409 | } 1410 | return this; 1411 | }; 1412 | 1413 | /** 1414 | * Set test UI `name`, defaults to "bdd". 1415 | * 1416 | * @param {String} bdd 1417 | * @api public 1418 | */ 1419 | 1420 | Mocha.prototype.ui = function(name){ 1421 | name = name || 'bdd'; 1422 | this._ui = exports.interfaces[name]; 1423 | if (!this._ui) throw new Error('invalid interface "' + name + '"'); 1424 | this._ui = this._ui(this.suite); 1425 | return this; 1426 | }; 1427 | 1428 | /** 1429 | * Load registered files. 1430 | * 1431 | * @api private 1432 | */ 1433 | 1434 | Mocha.prototype.loadFiles = function(fn){ 1435 | var self = this; 1436 | var suite = this.suite; 1437 | var pending = this.files.length; 1438 | this.files.forEach(function(file){ 1439 | file = path.resolve(file); 1440 | suite.emit('pre-require', global, file, self); 1441 | suite.emit('require', require(file), file, self); 1442 | suite.emit('post-require', global, file, self); 1443 | --pending || (fn && fn()); 1444 | }); 1445 | }; 1446 | 1447 | /** 1448 | * Enable growl support. 1449 | * 1450 | * @api private 1451 | */ 1452 | 1453 | Mocha.prototype._growl = function(runner, reporter) { 1454 | var notify = require('growl'); 1455 | 1456 | runner.on('end', function(){ 1457 | var stats = reporter.stats; 1458 | if (stats.failures) { 1459 | var msg = stats.failures + ' of ' + runner.total + ' tests failed'; 1460 | notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); 1461 | } else { 1462 | notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { 1463 | name: 'mocha' 1464 | , title: 'Passed' 1465 | , image: image('ok') 1466 | }); 1467 | } 1468 | }); 1469 | }; 1470 | 1471 | /** 1472 | * Add regexp to grep, if `re` is a string it is escaped. 1473 | * 1474 | * @param {RegExp|String} re 1475 | * @return {Mocha} 1476 | * @api public 1477 | */ 1478 | 1479 | Mocha.prototype.grep = function(re){ 1480 | this.options.grep = 'string' == typeof re 1481 | ? new RegExp(utils.escapeRegexp(re)) 1482 | : re; 1483 | return this; 1484 | }; 1485 | 1486 | /** 1487 | * Invert `.grep()` matches. 1488 | * 1489 | * @return {Mocha} 1490 | * @api public 1491 | */ 1492 | 1493 | Mocha.prototype.invert = function(){ 1494 | this.options.invert = true; 1495 | return this; 1496 | }; 1497 | 1498 | /** 1499 | * Ignore global leaks. 1500 | * 1501 | * @param {Boolean} ignore 1502 | * @return {Mocha} 1503 | * @api public 1504 | */ 1505 | 1506 | Mocha.prototype.ignoreLeaks = function(ignore){ 1507 | this.options.ignoreLeaks = !!ignore; 1508 | return this; 1509 | }; 1510 | 1511 | /** 1512 | * Enable global leak checking. 1513 | * 1514 | * @return {Mocha} 1515 | * @api public 1516 | */ 1517 | 1518 | Mocha.prototype.checkLeaks = function(){ 1519 | this.options.ignoreLeaks = false; 1520 | return this; 1521 | }; 1522 | 1523 | /** 1524 | * Enable growl support. 1525 | * 1526 | * @return {Mocha} 1527 | * @api public 1528 | */ 1529 | 1530 | Mocha.prototype.growl = function(){ 1531 | this.options.growl = true; 1532 | return this; 1533 | }; 1534 | 1535 | /** 1536 | * Ignore `globals` array or string. 1537 | * 1538 | * @param {Array|String} globals 1539 | * @return {Mocha} 1540 | * @api public 1541 | */ 1542 | 1543 | Mocha.prototype.globals = function(globals){ 1544 | this.options.globals = (this.options.globals || []).concat(globals); 1545 | return this; 1546 | }; 1547 | 1548 | /** 1549 | * Set the timeout in milliseconds. 1550 | * 1551 | * @param {Number} timeout 1552 | * @return {Mocha} 1553 | * @api public 1554 | */ 1555 | 1556 | Mocha.prototype.timeout = function(timeout){ 1557 | this.suite.timeout(timeout); 1558 | return this; 1559 | }; 1560 | 1561 | /** 1562 | * Set slowness threshold in milliseconds. 1563 | * 1564 | * @param {Number} slow 1565 | * @return {Mocha} 1566 | * @api public 1567 | */ 1568 | 1569 | Mocha.prototype.slow = function(slow){ 1570 | this.suite.slow(slow); 1571 | return this; 1572 | }; 1573 | 1574 | /** 1575 | * Makes all tests async (accepting a callback) 1576 | * 1577 | * @return {Mocha} 1578 | * @api public 1579 | */ 1580 | 1581 | Mocha.prototype.asyncOnly = function(){ 1582 | this.options.asyncOnly = true; 1583 | return this; 1584 | }; 1585 | 1586 | /** 1587 | * Run tests and invoke `fn()` when complete. 1588 | * 1589 | * @param {Function} fn 1590 | * @return {Runner} 1591 | * @api public 1592 | */ 1593 | 1594 | Mocha.prototype.run = function(fn){ 1595 | if (this.files.length) this.loadFiles(); 1596 | var suite = this.suite; 1597 | var options = this.options; 1598 | var runner = new exports.Runner(suite); 1599 | var reporter = new this._reporter(runner); 1600 | runner.ignoreLeaks = false !== options.ignoreLeaks; 1601 | runner.asyncOnly = options.asyncOnly; 1602 | if (options.grep) runner.grep(options.grep, options.invert); 1603 | if (options.globals) runner.globals(options.globals); 1604 | if (options.growl) this._growl(runner, reporter); 1605 | return runner.run(fn); 1606 | }; 1607 | 1608 | }); // module: mocha.js 1609 | 1610 | require.register("ms.js", function(module, exports, require){ 1611 | 1612 | /** 1613 | * Helpers. 1614 | */ 1615 | 1616 | var s = 1000; 1617 | var m = s * 60; 1618 | var h = m * 60; 1619 | var d = h * 24; 1620 | 1621 | /** 1622 | * Parse or format the given `val`. 1623 | * 1624 | * @param {String|Number} val 1625 | * @return {String|Number} 1626 | * @api public 1627 | */ 1628 | 1629 | module.exports = function(val){ 1630 | if ('string' == typeof val) return parse(val); 1631 | return format(val); 1632 | } 1633 | 1634 | /** 1635 | * Parse the given `str` and return milliseconds. 1636 | * 1637 | * @param {String} str 1638 | * @return {Number} 1639 | * @api private 1640 | */ 1641 | 1642 | function parse(str) { 1643 | var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); 1644 | if (!m) return; 1645 | var n = parseFloat(m[1]); 1646 | var type = (m[2] || 'ms').toLowerCase(); 1647 | switch (type) { 1648 | case 'years': 1649 | case 'year': 1650 | case 'y': 1651 | return n * 31557600000; 1652 | case 'days': 1653 | case 'day': 1654 | case 'd': 1655 | return n * 86400000; 1656 | case 'hours': 1657 | case 'hour': 1658 | case 'h': 1659 | return n * 3600000; 1660 | case 'minutes': 1661 | case 'minute': 1662 | case 'm': 1663 | return n * 60000; 1664 | case 'seconds': 1665 | case 'second': 1666 | case 's': 1667 | return n * 1000; 1668 | case 'ms': 1669 | return n; 1670 | } 1671 | } 1672 | 1673 | /** 1674 | * Format the given `ms`. 1675 | * 1676 | * @param {Number} ms 1677 | * @return {String} 1678 | * @api public 1679 | */ 1680 | 1681 | function format(ms) { 1682 | if (ms == d) return Math.round(ms / d) + ' day'; 1683 | if (ms > d) return Math.round(ms / d) + ' days'; 1684 | if (ms == h) return Math.round(ms / h) + ' hour'; 1685 | if (ms > h) return Math.round(ms / h) + ' hours'; 1686 | if (ms == m) return Math.round(ms / m) + ' minute'; 1687 | if (ms > m) return Math.round(ms / m) + ' minutes'; 1688 | if (ms == s) return Math.round(ms / s) + ' second'; 1689 | if (ms > s) return Math.round(ms / s) + ' seconds'; 1690 | return ms + ' ms'; 1691 | } 1692 | }); // module: ms.js 1693 | 1694 | require.register("reporters/base.js", function(module, exports, require){ 1695 | 1696 | /** 1697 | * Module dependencies. 1698 | */ 1699 | 1700 | var tty = require('browser/tty') 1701 | , diff = require('browser/diff') 1702 | , ms = require('../ms'); 1703 | 1704 | /** 1705 | * Save timer references to avoid Sinon interfering (see GH-237). 1706 | */ 1707 | 1708 | var Date = global.Date 1709 | , setTimeout = global.setTimeout 1710 | , setInterval = global.setInterval 1711 | , clearTimeout = global.clearTimeout 1712 | , clearInterval = global.clearInterval; 1713 | 1714 | /** 1715 | * Check if both stdio streams are associated with a tty. 1716 | */ 1717 | 1718 | var isatty = tty.isatty(1) && tty.isatty(2); 1719 | 1720 | /** 1721 | * Expose `Base`. 1722 | */ 1723 | 1724 | exports = module.exports = Base; 1725 | 1726 | /** 1727 | * Enable coloring by default. 1728 | */ 1729 | 1730 | exports.useColors = isatty; 1731 | 1732 | /** 1733 | * Default color map. 1734 | */ 1735 | 1736 | exports.colors = { 1737 | 'pass': 90 1738 | , 'fail': 31 1739 | , 'bright pass': 92 1740 | , 'bright fail': 91 1741 | , 'bright yellow': 93 1742 | , 'pending': 36 1743 | , 'suite': 0 1744 | , 'error title': 0 1745 | , 'error message': 31 1746 | , 'error stack': 90 1747 | , 'checkmark': 32 1748 | , 'fast': 90 1749 | , 'medium': 33 1750 | , 'slow': 31 1751 | , 'green': 32 1752 | , 'light': 90 1753 | , 'diff gutter': 90 1754 | , 'diff added': 42 1755 | , 'diff removed': 41 1756 | }; 1757 | 1758 | /** 1759 | * Default symbol map. 1760 | */ 1761 | 1762 | exports.symbols = { 1763 | ok: '✓', 1764 | err: '✖', 1765 | dot: '․' 1766 | }; 1767 | 1768 | // With node.js on Windows: use symbols available in terminal default fonts 1769 | if ('win32' == process.platform) { 1770 | exports.symbols.ok = '\u221A'; 1771 | exports.symbols.err = '\u00D7'; 1772 | exports.symbols.dot = '.'; 1773 | } 1774 | 1775 | /** 1776 | * Color `str` with the given `type`, 1777 | * allowing colors to be disabled, 1778 | * as well as user-defined color 1779 | * schemes. 1780 | * 1781 | * @param {String} type 1782 | * @param {String} str 1783 | * @return {String} 1784 | * @api private 1785 | */ 1786 | 1787 | var color = exports.color = function(type, str) { 1788 | if (!exports.useColors) return str; 1789 | return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; 1790 | }; 1791 | 1792 | /** 1793 | * Expose term window size, with some 1794 | * defaults for when stderr is not a tty. 1795 | */ 1796 | 1797 | exports.window = { 1798 | width: isatty 1799 | ? process.stdout.getWindowSize 1800 | ? process.stdout.getWindowSize(1)[0] 1801 | : tty.getWindowSize()[1] 1802 | : 75 1803 | }; 1804 | 1805 | /** 1806 | * Expose some basic cursor interactions 1807 | * that are common among reporters. 1808 | */ 1809 | 1810 | exports.cursor = { 1811 | hide: function(){ 1812 | process.stdout.write('\u001b[?25l'); 1813 | }, 1814 | 1815 | show: function(){ 1816 | process.stdout.write('\u001b[?25h'); 1817 | }, 1818 | 1819 | deleteLine: function(){ 1820 | process.stdout.write('\u001b[2K'); 1821 | }, 1822 | 1823 | beginningOfLine: function(){ 1824 | process.stdout.write('\u001b[0G'); 1825 | }, 1826 | 1827 | CR: function(){ 1828 | exports.cursor.deleteLine(); 1829 | exports.cursor.beginningOfLine(); 1830 | } 1831 | }; 1832 | 1833 | /** 1834 | * Outut the given `failures` as a list. 1835 | * 1836 | * @param {Array} failures 1837 | * @api public 1838 | */ 1839 | 1840 | exports.list = function(failures){ 1841 | console.error(); 1842 | failures.forEach(function(test, i){ 1843 | // format 1844 | var fmt = color('error title', ' %s) %s:\n') 1845 | + color('error message', ' %s') 1846 | + color('error stack', '\n%s\n'); 1847 | 1848 | // msg 1849 | var err = test.err 1850 | , message = err.message || '' 1851 | , stack = err.stack || message 1852 | , index = stack.indexOf(message) + message.length 1853 | , msg = stack.slice(0, index) 1854 | , actual = err.actual 1855 | , expected = err.expected 1856 | , escape = true; 1857 | 1858 | // uncaught 1859 | if (err.uncaught) { 1860 | msg = 'Uncaught ' + msg; 1861 | } 1862 | 1863 | // explicitly show diff 1864 | if (err.showDiff && sameType(actual, expected)) { 1865 | escape = false; 1866 | err.actual = actual = stringify(actual); 1867 | err.expected = expected = stringify(expected); 1868 | } 1869 | 1870 | // actual / expected diff 1871 | if ('string' == typeof actual && 'string' == typeof expected) { 1872 | msg = errorDiff(err, 'Words', escape); 1873 | 1874 | // linenos 1875 | var lines = msg.split('\n'); 1876 | if (lines.length > 4) { 1877 | var width = String(lines.length).length; 1878 | msg = lines.map(function(str, i){ 1879 | return pad(++i, width) + ' |' + ' ' + str; 1880 | }).join('\n'); 1881 | } 1882 | 1883 | // legend 1884 | msg = '\n' 1885 | + color('diff removed', 'actual') 1886 | + ' ' 1887 | + color('diff added', 'expected') 1888 | + '\n\n' 1889 | + msg 1890 | + '\n'; 1891 | 1892 | // indent 1893 | msg = msg.replace(/^/gm, ' '); 1894 | 1895 | fmt = color('error title', ' %s) %s:\n%s') 1896 | + color('error stack', '\n%s\n'); 1897 | } 1898 | 1899 | // indent stack trace without msg 1900 | stack = stack.slice(index ? index + 1 : index) 1901 | .replace(/^/gm, ' '); 1902 | 1903 | console.error(fmt, (i + 1), test.fullTitle(), msg, stack); 1904 | }); 1905 | }; 1906 | 1907 | /** 1908 | * Initialize a new `Base` reporter. 1909 | * 1910 | * All other reporters generally 1911 | * inherit from this reporter, providing 1912 | * stats such as test duration, number 1913 | * of tests passed / failed etc. 1914 | * 1915 | * @param {Runner} runner 1916 | * @api public 1917 | */ 1918 | 1919 | function Base(runner) { 1920 | var self = this 1921 | , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } 1922 | , failures = this.failures = []; 1923 | 1924 | if (!runner) return; 1925 | this.runner = runner; 1926 | 1927 | runner.stats = stats; 1928 | 1929 | runner.on('start', function(){ 1930 | stats.start = new Date; 1931 | }); 1932 | 1933 | runner.on('suite', function(suite){ 1934 | stats.suites = stats.suites || 0; 1935 | suite.root || stats.suites++; 1936 | }); 1937 | 1938 | runner.on('test end', function(test){ 1939 | stats.tests = stats.tests || 0; 1940 | stats.tests++; 1941 | }); 1942 | 1943 | runner.on('pass', function(test){ 1944 | stats.passes = stats.passes || 0; 1945 | 1946 | var medium = test.slow() / 2; 1947 | test.speed = test.duration > test.slow() 1948 | ? 'slow' 1949 | : test.duration > medium 1950 | ? 'medium' 1951 | : 'fast'; 1952 | 1953 | stats.passes++; 1954 | }); 1955 | 1956 | runner.on('fail', function(test, err){ 1957 | stats.failures = stats.failures || 0; 1958 | stats.failures++; 1959 | test.err = err; 1960 | failures.push(test); 1961 | }); 1962 | 1963 | runner.on('end', function(){ 1964 | stats.end = new Date; 1965 | stats.duration = new Date - stats.start; 1966 | }); 1967 | 1968 | runner.on('pending', function(){ 1969 | stats.pending++; 1970 | }); 1971 | } 1972 | 1973 | /** 1974 | * Output common epilogue used by many of 1975 | * the bundled reporters. 1976 | * 1977 | * @api public 1978 | */ 1979 | 1980 | Base.prototype.epilogue = function(){ 1981 | var stats = this.stats; 1982 | var tests; 1983 | var fmt; 1984 | 1985 | console.log(); 1986 | 1987 | // passes 1988 | fmt = color('bright pass', ' ') 1989 | + color('green', ' %d passing') 1990 | + color('light', ' (%s)'); 1991 | 1992 | console.log(fmt, 1993 | stats.passes || 0, 1994 | ms(stats.duration)); 1995 | 1996 | // pending 1997 | if (stats.pending) { 1998 | fmt = color('pending', ' ') 1999 | + color('pending', ' %d pending'); 2000 | 2001 | console.log(fmt, stats.pending); 2002 | } 2003 | 2004 | // failures 2005 | if (stats.failures) { 2006 | fmt = color('fail', ' %d failing'); 2007 | 2008 | console.error(fmt, 2009 | stats.failures); 2010 | 2011 | Base.list(this.failures); 2012 | console.error(); 2013 | } 2014 | 2015 | console.log(); 2016 | }; 2017 | 2018 | /** 2019 | * Pad the given `str` to `len`. 2020 | * 2021 | * @param {String} str 2022 | * @param {String} len 2023 | * @return {String} 2024 | * @api private 2025 | */ 2026 | 2027 | function pad(str, len) { 2028 | str = String(str); 2029 | return Array(len - str.length + 1).join(' ') + str; 2030 | } 2031 | 2032 | /** 2033 | * Return a character diff for `err`. 2034 | * 2035 | * @param {Error} err 2036 | * @return {String} 2037 | * @api private 2038 | */ 2039 | 2040 | function errorDiff(err, type, escape) { 2041 | return diff['diff' + type](err.actual, err.expected).map(function(str){ 2042 | if (escape) { 2043 | str.value = str.value 2044 | .replace(/\t/g, '') 2045 | .replace(/\r/g, '') 2046 | .replace(/\n/g, '\n'); 2047 | } 2048 | if (str.added) return colorLines('diff added', str.value); 2049 | if (str.removed) return colorLines('diff removed', str.value); 2050 | return str.value; 2051 | }).join(''); 2052 | } 2053 | 2054 | /** 2055 | * Color lines for `str`, using the color `name`. 2056 | * 2057 | * @param {String} name 2058 | * @param {String} str 2059 | * @return {String} 2060 | * @api private 2061 | */ 2062 | 2063 | function colorLines(name, str) { 2064 | return str.split('\n').map(function(str){ 2065 | return color(name, str); 2066 | }).join('\n'); 2067 | } 2068 | 2069 | /** 2070 | * Stringify `obj`. 2071 | * 2072 | * @param {Mixed} obj 2073 | * @return {String} 2074 | * @api private 2075 | */ 2076 | 2077 | function stringify(obj) { 2078 | if (obj instanceof RegExp) return obj.toString(); 2079 | return JSON.stringify(obj, null, 2); 2080 | } 2081 | 2082 | /** 2083 | * Check that a / b have the same type. 2084 | * 2085 | * @param {Object} a 2086 | * @param {Object} b 2087 | * @return {Boolean} 2088 | * @api private 2089 | */ 2090 | 2091 | function sameType(a, b) { 2092 | a = Object.prototype.toString.call(a); 2093 | b = Object.prototype.toString.call(b); 2094 | return a == b; 2095 | } 2096 | 2097 | }); // module: reporters/base.js 2098 | 2099 | require.register("reporters/doc.js", function(module, exports, require){ 2100 | 2101 | /** 2102 | * Module dependencies. 2103 | */ 2104 | 2105 | var Base = require('./base') 2106 | , utils = require('../utils'); 2107 | 2108 | /** 2109 | * Expose `Doc`. 2110 | */ 2111 | 2112 | exports = module.exports = Doc; 2113 | 2114 | /** 2115 | * Initialize a new `Doc` reporter. 2116 | * 2117 | * @param {Runner} runner 2118 | * @api public 2119 | */ 2120 | 2121 | function Doc(runner) { 2122 | Base.call(this, runner); 2123 | 2124 | var self = this 2125 | , stats = this.stats 2126 | , total = runner.total 2127 | , indents = 2; 2128 | 2129 | function indent() { 2130 | return Array(indents).join(' '); 2131 | } 2132 | 2133 | runner.on('suite', function(suite){ 2134 | if (suite.root) return; 2135 | ++indents; 2136 | console.log('%s
', indent()); 2137 | ++indents; 2138 | console.log('%s

%s

', indent(), utils.escape(suite.title)); 2139 | console.log('%s
', indent()); 2140 | }); 2141 | 2142 | runner.on('suite end', function(suite){ 2143 | if (suite.root) return; 2144 | console.log('%s
', indent()); 2145 | --indents; 2146 | console.log('%s
', indent()); 2147 | --indents; 2148 | }); 2149 | 2150 | runner.on('pass', function(test){ 2151 | console.log('%s
%s
', indent(), utils.escape(test.title)); 2152 | var code = utils.escape(utils.clean(test.fn.toString())); 2153 | console.log('%s
%s
', indent(), code); 2154 | }); 2155 | } 2156 | 2157 | }); // module: reporters/doc.js 2158 | 2159 | require.register("reporters/dot.js", function(module, exports, require){ 2160 | 2161 | /** 2162 | * Module dependencies. 2163 | */ 2164 | 2165 | var Base = require('./base') 2166 | , color = Base.color; 2167 | 2168 | /** 2169 | * Expose `Dot`. 2170 | */ 2171 | 2172 | exports = module.exports = Dot; 2173 | 2174 | /** 2175 | * Initialize a new `Dot` matrix test reporter. 2176 | * 2177 | * @param {Runner} runner 2178 | * @api public 2179 | */ 2180 | 2181 | function Dot(runner) { 2182 | Base.call(this, runner); 2183 | 2184 | var self = this 2185 | , stats = this.stats 2186 | , width = Base.window.width * .75 | 0 2187 | , n = 0; 2188 | 2189 | runner.on('start', function(){ 2190 | process.stdout.write('\n '); 2191 | }); 2192 | 2193 | runner.on('pending', function(test){ 2194 | process.stdout.write(color('pending', Base.symbols.dot)); 2195 | }); 2196 | 2197 | runner.on('pass', function(test){ 2198 | if (++n % width == 0) process.stdout.write('\n '); 2199 | if ('slow' == test.speed) { 2200 | process.stdout.write(color('bright yellow', Base.symbols.dot)); 2201 | } else { 2202 | process.stdout.write(color(test.speed, Base.symbols.dot)); 2203 | } 2204 | }); 2205 | 2206 | runner.on('fail', function(test, err){ 2207 | if (++n % width == 0) process.stdout.write('\n '); 2208 | process.stdout.write(color('fail', Base.symbols.dot)); 2209 | }); 2210 | 2211 | runner.on('end', function(){ 2212 | console.log(); 2213 | self.epilogue(); 2214 | }); 2215 | } 2216 | 2217 | /** 2218 | * Inherit from `Base.prototype`. 2219 | */ 2220 | 2221 | function F(){}; 2222 | F.prototype = Base.prototype; 2223 | Dot.prototype = new F; 2224 | Dot.prototype.constructor = Dot; 2225 | 2226 | }); // module: reporters/dot.js 2227 | 2228 | require.register("reporters/html-cov.js", function(module, exports, require){ 2229 | 2230 | /** 2231 | * Module dependencies. 2232 | */ 2233 | 2234 | var JSONCov = require('./json-cov') 2235 | , fs = require('browser/fs'); 2236 | 2237 | /** 2238 | * Expose `HTMLCov`. 2239 | */ 2240 | 2241 | exports = module.exports = HTMLCov; 2242 | 2243 | /** 2244 | * Initialize a new `JsCoverage` reporter. 2245 | * 2246 | * @param {Runner} runner 2247 | * @api public 2248 | */ 2249 | 2250 | function HTMLCov(runner) { 2251 | var jade = require('jade') 2252 | , file = __dirname + '/templates/coverage.jade' 2253 | , str = fs.readFileSync(file, 'utf8') 2254 | , fn = jade.compile(str, { filename: file }) 2255 | , self = this; 2256 | 2257 | JSONCov.call(this, runner, false); 2258 | 2259 | runner.on('end', function(){ 2260 | process.stdout.write(fn({ 2261 | cov: self.cov 2262 | , coverageClass: coverageClass 2263 | })); 2264 | }); 2265 | } 2266 | 2267 | /** 2268 | * Return coverage class for `n`. 2269 | * 2270 | * @return {String} 2271 | * @api private 2272 | */ 2273 | 2274 | function coverageClass(n) { 2275 | if (n >= 75) return 'high'; 2276 | if (n >= 50) return 'medium'; 2277 | if (n >= 25) return 'low'; 2278 | return 'terrible'; 2279 | } 2280 | }); // module: reporters/html-cov.js 2281 | 2282 | require.register("reporters/html.js", function(module, exports, require){ 2283 | 2284 | /** 2285 | * Module dependencies. 2286 | */ 2287 | 2288 | var Base = require('./base') 2289 | , utils = require('../utils') 2290 | , Progress = require('../browser/progress') 2291 | , escape = utils.escape; 2292 | 2293 | /** 2294 | * Save timer references to avoid Sinon interfering (see GH-237). 2295 | */ 2296 | 2297 | var Date = global.Date 2298 | , setTimeout = global.setTimeout 2299 | , setInterval = global.setInterval 2300 | , clearTimeout = global.clearTimeout 2301 | , clearInterval = global.clearInterval; 2302 | 2303 | /** 2304 | * Expose `Doc`. 2305 | */ 2306 | 2307 | exports = module.exports = HTML; 2308 | 2309 | /** 2310 | * Stats template. 2311 | */ 2312 | 2313 | var statsTemplate = '
    ' 2314 | + '
  • ' 2315 | + '
  • passes: 0
  • ' 2316 | + '
  • failures: 0
  • ' 2317 | + '
  • duration: 0s
  • ' 2318 | + '
'; 2319 | 2320 | /** 2321 | * Initialize a new `Doc` reporter. 2322 | * 2323 | * @param {Runner} runner 2324 | * @api public 2325 | */ 2326 | 2327 | function HTML(runner, root) { 2328 | Base.call(this, runner); 2329 | 2330 | var self = this 2331 | , stats = this.stats 2332 | , total = runner.total 2333 | , stat = fragment(statsTemplate) 2334 | , items = stat.getElementsByTagName('li') 2335 | , passes = items[1].getElementsByTagName('em')[0] 2336 | , passesLink = items[1].getElementsByTagName('a')[0] 2337 | , failures = items[2].getElementsByTagName('em')[0] 2338 | , failuresLink = items[2].getElementsByTagName('a')[0] 2339 | , duration = items[3].getElementsByTagName('em')[0] 2340 | , canvas = stat.getElementsByTagName('canvas')[0] 2341 | , report = fragment('
    ') 2342 | , stack = [report] 2343 | , progress 2344 | , ctx 2345 | 2346 | root = root || document.getElementById('mocha'); 2347 | 2348 | if (canvas.getContext) { 2349 | var ratio = window.devicePixelRatio || 1; 2350 | canvas.style.width = canvas.width; 2351 | canvas.style.height = canvas.height; 2352 | canvas.width *= ratio; 2353 | canvas.height *= ratio; 2354 | ctx = canvas.getContext('2d'); 2355 | ctx.scale(ratio, ratio); 2356 | progress = new Progress; 2357 | } 2358 | 2359 | if (!root) return error('#mocha div missing, add it to your document'); 2360 | 2361 | // pass toggle 2362 | on(passesLink, 'click', function(){ 2363 | unhide(); 2364 | var name = /pass/.test(report.className) ? '' : ' pass'; 2365 | report.className = report.className.replace(/fail|pass/g, '') + name; 2366 | if (report.className.trim()) hideSuitesWithout('test pass'); 2367 | }); 2368 | 2369 | // failure toggle 2370 | on(failuresLink, 'click', function(){ 2371 | unhide(); 2372 | var name = /fail/.test(report.className) ? '' : ' fail'; 2373 | report.className = report.className.replace(/fail|pass/g, '') + name; 2374 | if (report.className.trim()) hideSuitesWithout('test fail'); 2375 | }); 2376 | 2377 | root.appendChild(stat); 2378 | root.appendChild(report); 2379 | 2380 | if (progress) progress.size(40); 2381 | 2382 | runner.on('suite', function(suite){ 2383 | if (suite.root) return; 2384 | 2385 | // suite 2386 | var url = '?grep=' + encodeURIComponent(suite.fullTitle()); 2387 | var el = fragment('
  • %s

  • ', url, escape(suite.title)); 2388 | 2389 | // container 2390 | stack[0].appendChild(el); 2391 | stack.unshift(document.createElement('ul')); 2392 | el.appendChild(stack[0]); 2393 | }); 2394 | 2395 | runner.on('suite end', function(suite){ 2396 | if (suite.root) return; 2397 | stack.shift(); 2398 | }); 2399 | 2400 | runner.on('fail', function(test, err){ 2401 | if ('hook' == test.type) runner.emit('test end', test); 2402 | }); 2403 | 2404 | runner.on('test end', function(test){ 2405 | // TODO: add to stats 2406 | var percent = stats.tests / this.total * 100 | 0; 2407 | if (progress) progress.update(percent).draw(ctx); 2408 | 2409 | // update stats 2410 | var ms = new Date - stats.start; 2411 | text(passes, stats.passes); 2412 | text(failures, stats.failures); 2413 | text(duration, (ms / 1000).toFixed(2)); 2414 | 2415 | // test 2416 | if ('passed' == test.state) { 2417 | var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle())); 2418 | } else if (test.pending) { 2419 | var el = fragment('
  • %e

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

  • ', test.title, encodeURIComponent(test.fullTitle())); 2422 | var str = test.err.stack || test.err.toString(); 2423 | 2424 | // FF / Opera do not add the message 2425 | if (!~str.indexOf(test.err.message)) { 2426 | str = test.err.message + '\n' + str; 2427 | } 2428 | 2429 | // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we 2430 | // check for the result of the stringifying. 2431 | if ('[object Error]' == str) str = test.err.message; 2432 | 2433 | // Safari doesn't give you a stack. Let's at least provide a source line. 2434 | if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { 2435 | str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; 2436 | } 2437 | 2438 | el.appendChild(fragment('
    %e
    ', str)); 2439 | } 2440 | 2441 | // toggle code 2442 | // TODO: defer 2443 | if (!test.pending) { 2444 | var h2 = el.getElementsByTagName('h2')[0]; 2445 | 2446 | on(h2, 'click', function(){ 2447 | pre.style.display = 'none' == pre.style.display 2448 | ? 'block' 2449 | : 'none'; 2450 | }); 2451 | 2452 | var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); 2453 | el.appendChild(pre); 2454 | pre.style.display = 'none'; 2455 | } 2456 | 2457 | // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. 2458 | if (stack[0]) stack[0].appendChild(el); 2459 | }); 2460 | } 2461 | 2462 | /** 2463 | * Display error `msg`. 2464 | */ 2465 | 2466 | function error(msg) { 2467 | document.body.appendChild(fragment('
    %s
    ', msg)); 2468 | } 2469 | 2470 | /** 2471 | * Return a DOM fragment from `html`. 2472 | */ 2473 | 2474 | function fragment(html) { 2475 | var args = arguments 2476 | , div = document.createElement('div') 2477 | , i = 1; 2478 | 2479 | div.innerHTML = html.replace(/%([se])/g, function(_, type){ 2480 | switch (type) { 2481 | case 's': return String(args[i++]); 2482 | case 'e': return escape(args[i++]); 2483 | } 2484 | }); 2485 | 2486 | return div.firstChild; 2487 | } 2488 | 2489 | /** 2490 | * Check for suites that do not have elements 2491 | * with `classname`, and hide them. 2492 | */ 2493 | 2494 | function hideSuitesWithout(classname) { 2495 | var suites = document.getElementsByClassName('suite'); 2496 | for (var i = 0; i < suites.length; i++) { 2497 | var els = suites[i].getElementsByClassName(classname); 2498 | if (0 == els.length) suites[i].className += ' hidden'; 2499 | } 2500 | } 2501 | 2502 | /** 2503 | * Unhide .hidden suites. 2504 | */ 2505 | 2506 | function unhide() { 2507 | var els = document.getElementsByClassName('suite hidden'); 2508 | for (var i = 0; i < els.length; ++i) { 2509 | els[i].className = els[i].className.replace('suite hidden', 'suite'); 2510 | } 2511 | } 2512 | 2513 | /** 2514 | * Set `el` text to `str`. 2515 | */ 2516 | 2517 | function text(el, str) { 2518 | if (el.textContent) { 2519 | el.textContent = str; 2520 | } else { 2521 | el.innerText = str; 2522 | } 2523 | } 2524 | 2525 | /** 2526 | * Listen on `event` with callback `fn`. 2527 | */ 2528 | 2529 | function on(el, event, fn) { 2530 | if (el.addEventListener) { 2531 | el.addEventListener(event, fn, false); 2532 | } else { 2533 | el.attachEvent('on' + event, fn); 2534 | } 2535 | } 2536 | 2537 | }); // module: reporters/html.js 2538 | 2539 | require.register("reporters/index.js", function(module, exports, require){ 2540 | 2541 | exports.Base = require('./base'); 2542 | exports.Dot = require('./dot'); 2543 | exports.Doc = require('./doc'); 2544 | exports.TAP = require('./tap'); 2545 | exports.JSON = require('./json'); 2546 | exports.HTML = require('./html'); 2547 | exports.List = require('./list'); 2548 | exports.Min = require('./min'); 2549 | exports.Spec = require('./spec'); 2550 | exports.Nyan = require('./nyan'); 2551 | exports.XUnit = require('./xunit'); 2552 | exports.Markdown = require('./markdown'); 2553 | exports.Progress = require('./progress'); 2554 | exports.Landing = require('./landing'); 2555 | exports.JSONCov = require('./json-cov'); 2556 | exports.HTMLCov = require('./html-cov'); 2557 | exports.JSONStream = require('./json-stream'); 2558 | exports.Teamcity = require('./teamcity'); 2559 | 2560 | }); // module: reporters/index.js 2561 | 2562 | require.register("reporters/json-cov.js", function(module, exports, require){ 2563 | 2564 | /** 2565 | * Module dependencies. 2566 | */ 2567 | 2568 | var Base = require('./base'); 2569 | 2570 | /** 2571 | * Expose `JSONCov`. 2572 | */ 2573 | 2574 | exports = module.exports = JSONCov; 2575 | 2576 | /** 2577 | * Initialize a new `JsCoverage` reporter. 2578 | * 2579 | * @param {Runner} runner 2580 | * @param {Boolean} output 2581 | * @api public 2582 | */ 2583 | 2584 | function JSONCov(runner, output) { 2585 | var self = this 2586 | , output = 1 == arguments.length ? true : output; 2587 | 2588 | Base.call(this, runner); 2589 | 2590 | var tests = [] 2591 | , failures = [] 2592 | , passes = []; 2593 | 2594 | runner.on('test end', function(test){ 2595 | tests.push(test); 2596 | }); 2597 | 2598 | runner.on('pass', function(test){ 2599 | passes.push(test); 2600 | }); 2601 | 2602 | runner.on('fail', function(test){ 2603 | failures.push(test); 2604 | }); 2605 | 2606 | runner.on('end', function(){ 2607 | var cov = global._$jscoverage || {}; 2608 | var result = self.cov = map(cov); 2609 | result.stats = self.stats; 2610 | result.tests = tests.map(clean); 2611 | result.failures = failures.map(clean); 2612 | result.passes = passes.map(clean); 2613 | if (!output) return; 2614 | process.stdout.write(JSON.stringify(result, null, 2 )); 2615 | }); 2616 | } 2617 | 2618 | /** 2619 | * Map jscoverage data to a JSON structure 2620 | * suitable for reporting. 2621 | * 2622 | * @param {Object} cov 2623 | * @return {Object} 2624 | * @api private 2625 | */ 2626 | 2627 | function map(cov) { 2628 | var ret = { 2629 | instrumentation: 'node-jscoverage' 2630 | , sloc: 0 2631 | , hits: 0 2632 | , misses: 0 2633 | , coverage: 0 2634 | , files: [] 2635 | }; 2636 | 2637 | for (var filename in cov) { 2638 | var data = coverage(filename, cov[filename]); 2639 | ret.files.push(data); 2640 | ret.hits += data.hits; 2641 | ret.misses += data.misses; 2642 | ret.sloc += data.sloc; 2643 | } 2644 | 2645 | ret.files.sort(function(a, b) { 2646 | return a.filename.localeCompare(b.filename); 2647 | }); 2648 | 2649 | if (ret.sloc > 0) { 2650 | ret.coverage = (ret.hits / ret.sloc) * 100; 2651 | } 2652 | 2653 | return ret; 2654 | }; 2655 | 2656 | /** 2657 | * Map jscoverage data for a single source file 2658 | * to a JSON structure suitable for reporting. 2659 | * 2660 | * @param {String} filename name of the source file 2661 | * @param {Object} data jscoverage coverage data 2662 | * @return {Object} 2663 | * @api private 2664 | */ 2665 | 2666 | function coverage(filename, data) { 2667 | var ret = { 2668 | filename: filename, 2669 | coverage: 0, 2670 | hits: 0, 2671 | misses: 0, 2672 | sloc: 0, 2673 | source: {} 2674 | }; 2675 | 2676 | data.source.forEach(function(line, num){ 2677 | num++; 2678 | 2679 | if (data[num] === 0) { 2680 | ret.misses++; 2681 | ret.sloc++; 2682 | } else if (data[num] !== undefined) { 2683 | ret.hits++; 2684 | ret.sloc++; 2685 | } 2686 | 2687 | ret.source[num] = { 2688 | source: line 2689 | , coverage: data[num] === undefined 2690 | ? '' 2691 | : data[num] 2692 | }; 2693 | }); 2694 | 2695 | ret.coverage = ret.hits / ret.sloc * 100; 2696 | 2697 | return ret; 2698 | } 2699 | 2700 | /** 2701 | * Return a plain-object representation of `test` 2702 | * free of cyclic properties etc. 2703 | * 2704 | * @param {Object} test 2705 | * @return {Object} 2706 | * @api private 2707 | */ 2708 | 2709 | function clean(test) { 2710 | return { 2711 | title: test.title 2712 | , fullTitle: test.fullTitle() 2713 | , duration: test.duration 2714 | } 2715 | } 2716 | 2717 | }); // module: reporters/json-cov.js 2718 | 2719 | require.register("reporters/json-stream.js", function(module, exports, require){ 2720 | 2721 | /** 2722 | * Module dependencies. 2723 | */ 2724 | 2725 | var Base = require('./base') 2726 | , color = Base.color; 2727 | 2728 | /** 2729 | * Expose `List`. 2730 | */ 2731 | 2732 | exports = module.exports = List; 2733 | 2734 | /** 2735 | * Initialize a new `List` test reporter. 2736 | * 2737 | * @param {Runner} runner 2738 | * @api public 2739 | */ 2740 | 2741 | function List(runner) { 2742 | Base.call(this, runner); 2743 | 2744 | var self = this 2745 | , stats = this.stats 2746 | , total = runner.total; 2747 | 2748 | runner.on('start', function(){ 2749 | console.log(JSON.stringify(['start', { total: total }])); 2750 | }); 2751 | 2752 | runner.on('pass', function(test){ 2753 | console.log(JSON.stringify(['pass', clean(test)])); 2754 | }); 2755 | 2756 | runner.on('fail', function(test, err){ 2757 | console.log(JSON.stringify(['fail', clean(test)])); 2758 | }); 2759 | 2760 | runner.on('end', function(){ 2761 | process.stdout.write(JSON.stringify(['end', self.stats])); 2762 | }); 2763 | } 2764 | 2765 | /** 2766 | * Return a plain-object representation of `test` 2767 | * free of cyclic properties etc. 2768 | * 2769 | * @param {Object} test 2770 | * @return {Object} 2771 | * @api private 2772 | */ 2773 | 2774 | function clean(test) { 2775 | return { 2776 | title: test.title 2777 | , fullTitle: test.fullTitle() 2778 | , duration: test.duration 2779 | } 2780 | } 2781 | }); // module: reporters/json-stream.js 2782 | 2783 | require.register("reporters/json.js", function(module, exports, require){ 2784 | 2785 | /** 2786 | * Module dependencies. 2787 | */ 2788 | 2789 | var Base = require('./base') 2790 | , cursor = Base.cursor 2791 | , color = Base.color; 2792 | 2793 | /** 2794 | * Expose `JSON`. 2795 | */ 2796 | 2797 | exports = module.exports = JSONReporter; 2798 | 2799 | /** 2800 | * Initialize a new `JSON` reporter. 2801 | * 2802 | * @param {Runner} runner 2803 | * @api public 2804 | */ 2805 | 2806 | function JSONReporter(runner) { 2807 | var self = this; 2808 | Base.call(this, runner); 2809 | 2810 | var tests = [] 2811 | , failures = [] 2812 | , passes = []; 2813 | 2814 | runner.on('test end', function(test){ 2815 | tests.push(test); 2816 | }); 2817 | 2818 | runner.on('pass', function(test){ 2819 | passes.push(test); 2820 | }); 2821 | 2822 | runner.on('fail', function(test){ 2823 | failures.push(test); 2824 | }); 2825 | 2826 | runner.on('end', function(){ 2827 | var obj = { 2828 | stats: self.stats 2829 | , tests: tests.map(clean) 2830 | , failures: failures.map(clean) 2831 | , passes: passes.map(clean) 2832 | }; 2833 | 2834 | process.stdout.write(JSON.stringify(obj, null, 2)); 2835 | }); 2836 | } 2837 | 2838 | /** 2839 | * Return a plain-object representation of `test` 2840 | * free of cyclic properties etc. 2841 | * 2842 | * @param {Object} test 2843 | * @return {Object} 2844 | * @api private 2845 | */ 2846 | 2847 | function clean(test) { 2848 | return { 2849 | title: test.title 2850 | , fullTitle: test.fullTitle() 2851 | , duration: test.duration 2852 | } 2853 | } 2854 | }); // module: reporters/json.js 2855 | 2856 | require.register("reporters/landing.js", function(module, exports, require){ 2857 | 2858 | /** 2859 | * Module dependencies. 2860 | */ 2861 | 2862 | var Base = require('./base') 2863 | , cursor = Base.cursor 2864 | , color = Base.color; 2865 | 2866 | /** 2867 | * Expose `Landing`. 2868 | */ 2869 | 2870 | exports = module.exports = Landing; 2871 | 2872 | /** 2873 | * Airplane color. 2874 | */ 2875 | 2876 | Base.colors.plane = 0; 2877 | 2878 | /** 2879 | * Airplane crash color. 2880 | */ 2881 | 2882 | Base.colors['plane crash'] = 31; 2883 | 2884 | /** 2885 | * Runway color. 2886 | */ 2887 | 2888 | Base.colors.runway = 90; 2889 | 2890 | /** 2891 | * Initialize a new `Landing` reporter. 2892 | * 2893 | * @param {Runner} runner 2894 | * @api public 2895 | */ 2896 | 2897 | function Landing(runner) { 2898 | Base.call(this, runner); 2899 | 2900 | var self = this 2901 | , stats = this.stats 2902 | , width = Base.window.width * .75 | 0 2903 | , total = runner.total 2904 | , stream = process.stdout 2905 | , plane = color('plane', '✈') 2906 | , crashed = -1 2907 | , n = 0; 2908 | 2909 | function runway() { 2910 | var buf = Array(width).join('-'); 2911 | return ' ' + color('runway', buf); 2912 | } 2913 | 2914 | runner.on('start', function(){ 2915 | stream.write('\n '); 2916 | cursor.hide(); 2917 | }); 2918 | 2919 | runner.on('test end', function(test){ 2920 | // check if the plane crashed 2921 | var col = -1 == crashed 2922 | ? width * ++n / total | 0 2923 | : crashed; 2924 | 2925 | // show the crash 2926 | if ('failed' == test.state) { 2927 | plane = color('plane crash', '✈'); 2928 | crashed = col; 2929 | } 2930 | 2931 | // render landing strip 2932 | stream.write('\u001b[4F\n\n'); 2933 | stream.write(runway()); 2934 | stream.write('\n '); 2935 | stream.write(color('runway', Array(col).join('⋅'))); 2936 | stream.write(plane) 2937 | stream.write(color('runway', Array(width - col).join('⋅') + '\n')); 2938 | stream.write(runway()); 2939 | stream.write('\u001b[0m'); 2940 | }); 2941 | 2942 | runner.on('end', function(){ 2943 | cursor.show(); 2944 | console.log(); 2945 | self.epilogue(); 2946 | }); 2947 | } 2948 | 2949 | /** 2950 | * Inherit from `Base.prototype`. 2951 | */ 2952 | 2953 | function F(){}; 2954 | F.prototype = Base.prototype; 2955 | Landing.prototype = new F; 2956 | Landing.prototype.constructor = Landing; 2957 | 2958 | }); // module: reporters/landing.js 2959 | 2960 | require.register("reporters/list.js", function(module, exports, require){ 2961 | 2962 | /** 2963 | * Module dependencies. 2964 | */ 2965 | 2966 | var Base = require('./base') 2967 | , cursor = Base.cursor 2968 | , color = Base.color; 2969 | 2970 | /** 2971 | * Expose `List`. 2972 | */ 2973 | 2974 | exports = module.exports = List; 2975 | 2976 | /** 2977 | * Initialize a new `List` test reporter. 2978 | * 2979 | * @param {Runner} runner 2980 | * @api public 2981 | */ 2982 | 2983 | function List(runner) { 2984 | Base.call(this, runner); 2985 | 2986 | var self = this 2987 | , stats = this.stats 2988 | , n = 0; 2989 | 2990 | runner.on('start', function(){ 2991 | console.log(); 2992 | }); 2993 | 2994 | runner.on('test', function(test){ 2995 | process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); 2996 | }); 2997 | 2998 | runner.on('pending', function(test){ 2999 | var fmt = color('checkmark', ' -') 3000 | + color('pending', ' %s'); 3001 | console.log(fmt, test.fullTitle()); 3002 | }); 3003 | 3004 | runner.on('pass', function(test){ 3005 | var fmt = color('checkmark', ' '+Base.symbols.dot) 3006 | + color('pass', ' %s: ') 3007 | + color(test.speed, '%dms'); 3008 | cursor.CR(); 3009 | console.log(fmt, test.fullTitle(), test.duration); 3010 | }); 3011 | 3012 | runner.on('fail', function(test, err){ 3013 | cursor.CR(); 3014 | console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); 3015 | }); 3016 | 3017 | runner.on('end', self.epilogue.bind(self)); 3018 | } 3019 | 3020 | /** 3021 | * Inherit from `Base.prototype`. 3022 | */ 3023 | 3024 | function F(){}; 3025 | F.prototype = Base.prototype; 3026 | List.prototype = new F; 3027 | List.prototype.constructor = List; 3028 | 3029 | 3030 | }); // module: reporters/list.js 3031 | 3032 | require.register("reporters/markdown.js", function(module, exports, require){ 3033 | /** 3034 | * Module dependencies. 3035 | */ 3036 | 3037 | var Base = require('./base') 3038 | , utils = require('../utils'); 3039 | 3040 | /** 3041 | * Expose `Markdown`. 3042 | */ 3043 | 3044 | exports = module.exports = Markdown; 3045 | 3046 | /** 3047 | * Initialize a new `Markdown` reporter. 3048 | * 3049 | * @param {Runner} runner 3050 | * @api public 3051 | */ 3052 | 3053 | function Markdown(runner) { 3054 | Base.call(this, runner); 3055 | 3056 | var self = this 3057 | , stats = this.stats 3058 | , level = 0 3059 | , buf = ''; 3060 | 3061 | function title(str) { 3062 | return Array(level).join('#') + ' ' + str; 3063 | } 3064 | 3065 | function indent() { 3066 | return Array(level).join(' '); 3067 | } 3068 | 3069 | function mapTOC(suite, obj) { 3070 | var ret = obj; 3071 | obj = obj[suite.title] = obj[suite.title] || { suite: suite }; 3072 | suite.suites.forEach(function(suite){ 3073 | mapTOC(suite, obj); 3074 | }); 3075 | return ret; 3076 | } 3077 | 3078 | function stringifyTOC(obj, level) { 3079 | ++level; 3080 | var buf = ''; 3081 | var link; 3082 | for (var key in obj) { 3083 | if ('suite' == key) continue; 3084 | if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; 3085 | if (key) buf += Array(level).join(' ') + link; 3086 | buf += stringifyTOC(obj[key], level); 3087 | } 3088 | --level; 3089 | return buf; 3090 | } 3091 | 3092 | function generateTOC(suite) { 3093 | var obj = mapTOC(suite, {}); 3094 | return stringifyTOC(obj, 0); 3095 | } 3096 | 3097 | generateTOC(runner.suite); 3098 | 3099 | runner.on('suite', function(suite){ 3100 | ++level; 3101 | var slug = utils.slug(suite.fullTitle()); 3102 | buf += '' + '\n'; 3103 | buf += title(suite.title) + '\n'; 3104 | }); 3105 | 3106 | runner.on('suite end', function(suite){ 3107 | --level; 3108 | }); 3109 | 3110 | runner.on('pass', function(test){ 3111 | var code = utils.clean(test.fn.toString()); 3112 | buf += test.title + '.\n'; 3113 | buf += '\n```js\n'; 3114 | buf += code + '\n'; 3115 | buf += '```\n\n'; 3116 | }); 3117 | 3118 | runner.on('end', function(){ 3119 | process.stdout.write('# TOC\n'); 3120 | process.stdout.write(generateTOC(runner.suite)); 3121 | process.stdout.write(buf); 3122 | }); 3123 | } 3124 | }); // module: reporters/markdown.js 3125 | 3126 | require.register("reporters/min.js", function(module, exports, require){ 3127 | 3128 | /** 3129 | * Module dependencies. 3130 | */ 3131 | 3132 | var Base = require('./base'); 3133 | 3134 | /** 3135 | * Expose `Min`. 3136 | */ 3137 | 3138 | exports = module.exports = Min; 3139 | 3140 | /** 3141 | * Initialize a new `Min` minimal test reporter (best used with --watch). 3142 | * 3143 | * @param {Runner} runner 3144 | * @api public 3145 | */ 3146 | 3147 | function Min(runner) { 3148 | Base.call(this, runner); 3149 | 3150 | runner.on('start', function(){ 3151 | // clear screen 3152 | process.stdout.write('\u001b[2J'); 3153 | // set cursor position 3154 | process.stdout.write('\u001b[1;3H'); 3155 | }); 3156 | 3157 | runner.on('end', this.epilogue.bind(this)); 3158 | } 3159 | 3160 | /** 3161 | * Inherit from `Base.prototype`. 3162 | */ 3163 | 3164 | function F(){}; 3165 | F.prototype = Base.prototype; 3166 | Min.prototype = new F; 3167 | Min.prototype.constructor = Min; 3168 | 3169 | 3170 | }); // module: reporters/min.js 3171 | 3172 | require.register("reporters/nyan.js", function(module, exports, require){ 3173 | /** 3174 | * Module dependencies. 3175 | */ 3176 | 3177 | var Base = require('./base') 3178 | , color = Base.color; 3179 | 3180 | /** 3181 | * Expose `Dot`. 3182 | */ 3183 | 3184 | exports = module.exports = NyanCat; 3185 | 3186 | /** 3187 | * Initialize a new `Dot` matrix test reporter. 3188 | * 3189 | * @param {Runner} runner 3190 | * @api public 3191 | */ 3192 | 3193 | function NyanCat(runner) { 3194 | Base.call(this, runner); 3195 | 3196 | var self = this 3197 | , stats = this.stats 3198 | , width = Base.window.width * .75 | 0 3199 | , rainbowColors = this.rainbowColors = self.generateColors() 3200 | , colorIndex = this.colorIndex = 0 3201 | , numerOfLines = this.numberOfLines = 4 3202 | , trajectories = this.trajectories = [[], [], [], []] 3203 | , nyanCatWidth = this.nyanCatWidth = 11 3204 | , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) 3205 | , scoreboardWidth = this.scoreboardWidth = 5 3206 | , tick = this.tick = 0 3207 | , n = 0; 3208 | 3209 | runner.on('start', function(){ 3210 | Base.cursor.hide(); 3211 | self.draw('start'); 3212 | }); 3213 | 3214 | runner.on('pending', function(test){ 3215 | self.draw('pending'); 3216 | }); 3217 | 3218 | runner.on('pass', function(test){ 3219 | self.draw('pass'); 3220 | }); 3221 | 3222 | runner.on('fail', function(test, err){ 3223 | self.draw('fail'); 3224 | }); 3225 | 3226 | runner.on('end', function(){ 3227 | Base.cursor.show(); 3228 | for (var i = 0; i < self.numberOfLines; i++) write('\n'); 3229 | self.epilogue(); 3230 | }); 3231 | } 3232 | 3233 | /** 3234 | * Draw the nyan cat with runner `status`. 3235 | * 3236 | * @param {String} status 3237 | * @api private 3238 | */ 3239 | 3240 | NyanCat.prototype.draw = function(status){ 3241 | this.appendRainbow(); 3242 | this.drawScoreboard(); 3243 | this.drawRainbow(); 3244 | this.drawNyanCat(status); 3245 | this.tick = !this.tick; 3246 | }; 3247 | 3248 | /** 3249 | * Draw the "scoreboard" showing the number 3250 | * of passes, failures and pending tests. 3251 | * 3252 | * @api private 3253 | */ 3254 | 3255 | NyanCat.prototype.drawScoreboard = function(){ 3256 | var stats = this.stats; 3257 | var colors = Base.colors; 3258 | 3259 | function draw(color, n) { 3260 | write(' '); 3261 | write('\u001b[' + color + 'm' + n + '\u001b[0m'); 3262 | write('\n'); 3263 | } 3264 | 3265 | draw(colors.green, stats.passes); 3266 | draw(colors.fail, stats.failures); 3267 | draw(colors.pending, stats.pending); 3268 | write('\n'); 3269 | 3270 | this.cursorUp(this.numberOfLines); 3271 | }; 3272 | 3273 | /** 3274 | * Append the rainbow. 3275 | * 3276 | * @api private 3277 | */ 3278 | 3279 | NyanCat.prototype.appendRainbow = function(){ 3280 | var segment = this.tick ? '_' : '-'; 3281 | var rainbowified = this.rainbowify(segment); 3282 | 3283 | for (var index = 0; index < this.numberOfLines; index++) { 3284 | var trajectory = this.trajectories[index]; 3285 | if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); 3286 | trajectory.push(rainbowified); 3287 | } 3288 | }; 3289 | 3290 | /** 3291 | * Draw the rainbow. 3292 | * 3293 | * @api private 3294 | */ 3295 | 3296 | NyanCat.prototype.drawRainbow = function(){ 3297 | var self = this; 3298 | 3299 | this.trajectories.forEach(function(line, index) { 3300 | write('\u001b[' + self.scoreboardWidth + 'C'); 3301 | write(line.join('')); 3302 | write('\n'); 3303 | }); 3304 | 3305 | this.cursorUp(this.numberOfLines); 3306 | }; 3307 | 3308 | /** 3309 | * Draw the nyan cat with `status`. 3310 | * 3311 | * @param {String} status 3312 | * @api private 3313 | */ 3314 | 3315 | NyanCat.prototype.drawNyanCat = function(status) { 3316 | var self = this; 3317 | var startWidth = this.scoreboardWidth + this.trajectories[0].length; 3318 | var color = '\u001b[' + startWidth + 'C'; 3319 | var padding = ''; 3320 | 3321 | write(color); 3322 | write('_,------,'); 3323 | write('\n'); 3324 | 3325 | write(color); 3326 | padding = self.tick ? ' ' : ' '; 3327 | write('_|' + padding + '/\\_/\\ '); 3328 | write('\n'); 3329 | 3330 | write(color); 3331 | padding = self.tick ? '_' : '__'; 3332 | var tail = self.tick ? '~' : '^'; 3333 | var face; 3334 | switch (status) { 3335 | case 'pass': 3336 | face = '( ^ .^)'; 3337 | break; 3338 | case 'fail': 3339 | face = '( o .o)'; 3340 | break; 3341 | default: 3342 | face = '( - .-)'; 3343 | } 3344 | write(tail + '|' + padding + face + ' '); 3345 | write('\n'); 3346 | 3347 | write(color); 3348 | padding = self.tick ? ' ' : ' '; 3349 | write(padding + '"" "" '); 3350 | write('\n'); 3351 | 3352 | this.cursorUp(this.numberOfLines); 3353 | }; 3354 | 3355 | /** 3356 | * Move cursor up `n`. 3357 | * 3358 | * @param {Number} n 3359 | * @api private 3360 | */ 3361 | 3362 | NyanCat.prototype.cursorUp = function(n) { 3363 | write('\u001b[' + n + 'A'); 3364 | }; 3365 | 3366 | /** 3367 | * Move cursor down `n`. 3368 | * 3369 | * @param {Number} n 3370 | * @api private 3371 | */ 3372 | 3373 | NyanCat.prototype.cursorDown = function(n) { 3374 | write('\u001b[' + n + 'B'); 3375 | }; 3376 | 3377 | /** 3378 | * Generate rainbow colors. 3379 | * 3380 | * @return {Array} 3381 | * @api private 3382 | */ 3383 | 3384 | NyanCat.prototype.generateColors = function(){ 3385 | var colors = []; 3386 | 3387 | for (var i = 0; i < (6 * 7); i++) { 3388 | var pi3 = Math.floor(Math.PI / 3); 3389 | var n = (i * (1.0 / 6)); 3390 | var r = Math.floor(3 * Math.sin(n) + 3); 3391 | var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); 3392 | var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); 3393 | colors.push(36 * r + 6 * g + b + 16); 3394 | } 3395 | 3396 | return colors; 3397 | }; 3398 | 3399 | /** 3400 | * Apply rainbow to the given `str`. 3401 | * 3402 | * @param {String} str 3403 | * @return {String} 3404 | * @api private 3405 | */ 3406 | 3407 | NyanCat.prototype.rainbowify = function(str){ 3408 | var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; 3409 | this.colorIndex += 1; 3410 | return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; 3411 | }; 3412 | 3413 | /** 3414 | * Stdout helper. 3415 | */ 3416 | 3417 | function write(string) { 3418 | process.stdout.write(string); 3419 | } 3420 | 3421 | /** 3422 | * Inherit from `Base.prototype`. 3423 | */ 3424 | 3425 | function F(){}; 3426 | F.prototype = Base.prototype; 3427 | NyanCat.prototype = new F; 3428 | NyanCat.prototype.constructor = NyanCat; 3429 | 3430 | 3431 | }); // module: reporters/nyan.js 3432 | 3433 | require.register("reporters/progress.js", function(module, exports, require){ 3434 | 3435 | /** 3436 | * Module dependencies. 3437 | */ 3438 | 3439 | var Base = require('./base') 3440 | , cursor = Base.cursor 3441 | , color = Base.color; 3442 | 3443 | /** 3444 | * Expose `Progress`. 3445 | */ 3446 | 3447 | exports = module.exports = Progress; 3448 | 3449 | /** 3450 | * General progress bar color. 3451 | */ 3452 | 3453 | Base.colors.progress = 90; 3454 | 3455 | /** 3456 | * Initialize a new `Progress` bar test reporter. 3457 | * 3458 | * @param {Runner} runner 3459 | * @param {Object} options 3460 | * @api public 3461 | */ 3462 | 3463 | function Progress(runner, options) { 3464 | Base.call(this, runner); 3465 | 3466 | var self = this 3467 | , options = options || {} 3468 | , stats = this.stats 3469 | , width = Base.window.width * .50 | 0 3470 | , total = runner.total 3471 | , complete = 0 3472 | , max = Math.max; 3473 | 3474 | // default chars 3475 | options.open = options.open || '['; 3476 | options.complete = options.complete || '▬'; 3477 | options.incomplete = options.incomplete || Base.symbols.dot; 3478 | options.close = options.close || ']'; 3479 | options.verbose = false; 3480 | 3481 | // tests started 3482 | runner.on('start', function(){ 3483 | console.log(); 3484 | cursor.hide(); 3485 | }); 3486 | 3487 | // tests complete 3488 | runner.on('test end', function(){ 3489 | complete++; 3490 | var incomplete = total - complete 3491 | , percent = complete / total 3492 | , n = width * percent | 0 3493 | , i = width - n; 3494 | 3495 | cursor.CR(); 3496 | process.stdout.write('\u001b[J'); 3497 | process.stdout.write(color('progress', ' ' + options.open)); 3498 | process.stdout.write(Array(n).join(options.complete)); 3499 | process.stdout.write(Array(i).join(options.incomplete)); 3500 | process.stdout.write(color('progress', options.close)); 3501 | if (options.verbose) { 3502 | process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); 3503 | } 3504 | }); 3505 | 3506 | // tests are complete, output some stats 3507 | // and the failures if any 3508 | runner.on('end', function(){ 3509 | cursor.show(); 3510 | console.log(); 3511 | self.epilogue(); 3512 | }); 3513 | } 3514 | 3515 | /** 3516 | * Inherit from `Base.prototype`. 3517 | */ 3518 | 3519 | function F(){}; 3520 | F.prototype = Base.prototype; 3521 | Progress.prototype = new F; 3522 | Progress.prototype.constructor = Progress; 3523 | 3524 | 3525 | }); // module: reporters/progress.js 3526 | 3527 | require.register("reporters/spec.js", function(module, exports, require){ 3528 | 3529 | /** 3530 | * Module dependencies. 3531 | */ 3532 | 3533 | var Base = require('./base') 3534 | , cursor = Base.cursor 3535 | , color = Base.color; 3536 | 3537 | /** 3538 | * Expose `Spec`. 3539 | */ 3540 | 3541 | exports = module.exports = Spec; 3542 | 3543 | /** 3544 | * Initialize a new `Spec` test reporter. 3545 | * 3546 | * @param {Runner} runner 3547 | * @api public 3548 | */ 3549 | 3550 | function Spec(runner) { 3551 | Base.call(this, runner); 3552 | 3553 | var self = this 3554 | , stats = this.stats 3555 | , indents = 0 3556 | , n = 0; 3557 | 3558 | function indent() { 3559 | return Array(indents).join(' ') 3560 | } 3561 | 3562 | runner.on('start', function(){ 3563 | console.log(); 3564 | }); 3565 | 3566 | runner.on('suite', function(suite){ 3567 | ++indents; 3568 | console.log(color('suite', '%s%s'), indent(), suite.title); 3569 | }); 3570 | 3571 | runner.on('suite end', function(suite){ 3572 | --indents; 3573 | if (1 == indents) console.log(); 3574 | }); 3575 | 3576 | runner.on('test', function(test){ 3577 | process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': ')); 3578 | }); 3579 | 3580 | runner.on('pending', function(test){ 3581 | var fmt = indent() + color('pending', ' - %s'); 3582 | console.log(fmt, test.title); 3583 | }); 3584 | 3585 | runner.on('pass', function(test){ 3586 | if ('fast' == test.speed) { 3587 | var fmt = indent() 3588 | + color('checkmark', ' ' + Base.symbols.ok) 3589 | + color('pass', ' %s '); 3590 | cursor.CR(); 3591 | console.log(fmt, test.title); 3592 | } else { 3593 | var fmt = indent() 3594 | + color('checkmark', ' ' + Base.symbols.ok) 3595 | + color('pass', ' %s ') 3596 | + color(test.speed, '(%dms)'); 3597 | cursor.CR(); 3598 | console.log(fmt, test.title, test.duration); 3599 | } 3600 | }); 3601 | 3602 | runner.on('fail', function(test, err){ 3603 | cursor.CR(); 3604 | console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); 3605 | }); 3606 | 3607 | runner.on('end', self.epilogue.bind(self)); 3608 | } 3609 | 3610 | /** 3611 | * Inherit from `Base.prototype`. 3612 | */ 3613 | 3614 | function F(){}; 3615 | F.prototype = Base.prototype; 3616 | Spec.prototype = new F; 3617 | Spec.prototype.constructor = Spec; 3618 | 3619 | 3620 | }); // module: reporters/spec.js 3621 | 3622 | require.register("reporters/tap.js", function(module, exports, require){ 3623 | 3624 | /** 3625 | * Module dependencies. 3626 | */ 3627 | 3628 | var Base = require('./base') 3629 | , cursor = Base.cursor 3630 | , color = Base.color; 3631 | 3632 | /** 3633 | * Expose `TAP`. 3634 | */ 3635 | 3636 | exports = module.exports = TAP; 3637 | 3638 | /** 3639 | * Initialize a new `TAP` reporter. 3640 | * 3641 | * @param {Runner} runner 3642 | * @api public 3643 | */ 3644 | 3645 | function TAP(runner) { 3646 | Base.call(this, runner); 3647 | 3648 | var self = this 3649 | , stats = this.stats 3650 | , n = 1 3651 | , passes = 0 3652 | , failures = 0; 3653 | 3654 | runner.on('start', function(){ 3655 | var total = runner.grepTotal(runner.suite); 3656 | console.log('%d..%d', 1, total); 3657 | }); 3658 | 3659 | runner.on('test end', function(){ 3660 | ++n; 3661 | }); 3662 | 3663 | runner.on('pending', function(test){ 3664 | console.log('ok %d %s # SKIP -', n, title(test)); 3665 | }); 3666 | 3667 | runner.on('pass', function(test){ 3668 | passes++; 3669 | console.log('ok %d %s', n, title(test)); 3670 | }); 3671 | 3672 | runner.on('fail', function(test, err){ 3673 | failures++; 3674 | console.log('not ok %d %s', n, title(test)); 3675 | if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); 3676 | }); 3677 | 3678 | runner.on('end', function(){ 3679 | console.log('# tests ' + (passes + failures)); 3680 | console.log('# pass ' + passes); 3681 | console.log('# fail ' + failures); 3682 | }); 3683 | } 3684 | 3685 | /** 3686 | * Return a TAP-safe title of `test` 3687 | * 3688 | * @param {Object} test 3689 | * @return {String} 3690 | * @api private 3691 | */ 3692 | 3693 | function title(test) { 3694 | return test.fullTitle().replace(/#/g, ''); 3695 | } 3696 | 3697 | }); // module: reporters/tap.js 3698 | 3699 | require.register("reporters/teamcity.js", function(module, exports, require){ 3700 | 3701 | /** 3702 | * Module dependencies. 3703 | */ 3704 | 3705 | var Base = require('./base'); 3706 | 3707 | /** 3708 | * Expose `Teamcity`. 3709 | */ 3710 | 3711 | exports = module.exports = Teamcity; 3712 | 3713 | /** 3714 | * Initialize a new `Teamcity` reporter. 3715 | * 3716 | * @param {Runner} runner 3717 | * @api public 3718 | */ 3719 | 3720 | function Teamcity(runner) { 3721 | Base.call(this, runner); 3722 | var stats = this.stats; 3723 | 3724 | runner.on('start', function() { 3725 | console.log("##teamcity[testSuiteStarted name='mocha.suite']"); 3726 | }); 3727 | 3728 | runner.on('test', function(test) { 3729 | console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']"); 3730 | }); 3731 | 3732 | runner.on('fail', function(test, err) { 3733 | console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']"); 3734 | }); 3735 | 3736 | runner.on('pending', function(test) { 3737 | console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']"); 3738 | }); 3739 | 3740 | runner.on('test end', function(test) { 3741 | console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']"); 3742 | }); 3743 | 3744 | runner.on('end', function() { 3745 | console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']"); 3746 | }); 3747 | } 3748 | 3749 | /** 3750 | * Escape the given `str`. 3751 | */ 3752 | 3753 | function escape(str) { 3754 | return str 3755 | .replace(/\|/g, "||") 3756 | .replace(/\n/g, "|n") 3757 | .replace(/\r/g, "|r") 3758 | .replace(/\[/g, "|[") 3759 | .replace(/\]/g, "|]") 3760 | .replace(/\u0085/g, "|x") 3761 | .replace(/\u2028/g, "|l") 3762 | .replace(/\u2029/g, "|p") 3763 | .replace(/'/g, "|'"); 3764 | } 3765 | 3766 | }); // module: reporters/teamcity.js 3767 | 3768 | require.register("reporters/xunit.js", function(module, exports, require){ 3769 | 3770 | /** 3771 | * Module dependencies. 3772 | */ 3773 | 3774 | var Base = require('./base') 3775 | , utils = require('../utils') 3776 | , escape = utils.escape; 3777 | 3778 | /** 3779 | * Save timer references to avoid Sinon interfering (see GH-237). 3780 | */ 3781 | 3782 | var Date = global.Date 3783 | , setTimeout = global.setTimeout 3784 | , setInterval = global.setInterval 3785 | , clearTimeout = global.clearTimeout 3786 | , clearInterval = global.clearInterval; 3787 | 3788 | /** 3789 | * Expose `XUnit`. 3790 | */ 3791 | 3792 | exports = module.exports = XUnit; 3793 | 3794 | /** 3795 | * Initialize a new `XUnit` reporter. 3796 | * 3797 | * @param {Runner} runner 3798 | * @api public 3799 | */ 3800 | 3801 | function XUnit(runner) { 3802 | Base.call(this, runner); 3803 | var stats = this.stats 3804 | , tests = [] 3805 | , self = this; 3806 | 3807 | runner.on('pass', function(test){ 3808 | tests.push(test); 3809 | }); 3810 | 3811 | runner.on('fail', function(test){ 3812 | tests.push(test); 3813 | }); 3814 | 3815 | runner.on('end', function(){ 3816 | console.log(tag('testsuite', { 3817 | name: 'Mocha Tests' 3818 | , tests: stats.tests 3819 | , failures: stats.failures 3820 | , errors: stats.failures 3821 | , skipped: stats.tests - stats.failures - stats.passes 3822 | , timestamp: (new Date).toUTCString() 3823 | , time: (stats.duration / 1000) || 0 3824 | }, false)); 3825 | 3826 | tests.forEach(test); 3827 | console.log(''); 3828 | }); 3829 | } 3830 | 3831 | /** 3832 | * Inherit from `Base.prototype`. 3833 | */ 3834 | 3835 | function F(){}; 3836 | F.prototype = Base.prototype; 3837 | XUnit.prototype = new F; 3838 | XUnit.prototype.constructor = XUnit; 3839 | 3840 | 3841 | /** 3842 | * Output tag for the given `test.` 3843 | */ 3844 | 3845 | function test(test) { 3846 | var attrs = { 3847 | classname: test.parent.fullTitle() 3848 | , name: test.title 3849 | , time: test.duration / 1000 3850 | }; 3851 | 3852 | if ('failed' == test.state) { 3853 | var err = test.err; 3854 | attrs.message = escape(err.message); 3855 | console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); 3856 | } else if (test.pending) { 3857 | console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); 3858 | } else { 3859 | console.log(tag('testcase', attrs, true) ); 3860 | } 3861 | } 3862 | 3863 | /** 3864 | * HTML tag helper. 3865 | */ 3866 | 3867 | function tag(name, attrs, close, content) { 3868 | var end = close ? '/>' : '>' 3869 | , pairs = [] 3870 | , tag; 3871 | 3872 | for (var key in attrs) { 3873 | pairs.push(key + '="' + escape(attrs[key]) + '"'); 3874 | } 3875 | 3876 | tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; 3877 | if (content) tag += content + ''; 3887 | } 3888 | 3889 | }); // module: reporters/xunit.js 3890 | 3891 | require.register("runnable.js", function(module, exports, require){ 3892 | 3893 | /** 3894 | * Module dependencies. 3895 | */ 3896 | 3897 | var EventEmitter = require('browser/events').EventEmitter 3898 | , debug = require('browser/debug')('mocha:runnable') 3899 | , milliseconds = require('./ms'); 3900 | 3901 | /** 3902 | * Save timer references to avoid Sinon interfering (see GH-237). 3903 | */ 3904 | 3905 | var Date = global.Date 3906 | , setTimeout = global.setTimeout 3907 | , setInterval = global.setInterval 3908 | , clearTimeout = global.clearTimeout 3909 | , clearInterval = global.clearInterval; 3910 | 3911 | /** 3912 | * Object#toString(). 3913 | */ 3914 | 3915 | var toString = Object.prototype.toString; 3916 | 3917 | /** 3918 | * Expose `Runnable`. 3919 | */ 3920 | 3921 | module.exports = Runnable; 3922 | 3923 | /** 3924 | * Initialize a new `Runnable` with the given `title` and callback `fn`. 3925 | * 3926 | * @param {String} title 3927 | * @param {Function} fn 3928 | * @api private 3929 | */ 3930 | 3931 | function Runnable(title, fn) { 3932 | this.title = title; 3933 | this.fn = fn; 3934 | this.async = fn && fn.length; 3935 | this.sync = ! this.async; 3936 | this._timeout = 2000; 3937 | this._slow = 75; 3938 | this.timedOut = false; 3939 | } 3940 | 3941 | /** 3942 | * Inherit from `EventEmitter.prototype`. 3943 | */ 3944 | 3945 | function F(){}; 3946 | F.prototype = EventEmitter.prototype; 3947 | Runnable.prototype = new F; 3948 | Runnable.prototype.constructor = Runnable; 3949 | 3950 | 3951 | /** 3952 | * Set & get timeout `ms`. 3953 | * 3954 | * @param {Number|String} ms 3955 | * @return {Runnable|Number} ms or self 3956 | * @api private 3957 | */ 3958 | 3959 | Runnable.prototype.timeout = function(ms){ 3960 | if (0 == arguments.length) return this._timeout; 3961 | if ('string' == typeof ms) ms = milliseconds(ms); 3962 | debug('timeout %d', ms); 3963 | this._timeout = ms; 3964 | if (this.timer) this.resetTimeout(); 3965 | return this; 3966 | }; 3967 | 3968 | /** 3969 | * Set & get slow `ms`. 3970 | * 3971 | * @param {Number|String} ms 3972 | * @return {Runnable|Number} ms or self 3973 | * @api private 3974 | */ 3975 | 3976 | Runnable.prototype.slow = function(ms){ 3977 | if (0 === arguments.length) return this._slow; 3978 | if ('string' == typeof ms) ms = milliseconds(ms); 3979 | debug('timeout %d', ms); 3980 | this._slow = ms; 3981 | return this; 3982 | }; 3983 | 3984 | /** 3985 | * Return the full title generated by recursively 3986 | * concatenating the parent's full title. 3987 | * 3988 | * @return {String} 3989 | * @api public 3990 | */ 3991 | 3992 | Runnable.prototype.fullTitle = function(){ 3993 | return this.parent.fullTitle() + ' ' + this.title; 3994 | }; 3995 | 3996 | /** 3997 | * Clear the timeout. 3998 | * 3999 | * @api private 4000 | */ 4001 | 4002 | Runnable.prototype.clearTimeout = function(){ 4003 | clearTimeout(this.timer); 4004 | }; 4005 | 4006 | /** 4007 | * Inspect the runnable void of private properties. 4008 | * 4009 | * @return {String} 4010 | * @api private 4011 | */ 4012 | 4013 | Runnable.prototype.inspect = function(){ 4014 | return JSON.stringify(this, function(key, val){ 4015 | if ('_' == key[0]) return; 4016 | if ('parent' == key) return '#'; 4017 | if ('ctx' == key) return '#'; 4018 | return val; 4019 | }, 2); 4020 | }; 4021 | 4022 | /** 4023 | * Reset the timeout. 4024 | * 4025 | * @api private 4026 | */ 4027 | 4028 | Runnable.prototype.resetTimeout = function(){ 4029 | var self = this; 4030 | var ms = this.timeout() || 1e9; 4031 | 4032 | this.clearTimeout(); 4033 | this.timer = setTimeout(function(){ 4034 | self.callback(new Error('timeout of ' + ms + 'ms exceeded')); 4035 | self.timedOut = true; 4036 | }, ms); 4037 | }; 4038 | 4039 | /** 4040 | * Run the test and invoke `fn(err)`. 4041 | * 4042 | * @param {Function} fn 4043 | * @api private 4044 | */ 4045 | 4046 | Runnable.prototype.run = function(fn){ 4047 | var self = this 4048 | , ms = this.timeout() 4049 | , start = new Date 4050 | , ctx = this.ctx 4051 | , finished 4052 | , emitted; 4053 | 4054 | if (ctx) ctx.runnable(this); 4055 | 4056 | // timeout 4057 | if (this.async) { 4058 | if (ms) { 4059 | this.timer = setTimeout(function(){ 4060 | done(new Error('timeout of ' + ms + 'ms exceeded')); 4061 | self.timedOut = true; 4062 | }, ms); 4063 | } 4064 | } 4065 | 4066 | // called multiple times 4067 | function multiple(err) { 4068 | if (emitted) return; 4069 | emitted = true; 4070 | self.emit('error', err || new Error('done() called multiple times')); 4071 | } 4072 | 4073 | // finished 4074 | function done(err) { 4075 | if (self.timedOut) return; 4076 | if (finished) return multiple(err); 4077 | self.clearTimeout(); 4078 | self.duration = new Date - start; 4079 | finished = true; 4080 | fn(err); 4081 | } 4082 | 4083 | // for .resetTimeout() 4084 | this.callback = done; 4085 | 4086 | // async 4087 | if (this.async) { 4088 | try { 4089 | this.fn.call(ctx, function(err){ 4090 | if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); 4091 | if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); 4092 | done(); 4093 | }); 4094 | } catch (err) { 4095 | done(err); 4096 | } 4097 | return; 4098 | } 4099 | 4100 | if (this.asyncOnly) { 4101 | return done(new Error('--async-only option in use without declaring `done()`')); 4102 | } 4103 | 4104 | // sync 4105 | try { 4106 | if (!this.pending) this.fn.call(ctx); 4107 | this.duration = new Date - start; 4108 | fn(); 4109 | } catch (err) { 4110 | fn(err); 4111 | } 4112 | }; 4113 | 4114 | }); // module: runnable.js 4115 | 4116 | require.register("runner.js", function(module, exports, require){ 4117 | /** 4118 | * Module dependencies. 4119 | */ 4120 | 4121 | var EventEmitter = require('browser/events').EventEmitter 4122 | , debug = require('browser/debug')('mocha:runner') 4123 | , Test = require('./test') 4124 | , utils = require('./utils') 4125 | , filter = utils.filter 4126 | , keys = utils.keys; 4127 | 4128 | /** 4129 | * Non-enumerable globals. 4130 | */ 4131 | 4132 | var globals = [ 4133 | 'setTimeout', 4134 | 'clearTimeout', 4135 | 'setInterval', 4136 | 'clearInterval', 4137 | 'XMLHttpRequest', 4138 | 'Date' 4139 | ]; 4140 | 4141 | /** 4142 | * Expose `Runner`. 4143 | */ 4144 | 4145 | module.exports = Runner; 4146 | 4147 | /** 4148 | * Initialize a `Runner` for the given `suite`. 4149 | * 4150 | * Events: 4151 | * 4152 | * - `start` execution started 4153 | * - `end` execution complete 4154 | * - `suite` (suite) test suite execution started 4155 | * - `suite end` (suite) all tests (and sub-suites) have finished 4156 | * - `test` (test) test execution started 4157 | * - `test end` (test) test completed 4158 | * - `hook` (hook) hook execution started 4159 | * - `hook end` (hook) hook complete 4160 | * - `pass` (test) test passed 4161 | * - `fail` (test, err) test failed 4162 | * - `pending` (test) test pending 4163 | * 4164 | * @api public 4165 | */ 4166 | 4167 | function Runner(suite) { 4168 | var self = this; 4169 | this._globals = []; 4170 | this.suite = suite; 4171 | this.total = suite.total(); 4172 | this.failures = 0; 4173 | this.on('test end', function(test){ self.checkGlobals(test); }); 4174 | this.on('hook end', function(hook){ self.checkGlobals(hook); }); 4175 | this.grep(/.*/); 4176 | this.globals(this.globalProps().concat(['errno'])); 4177 | } 4178 | 4179 | /** 4180 | * Wrapper for setImmediate, process.nextTick, or browser polyfill. 4181 | * 4182 | * @param {Function} fn 4183 | * @api private 4184 | */ 4185 | 4186 | Runner.immediately = global.setImmediate || process.nextTick; 4187 | 4188 | /** 4189 | * Inherit from `EventEmitter.prototype`. 4190 | */ 4191 | 4192 | function F(){}; 4193 | F.prototype = EventEmitter.prototype; 4194 | Runner.prototype = new F; 4195 | Runner.prototype.constructor = Runner; 4196 | 4197 | 4198 | /** 4199 | * Run tests with full titles matching `re`. Updates runner.total 4200 | * with number of tests matched. 4201 | * 4202 | * @param {RegExp} re 4203 | * @param {Boolean} invert 4204 | * @return {Runner} for chaining 4205 | * @api public 4206 | */ 4207 | 4208 | Runner.prototype.grep = function(re, invert){ 4209 | debug('grep %s', re); 4210 | this._grep = re; 4211 | this._invert = invert; 4212 | this.total = this.grepTotal(this.suite); 4213 | return this; 4214 | }; 4215 | 4216 | /** 4217 | * Returns the number of tests matching the grep search for the 4218 | * given suite. 4219 | * 4220 | * @param {Suite} suite 4221 | * @return {Number} 4222 | * @api public 4223 | */ 4224 | 4225 | Runner.prototype.grepTotal = function(suite) { 4226 | var self = this; 4227 | var total = 0; 4228 | 4229 | suite.eachTest(function(test){ 4230 | var match = self._grep.test(test.fullTitle()); 4231 | if (self._invert) match = !match; 4232 | if (match) total++; 4233 | }); 4234 | 4235 | return total; 4236 | }; 4237 | 4238 | /** 4239 | * Return a list of global properties. 4240 | * 4241 | * @return {Array} 4242 | * @api private 4243 | */ 4244 | 4245 | Runner.prototype.globalProps = function() { 4246 | var props = utils.keys(global); 4247 | 4248 | // non-enumerables 4249 | for (var i = 0; i < globals.length; ++i) { 4250 | if (~utils.indexOf(props, globals[i])) continue; 4251 | props.push(globals[i]); 4252 | } 4253 | 4254 | return props; 4255 | }; 4256 | 4257 | /** 4258 | * Allow the given `arr` of globals. 4259 | * 4260 | * @param {Array} arr 4261 | * @return {Runner} for chaining 4262 | * @api public 4263 | */ 4264 | 4265 | Runner.prototype.globals = function(arr){ 4266 | if (0 == arguments.length) return this._globals; 4267 | debug('globals %j', arr); 4268 | utils.forEach(arr, function(arr){ 4269 | this._globals.push(arr); 4270 | }, this); 4271 | return this; 4272 | }; 4273 | 4274 | /** 4275 | * Check for global variable leaks. 4276 | * 4277 | * @api private 4278 | */ 4279 | 4280 | Runner.prototype.checkGlobals = function(test){ 4281 | if (this.ignoreLeaks) return; 4282 | var ok = this._globals; 4283 | var globals = this.globalProps(); 4284 | var isNode = process.kill; 4285 | var leaks; 4286 | 4287 | // check length - 2 ('errno' and 'location' globals) 4288 | if (isNode && 1 == ok.length - globals.length) return 4289 | else if (2 == ok.length - globals.length) return; 4290 | 4291 | leaks = filterLeaks(ok, globals); 4292 | this._globals = this._globals.concat(leaks); 4293 | 4294 | if (leaks.length > 1) { 4295 | this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); 4296 | } else if (leaks.length) { 4297 | this.fail(test, new Error('global leak detected: ' + leaks[0])); 4298 | } 4299 | }; 4300 | 4301 | /** 4302 | * Fail the given `test`. 4303 | * 4304 | * @param {Test} test 4305 | * @param {Error} err 4306 | * @api private 4307 | */ 4308 | 4309 | Runner.prototype.fail = function(test, err){ 4310 | ++this.failures; 4311 | test.state = 'failed'; 4312 | 4313 | if ('string' == typeof err) { 4314 | err = new Error('the string "' + err + '" was thrown, throw an Error :)'); 4315 | } 4316 | 4317 | this.emit('fail', test, err); 4318 | }; 4319 | 4320 | /** 4321 | * Fail the given `hook` with `err`. 4322 | * 4323 | * Hook failures (currently) hard-end due 4324 | * to that fact that a failing hook will 4325 | * surely cause subsequent tests to fail, 4326 | * causing jumbled reporting. 4327 | * 4328 | * @param {Hook} hook 4329 | * @param {Error} err 4330 | * @api private 4331 | */ 4332 | 4333 | Runner.prototype.failHook = function(hook, err){ 4334 | this.fail(hook, err); 4335 | this.emit('end'); 4336 | }; 4337 | 4338 | /** 4339 | * Run hook `name` callbacks and then invoke `fn()`. 4340 | * 4341 | * @param {String} name 4342 | * @param {Function} function 4343 | * @api private 4344 | */ 4345 | 4346 | Runner.prototype.hook = function(name, fn){ 4347 | var suite = this.suite 4348 | , hooks = suite['_' + name] 4349 | , self = this 4350 | , timer; 4351 | 4352 | function next(i) { 4353 | var hook = hooks[i]; 4354 | if (!hook) return fn(); 4355 | if (self.failures && suite.bail()) return fn(); 4356 | self.currentRunnable = hook; 4357 | 4358 | hook.ctx.currentTest = self.test; 4359 | 4360 | self.emit('hook', hook); 4361 | 4362 | hook.on('error', function(err){ 4363 | self.failHook(hook, err); 4364 | }); 4365 | 4366 | hook.run(function(err){ 4367 | hook.removeAllListeners('error'); 4368 | var testError = hook.error(); 4369 | if (testError) self.fail(self.test, testError); 4370 | if (err) return self.failHook(hook, err); 4371 | self.emit('hook end', hook); 4372 | delete hook.ctx.currentTest; 4373 | next(++i); 4374 | }); 4375 | } 4376 | 4377 | Runner.immediately(function(){ 4378 | next(0); 4379 | }); 4380 | }; 4381 | 4382 | /** 4383 | * Run hook `name` for the given array of `suites` 4384 | * in order, and callback `fn(err)`. 4385 | * 4386 | * @param {String} name 4387 | * @param {Array} suites 4388 | * @param {Function} fn 4389 | * @api private 4390 | */ 4391 | 4392 | Runner.prototype.hooks = function(name, suites, fn){ 4393 | var self = this 4394 | , orig = this.suite; 4395 | 4396 | function next(suite) { 4397 | self.suite = suite; 4398 | 4399 | if (!suite) { 4400 | self.suite = orig; 4401 | return fn(); 4402 | } 4403 | 4404 | self.hook(name, function(err){ 4405 | if (err) { 4406 | self.suite = orig; 4407 | return fn(err); 4408 | } 4409 | 4410 | next(suites.pop()); 4411 | }); 4412 | } 4413 | 4414 | next(suites.pop()); 4415 | }; 4416 | 4417 | /** 4418 | * Run hooks from the top level down. 4419 | * 4420 | * @param {String} name 4421 | * @param {Function} fn 4422 | * @api private 4423 | */ 4424 | 4425 | Runner.prototype.hookUp = function(name, fn){ 4426 | var suites = [this.suite].concat(this.parents()).reverse(); 4427 | this.hooks(name, suites, fn); 4428 | }; 4429 | 4430 | /** 4431 | * Run hooks from the bottom up. 4432 | * 4433 | * @param {String} name 4434 | * @param {Function} fn 4435 | * @api private 4436 | */ 4437 | 4438 | Runner.prototype.hookDown = function(name, fn){ 4439 | var suites = [this.suite].concat(this.parents()); 4440 | this.hooks(name, suites, fn); 4441 | }; 4442 | 4443 | /** 4444 | * Return an array of parent Suites from 4445 | * closest to furthest. 4446 | * 4447 | * @return {Array} 4448 | * @api private 4449 | */ 4450 | 4451 | Runner.prototype.parents = function(){ 4452 | var suite = this.suite 4453 | , suites = []; 4454 | while (suite = suite.parent) suites.push(suite); 4455 | return suites; 4456 | }; 4457 | 4458 | /** 4459 | * Run the current test and callback `fn(err)`. 4460 | * 4461 | * @param {Function} fn 4462 | * @api private 4463 | */ 4464 | 4465 | Runner.prototype.runTest = function(fn){ 4466 | var test = this.test 4467 | , self = this; 4468 | 4469 | if (this.asyncOnly) test.asyncOnly = true; 4470 | 4471 | try { 4472 | test.on('error', function(err){ 4473 | self.fail(test, err); 4474 | }); 4475 | test.run(fn); 4476 | } catch (err) { 4477 | fn(err); 4478 | } 4479 | }; 4480 | 4481 | /** 4482 | * Run tests in the given `suite` and invoke 4483 | * the callback `fn()` when complete. 4484 | * 4485 | * @param {Suite} suite 4486 | * @param {Function} fn 4487 | * @api private 4488 | */ 4489 | 4490 | Runner.prototype.runTests = function(suite, fn){ 4491 | var self = this 4492 | , tests = suite.tests.slice() 4493 | , test; 4494 | 4495 | function next(err) { 4496 | // if we bail after first err 4497 | if (self.failures && suite._bail) return fn(); 4498 | 4499 | // next test 4500 | test = tests.shift(); 4501 | 4502 | // all done 4503 | if (!test) return fn(); 4504 | 4505 | // grep 4506 | var match = self._grep.test(test.fullTitle()); 4507 | if (self._invert) match = !match; 4508 | if (!match) return next(); 4509 | 4510 | // pending 4511 | if (test.pending) { 4512 | self.emit('pending', test); 4513 | self.emit('test end', test); 4514 | return next(); 4515 | } 4516 | 4517 | // execute test and hook(s) 4518 | self.emit('test', self.test = test); 4519 | self.hookDown('beforeEach', function(){ 4520 | self.currentRunnable = self.test; 4521 | self.runTest(function(err){ 4522 | test = self.test; 4523 | 4524 | if (err) { 4525 | self.fail(test, err); 4526 | self.emit('test end', test); 4527 | return self.hookUp('afterEach', next); 4528 | } 4529 | 4530 | test.state = 'passed'; 4531 | self.emit('pass', test); 4532 | self.emit('test end', test); 4533 | self.hookUp('afterEach', next); 4534 | }); 4535 | }); 4536 | } 4537 | 4538 | this.next = next; 4539 | next(); 4540 | }; 4541 | 4542 | /** 4543 | * Run the given `suite` and invoke the 4544 | * callback `fn()` when complete. 4545 | * 4546 | * @param {Suite} suite 4547 | * @param {Function} fn 4548 | * @api private 4549 | */ 4550 | 4551 | Runner.prototype.runSuite = function(suite, fn){ 4552 | var total = this.grepTotal(suite) 4553 | , self = this 4554 | , i = 0; 4555 | 4556 | debug('run suite %s', suite.fullTitle()); 4557 | 4558 | if (!total) return fn(); 4559 | 4560 | this.emit('suite', this.suite = suite); 4561 | 4562 | function next() { 4563 | var curr = suite.suites[i++]; 4564 | if (!curr) return done(); 4565 | self.runSuite(curr, next); 4566 | } 4567 | 4568 | function done() { 4569 | self.suite = suite; 4570 | self.hook('afterAll', function(){ 4571 | self.emit('suite end', suite); 4572 | fn(); 4573 | }); 4574 | } 4575 | 4576 | this.hook('beforeAll', function(){ 4577 | self.runTests(suite, next); 4578 | }); 4579 | }; 4580 | 4581 | /** 4582 | * Handle uncaught exceptions. 4583 | * 4584 | * @param {Error} err 4585 | * @api private 4586 | */ 4587 | 4588 | Runner.prototype.uncaught = function(err){ 4589 | debug('uncaught exception %s', err.message); 4590 | var runnable = this.currentRunnable; 4591 | if (!runnable || 'failed' == runnable.state) return; 4592 | runnable.clearTimeout(); 4593 | err.uncaught = true; 4594 | this.fail(runnable, err); 4595 | 4596 | // recover from test 4597 | if ('test' == runnable.type) { 4598 | this.emit('test end', runnable); 4599 | this.hookUp('afterEach', this.next); 4600 | return; 4601 | } 4602 | 4603 | // bail on hooks 4604 | this.emit('end'); 4605 | }; 4606 | 4607 | /** 4608 | * Run the root suite and invoke `fn(failures)` 4609 | * on completion. 4610 | * 4611 | * @param {Function} fn 4612 | * @return {Runner} for chaining 4613 | * @api public 4614 | */ 4615 | 4616 | Runner.prototype.run = function(fn){ 4617 | var self = this 4618 | , fn = fn || function(){}; 4619 | 4620 | function uncaught(err){ 4621 | self.uncaught(err); 4622 | } 4623 | 4624 | debug('start'); 4625 | 4626 | // callback 4627 | this.on('end', function(){ 4628 | debug('end'); 4629 | process.removeListener('uncaughtException', uncaught); 4630 | fn(self.failures); 4631 | }); 4632 | 4633 | // run suites 4634 | this.emit('start'); 4635 | this.runSuite(this.suite, function(){ 4636 | debug('finished running'); 4637 | self.emit('end'); 4638 | }); 4639 | 4640 | // uncaught exception 4641 | process.on('uncaughtException', uncaught); 4642 | 4643 | return this; 4644 | }; 4645 | 4646 | /** 4647 | * Filter leaks with the given globals flagged as `ok`. 4648 | * 4649 | * @param {Array} ok 4650 | * @param {Array} globals 4651 | * @return {Array} 4652 | * @api private 4653 | */ 4654 | 4655 | function filterLeaks(ok, globals) { 4656 | return filter(globals, function(key){ 4657 | // Firefox and Chrome exposes iframes as index inside the window object 4658 | if (/^d+/.test(key)) return false; 4659 | var matched = filter(ok, function(ok){ 4660 | if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); 4661 | // Opera and IE expose global variables for HTML element IDs (issue #243) 4662 | if (/^mocha-/.test(key)) return true; 4663 | return key == ok; 4664 | }); 4665 | return matched.length == 0 && (!global.navigator || 'onerror' !== key); 4666 | }); 4667 | } 4668 | 4669 | }); // module: runner.js 4670 | 4671 | require.register("suite.js", function(module, exports, require){ 4672 | 4673 | /** 4674 | * Module dependencies. 4675 | */ 4676 | 4677 | var EventEmitter = require('browser/events').EventEmitter 4678 | , debug = require('browser/debug')('mocha:suite') 4679 | , milliseconds = require('./ms') 4680 | , utils = require('./utils') 4681 | , Hook = require('./hook'); 4682 | 4683 | /** 4684 | * Expose `Suite`. 4685 | */ 4686 | 4687 | exports = module.exports = Suite; 4688 | 4689 | /** 4690 | * Create a new `Suite` with the given `title` 4691 | * and parent `Suite`. When a suite with the 4692 | * same title is already present, that suite 4693 | * is returned to provide nicer reporter 4694 | * and more flexible meta-testing. 4695 | * 4696 | * @param {Suite} parent 4697 | * @param {String} title 4698 | * @return {Suite} 4699 | * @api public 4700 | */ 4701 | 4702 | exports.create = function(parent, title){ 4703 | var suite = new Suite(title, parent.ctx); 4704 | suite.parent = parent; 4705 | if (parent.pending) suite.pending = true; 4706 | title = suite.fullTitle(); 4707 | parent.addSuite(suite); 4708 | return suite; 4709 | }; 4710 | 4711 | /** 4712 | * Initialize a new `Suite` with the given 4713 | * `title` and `ctx`. 4714 | * 4715 | * @param {String} title 4716 | * @param {Context} ctx 4717 | * @api private 4718 | */ 4719 | 4720 | function Suite(title, ctx) { 4721 | this.title = title; 4722 | this.ctx = ctx; 4723 | this.suites = []; 4724 | this.tests = []; 4725 | this.pending = false; 4726 | this._beforeEach = []; 4727 | this._beforeAll = []; 4728 | this._afterEach = []; 4729 | this._afterAll = []; 4730 | this.root = !title; 4731 | this._timeout = 2000; 4732 | this._slow = 75; 4733 | this._bail = false; 4734 | } 4735 | 4736 | /** 4737 | * Inherit from `EventEmitter.prototype`. 4738 | */ 4739 | 4740 | function F(){}; 4741 | F.prototype = EventEmitter.prototype; 4742 | Suite.prototype = new F; 4743 | Suite.prototype.constructor = Suite; 4744 | 4745 | 4746 | /** 4747 | * Return a clone of this `Suite`. 4748 | * 4749 | * @return {Suite} 4750 | * @api private 4751 | */ 4752 | 4753 | Suite.prototype.clone = function(){ 4754 | var suite = new Suite(this.title); 4755 | debug('clone'); 4756 | suite.ctx = this.ctx; 4757 | suite.timeout(this.timeout()); 4758 | suite.slow(this.slow()); 4759 | suite.bail(this.bail()); 4760 | return suite; 4761 | }; 4762 | 4763 | /** 4764 | * Set timeout `ms` or short-hand such as "2s". 4765 | * 4766 | * @param {Number|String} ms 4767 | * @return {Suite|Number} for chaining 4768 | * @api private 4769 | */ 4770 | 4771 | Suite.prototype.timeout = function(ms){ 4772 | if (0 == arguments.length) return this._timeout; 4773 | if ('string' == typeof ms) ms = milliseconds(ms); 4774 | debug('timeout %d', ms); 4775 | this._timeout = parseInt(ms, 10); 4776 | return this; 4777 | }; 4778 | 4779 | /** 4780 | * Set slow `ms` or short-hand such as "2s". 4781 | * 4782 | * @param {Number|String} ms 4783 | * @return {Suite|Number} for chaining 4784 | * @api private 4785 | */ 4786 | 4787 | Suite.prototype.slow = function(ms){ 4788 | if (0 === arguments.length) return this._slow; 4789 | if ('string' == typeof ms) ms = milliseconds(ms); 4790 | debug('slow %d', ms); 4791 | this._slow = ms; 4792 | return this; 4793 | }; 4794 | 4795 | /** 4796 | * Sets whether to bail after first error. 4797 | * 4798 | * @parma {Boolean} bail 4799 | * @return {Suite|Number} for chaining 4800 | * @api private 4801 | */ 4802 | 4803 | Suite.prototype.bail = function(bail){ 4804 | if (0 == arguments.length) return this._bail; 4805 | debug('bail %s', bail); 4806 | this._bail = bail; 4807 | return this; 4808 | }; 4809 | 4810 | /** 4811 | * Run `fn(test[, done])` before running tests. 4812 | * 4813 | * @param {Function} fn 4814 | * @return {Suite} for chaining 4815 | * @api private 4816 | */ 4817 | 4818 | Suite.prototype.beforeAll = function(fn){ 4819 | if (this.pending) return this; 4820 | var hook = new Hook('"before all" hook', fn); 4821 | hook.parent = this; 4822 | hook.timeout(this.timeout()); 4823 | hook.slow(this.slow()); 4824 | hook.ctx = this.ctx; 4825 | this._beforeAll.push(hook); 4826 | this.emit('beforeAll', hook); 4827 | return this; 4828 | }; 4829 | 4830 | /** 4831 | * Run `fn(test[, done])` after running tests. 4832 | * 4833 | * @param {Function} fn 4834 | * @return {Suite} for chaining 4835 | * @api private 4836 | */ 4837 | 4838 | Suite.prototype.afterAll = function(fn){ 4839 | if (this.pending) return this; 4840 | var hook = new Hook('"after all" hook', fn); 4841 | hook.parent = this; 4842 | hook.timeout(this.timeout()); 4843 | hook.slow(this.slow()); 4844 | hook.ctx = this.ctx; 4845 | this._afterAll.push(hook); 4846 | this.emit('afterAll', hook); 4847 | return this; 4848 | }; 4849 | 4850 | /** 4851 | * Run `fn(test[, done])` before each test case. 4852 | * 4853 | * @param {Function} fn 4854 | * @return {Suite} for chaining 4855 | * @api private 4856 | */ 4857 | 4858 | Suite.prototype.beforeEach = function(fn){ 4859 | if (this.pending) return this; 4860 | var hook = new Hook('"before each" hook', fn); 4861 | hook.parent = this; 4862 | hook.timeout(this.timeout()); 4863 | hook.slow(this.slow()); 4864 | hook.ctx = this.ctx; 4865 | this._beforeEach.push(hook); 4866 | this.emit('beforeEach', hook); 4867 | return this; 4868 | }; 4869 | 4870 | /** 4871 | * Run `fn(test[, done])` after each test case. 4872 | * 4873 | * @param {Function} fn 4874 | * @return {Suite} for chaining 4875 | * @api private 4876 | */ 4877 | 4878 | Suite.prototype.afterEach = function(fn){ 4879 | if (this.pending) return this; 4880 | var hook = new Hook('"after each" hook', fn); 4881 | hook.parent = this; 4882 | hook.timeout(this.timeout()); 4883 | hook.slow(this.slow()); 4884 | hook.ctx = this.ctx; 4885 | this._afterEach.push(hook); 4886 | this.emit('afterEach', hook); 4887 | return this; 4888 | }; 4889 | 4890 | /** 4891 | * Add a test `suite`. 4892 | * 4893 | * @param {Suite} suite 4894 | * @return {Suite} for chaining 4895 | * @api private 4896 | */ 4897 | 4898 | Suite.prototype.addSuite = function(suite){ 4899 | suite.parent = this; 4900 | suite.timeout(this.timeout()); 4901 | suite.slow(this.slow()); 4902 | suite.bail(this.bail()); 4903 | this.suites.push(suite); 4904 | this.emit('suite', suite); 4905 | return this; 4906 | }; 4907 | 4908 | /** 4909 | * Add a `test` to this suite. 4910 | * 4911 | * @param {Test} test 4912 | * @return {Suite} for chaining 4913 | * @api private 4914 | */ 4915 | 4916 | Suite.prototype.addTest = function(test){ 4917 | test.parent = this; 4918 | test.timeout(this.timeout()); 4919 | test.slow(this.slow()); 4920 | test.ctx = this.ctx; 4921 | this.tests.push(test); 4922 | this.emit('test', test); 4923 | return this; 4924 | }; 4925 | 4926 | /** 4927 | * Return the full title generated by recursively 4928 | * concatenating the parent's full title. 4929 | * 4930 | * @return {String} 4931 | * @api public 4932 | */ 4933 | 4934 | Suite.prototype.fullTitle = function(){ 4935 | if (this.parent) { 4936 | var full = this.parent.fullTitle(); 4937 | if (full) return full + ' ' + this.title; 4938 | } 4939 | return this.title; 4940 | }; 4941 | 4942 | /** 4943 | * Return the total number of tests. 4944 | * 4945 | * @return {Number} 4946 | * @api public 4947 | */ 4948 | 4949 | Suite.prototype.total = function(){ 4950 | return utils.reduce(this.suites, function(sum, suite){ 4951 | return sum + suite.total(); 4952 | }, 0) + this.tests.length; 4953 | }; 4954 | 4955 | /** 4956 | * Iterates through each suite recursively to find 4957 | * all tests. Applies a function in the format 4958 | * `fn(test)`. 4959 | * 4960 | * @param {Function} fn 4961 | * @return {Suite} 4962 | * @api private 4963 | */ 4964 | 4965 | Suite.prototype.eachTest = function(fn){ 4966 | utils.forEach(this.tests, fn); 4967 | utils.forEach(this.suites, function(suite){ 4968 | suite.eachTest(fn); 4969 | }); 4970 | return this; 4971 | }; 4972 | 4973 | }); // module: suite.js 4974 | 4975 | require.register("test.js", function(module, exports, require){ 4976 | 4977 | /** 4978 | * Module dependencies. 4979 | */ 4980 | 4981 | var Runnable = require('./runnable'); 4982 | 4983 | /** 4984 | * Expose `Test`. 4985 | */ 4986 | 4987 | module.exports = Test; 4988 | 4989 | /** 4990 | * Initialize a new `Test` with the given `title` and callback `fn`. 4991 | * 4992 | * @param {String} title 4993 | * @param {Function} fn 4994 | * @api private 4995 | */ 4996 | 4997 | function Test(title, fn) { 4998 | Runnable.call(this, title, fn); 4999 | this.pending = !fn; 5000 | this.type = 'test'; 5001 | } 5002 | 5003 | /** 5004 | * Inherit from `Runnable.prototype`. 5005 | */ 5006 | 5007 | function F(){}; 5008 | F.prototype = Runnable.prototype; 5009 | Test.prototype = new F; 5010 | Test.prototype.constructor = Test; 5011 | 5012 | 5013 | }); // module: test.js 5014 | 5015 | require.register("utils.js", function(module, exports, require){ 5016 | 5017 | /** 5018 | * Module dependencies. 5019 | */ 5020 | 5021 | var fs = require('browser/fs') 5022 | , path = require('browser/path') 5023 | , join = path.join 5024 | , debug = require('browser/debug')('mocha:watch'); 5025 | 5026 | /** 5027 | * Ignored directories. 5028 | */ 5029 | 5030 | var ignore = ['node_modules', '.git']; 5031 | 5032 | /** 5033 | * Escape special characters in the given string of html. 5034 | * 5035 | * @param {String} html 5036 | * @return {String} 5037 | * @api private 5038 | */ 5039 | 5040 | exports.escape = function(html){ 5041 | return String(html) 5042 | .replace(/&/g, '&') 5043 | .replace(/"/g, '"') 5044 | .replace(//g, '>'); 5046 | }; 5047 | 5048 | /** 5049 | * Array#forEach (<=IE8) 5050 | * 5051 | * @param {Array} array 5052 | * @param {Function} fn 5053 | * @param {Object} scope 5054 | * @api private 5055 | */ 5056 | 5057 | exports.forEach = function(arr, fn, scope){ 5058 | for (var i = 0, l = arr.length; i < l; i++) 5059 | fn.call(scope, arr[i], i); 5060 | }; 5061 | 5062 | /** 5063 | * Array#indexOf (<=IE8) 5064 | * 5065 | * @parma {Array} arr 5066 | * @param {Object} obj to find index of 5067 | * @param {Number} start 5068 | * @api private 5069 | */ 5070 | 5071 | exports.indexOf = function(arr, obj, start){ 5072 | for (var i = start || 0, l = arr.length; i < l; i++) { 5073 | if (arr[i] === obj) 5074 | return i; 5075 | } 5076 | return -1; 5077 | }; 5078 | 5079 | /** 5080 | * Array#reduce (<=IE8) 5081 | * 5082 | * @param {Array} array 5083 | * @param {Function} fn 5084 | * @param {Object} initial value 5085 | * @api private 5086 | */ 5087 | 5088 | exports.reduce = function(arr, fn, val){ 5089 | var rval = val; 5090 | 5091 | for (var i = 0, l = arr.length; i < l; i++) { 5092 | rval = fn(rval, arr[i], i, arr); 5093 | } 5094 | 5095 | return rval; 5096 | }; 5097 | 5098 | /** 5099 | * Array#filter (<=IE8) 5100 | * 5101 | * @param {Array} array 5102 | * @param {Function} fn 5103 | * @api private 5104 | */ 5105 | 5106 | exports.filter = function(arr, fn){ 5107 | var ret = []; 5108 | 5109 | for (var i = 0, l = arr.length; i < l; i++) { 5110 | var val = arr[i]; 5111 | if (fn(val, i, arr)) ret.push(val); 5112 | } 5113 | 5114 | return ret; 5115 | }; 5116 | 5117 | /** 5118 | * Object.keys (<=IE8) 5119 | * 5120 | * @param {Object} obj 5121 | * @return {Array} keys 5122 | * @api private 5123 | */ 5124 | 5125 | exports.keys = Object.keys || function(obj) { 5126 | var keys = [] 5127 | , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 5128 | 5129 | for (var key in obj) { 5130 | if (has.call(obj, key)) { 5131 | keys.push(key); 5132 | } 5133 | } 5134 | 5135 | return keys; 5136 | }; 5137 | 5138 | /** 5139 | * Watch the given `files` for changes 5140 | * and invoke `fn(file)` on modification. 5141 | * 5142 | * @param {Array} files 5143 | * @param {Function} fn 5144 | * @api private 5145 | */ 5146 | 5147 | exports.watch = function(files, fn){ 5148 | var options = { interval: 100 }; 5149 | files.forEach(function(file){ 5150 | debug('file %s', file); 5151 | fs.watchFile(file, options, function(curr, prev){ 5152 | if (prev.mtime < curr.mtime) fn(file); 5153 | }); 5154 | }); 5155 | }; 5156 | 5157 | /** 5158 | * Ignored files. 5159 | */ 5160 | 5161 | function ignored(path){ 5162 | return !~ignore.indexOf(path); 5163 | } 5164 | 5165 | /** 5166 | * Lookup files in the given `dir`. 5167 | * 5168 | * @return {Array} 5169 | * @api private 5170 | */ 5171 | 5172 | exports.files = function(dir, ret){ 5173 | ret = ret || []; 5174 | 5175 | fs.readdirSync(dir) 5176 | .filter(ignored) 5177 | .forEach(function(path){ 5178 | path = join(dir, path); 5179 | if (fs.statSync(path).isDirectory()) { 5180 | exports.files(path, ret); 5181 | } else if (path.match(/\.(js|coffee)$/)) { 5182 | ret.push(path); 5183 | } 5184 | }); 5185 | 5186 | return ret; 5187 | }; 5188 | 5189 | /** 5190 | * Compute a slug from the given `str`. 5191 | * 5192 | * @param {String} str 5193 | * @return {String} 5194 | * @api private 5195 | */ 5196 | 5197 | exports.slug = function(str){ 5198 | return str 5199 | .toLowerCase() 5200 | .replace(/ +/g, '-') 5201 | .replace(/[^-\w]/g, ''); 5202 | }; 5203 | 5204 | /** 5205 | * Strip the function definition from `str`, 5206 | * and re-indent for pre whitespace. 5207 | */ 5208 | 5209 | exports.clean = function(str) { 5210 | str = str 5211 | .replace(/^function *\(.*\) *{/, '') 5212 | .replace(/\s+\}$/, ''); 5213 | 5214 | var whitespace = str.match(/^\n?(\s*)/)[1] 5215 | , re = new RegExp('^' + whitespace, 'gm'); 5216 | 5217 | str = str.replace(re, ''); 5218 | 5219 | return exports.trim(str); 5220 | }; 5221 | 5222 | /** 5223 | * Escape regular expression characters in `str`. 5224 | * 5225 | * @param {String} str 5226 | * @return {String} 5227 | * @api private 5228 | */ 5229 | 5230 | exports.escapeRegexp = function(str){ 5231 | return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); 5232 | }; 5233 | 5234 | /** 5235 | * Trim the given `str`. 5236 | * 5237 | * @param {String} str 5238 | * @return {String} 5239 | * @api private 5240 | */ 5241 | 5242 | exports.trim = function(str){ 5243 | return str.replace(/^\s+|\s+$/g, ''); 5244 | }; 5245 | 5246 | /** 5247 | * Parse the given `qs`. 5248 | * 5249 | * @param {String} qs 5250 | * @return {Object} 5251 | * @api private 5252 | */ 5253 | 5254 | exports.parseQuery = function(qs){ 5255 | return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ 5256 | var i = pair.indexOf('=') 5257 | , key = pair.slice(0, i) 5258 | , val = pair.slice(++i); 5259 | 5260 | obj[key] = decodeURIComponent(val); 5261 | return obj; 5262 | }, {}); 5263 | }; 5264 | 5265 | /** 5266 | * Highlight the given string of `js`. 5267 | * 5268 | * @param {String} js 5269 | * @return {String} 5270 | * @api private 5271 | */ 5272 | 5273 | function highlight(js) { 5274 | return js 5275 | .replace(//g, '>') 5277 | .replace(/\/\/(.*)/gm, '//$1') 5278 | .replace(/('.*?')/gm, '$1') 5279 | .replace(/(\d+\.\d+)/gm, '$1') 5280 | .replace(/(\d+)/gm, '$1') 5281 | .replace(/\bnew *(\w+)/gm, 'new $1') 5282 | .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') 5283 | } 5284 | 5285 | /** 5286 | * Highlight the contents of tag `name`. 5287 | * 5288 | * @param {String} name 5289 | * @api private 5290 | */ 5291 | 5292 | exports.highlightTags = function(name) { 5293 | var code = document.getElementsByTagName(name); 5294 | for (var i = 0, len = code.length; i < len; ++i) { 5295 | code[i].innerHTML = highlight(code[i].innerHTML); 5296 | } 5297 | }; 5298 | 5299 | }); // module: utils.js 5300 | // The global object is "self" in Web Workers. 5301 | global = (function() { return this; })(); 5302 | 5303 | /** 5304 | * Save timer references to avoid Sinon interfering (see GH-237). 5305 | */ 5306 | 5307 | var Date = global.Date; 5308 | var setTimeout = global.setTimeout; 5309 | var setInterval = global.setInterval; 5310 | var clearTimeout = global.clearTimeout; 5311 | var clearInterval = global.clearInterval; 5312 | 5313 | /** 5314 | * Node shims. 5315 | * 5316 | * These are meant only to allow 5317 | * mocha.js to run untouched, not 5318 | * to allow running node code in 5319 | * the browser. 5320 | */ 5321 | 5322 | var process = {}; 5323 | process.exit = function(status){}; 5324 | process.stdout = {}; 5325 | 5326 | /** 5327 | * Remove uncaughtException listener. 5328 | */ 5329 | 5330 | process.removeListener = function(e){ 5331 | if ('uncaughtException' == e) { 5332 | global.onerror = function() {}; 5333 | } 5334 | }; 5335 | 5336 | /** 5337 | * Implements uncaughtException listener. 5338 | */ 5339 | 5340 | process.on = function(e, fn){ 5341 | if ('uncaughtException' == e) { 5342 | global.onerror = function(err, url, line){ 5343 | fn(new Error(err + ' (' + url + ':' + line + ')')); 5344 | }; 5345 | } 5346 | }; 5347 | 5348 | /** 5349 | * Expose mocha. 5350 | */ 5351 | 5352 | var Mocha = global.Mocha = require('mocha'), 5353 | mocha = global.mocha = new Mocha({ reporter: 'html' }); 5354 | 5355 | var immediateQueue = [] 5356 | , immediateTimeout; 5357 | 5358 | function timeslice() { 5359 | var immediateStart = new Date().getTime(); 5360 | while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { 5361 | immediateQueue.shift()(); 5362 | } 5363 | if (immediateQueue.length) { 5364 | immediateTimeout = setTimeout(timeslice, 0); 5365 | } else { 5366 | immediateTimeout = null; 5367 | } 5368 | } 5369 | 5370 | /** 5371 | * High-performance override of Runner.immediately. 5372 | */ 5373 | 5374 | Mocha.Runner.immediately = function(callback) { 5375 | immediateQueue.push(callback); 5376 | if (!immediateTimeout) { 5377 | immediateTimeout = setTimeout(timeslice, 0); 5378 | } 5379 | }; 5380 | 5381 | /** 5382 | * Override ui to ensure that the ui functions are initialized. 5383 | * Normally this would happen in Mocha.prototype.loadFiles. 5384 | */ 5385 | 5386 | mocha.ui = function(ui){ 5387 | Mocha.prototype.ui.call(this, ui); 5388 | this.suite.emit('pre-require', global, null, this); 5389 | return this; 5390 | }; 5391 | 5392 | /** 5393 | * Setup mocha with the given setting options. 5394 | */ 5395 | 5396 | mocha.setup = function(opts){ 5397 | if ('string' == typeof opts) opts = { ui: opts }; 5398 | for (var opt in opts) this[opt](opts[opt]); 5399 | return this; 5400 | }; 5401 | 5402 | /** 5403 | * Run mocha, returning the Runner. 5404 | */ 5405 | 5406 | mocha.run = function(fn){ 5407 | var options = mocha.options; 5408 | mocha.globals('location'); 5409 | 5410 | var query = Mocha.utils.parseQuery(global.location.search || ''); 5411 | if (query.grep) mocha.grep(query.grep); 5412 | if (query.invert) mocha.invert(); 5413 | 5414 | return Mocha.prototype.run.call(mocha, function(){ 5415 | // The DOM Document is not available in Web Workers. 5416 | if (global.document) { 5417 | Mocha.utils.highlightTags('code'); 5418 | } 5419 | if (fn) fn(); 5420 | }); 5421 | }; 5422 | 5423 | /** 5424 | * Expose the process shim. 5425 | */ 5426 | 5427 | Mocha.process = process; 5428 | })(); 5429 | --------------------------------------------------------------------------------