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

%s

', indent(), utils.escape(suite.title)); 2071 | console.log('%s
', indent()); 2072 | }); 2073 | 2074 | runner.on('suite end', function(suite){ 2075 | if (suite.root) return; 2076 | console.log('%s
', indent()); 2077 | --indents; 2078 | console.log('%s
', indent()); 2079 | --indents; 2080 | }); 2081 | 2082 | runner.on('pass', function(test){ 2083 | console.log('%s
%s
', indent(), utils.escape(test.title)); 2084 | var code = utils.escape(utils.clean(test.fn.toString())); 2085 | console.log('%s
%s
', indent(), code); 2086 | }); 2087 | } 2088 | 2089 | }); // module: reporters/doc.js 2090 | 2091 | require.register("reporters/dot.js", function(module, exports, require){ 2092 | 2093 | /** 2094 | * Module dependencies. 2095 | */ 2096 | 2097 | var Base = require('./base') 2098 | , color = Base.color; 2099 | 2100 | /** 2101 | * Expose `Dot`. 2102 | */ 2103 | 2104 | exports = module.exports = Dot; 2105 | 2106 | /** 2107 | * Initialize a new `Dot` matrix test reporter. 2108 | * 2109 | * @param {Runner} runner 2110 | * @api public 2111 | */ 2112 | 2113 | function Dot(runner) { 2114 | Base.call(this, runner); 2115 | 2116 | var self = this 2117 | , stats = this.stats 2118 | , width = Base.window.width * .75 | 0 2119 | , n = 0; 2120 | 2121 | runner.on('start', function(){ 2122 | process.stdout.write('\n '); 2123 | }); 2124 | 2125 | runner.on('pending', function(test){ 2126 | process.stdout.write(color('pending', Base.symbols.dot)); 2127 | }); 2128 | 2129 | runner.on('pass', function(test){ 2130 | if (++n % width == 0) process.stdout.write('\n '); 2131 | if ('slow' == test.speed) { 2132 | process.stdout.write(color('bright yellow', Base.symbols.dot)); 2133 | } else { 2134 | process.stdout.write(color(test.speed, Base.symbols.dot)); 2135 | } 2136 | }); 2137 | 2138 | runner.on('fail', function(test, err){ 2139 | if (++n % width == 0) process.stdout.write('\n '); 2140 | process.stdout.write(color('fail', Base.symbols.dot)); 2141 | }); 2142 | 2143 | runner.on('end', function(){ 2144 | console.log(); 2145 | self.epilogue(); 2146 | }); 2147 | } 2148 | 2149 | /** 2150 | * Inherit from `Base.prototype`. 2151 | */ 2152 | 2153 | function F(){}; 2154 | F.prototype = Base.prototype; 2155 | Dot.prototype = new F; 2156 | Dot.prototype.constructor = Dot; 2157 | 2158 | }); // module: reporters/dot.js 2159 | 2160 | require.register("reporters/html-cov.js", function(module, exports, require){ 2161 | 2162 | /** 2163 | * Module dependencies. 2164 | */ 2165 | 2166 | var JSONCov = require('./json-cov') 2167 | , fs = require('browser/fs'); 2168 | 2169 | /** 2170 | * Expose `HTMLCov`. 2171 | */ 2172 | 2173 | exports = module.exports = HTMLCov; 2174 | 2175 | /** 2176 | * Initialize a new `JsCoverage` reporter. 2177 | * 2178 | * @param {Runner} runner 2179 | * @api public 2180 | */ 2181 | 2182 | function HTMLCov(runner) { 2183 | var jade = require('jade') 2184 | , file = __dirname + '/templates/coverage.jade' 2185 | , str = fs.readFileSync(file, 'utf8') 2186 | , fn = jade.compile(str, { filename: file }) 2187 | , self = this; 2188 | 2189 | JSONCov.call(this, runner, false); 2190 | 2191 | runner.on('end', function(){ 2192 | process.stdout.write(fn({ 2193 | cov: self.cov 2194 | , coverageClass: coverageClass 2195 | })); 2196 | }); 2197 | } 2198 | 2199 | /** 2200 | * Return coverage class for `n`. 2201 | * 2202 | * @return {String} 2203 | * @api private 2204 | */ 2205 | 2206 | function coverageClass(n) { 2207 | if (n >= 75) return 'high'; 2208 | if (n >= 50) return 'medium'; 2209 | if (n >= 25) return 'low'; 2210 | return 'terrible'; 2211 | } 2212 | }); // module: reporters/html-cov.js 2213 | 2214 | require.register("reporters/html.js", function(module, exports, require){ 2215 | 2216 | /** 2217 | * Module dependencies. 2218 | */ 2219 | 2220 | var Base = require('./base') 2221 | , utils = require('../utils') 2222 | , Progress = require('../browser/progress') 2223 | , escape = utils.escape; 2224 | 2225 | /** 2226 | * Save timer references to avoid Sinon interfering (see GH-237). 2227 | */ 2228 | 2229 | var Date = global.Date 2230 | , setTimeout = global.setTimeout 2231 | , setInterval = global.setInterval 2232 | , clearTimeout = global.clearTimeout 2233 | , clearInterval = global.clearInterval; 2234 | 2235 | /** 2236 | * Expose `Doc`. 2237 | */ 2238 | 2239 | exports = module.exports = HTML; 2240 | 2241 | /** 2242 | * Stats template. 2243 | */ 2244 | 2245 | var statsTemplate = '
    ' 2246 | + '
  • ' 2247 | + '
  • passes: 0
  • ' 2248 | + '
  • failures: 0
  • ' 2249 | + '
  • duration: 0s
  • ' 2250 | + '
