mocha 5.1.1 → 6.0.0
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.
- package/CHANGELOG.md +686 -984
- package/README.md +2 -1
- package/{images → assets/growl}/error.png +0 -0
- package/{images → assets/growl}/ok.png +0 -0
- package/bin/_mocha +4 -595
- package/bin/mocha +121 -61
- package/bin/options.js +6 -39
- package/browser-entry.js +21 -17
- package/lib/browser/growl.js +165 -2
- package/lib/browser/progress.js +11 -11
- package/lib/{template.html → browser/template.html} +0 -0
- package/lib/browser/tty.js +2 -2
- package/lib/cli/cli.js +68 -0
- package/lib/cli/commands.js +13 -0
- package/lib/cli/config.js +79 -0
- package/lib/cli/index.js +9 -0
- package/lib/cli/init.js +37 -0
- package/lib/cli/node-flags.js +69 -0
- package/lib/cli/one-and-dones.js +70 -0
- package/lib/cli/options.js +330 -0
- package/lib/cli/run-helpers.js +337 -0
- package/lib/cli/run-option-metadata.js +76 -0
- package/lib/cli/run.js +297 -0
- package/lib/context.js +14 -14
- package/lib/errors.js +141 -0
- package/lib/growl.js +136 -0
- package/lib/hook.js +5 -16
- package/lib/interfaces/bdd.js +16 -13
- package/lib/interfaces/common.js +62 -18
- package/lib/interfaces/exports.js +5 -8
- package/lib/interfaces/qunit.js +10 -10
- package/lib/interfaces/tdd.js +12 -11
- package/lib/mocha.js +477 -256
- package/lib/mocharc.json +10 -0
- package/lib/pending.js +1 -5
- package/lib/reporters/base.js +95 -117
- package/lib/reporters/doc.js +23 -9
- package/lib/reporters/dot.js +19 -13
- package/lib/reporters/html.js +82 -47
- package/lib/reporters/json-stream.js +43 -23
- package/lib/reporters/json.js +32 -23
- package/lib/reporters/landing.js +16 -9
- package/lib/reporters/list.js +19 -11
- package/lib/reporters/markdown.js +18 -12
- package/lib/reporters/min.js +8 -4
- package/lib/reporters/nyan.js +42 -35
- package/lib/reporters/progress.js +12 -7
- package/lib/reporters/spec.js +23 -12
- package/lib/reporters/tap.js +250 -32
- package/lib/reporters/xunit.js +61 -35
- package/lib/runnable.js +152 -95
- package/lib/runner.js +296 -248
- package/lib/stats-collector.js +83 -0
- package/lib/suite.js +294 -75
- package/lib/test.js +16 -15
- package/lib/utils.js +419 -146
- package/mocha.js +4589 -2228
- package/package.json +137 -38
- package/lib/ms.js +0 -94
- package/lib/reporters/base.js.orig +0 -498
- package/lib/reporters/json.js.orig +0 -128
package/lib/utils.js
CHANGED
|
@@ -1,47 +1,55 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Various utility functions used throughout Mocha's codebase.
|
|
5
|
+
* @module utils
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Module dependencies.
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
|
-
var debug = require('debug')('mocha:watch');
|
|
12
12
|
var fs = require('fs');
|
|
13
|
-
var glob = require('glob');
|
|
14
13
|
var path = require('path');
|
|
15
|
-
var
|
|
14
|
+
var util = require('util');
|
|
15
|
+
var glob = require('glob');
|
|
16
16
|
var he = require('he');
|
|
17
|
+
var errors = require('./errors');
|
|
18
|
+
var createNoFilesMatchPatternError = errors.createNoFilesMatchPatternError;
|
|
19
|
+
var createMissingArgumentError = errors.createMissingArgumentError;
|
|
20
|
+
|
|
21
|
+
var assign = (exports.assign = require('object.assign').getPolyfill());
|
|
17
22
|
|
|
18
23
|
/**
|
|
19
|
-
*
|
|
24
|
+
* Inherit the prototype methods from one constructor into another.
|
|
25
|
+
*
|
|
26
|
+
* @param {function} ctor - Constructor function which needs to inherit the
|
|
27
|
+
* prototype.
|
|
28
|
+
* @param {function} superCtor - Constructor function to inherit prototype from.
|
|
29
|
+
* @throws {TypeError} if either constructor is null, or if super constructor
|
|
30
|
+
* lacks a prototype.
|
|
20
31
|
*/
|
|
21
|
-
|
|
22
|
-
var ignore = ['node_modules', '.git'];
|
|
23
|
-
|
|
24
|
-
exports.inherits = require('util').inherits;
|
|
32
|
+
exports.inherits = util.inherits;
|
|
25
33
|
|
|
26
34
|
/**
|
|
27
35
|
* Escape special characters in the given string of html.
|
|
28
36
|
*
|
|
29
|
-
* @
|
|
37
|
+
* @private
|
|
30
38
|
* @param {string} html
|
|
31
39
|
* @return {string}
|
|
32
40
|
*/
|
|
33
|
-
exports.escape = function
|
|
34
|
-
return he.encode(String(html), {
|
|
41
|
+
exports.escape = function(html) {
|
|
42
|
+
return he.encode(String(html), {useNamedReferences: false});
|
|
35
43
|
};
|
|
36
44
|
|
|
37
45
|
/**
|
|
38
46
|
* Test if the given obj is type of string.
|
|
39
47
|
*
|
|
40
|
-
* @
|
|
48
|
+
* @private
|
|
41
49
|
* @param {Object} obj
|
|
42
50
|
* @return {boolean}
|
|
43
51
|
*/
|
|
44
|
-
exports.isString = function
|
|
52
|
+
exports.isString = function(obj) {
|
|
45
53
|
return typeof obj === 'string';
|
|
46
54
|
};
|
|
47
55
|
|
|
@@ -49,15 +57,16 @@ exports.isString = function (obj) {
|
|
|
49
57
|
* Watch the given `files` for changes
|
|
50
58
|
* and invoke `fn(file)` on modification.
|
|
51
59
|
*
|
|
52
|
-
* @
|
|
60
|
+
* @private
|
|
53
61
|
* @param {Array} files
|
|
54
62
|
* @param {Function} fn
|
|
55
63
|
*/
|
|
56
|
-
exports.watch = function
|
|
57
|
-
var options = {
|
|
58
|
-
|
|
64
|
+
exports.watch = function(files, fn) {
|
|
65
|
+
var options = {interval: 100};
|
|
66
|
+
var debug = require('debug')('mocha:watch');
|
|
67
|
+
files.forEach(function(file) {
|
|
59
68
|
debug('file %s', file);
|
|
60
|
-
fs.watchFile(file, options, function
|
|
69
|
+
fs.watchFile(file, options, function(curr, prev) {
|
|
61
70
|
if (prev.mtime < curr.mtime) {
|
|
62
71
|
fn(file);
|
|
63
72
|
}
|
|
@@ -66,39 +75,52 @@ exports.watch = function (files, fn) {
|
|
|
66
75
|
};
|
|
67
76
|
|
|
68
77
|
/**
|
|
69
|
-
*
|
|
78
|
+
* Predicate to screen `pathname` for further consideration.
|
|
70
79
|
*
|
|
71
|
-
* @
|
|
72
|
-
*
|
|
73
|
-
*
|
|
80
|
+
* @description
|
|
81
|
+
* Returns <code>false</code> for pathname referencing:
|
|
82
|
+
* <ul>
|
|
83
|
+
* <li>'npm' package installation directory
|
|
84
|
+
* <li>'git' version control directory
|
|
85
|
+
* </ul>
|
|
86
|
+
*
|
|
87
|
+
* @private
|
|
88
|
+
* @param {string} pathname - File or directory name to screen
|
|
89
|
+
* @return {boolean} whether pathname should be further considered
|
|
90
|
+
* @example
|
|
91
|
+
* ['node_modules', 'test.js'].filter(considerFurther); // => ['test.js']
|
|
74
92
|
*/
|
|
75
|
-
function
|
|
76
|
-
|
|
93
|
+
function considerFurther(pathname) {
|
|
94
|
+
var ignore = ['node_modules', '.git'];
|
|
95
|
+
|
|
96
|
+
return !~ignore.indexOf(pathname);
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
/**
|
|
80
100
|
* Lookup files in the given `dir`.
|
|
81
101
|
*
|
|
82
|
-
* @
|
|
102
|
+
* @description
|
|
103
|
+
* Filenames are returned in _traversal_ order by the OS/filesystem.
|
|
104
|
+
* **Make no assumption that the names will be sorted in any fashion.**
|
|
105
|
+
*
|
|
106
|
+
* @private
|
|
83
107
|
* @param {string} dir
|
|
84
|
-
* @param {string[]} [
|
|
108
|
+
* @param {string[]} [exts=['js']]
|
|
85
109
|
* @param {Array} [ret=[]]
|
|
86
110
|
* @return {Array}
|
|
87
111
|
*/
|
|
88
|
-
exports.files = function
|
|
112
|
+
exports.files = function(dir, exts, ret) {
|
|
89
113
|
ret = ret || [];
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
var re = new RegExp('\\.(' + ext.join('|') + ')$');
|
|
114
|
+
exts = exts || ['js'];
|
|
93
115
|
|
|
94
116
|
fs.readdirSync(dir)
|
|
95
|
-
.filter(
|
|
96
|
-
.forEach(function
|
|
97
|
-
|
|
98
|
-
if (fs.lstatSync(
|
|
99
|
-
exports.files(
|
|
100
|
-
} else if (
|
|
101
|
-
ret.push(
|
|
117
|
+
.filter(considerFurther)
|
|
118
|
+
.forEach(function(dirent) {
|
|
119
|
+
var pathname = path.join(dir, dirent);
|
|
120
|
+
if (fs.lstatSync(pathname).isDirectory()) {
|
|
121
|
+
exports.files(pathname, exts, ret);
|
|
122
|
+
} else if (hasMatchingExtname(pathname, exts)) {
|
|
123
|
+
ret.push(pathname);
|
|
102
124
|
}
|
|
103
125
|
});
|
|
104
126
|
|
|
@@ -108,11 +130,11 @@ exports.files = function (dir, ext, ret) {
|
|
|
108
130
|
/**
|
|
109
131
|
* Compute a slug from the given `str`.
|
|
110
132
|
*
|
|
111
|
-
* @
|
|
133
|
+
* @private
|
|
112
134
|
* @param {string} str
|
|
113
135
|
* @return {string}
|
|
114
136
|
*/
|
|
115
|
-
exports.slug = function
|
|
137
|
+
exports.slug = function(str) {
|
|
116
138
|
return str
|
|
117
139
|
.toLowerCase()
|
|
118
140
|
.replace(/ +/g, '-')
|
|
@@ -125,15 +147,22 @@ exports.slug = function (str) {
|
|
|
125
147
|
* @param {string} str
|
|
126
148
|
* @return {string}
|
|
127
149
|
*/
|
|
128
|
-
exports.clean = function
|
|
150
|
+
exports.clean = function(str) {
|
|
129
151
|
str = str
|
|
130
|
-
.replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
|
|
152
|
+
.replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
|
|
153
|
+
.replace(/^\uFEFF/, '')
|
|
131
154
|
// (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content
|
|
132
|
-
.replace(
|
|
155
|
+
.replace(
|
|
156
|
+
/^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/,
|
|
157
|
+
'$1$2$3'
|
|
158
|
+
);
|
|
133
159
|
|
|
134
160
|
var spaces = str.match(/^\n?( *)/)[1].length;
|
|
135
161
|
var tabs = str.match(/^\n?(\t*)/)[1].length;
|
|
136
|
-
var re = new RegExp(
|
|
162
|
+
var re = new RegExp(
|
|
163
|
+
'^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}',
|
|
164
|
+
'gm'
|
|
165
|
+
);
|
|
137
166
|
|
|
138
167
|
str = str.replace(re, '');
|
|
139
168
|
|
|
@@ -143,31 +172,34 @@ exports.clean = function (str) {
|
|
|
143
172
|
/**
|
|
144
173
|
* Parse the given `qs`.
|
|
145
174
|
*
|
|
146
|
-
* @
|
|
175
|
+
* @private
|
|
147
176
|
* @param {string} qs
|
|
148
177
|
* @return {Object}
|
|
149
178
|
*/
|
|
150
|
-
exports.parseQuery = function
|
|
151
|
-
return qs
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
179
|
+
exports.parseQuery = function(qs) {
|
|
180
|
+
return qs
|
|
181
|
+
.replace('?', '')
|
|
182
|
+
.split('&')
|
|
183
|
+
.reduce(function(obj, pair) {
|
|
184
|
+
var i = pair.indexOf('=');
|
|
185
|
+
var key = pair.slice(0, i);
|
|
186
|
+
var val = pair.slice(++i);
|
|
187
|
+
|
|
188
|
+
// Due to how the URLSearchParams API treats spaces
|
|
189
|
+
obj[key] = decodeURIComponent(val.replace(/\+/g, '%20'));
|
|
190
|
+
|
|
191
|
+
return obj;
|
|
192
|
+
}, {});
|
|
161
193
|
};
|
|
162
194
|
|
|
163
195
|
/**
|
|
164
196
|
* Highlight the given string of `js`.
|
|
165
197
|
*
|
|
166
|
-
* @
|
|
198
|
+
* @private
|
|
167
199
|
* @param {string} js
|
|
168
200
|
* @return {string}
|
|
169
201
|
*/
|
|
170
|
-
function highlight
|
|
202
|
+
function highlight(js) {
|
|
171
203
|
return js
|
|
172
204
|
.replace(/</g, '<')
|
|
173
205
|
.replace(/>/g, '>')
|
|
@@ -175,17 +207,23 @@ function highlight (js) {
|
|
|
175
207
|
.replace(/('.*?')/gm, '<span class="string">$1</span>')
|
|
176
208
|
.replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
|
|
177
209
|
.replace(/(\d+)/gm, '<span class="number">$1</span>')
|
|
178
|
-
.replace(
|
|
179
|
-
|
|
210
|
+
.replace(
|
|
211
|
+
/\bnew[ \t]+(\w+)/gm,
|
|
212
|
+
'<span class="keyword">new</span> <span class="init">$1</span>'
|
|
213
|
+
)
|
|
214
|
+
.replace(
|
|
215
|
+
/\b(function|new|throw|return|var|if|else)\b/gm,
|
|
216
|
+
'<span class="keyword">$1</span>'
|
|
217
|
+
);
|
|
180
218
|
}
|
|
181
219
|
|
|
182
220
|
/**
|
|
183
221
|
* Highlight the contents of tag `name`.
|
|
184
222
|
*
|
|
185
|
-
* @
|
|
223
|
+
* @private
|
|
186
224
|
* @param {string} name
|
|
187
225
|
*/
|
|
188
|
-
exports.highlightTags = function
|
|
226
|
+
exports.highlightTags = function(name) {
|
|
189
227
|
var code = document.getElementById('mocha').getElementsByTagName(name);
|
|
190
228
|
for (var i = 0, len = code.length; i < len; ++i) {
|
|
191
229
|
code[i].innerHTML = highlight(code[i].innerHTML);
|
|
@@ -201,12 +239,12 @@ exports.highlightTags = function (name) {
|
|
|
201
239
|
* Objects w/ no properties return `'{}'`
|
|
202
240
|
* All else: return result of `value.toString()`
|
|
203
241
|
*
|
|
204
|
-
* @
|
|
242
|
+
* @private
|
|
205
243
|
* @param {*} value The value to inspect.
|
|
206
244
|
* @param {string} typeHint The type of the value
|
|
207
245
|
* @returns {string}
|
|
208
246
|
*/
|
|
209
|
-
function emptyRepresentation
|
|
247
|
+
function emptyRepresentation(value, typeHint) {
|
|
210
248
|
switch (typeHint) {
|
|
211
249
|
case 'function':
|
|
212
250
|
return '[Function]';
|
|
@@ -223,7 +261,7 @@ function emptyRepresentation (value, typeHint) {
|
|
|
223
261
|
* Takes some variable and asks `Object.prototype.toString()` what it thinks it
|
|
224
262
|
* is.
|
|
225
263
|
*
|
|
226
|
-
* @
|
|
264
|
+
* @private
|
|
227
265
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
|
|
228
266
|
* @param {*} value The value to test.
|
|
229
267
|
* @returns {string} Computed type
|
|
@@ -240,7 +278,7 @@ function emptyRepresentation (value, typeHint) {
|
|
|
240
278
|
* type(global) // 'global'
|
|
241
279
|
* type(new String('foo') // 'object'
|
|
242
280
|
*/
|
|
243
|
-
var type = exports.type = function type
|
|
281
|
+
var type = (exports.type = function type(value) {
|
|
244
282
|
if (value === undefined) {
|
|
245
283
|
return 'undefined';
|
|
246
284
|
} else if (value === null) {
|
|
@@ -248,10 +286,11 @@ var type = exports.type = function type (value) {
|
|
|
248
286
|
} else if (Buffer.isBuffer(value)) {
|
|
249
287
|
return 'buffer';
|
|
250
288
|
}
|
|
251
|
-
return Object.prototype.toString
|
|
289
|
+
return Object.prototype.toString
|
|
290
|
+
.call(value)
|
|
252
291
|
.replace(/^\[.+\s(.+?)]$/, '$1')
|
|
253
292
|
.toLowerCase();
|
|
254
|
-
};
|
|
293
|
+
});
|
|
255
294
|
|
|
256
295
|
/**
|
|
257
296
|
* Stringify `value`. Different behavior depending on type of value:
|
|
@@ -263,26 +302,28 @@ var type = exports.type = function type (value) {
|
|
|
263
302
|
* - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
|
|
264
303
|
* JSON.stringify().
|
|
265
304
|
*
|
|
266
|
-
* @
|
|
305
|
+
* @private
|
|
267
306
|
* @see exports.type
|
|
268
307
|
* @param {*} value
|
|
269
308
|
* @return {string}
|
|
270
309
|
*/
|
|
271
|
-
exports.stringify = function
|
|
310
|
+
exports.stringify = function(value) {
|
|
272
311
|
var typeHint = type(value);
|
|
273
312
|
|
|
274
313
|
if (!~['object', 'array', 'function'].indexOf(typeHint)) {
|
|
275
314
|
if (typeHint === 'buffer') {
|
|
276
315
|
var json = Buffer.prototype.toJSON.call(value);
|
|
277
316
|
// Based on the toJSON result
|
|
278
|
-
return jsonStringify(
|
|
279
|
-
.
|
|
317
|
+
return jsonStringify(
|
|
318
|
+
json.data && json.type ? json.data : json,
|
|
319
|
+
2
|
|
320
|
+
).replace(/,(\n|$)/g, '$1');
|
|
280
321
|
}
|
|
281
322
|
|
|
282
323
|
// IE7/IE8 has a bizarre String constructor; needs to be coerced
|
|
283
324
|
// into an array and back to obj.
|
|
284
325
|
if (typeHint === 'string' && typeof value === 'object') {
|
|
285
|
-
value = value.split('').reduce(function
|
|
326
|
+
value = value.split('').reduce(function(acc, char, idx) {
|
|
286
327
|
acc[idx] = char;
|
|
287
328
|
return acc;
|
|
288
329
|
}, {});
|
|
@@ -294,7 +335,10 @@ exports.stringify = function (value) {
|
|
|
294
335
|
|
|
295
336
|
for (var prop in value) {
|
|
296
337
|
if (Object.prototype.hasOwnProperty.call(value, prop)) {
|
|
297
|
-
return jsonStringify(
|
|
338
|
+
return jsonStringify(
|
|
339
|
+
exports.canonicalize(value, null, typeHint),
|
|
340
|
+
2
|
|
341
|
+
).replace(/,(\n|$)/g, '$1');
|
|
298
342
|
}
|
|
299
343
|
}
|
|
300
344
|
|
|
@@ -304,13 +348,13 @@ exports.stringify = function (value) {
|
|
|
304
348
|
/**
|
|
305
349
|
* like JSON.stringify but more sense.
|
|
306
350
|
*
|
|
307
|
-
* @
|
|
351
|
+
* @private
|
|
308
352
|
* @param {Object} object
|
|
309
353
|
* @param {number=} spaces
|
|
310
354
|
* @param {number=} depth
|
|
311
355
|
* @returns {*}
|
|
312
356
|
*/
|
|
313
|
-
function jsonStringify
|
|
357
|
+
function jsonStringify(object, spaces, depth) {
|
|
314
358
|
if (typeof spaces === 'undefined') {
|
|
315
359
|
// primitive types
|
|
316
360
|
return _stringify(object);
|
|
@@ -320,13 +364,16 @@ function jsonStringify (object, spaces, depth) {
|
|
|
320
364
|
var space = spaces * depth;
|
|
321
365
|
var str = Array.isArray(object) ? '[' : '{';
|
|
322
366
|
var end = Array.isArray(object) ? ']' : '}';
|
|
323
|
-
var length =
|
|
367
|
+
var length =
|
|
368
|
+
typeof object.length === 'number'
|
|
369
|
+
? object.length
|
|
370
|
+
: Object.keys(object).length;
|
|
324
371
|
// `.repeat()` polyfill
|
|
325
|
-
function repeat
|
|
372
|
+
function repeat(s, n) {
|
|
326
373
|
return new Array(n).join(s);
|
|
327
374
|
}
|
|
328
375
|
|
|
329
|
-
function _stringify
|
|
376
|
+
function _stringify(val) {
|
|
330
377
|
switch (type(val)) {
|
|
331
378
|
case 'null':
|
|
332
379
|
case 'undefined':
|
|
@@ -340,9 +387,10 @@ function jsonStringify (object, spaces, depth) {
|
|
|
340
387
|
case 'regexp':
|
|
341
388
|
case 'symbol':
|
|
342
389
|
case 'number':
|
|
343
|
-
val =
|
|
344
|
-
|
|
345
|
-
|
|
390
|
+
val =
|
|
391
|
+
val === 0 && 1 / val === -Infinity // `-0`
|
|
392
|
+
? '-0'
|
|
393
|
+
: val.toString();
|
|
346
394
|
break;
|
|
347
395
|
case 'date':
|
|
348
396
|
var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString();
|
|
@@ -355,9 +403,10 @@ function jsonStringify (object, spaces, depth) {
|
|
|
355
403
|
val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
|
|
356
404
|
break;
|
|
357
405
|
default:
|
|
358
|
-
val =
|
|
359
|
-
|
|
360
|
-
|
|
406
|
+
val =
|
|
407
|
+
val === '[Function]' || val === '[Circular]'
|
|
408
|
+
? val
|
|
409
|
+
: JSON.stringify(val); // string
|
|
361
410
|
}
|
|
362
411
|
return val;
|
|
363
412
|
}
|
|
@@ -367,15 +416,19 @@ function jsonStringify (object, spaces, depth) {
|
|
|
367
416
|
continue; // not my business
|
|
368
417
|
}
|
|
369
418
|
--length;
|
|
370
|
-
str +=
|
|
419
|
+
str +=
|
|
420
|
+
'\n ' +
|
|
421
|
+
repeat(' ', space) +
|
|
371
422
|
(Array.isArray(object) ? '' : '"' + i + '": ') + // key
|
|
372
423
|
_stringify(object[i]) + // value
|
|
373
424
|
(length ? ',' : ''); // comma
|
|
374
425
|
}
|
|
375
426
|
|
|
376
|
-
return
|
|
427
|
+
return (
|
|
428
|
+
str +
|
|
377
429
|
// [], {}
|
|
378
|
-
(str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
|
|
430
|
+
(str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
|
|
431
|
+
);
|
|
379
432
|
}
|
|
380
433
|
|
|
381
434
|
/**
|
|
@@ -390,20 +443,20 @@ function jsonStringify (object, spaces, depth) {
|
|
|
390
443
|
* - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
|
|
391
444
|
* - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
|
|
392
445
|
*
|
|
393
|
-
* @
|
|
446
|
+
* @private
|
|
394
447
|
* @see {@link exports.stringify}
|
|
395
448
|
* @param {*} value Thing to inspect. May or may not have properties.
|
|
396
449
|
* @param {Array} [stack=[]] Stack of seen values
|
|
397
450
|
* @param {string} [typeHint] Type hint
|
|
398
451
|
* @return {(Object|Array|Function|string|undefined)}
|
|
399
452
|
*/
|
|
400
|
-
exports.canonicalize = function canonicalize
|
|
453
|
+
exports.canonicalize = function canonicalize(value, stack, typeHint) {
|
|
401
454
|
var canonicalizedObj;
|
|
402
455
|
/* eslint-disable no-unused-vars */
|
|
403
456
|
var prop;
|
|
404
457
|
/* eslint-enable no-unused-vars */
|
|
405
458
|
typeHint = typeHint || type(value);
|
|
406
|
-
function withStack
|
|
459
|
+
function withStack(value, fn) {
|
|
407
460
|
stack.push(value);
|
|
408
461
|
fn();
|
|
409
462
|
stack.pop();
|
|
@@ -422,8 +475,8 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
|
|
|
422
475
|
canonicalizedObj = value;
|
|
423
476
|
break;
|
|
424
477
|
case 'array':
|
|
425
|
-
withStack(value, function
|
|
426
|
-
canonicalizedObj = value.map(function
|
|
478
|
+
withStack(value, function() {
|
|
479
|
+
canonicalizedObj = value.map(function(item) {
|
|
427
480
|
return exports.canonicalize(item, stack);
|
|
428
481
|
});
|
|
429
482
|
});
|
|
@@ -442,10 +495,12 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
|
|
|
442
495
|
/* falls through */
|
|
443
496
|
case 'object':
|
|
444
497
|
canonicalizedObj = canonicalizedObj || {};
|
|
445
|
-
withStack(value, function
|
|
446
|
-
Object.keys(value)
|
|
447
|
-
|
|
448
|
-
|
|
498
|
+
withStack(value, function() {
|
|
499
|
+
Object.keys(value)
|
|
500
|
+
.sort()
|
|
501
|
+
.forEach(function(key) {
|
|
502
|
+
canonicalizedObj[key] = exports.canonicalize(value[key], stack);
|
|
503
|
+
});
|
|
449
504
|
});
|
|
450
505
|
break;
|
|
451
506
|
case 'date':
|
|
@@ -462,34 +517,82 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
|
|
|
462
517
|
return canonicalizedObj;
|
|
463
518
|
};
|
|
464
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Determines if pathname has a matching file extension.
|
|
522
|
+
*
|
|
523
|
+
* @private
|
|
524
|
+
* @param {string} pathname - Pathname to check for match.
|
|
525
|
+
* @param {string[]} exts - List of file extensions (sans period).
|
|
526
|
+
* @return {boolean} whether file extension matches.
|
|
527
|
+
* @example
|
|
528
|
+
* hasMatchingExtname('foo.html', ['js', 'css']); // => false
|
|
529
|
+
*/
|
|
530
|
+
function hasMatchingExtname(pathname, exts) {
|
|
531
|
+
var suffix = path.extname(pathname).slice(1);
|
|
532
|
+
return exts.some(function(element) {
|
|
533
|
+
return suffix === element;
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Determines if pathname would be a "hidden" file (or directory) on UN*X.
|
|
539
|
+
*
|
|
540
|
+
* @description
|
|
541
|
+
* On UN*X, pathnames beginning with a full stop (aka dot) are hidden during
|
|
542
|
+
* typical usage. Dotfiles, plain-text configuration files, are prime examples.
|
|
543
|
+
*
|
|
544
|
+
* @see {@link http://xahlee.info/UnixResource_dir/writ/unix_origin_of_dot_filename.html|Origin of Dot File Names}
|
|
545
|
+
*
|
|
546
|
+
* @private
|
|
547
|
+
* @param {string} pathname - Pathname to check for match.
|
|
548
|
+
* @return {boolean} whether pathname would be considered a hidden file.
|
|
549
|
+
* @example
|
|
550
|
+
* isHiddenOnUnix('.profile'); // => true
|
|
551
|
+
*/
|
|
552
|
+
function isHiddenOnUnix(pathname) {
|
|
553
|
+
return path.basename(pathname)[0] === '.';
|
|
554
|
+
}
|
|
555
|
+
|
|
465
556
|
/**
|
|
466
557
|
* Lookup file names at the given `path`.
|
|
467
558
|
*
|
|
468
|
-
* @
|
|
559
|
+
* @description
|
|
560
|
+
* Filenames are returned in _traversal_ order by the OS/filesystem.
|
|
561
|
+
* **Make no assumption that the names will be sorted in any fashion.**
|
|
562
|
+
*
|
|
469
563
|
* @public
|
|
470
|
-
* @
|
|
471
|
-
* @
|
|
472
|
-
* @param {string
|
|
473
|
-
* @param {
|
|
564
|
+
* @memberof Mocha.utils
|
|
565
|
+
* @todo Fix extension handling
|
|
566
|
+
* @param {string} filepath - Base path to start searching from.
|
|
567
|
+
* @param {string[]} extensions - File extensions to look for.
|
|
568
|
+
* @param {boolean} recursive - Whether to recurse into subdirectories.
|
|
474
569
|
* @return {string[]} An array of paths.
|
|
570
|
+
* @throws {Error} if no files match pattern.
|
|
571
|
+
* @throws {TypeError} if `filepath` is directory and `extensions` not provided.
|
|
475
572
|
*/
|
|
476
|
-
exports.lookupFiles = function lookupFiles
|
|
573
|
+
exports.lookupFiles = function lookupFiles(filepath, extensions, recursive) {
|
|
477
574
|
var files = [];
|
|
575
|
+
var stat;
|
|
478
576
|
|
|
479
577
|
if (!fs.existsSync(filepath)) {
|
|
480
578
|
if (fs.existsSync(filepath + '.js')) {
|
|
481
579
|
filepath += '.js';
|
|
482
580
|
} else {
|
|
581
|
+
// Handle glob
|
|
483
582
|
files = glob.sync(filepath);
|
|
484
583
|
if (!files.length) {
|
|
485
|
-
throw
|
|
584
|
+
throw createNoFilesMatchPatternError(
|
|
585
|
+
'Cannot find any files matching pattern ' + exports.dQuote(filepath),
|
|
586
|
+
filepath
|
|
587
|
+
);
|
|
486
588
|
}
|
|
487
589
|
return files;
|
|
488
590
|
}
|
|
489
591
|
}
|
|
490
592
|
|
|
593
|
+
// Handle file
|
|
491
594
|
try {
|
|
492
|
-
|
|
595
|
+
stat = fs.statSync(filepath);
|
|
493
596
|
if (stat.isFile()) {
|
|
494
597
|
return filepath;
|
|
495
598
|
}
|
|
@@ -498,13 +601,16 @@ exports.lookupFiles = function lookupFiles (filepath, extensions, recursive) {
|
|
|
498
601
|
return;
|
|
499
602
|
}
|
|
500
603
|
|
|
501
|
-
|
|
502
|
-
|
|
604
|
+
// Handle directory
|
|
605
|
+
fs.readdirSync(filepath).forEach(function(dirent) {
|
|
606
|
+
var pathname = path.join(filepath, dirent);
|
|
607
|
+
var stat;
|
|
608
|
+
|
|
503
609
|
try {
|
|
504
|
-
|
|
610
|
+
stat = fs.statSync(pathname);
|
|
505
611
|
if (stat.isDirectory()) {
|
|
506
612
|
if (recursive) {
|
|
507
|
-
files = files.concat(lookupFiles(
|
|
613
|
+
files = files.concat(lookupFiles(pathname, extensions, recursive));
|
|
508
614
|
}
|
|
509
615
|
return;
|
|
510
616
|
}
|
|
@@ -512,35 +618,73 @@ exports.lookupFiles = function lookupFiles (filepath, extensions, recursive) {
|
|
|
512
618
|
// ignore error
|
|
513
619
|
return;
|
|
514
620
|
}
|
|
515
|
-
|
|
516
|
-
|
|
621
|
+
if (!extensions) {
|
|
622
|
+
throw createMissingArgumentError(
|
|
623
|
+
util.format(
|
|
624
|
+
'Argument %s required when argument %s is a directory',
|
|
625
|
+
exports.sQuote('extensions'),
|
|
626
|
+
exports.sQuote('filepath')
|
|
627
|
+
),
|
|
628
|
+
'extensions',
|
|
629
|
+
'array'
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (
|
|
634
|
+
!stat.isFile() ||
|
|
635
|
+
!hasMatchingExtname(pathname, extensions) ||
|
|
636
|
+
isHiddenOnUnix(pathname)
|
|
637
|
+
) {
|
|
517
638
|
return;
|
|
518
639
|
}
|
|
519
|
-
files.push(
|
|
640
|
+
files.push(pathname);
|
|
520
641
|
});
|
|
521
642
|
|
|
522
643
|
return files;
|
|
523
644
|
};
|
|
524
645
|
|
|
525
646
|
/**
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
* @
|
|
647
|
+
* process.emitWarning or a polyfill
|
|
648
|
+
* @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options
|
|
649
|
+
* @ignore
|
|
529
650
|
*/
|
|
651
|
+
function emitWarning(msg, type) {
|
|
652
|
+
if (process.emitWarning) {
|
|
653
|
+
process.emitWarning(msg, type);
|
|
654
|
+
} else {
|
|
655
|
+
process.nextTick(function() {
|
|
656
|
+
console.warn(type + ': ' + msg);
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
}
|
|
530
660
|
|
|
531
|
-
|
|
532
|
-
|
|
661
|
+
/**
|
|
662
|
+
* Show a deprecation warning. Each distinct message is only displayed once.
|
|
663
|
+
* Ignores empty messages.
|
|
664
|
+
*
|
|
665
|
+
* @param {string} [msg] - Warning to print
|
|
666
|
+
* @private
|
|
667
|
+
*/
|
|
668
|
+
exports.deprecate = function deprecate(msg) {
|
|
669
|
+
msg = String(msg);
|
|
670
|
+
if (msg && !deprecate.cache[msg]) {
|
|
671
|
+
deprecate.cache[msg] = true;
|
|
672
|
+
emitWarning(msg, 'DeprecationWarning');
|
|
673
|
+
}
|
|
533
674
|
};
|
|
675
|
+
exports.deprecate.cache = {};
|
|
534
676
|
|
|
535
677
|
/**
|
|
536
|
-
*
|
|
678
|
+
* Show a generic warning.
|
|
679
|
+
* Ignores empty messages.
|
|
537
680
|
*
|
|
538
|
-
* @param {
|
|
539
|
-
* @
|
|
681
|
+
* @param {string} [msg] - Warning to print
|
|
682
|
+
* @private
|
|
540
683
|
*/
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
684
|
+
exports.warn = function warn(msg) {
|
|
685
|
+
if (msg) {
|
|
686
|
+
emitWarning(msg);
|
|
687
|
+
}
|
|
544
688
|
};
|
|
545
689
|
|
|
546
690
|
/**
|
|
@@ -552,9 +696,9 @@ exports.getError = function (err) {
|
|
|
552
696
|
* (i.e: strip Mocha and internal node functions from stack trace).
|
|
553
697
|
* @returns {Function}
|
|
554
698
|
*/
|
|
555
|
-
exports.stackTraceFilter = function
|
|
699
|
+
exports.stackTraceFilter = function() {
|
|
556
700
|
// TODO: Replace with `process.browser`
|
|
557
|
-
var is = typeof document === 'undefined' ? {
|
|
701
|
+
var is = typeof document === 'undefined' ? {node: true} : {browser: true};
|
|
558
702
|
var slash = path.sep;
|
|
559
703
|
var cwd;
|
|
560
704
|
if (is.node) {
|
|
@@ -562,30 +706,33 @@ exports.stackTraceFilter = function () {
|
|
|
562
706
|
} else {
|
|
563
707
|
cwd = (typeof location === 'undefined'
|
|
564
708
|
? window.location
|
|
565
|
-
: location
|
|
709
|
+
: location
|
|
710
|
+
).href.replace(/\/[^/]*$/, '/');
|
|
566
711
|
slash = '/';
|
|
567
712
|
}
|
|
568
713
|
|
|
569
|
-
function isMochaInternal
|
|
570
|
-
return (
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
714
|
+
function isMochaInternal(line) {
|
|
715
|
+
return (
|
|
716
|
+
~line.indexOf('node_modules' + slash + 'mocha' + slash) ||
|
|
717
|
+
~line.indexOf(slash + 'mocha.js')
|
|
718
|
+
);
|
|
574
719
|
}
|
|
575
720
|
|
|
576
|
-
function isNodeInternal
|
|
577
|
-
return (
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
721
|
+
function isNodeInternal(line) {
|
|
722
|
+
return (
|
|
723
|
+
~line.indexOf('(timers.js:') ||
|
|
724
|
+
~line.indexOf('(events.js:') ||
|
|
725
|
+
~line.indexOf('(node.js:') ||
|
|
726
|
+
~line.indexOf('(module.js:') ||
|
|
727
|
+
~line.indexOf('GeneratorFunctionPrototype.next (native)') ||
|
|
728
|
+
false
|
|
729
|
+
);
|
|
583
730
|
}
|
|
584
731
|
|
|
585
|
-
return function
|
|
732
|
+
return function(stack) {
|
|
586
733
|
stack = stack.split('\n');
|
|
587
734
|
|
|
588
|
-
stack = stack.reduce(function
|
|
735
|
+
stack = stack.reduce(function(list, line) {
|
|
589
736
|
if (isMochaInternal(line)) {
|
|
590
737
|
return list;
|
|
591
738
|
}
|
|
@@ -595,7 +742,7 @@ exports.stackTraceFilter = function () {
|
|
|
595
742
|
}
|
|
596
743
|
|
|
597
744
|
// Clean up cwd(absolute)
|
|
598
|
-
if (
|
|
745
|
+
if (/:\d+:\d+\)?$/.test(line)) {
|
|
599
746
|
line = line.replace('(' + cwd, '(');
|
|
600
747
|
}
|
|
601
748
|
|
|
@@ -609,16 +756,142 @@ exports.stackTraceFilter = function () {
|
|
|
609
756
|
|
|
610
757
|
/**
|
|
611
758
|
* Crude, but effective.
|
|
612
|
-
* @
|
|
759
|
+
* @public
|
|
613
760
|
* @param {*} value
|
|
614
761
|
* @returns {boolean} Whether or not `value` is a Promise
|
|
615
762
|
*/
|
|
616
|
-
exports.isPromise = function isPromise
|
|
617
|
-
return
|
|
763
|
+
exports.isPromise = function isPromise(value) {
|
|
764
|
+
return (
|
|
765
|
+
typeof value === 'object' &&
|
|
766
|
+
value !== null &&
|
|
767
|
+
typeof value.then === 'function'
|
|
768
|
+
);
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Clamps a numeric value to an inclusive range.
|
|
773
|
+
*
|
|
774
|
+
* @param {number} value - Value to be clamped.
|
|
775
|
+
* @param {numer[]} range - Two element array specifying [min, max] range.
|
|
776
|
+
* @returns {number} clamped value
|
|
777
|
+
*/
|
|
778
|
+
exports.clamp = function clamp(value, range) {
|
|
779
|
+
return Math.min(Math.max(value, range[0]), range[1]);
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Single quote text by combining with undirectional ASCII quotation marks.
|
|
784
|
+
*
|
|
785
|
+
* @description
|
|
786
|
+
* Provides a simple means of markup for quoting text to be used in output.
|
|
787
|
+
* Use this to quote names of variables, methods, and packages.
|
|
788
|
+
*
|
|
789
|
+
* <samp>package 'foo' cannot be found</samp>
|
|
790
|
+
*
|
|
791
|
+
* @private
|
|
792
|
+
* @param {string} str - Value to be quoted.
|
|
793
|
+
* @returns {string} quoted value
|
|
794
|
+
* @example
|
|
795
|
+
* sQuote('n') // => 'n'
|
|
796
|
+
*/
|
|
797
|
+
exports.sQuote = function(str) {
|
|
798
|
+
return "'" + str + "'";
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Double quote text by combining with undirectional ASCII quotation marks.
|
|
803
|
+
*
|
|
804
|
+
* @description
|
|
805
|
+
* Provides a simple means of markup for quoting text to be used in output.
|
|
806
|
+
* Use this to quote names of datatypes, classes, pathnames, and strings.
|
|
807
|
+
*
|
|
808
|
+
* <samp>argument 'value' must be "string" or "number"</samp>
|
|
809
|
+
*
|
|
810
|
+
* @private
|
|
811
|
+
* @param {string} str - Value to be quoted.
|
|
812
|
+
* @returns {string} quoted value
|
|
813
|
+
* @example
|
|
814
|
+
* dQuote('number') // => "number"
|
|
815
|
+
*/
|
|
816
|
+
exports.dQuote = function(str) {
|
|
817
|
+
return '"' + str + '"';
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Provides simplistic message translation for dealing with plurality.
|
|
822
|
+
*
|
|
823
|
+
* @description
|
|
824
|
+
* Use this to create messages which need to be singular or plural.
|
|
825
|
+
* Some languages have several plural forms, so _complete_ message clauses
|
|
826
|
+
* are preferable to generating the message on the fly.
|
|
827
|
+
*
|
|
828
|
+
* @private
|
|
829
|
+
* @param {number} n - Non-negative integer
|
|
830
|
+
* @param {string} msg1 - Message to be used in English for `n = 1`
|
|
831
|
+
* @param {string} msg2 - Message to be used in English for `n = 0, 2, 3, ...`
|
|
832
|
+
* @returns {string} message corresponding to value of `n`
|
|
833
|
+
* @example
|
|
834
|
+
* var sprintf = require('util').format;
|
|
835
|
+
* var pkgs = ['one', 'two'];
|
|
836
|
+
* var msg = sprintf(
|
|
837
|
+
* ngettext(
|
|
838
|
+
* pkgs.length,
|
|
839
|
+
* 'cannot load package: %s',
|
|
840
|
+
* 'cannot load packages: %s'
|
|
841
|
+
* ),
|
|
842
|
+
* pkgs.map(sQuote).join(', ')
|
|
843
|
+
* );
|
|
844
|
+
* console.log(msg); // => cannot load packages: 'one', 'two'
|
|
845
|
+
*/
|
|
846
|
+
exports.ngettext = function(n, msg1, msg2) {
|
|
847
|
+
if (typeof n === 'number' && n >= 0) {
|
|
848
|
+
return n === 1 ? msg1 : msg2;
|
|
849
|
+
}
|
|
618
850
|
};
|
|
619
851
|
|
|
620
852
|
/**
|
|
621
853
|
* It's a noop.
|
|
622
|
-
* @
|
|
854
|
+
* @public
|
|
623
855
|
*/
|
|
624
|
-
exports.noop = function
|
|
856
|
+
exports.noop = function() {};
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Creates a map-like object.
|
|
860
|
+
*
|
|
861
|
+
* @description
|
|
862
|
+
* A "map" is an object with no prototype, for our purposes. In some cases
|
|
863
|
+
* this would be more appropriate than a `Map`, especially if your environment
|
|
864
|
+
* doesn't support it. Recommended for use in Mocha's public APIs.
|
|
865
|
+
*
|
|
866
|
+
* @public
|
|
867
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map|MDN:Map}
|
|
868
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects|MDN:Object.create - Custom objects}
|
|
869
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign|MDN:Object.assign}
|
|
870
|
+
* @param {...*} [obj] - Arguments to `Object.assign()`.
|
|
871
|
+
* @returns {Object} An object with no prototype, having `...obj` properties
|
|
872
|
+
*/
|
|
873
|
+
exports.createMap = function(obj) {
|
|
874
|
+
return assign.apply(
|
|
875
|
+
null,
|
|
876
|
+
[Object.create(null)].concat(Array.prototype.slice.call(arguments))
|
|
877
|
+
);
|
|
878
|
+
};
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Creates a read-only map-like object.
|
|
882
|
+
*
|
|
883
|
+
* @description
|
|
884
|
+
* This differs from {@link module:utils.createMap createMap} only in that
|
|
885
|
+
* the argument must be non-empty, because the result is frozen.
|
|
886
|
+
*
|
|
887
|
+
* @see {@link module:utils.createMap createMap}
|
|
888
|
+
* @param {...*} [obj] - Arguments to `Object.assign()`.
|
|
889
|
+
* @returns {Object} A frozen object with no prototype, having `...obj` properties
|
|
890
|
+
* @throws {TypeError} if argument is not a non-empty object.
|
|
891
|
+
*/
|
|
892
|
+
exports.defineConstants = function(obj) {
|
|
893
|
+
if (type(obj) !== 'object' || !Object.keys(obj).length) {
|
|
894
|
+
throw new TypeError('Invalid argument; expected a non-empty object');
|
|
895
|
+
}
|
|
896
|
+
return Object.freeze(exports.createMap(obj));
|
|
897
|
+
};
|