mocha 1.7.3 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,287 @@
1
+ /* See license.txt for terms of usage */
2
+
3
+ /*
4
+ * Text diff implementation.
5
+ *
6
+ * This library supports the following APIS:
7
+ * JsDiff.diffChars: Character by character diff
8
+ * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
9
+ * JsDiff.diffLines: Line based diff
10
+ *
11
+ * JsDiff.diffCss: Diff targeted at CSS content
12
+ *
13
+ * These methods are based on the implementation proposed in
14
+ * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
15
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
16
+ */
17
+ var JsDiff = (function() {
18
+ function clonePath(path) {
19
+ return { newPos: path.newPos, components: path.components.slice(0) };
20
+ }
21
+ function removeEmpty(array) {
22
+ var ret = [];
23
+ for (var i = 0; i < array.length; i++) {
24
+ if (array[i]) {
25
+ ret.push(array[i]);
26
+ }
27
+ }
28
+ return ret;
29
+ }
30
+ function escapeHTML(s) {
31
+ var n = s;
32
+ n = n.replace(/&/g, "&amp;");
33
+ n = n.replace(/</g, "&lt;");
34
+ n = n.replace(/>/g, "&gt;");
35
+ n = n.replace(/"/g, "&quot;");
36
+
37
+ return n;
38
+ }
39
+
40
+
41
+ var fbDiff = function(ignoreWhitespace) {
42
+ this.ignoreWhitespace = ignoreWhitespace;
43
+ };
44
+ fbDiff.prototype = {
45
+ diff: function(oldString, newString) {
46
+ // Handle the identity case (this is due to unrolling editLength == 0
47
+ if (newString == oldString) {
48
+ return [{ value: newString }];
49
+ }
50
+ if (!newString) {
51
+ return [{ value: oldString, removed: true }];
52
+ }
53
+ if (!oldString) {
54
+ return [{ value: newString, added: true }];
55
+ }
56
+
57
+ newString = this.tokenize(newString);
58
+ oldString = this.tokenize(oldString);
59
+
60
+ var newLen = newString.length, oldLen = oldString.length;
61
+ var maxEditLength = newLen + oldLen;
62
+ var bestPath = [{ newPos: -1, components: [] }];
63
+
64
+ // Seed editLength = 0
65
+ var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
66
+ if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {
67
+ return bestPath[0].components;
68
+ }
69
+
70
+ for (var editLength = 1; editLength <= maxEditLength; editLength++) {
71
+ for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {
72
+ var basePath;
73
+ var addPath = bestPath[diagonalPath-1],
74
+ removePath = bestPath[diagonalPath+1];
75
+ oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
76
+ if (addPath) {
77
+ // No one else is going to attempt to use this value, clear it
78
+ bestPath[diagonalPath-1] = undefined;
79
+ }
80
+
81
+ var canAdd = addPath && addPath.newPos+1 < newLen;
82
+ var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
83
+ if (!canAdd && !canRemove) {
84
+ bestPath[diagonalPath] = undefined;
85
+ continue;
86
+ }
87
+
88
+ // Select the diagonal that we want to branch from. We select the prior
89
+ // path whose position in the new string is the farthest from the origin
90
+ // and does not pass the bounds of the diff graph
91
+ if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
92
+ basePath = clonePath(removePath);
93
+ this.pushComponent(basePath.components, oldString[oldPos], undefined, true);
94
+ } else {
95
+ basePath = clonePath(addPath);
96
+ basePath.newPos++;
97
+ this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);
98
+ }
99
+
100
+ var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);
101
+
102
+ if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {
103
+ return basePath.components;
104
+ } else {
105
+ bestPath[diagonalPath] = basePath;
106
+ }
107
+ }
108
+ }
109
+ },
110
+
111
+ pushComponent: function(components, value, added, removed) {
112
+ var last = components[components.length-1];
113
+ if (last && last.added === added && last.removed === removed) {
114
+ // We need to clone here as the component clone operation is just
115
+ // as shallow array clone
116
+ components[components.length-1] =
117
+ {value: this.join(last.value, value), added: added, removed: removed };
118
+ } else {
119
+ components.push({value: value, added: added, removed: removed });
120
+ }
121
+ },
122
+ extractCommon: function(basePath, newString, oldString, diagonalPath) {
123
+ var newLen = newString.length,
124
+ oldLen = oldString.length,
125
+ newPos = basePath.newPos,
126
+ oldPos = newPos - diagonalPath;
127
+ while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {
128
+ newPos++;
129
+ oldPos++;
130
+
131
+ this.pushComponent(basePath.components, newString[newPos], undefined, undefined);
132
+ }
133
+ basePath.newPos = newPos;
134
+ return oldPos;
135
+ },
136
+
137
+ equals: function(left, right) {
138
+ var reWhitespace = /\S/;
139
+ if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
140
+ return true;
141
+ } else {
142
+ return left == right;
143
+ }
144
+ },
145
+ join: function(left, right) {
146
+ return left + right;
147
+ },
148
+ tokenize: function(value) {
149
+ return value;
150
+ }
151
+ };
152
+
153
+ var CharDiff = new fbDiff();
154
+
155
+ var WordDiff = new fbDiff(true);
156
+ WordDiff.tokenize = function(value) {
157
+ return removeEmpty(value.split(/(\s+|\b)/));
158
+ };
159
+
160
+ var CssDiff = new fbDiff(true);
161
+ CssDiff.tokenize = function(value) {
162
+ return removeEmpty(value.split(/([{}:;,]|\s+)/));
163
+ };
164
+
165
+ var LineDiff = new fbDiff();
166
+ LineDiff.tokenize = function(value) {
167
+ return value.split(/^/m);
168
+ };
169
+
170
+ return {
171
+ diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
172
+ diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
173
+ diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
174
+
175
+ diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
176
+
177
+ createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
178
+ var ret = [];
179
+
180
+ ret.push("Index: " + fileName);
181
+ ret.push("===================================================================");
182
+ ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader));
183
+ ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader));
184
+
185
+ var diff = LineDiff.diff(oldStr, newStr);
186
+ if (!diff[diff.length-1].value) {
187
+ diff.pop(); // Remove trailing newline add
188
+ }
189
+ diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier
190
+
191
+ function contextLines(lines) {
192
+ return lines.map(function(entry) { return ' ' + entry; });
193
+ }
194
+ function eofNL(curRange, i, current) {
195
+ var last = diff[diff.length-2],
196
+ isLast = i === diff.length-2,
197
+ isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);
198
+
199
+ // Figure out if this is the last line for the given file and missing NL
200
+ if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
201
+ curRange.push('\');
202
+ }
203
+ }
204
+
205
+ var oldRangeStart = 0, newRangeStart = 0, curRange = [],
206
+ oldLine = 1, newLine = 1;
207
+ for (var i = 0; i < diff.length; i++) {
208
+ var current = diff[i],
209
+ lines = current.lines || current.value.replace(/\n$/, "").split("\n");
210
+ current.lines = lines;
211
+
212
+ if (current.added || current.removed) {
213
+ if (!oldRangeStart) {
214
+ var prev = diff[i-1];
215
+ oldRangeStart = oldLine;
216
+ newRangeStart = newLine;
217
+
218
+ if (prev) {
219
+ curRange = contextLines(prev.lines.slice(-4));
220
+ oldRangeStart -= curRange.length;
221
+ newRangeStart -= curRange.length;
222
+ }
223
+ }
224
+ curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; }));
225
+ eofNL(curRange, i, current);
226
+
227
+ if (current.added) {
228
+ newLine += lines.length;
229
+ } else {
230
+ oldLine += lines.length;
231
+ }
232
+ } else {
233
+ if (oldRangeStart) {
234
+ // Close out any changes that have been output (or join overlapping)
235
+ if (lines.length <= 8 && i < diff.length-2) {
236
+ // Overlapping
237
+ curRange.push.apply(curRange, contextLines(lines));
238
+ } else {
239
+ // end the range and output
240
+ var contextSize = Math.min(lines.length, 4);
241
+ ret.push(
242
+ "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize)
243
+ + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize)
244
+ + " @@");
245
+ ret.push.apply(ret, curRange);
246
+ ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
247
+ if (lines.length <= 4) {
248
+ eofNL(ret, i, current);
249
+ }
250
+
251
+ oldRangeStart = 0; newRangeStart = 0; curRange = [];
252
+ }
253
+ }
254
+ oldLine += lines.length;
255
+ newLine += lines.length;
256
+ }
257
+ }
258
+
259
+ return ret.join('\n') + '\n';
260
+ },
261
+
262
+ convertChangesToXML: function(changes){
263
+ var ret = [];
264
+ for ( var i = 0; i < changes.length; i++) {
265
+ var change = changes[i];
266
+ if (change.added) {
267
+ ret.push("<ins>");
268
+ } else if (change.removed) {
269
+ ret.push("<del>");
270
+ }
271
+
272
+ ret.push(escapeHTML(change.value));
273
+
274
+ if (change.added) {
275
+ ret.push("</ins>");
276
+ } else if (change.removed) {
277
+ ret.push("</del>");
278
+ }
279
+ }
280
+ return ret.join("");
281
+ }
282
+ };
283
+ })();
284
+
285
+ if (typeof module !== "undefined") {
286
+ module.exports = JsDiff;
287
+ }
package/lib/mocha.js CHANGED
@@ -52,6 +52,7 @@ function image(name) {
52
52
  * - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
53
53
  * - `globals` array of accepted globals
54
54
  * - `timeout` timeout in milliseconds
55
+ * - `bail` bail on the first test failure
55
56
  * - `slow` milliseconds to wait before considering a test slow
56
57
  * - `ignoreLeaks` ignore global leaks
57
58
  * - `grep` string or regexp to filter tests with
@@ -67,11 +68,25 @@ function Mocha(options) {
67
68
  this.grep(options.grep);
68
69
  this.suite = new exports.Suite('', new exports.Context);
69
70
  this.ui(options.ui);
71
+ this.bail(options.bail);
70
72
  this.reporter(options.reporter);
71
73
  if (options.timeout) this.timeout(options.timeout);
72
74
  if (options.slow) this.slow(options.slow);
73
75
  }
74
76
 
77
+ /**
78
+ * Enable or disable bailing on the first failure.
79
+ *
80
+ * @param {Boolean} [bail]
81
+ * @api public
82
+ */
83
+
84
+ Mocha.prototype.bail = function(bail){
85
+ if (0 == arguments.length) bail = true;
86
+ this.suite.bail(bail);
87
+ return this;
88
+ };
89
+
75
90
  /**
76
91
  * Add test `file`.
77
92
  *
@@ -87,7 +102,7 @@ Mocha.prototype.addFile = function(file){
87
102
  /**
88
103
  * Set reporter to `reporter`, defaults to "dot".
89
104
  *
90
- * @param {String|Function} reporter name of a reporter or a reporter constructor
105
+ * @param {String|Function} reporter name or constructor
91
106
  * @api public
92
107
  */
93
108
 
@@ -165,7 +165,7 @@ function HTML(runner, root) {
165
165
 
166
166
  on(h2, 'click', function(){
167
167
  pre.style.display = 'none' == pre.style.display
168
- ? 'inline-block'
168
+ ? 'block'
169
169
  : 'none';
170
170
  });
171
171
 
@@ -23,7 +23,6 @@ function Markdown(runner) {
23
23
 
24
24
  var self = this
25
25
  , stats = this.stats
26
- , total = runner.total
27
26
  , level = 0
28
27
  , buf = '';
29
28
 
@@ -25,7 +25,9 @@ function TAP(runner) {
25
25
 
26
26
  var self = this
27
27
  , stats = this.stats
28
- , n = 1;
28
+ , n = 1
29
+ , passes = 0
30
+ , failures = 0;
29
31
 
30
32
  runner.on('start', function(){
31
33
  var total = runner.grepTotal(runner.suite);
@@ -41,12 +43,20 @@ function TAP(runner) {
41
43
  });
42
44
 
43
45
  runner.on('pass', function(test){
46
+ passes++;
44
47
  console.log('ok %d %s', n, title(test));
45
48
  });
46
49
 
47
50
  runner.on('fail', function(test, err){
51
+ failures++;
48
52
  console.log('not ok %d %s', n, title(test));
49
- console.log(err.stack.replace(/^/gm, ' '));
53
+ if (err.stack) console.log(err.stack.replace(/^/gm, ' '));
54
+ });
55
+
56
+ runner.on('end', function(){
57
+ console.log('# tests ' + (passes + failures));
58
+ console.log('# pass ' + passes);
59
+ console.log('# fail ' + failures);
50
60
  });
51
61
  }
52
62
 
package/lib/runnable.js CHANGED
@@ -194,7 +194,7 @@ Runnable.prototype.run = function(fn){
194
194
  if (this.async) {
195
195
  try {
196
196
  this.fn.call(ctx, function(err){
197
- if (toString.call(err) === "[object Error]") return done(err);
197
+ if (err instanceof Error || toString.call(err) === "[object Error]") return done(err);
198
198
  if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
199
199
  done();
200
200
  });
package/lib/runner.js CHANGED
@@ -9,7 +9,8 @@ var EventEmitter = require('events').EventEmitter
9
9
  , utils = require('./utils')
10
10
  , filter = utils.filter
11
11
  , keys = utils.keys
12
- , noop = function(){};
12
+ , noop = function(){}
13
+ , immediately = global.setImmediate || process.nextTick;
13
14
 
14
15
  /**
15
16
  * Non-enumerable globals.
@@ -119,7 +120,7 @@ Runner.prototype.globalProps = function() {
119
120
 
120
121
  // non-enumerables
121
122
  for (var i = 0; i < globals.length; ++i) {
122
- if (~props.indexOf(globals[i])) continue;
123
+ if (~utils.indexOf(props, globals[i])) continue;
123
124
  props.push(globals[i]);
124
125
  }
125
126
 
@@ -185,7 +186,7 @@ Runner.prototype.fail = function(test, err){
185
186
  if ('string' == typeof err) {
186
187
  err = new Error('the string "' + err + '" was thrown, throw an Error :)');
187
188
  }
188
-
189
+
189
190
  this.emit('fail', test, err);
190
191
  };
191
192
 
@@ -242,7 +243,7 @@ Runner.prototype.hook = function(name, fn){
242
243
  });
243
244
  }
244
245
 
245
- process.nextTick(function(){
246
+ immediately(function(){
246
247
  next(0);
247
248
  });
248
249
  };
@@ -485,12 +486,16 @@ Runner.prototype.run = function(fn){
485
486
  var self = this
486
487
  , fn = fn || function(){};
487
488
 
489
+ function uncaught(err){
490
+ self.uncaught(err);
491
+ }
492
+
488
493
  debug('start');
489
494
 
490
495
  // callback
491
496
  this.on('end', function(){
492
497
  debug('end');
493
- process.removeListener('uncaughtException', self.uncaught.bind(self));
498
+ process.removeListener('uncaughtException', uncaught);
494
499
  fn(self.failures);
495
500
  });
496
501
 
@@ -502,7 +507,7 @@ Runner.prototype.run = function(fn){
502
507
  });
503
508
 
504
509
  // uncaught exception
505
- process.on('uncaughtException', this.uncaught.bind(this));
510
+ process.on('uncaughtException', uncaught);
506
511
 
507
512
  return this;
508
513
  };
package/lib/template.html CHANGED
@@ -3,6 +3,7 @@
3
3
  <head>
4
4
  <title>Mocha</title>
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
7
  <link rel="stylesheet" href="mocha.css" />
7
8
  </head>
8
9
  <body>
package/mocha.css CHANGED
@@ -1,4 +1,5 @@
1
- @charset "UTF-8";
1
+ @charset "utf-8";
2
+
2
3
  body {
3
4
  font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
4
5
  padding: 60px 50px;
@@ -53,6 +54,7 @@ body {
53
54
 
54
55
  #mocha .test {
55
56
  margin-left: 15px;
57
+ overflow: hidden;
56
58
  }
57
59
 
58
60
  #mocha .test.pending:hover h2::after {
@@ -129,7 +131,9 @@ body {
129
131
  }
130
132
 
131
133
  #mocha .test pre {
132
- display: inline-block;
134
+ display: block;
135
+ float: left;
136
+ clear: left;
133
137
  font: 12px/1.5 monaco, monospace;
134
138
  margin: 5px;
135
139
  padding: 15px;
@@ -148,7 +152,7 @@ body {
148
152
  #mocha .test a.replay {
149
153
  position: absolute;
150
154
  top: 3px;
151
- right: -20px;
155
+ right: 0;
152
156
  text-decoration: none;
153
157
  vertical-align: middle;
154
158
  display: block;
@@ -163,7 +167,7 @@ body {
163
167
  -webkit-transition: opacity 200ms;
164
168
  -moz-transition: opacity 200ms;
165
169
  transition: opacity 200ms;
166
- opacity: 0.2;
170
+ opacity: 0.3;
167
171
  color: #888;
168
172
  }
169
173
 
@@ -225,3 +229,13 @@ code .init { color: #2F6FAD }
225
229
  code .string { color: #5890AD }
226
230
  code .keyword { color: #8A6343 }
227
231
  code .number { color: #2F6FAD }
232
+
233
+ @media screen and (max-device-width: 480px) {
234
+ body {
235
+ padding: 60px 0px;
236
+ }
237
+
238
+ #stats {
239
+ position: absolute;
240
+ }
241
+ }