'; 2251 | 2252 | /** 2253 | * Initialize a new `Doc` reporter. 2254 | * 2255 | * @param {Runner} runner 2256 | * @api public 2257 | */ 2258 | 2259 | function HTML(runner, root) { 2260 | Base.call(this, runner); 2261 | 2262 | var self = this 2263 | , stats = this.stats 2264 | , total = runner.total 2265 | , stat = fragment(statsTemplate) 2266 | , items = stat.getElementsByTagName('li') 2267 | , passes = items[1].getElementsByTagName('em')[0] 2268 | , passesLink = items[1].getElementsByTagName('a')[0] 2269 | , failures = items[2].getElementsByTagName('em')[0] 2270 | , failuresLink = items[2].getElementsByTagName('a')[0] 2271 | , duration = items[3].getElementsByTagName('em')[0] 2272 | , canvas = stat.getElementsByTagName('canvas')[0] 2273 | , report = fragment('
    ') 2274 | , stack = [report] 2275 | , progress 2276 | , ctx 2277 | 2278 | root = root || document.getElementById('mocha'); 2279 | 2280 | if (canvas.getContext) { 2281 | var ratio = window.devicePixelRatio || 1; 2282 | canvas.style.width = canvas.width; 2283 | canvas.style.height = canvas.height; 2284 | canvas.width *= ratio; 2285 | canvas.height *= ratio; 2286 | ctx = canvas.getContext('2d'); 2287 | ctx.scale(ratio, ratio); 2288 | progress = new Progress; 2289 | } 2290 | 2291 | if (!root) return error('#mocha div missing, add it to your document'); 2292 | 2293 | // pass toggle 2294 | on(passesLink, 'click', function(){ 2295 | unhide(); 2296 | var name = /pass/.test(report.className) ? '' : ' pass'; 2297 | report.className = report.className.replace(/fail|pass/g, '') + name; 2298 | if (report.className.trim()) hideSuitesWithout('test pass'); 2299 | }); 2300 | 2301 | // failure toggle 2302 | on(failuresLink, 'click', function(){ 2303 | unhide(); 2304 | var name = /fail/.test(report.className) ? '' : ' fail'; 2305 | report.className = report.className.replace(/fail|pass/g, '') + name; 2306 | if (report.className.trim()) hideSuitesWithout('test fail'); 2307 | }); 2308 | 2309 | root.appendChild(stat); 2310 | root.appendChild(report); 2311 | 2312 | if (progress) progress.size(40); 2313 | 2314 | runner.on('suite', function(suite){ 2315 | if (suite.root) return; 2316 | 2317 | // suite 2318 | var url = '?grep=' + encodeURIComponent(suite.fullTitle()); 2319 | var el = fragment('
  • %s

  • ', url, escape(suite.title)); 2320 | 2321 | // container 2322 | stack[0].appendChild(el); 2323 | stack.unshift(document.createElement('ul')); 2324 | el.appendChild(stack[0]); 2325 | }); 2326 | 2327 | runner.on('suite end', function(suite){ 2328 | if (suite.root) return; 2329 | stack.shift(); 2330 | }); 2331 | 2332 | runner.on('fail', function(test, err){ 2333 | if ('hook' == test.type) runner.emit('test end', test); 2334 | }); 2335 | 2336 | runner.on('test end', function(test){ 2337 | window.scrollTo(0, document.body.scrollHeight); 2338 | 2339 | // TODO: add to stats 2340 | var percent = stats.tests / this.total * 100 | 0; 2341 | if (progress) progress.update(percent).draw(ctx); 2342 | 2343 | // update stats 2344 | var ms = new Date - stats.start; 2345 | text(passes, stats.passes); 2346 | text(failures, stats.failures); 2347 | text(duration, (ms / 1000).toFixed(2)); 2348 | 2349 | // test 2350 | if ('passed' == test.state) { 2351 | var el = fragment('
  • %e%ems

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

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

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