├── .gitignore
├── History.md
├── Makefile
├── Readme.md
├── component.json
├── index.css
├── lib
├── index.css
├── index.html
└── index.js
└── test
├── index.html
├── mocha.css
├── mocha.js
└── tests.js
/.gitignore:
--------------------------------------------------------------------------------
1 | components
2 | build
--------------------------------------------------------------------------------
/History.md:
--------------------------------------------------------------------------------
1 |
2 | 1.2.0 - August 26, 2014
3 | -----------------------
4 | * add duo support
5 |
6 | 0.0.2 - February 12, 2014
7 | -------------------------
8 | * peg modal at older version
9 |
10 | 0.0.1 - August 22, 2013
11 | -----------------------
12 | :sparkles:
13 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | build: components lib/index.js lib/index.html lib/index.css
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 | open test/index.html
13 |
14 | .PHONY: clean test
15 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # sheet
2 |
3 | A special modal that slides out from the right or left side of the screen.
4 |
5 | 
6 |
7 | ## Installation
8 |
9 | $ component install segmentio/sheet
10 |
11 | ## Example
12 |
13 | ```js
14 | var sheet = require('sheet');
15 | sheet(el).show();
16 | ```
17 |
18 | To use it, pass in the `el` you want to "sheet-ize".
19 |
20 | ## API
21 |
22 | ```html
23 |
24 |
25 |
26 | { Your element gets injected here. }
27 |
28 |
29 |
30 | ```
31 |
32 | A [`segmentio/overlay`](https://github.com/segmentio/overlay) element (with an `.overlay` class) is used to create the mask above the screen, so if you've already themed it you've got no more work to do.
33 |
34 |
35 | ### Sheet(el)
36 | Create a new `Sheet` instance with the given `el`.
37 |
38 | ### #show(fn)
39 | Show the sheet, emitting `show`, optionally calling `fn`.
40 |
41 | ### #hide(fn)
42 | Hide the sheet, emitting `hide`, optionally calling `fn`.
43 |
44 | ### #addClass(name)
45 | Add a class `name` to the `.sheet` and `.sheet-overlay`.
46 |
47 | ### #removeClass(name)
48 | Remove a class `name` from the `.sheet` and `.sheet-overlay`.
49 |
50 | ## License
51 |
52 | MIT
53 |
--------------------------------------------------------------------------------
/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sheet",
3 | "repo": "segmentio/sheet",
4 | "license": "MIT",
5 | "version": "1.2.0",
6 | "description": "A special modal that slides out from the right or left side of the screen.",
7 | "keywords": ["modal", "sheet", "ui", "overlay"],
8 | "dependencies": {
9 | "component/domify": "*",
10 | "component/delegate": "*",
11 | "segmentio/modal": "0.3.5",
12 | "ianstormtaylor/classes": "0.1.0"
13 | },
14 | "development": {
15 | "component/assert": "*",
16 | "segmentio/on-enter": "*"
17 | },
18 | "scripts": ["lib/index.js"],
19 | "styles": ["lib/index.css"],
20 | "templates": ["lib/index.html"],
21 | "main": "lib/index.js"
22 | }
23 |
--------------------------------------------------------------------------------
/index.css:
--------------------------------------------------------------------------------
1 | @import 'segmentio/modal';
2 | @import './lib/index.css';
--------------------------------------------------------------------------------
/lib/index.css:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Sheet.
4 |
5 | * .sheet
6 | * .sheet-close-button
7 | * [content]
8 | */
9 |
10 | .Sheet {
11 | position: absolute;
12 | top: 0;
13 | left: 0;
14 | right: 0;
15 | bottom: 0;
16 | background: white;
17 | }
18 |
19 |
20 | /**
21 | * Modal effect
22 | */
23 |
24 | .Modal[effect="sheet-right"],
25 | .Modal[effect="sheet-left"] {
26 | position: fixed;
27 | top: 0;
28 | bottom: 0;
29 | width: 60%;
30 | z-index: 101;
31 | -webkit-transition: -webkit-transform .3s;
32 | transition: transform .3s;
33 | max-width: none;
34 | -webkit-transform: translateX(0%);
35 | -moz-transform: translateX(0%);
36 | transform: translateX(0%);
37 | }
38 |
39 |
40 | /**
41 | * Right-aligned.
42 | */
43 |
44 | .Modal[effect="sheet-right"] {
45 | right: 0;
46 | left: auto;
47 | }
48 |
49 | .Modal[effect="sheet-right"].hidden {
50 | -webkit-transform: translate3d(110%,0,0);
51 | -moz-transform: translate3d(110%,0,0);
52 | transform: translate3d(100%,0,0);
53 | }
54 |
55 | /**
56 | * Left-aligned.
57 | */
58 |
59 | .Modal[effect="sheet-left"] {
60 | left: 0;
61 | right: auto;
62 | }
63 |
64 | .Modal[effect="sheet-left"].hidden {
65 | -webkit-transform: translate3d(-110%,0,0);
66 | -moz-transform: translate3d(-110%,0,0);
67 | transform: translate3d(-110%,0,0);
68 | }
--------------------------------------------------------------------------------
/lib/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 |
2 | var domify = require('domify');
3 | var modal = require('modal');
4 | var template = require('./index.html');
5 | var delegate = require('delegate');
6 | var classes = require('classes');
7 |
8 |
9 | /**
10 | * Expose `Sheet`.
11 | */
12 |
13 | module.exports = Sheet;
14 |
15 |
16 | /**
17 | * Initialize a new `Sheet`.
18 | *
19 | * @param {Element} content
20 | */
21 |
22 | function Sheet (content) {
23 | if (!(this instanceof Sheet)) return new Sheet(content);
24 | this.el = domify(template);
25 | this.el.appendChild(content);
26 | this.modal = modal(this.el)
27 | .overlay()
28 | .closable();
29 | this.align('right');
30 | delegate.bind(this.el, '[on-click="hide"]', 'click', this.hide.bind(this), true);
31 | }
32 |
33 |
34 | /**
35 | * Mixins
36 | */
37 |
38 | classes(Sheet.prototype);
39 |
40 |
41 | /**
42 | * Set the sheet's alignment.
43 | *
44 | * @param {String} side (left or right)
45 | * @return {Sheet}
46 | */
47 |
48 | Sheet.prototype.align = function (side) {
49 | this.modal.effect('sheet-' + side);
50 | return this;
51 | };
52 |
53 |
54 | /**
55 | * Show the sheet.
56 | *
57 | * @return {Sheet}
58 | */
59 | Sheet.prototype.show = function(){
60 | this.modal.show();
61 | return this;
62 | };
63 |
64 |
65 | /**
66 | * Hide the sheet.
67 | *
68 | * @return {Sheet}
69 | */
70 | Sheet.prototype.hide = function(){
71 | this.modal.hide();
72 | return this;
73 | };
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
34 |
35 |
--------------------------------------------------------------------------------
/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 | #mocha .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: 0 s '
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(' ', 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 + '' + name + end;
3817 | return tag;
3818 | }
3819 |
3820 | /**
3821 | * Return cdata escaped CDATA `str`.
3822 | */
3823 |
3824 | function cdata(str) {
3825 | return '';
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, '')
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('modal', function () {
2 |
3 | var assert = require('assert')
4 | , modal = require('modal');
5 |
6 | it('should be a constructor', function () {
7 | assert('function' === typeof modal);
8 | });
9 |
10 | });
--------------------------------------------------------------------------------