mocha 8.1.1 → 8.2.1
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 +88 -0
- package/README.md +2 -0
- package/browser-entry.js +2 -2
- package/lib/cli/cli.js +19 -8
- package/lib/cli/index.js +0 -6
- package/lib/cli/lookup-files.js +37 -31
- package/lib/cli/node-flags.js +6 -7
- package/lib/cli/options.js +5 -4
- package/lib/cli/run-helpers.js +21 -56
- package/lib/cli/run-option-metadata.js +25 -2
- package/lib/cli/run.js +5 -9
- package/lib/cli/watch-run.js +55 -30
- package/lib/errors.js +142 -20
- package/lib/hook.js +14 -9
- package/lib/mocha.js +266 -66
- package/lib/nodejs/buffered-worker-pool.js +1 -3
- package/lib/nodejs/file-unloader.js +15 -0
- package/lib/nodejs/parallel-buffered-runner.js +156 -18
- package/lib/nodejs/reporters/parallel-buffered.js +61 -29
- package/lib/nodejs/serializer.js +15 -7
- package/lib/nodejs/worker.js +9 -12
- package/lib/plugin-loader.js +286 -0
- package/lib/reporters/json-stream.js +2 -1
- package/lib/reporters/json.js +1 -0
- package/lib/runnable.js +6 -0
- package/lib/runner.js +239 -110
- package/lib/suite.js +34 -15
- package/lib/test.js +6 -2
- package/lib/utils.js +151 -66
- package/mocha.js +7807 -3995
- package/mocha.js.map +1 -1
- package/package.json +68 -56
package/lib/runner.js
CHANGED
|
@@ -8,7 +8,6 @@ var util = require('util');
|
|
|
8
8
|
var EventEmitter = require('events').EventEmitter;
|
|
9
9
|
var Pending = require('./pending');
|
|
10
10
|
var utils = require('./utils');
|
|
11
|
-
var inherits = utils.inherits;
|
|
12
11
|
var debug = require('debug')('mocha:runner');
|
|
13
12
|
var Runnable = require('./runnable');
|
|
14
13
|
var Suite = require('./suite');
|
|
@@ -24,11 +23,14 @@ var dQuote = utils.dQuote;
|
|
|
24
23
|
var sQuote = utils.sQuote;
|
|
25
24
|
var stackFilter = utils.stackTraceFilter();
|
|
26
25
|
var stringify = utils.stringify;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
createInvalidExceptionError,
|
|
29
|
+
createUnsupportedError,
|
|
30
|
+
createFatalError,
|
|
31
|
+
isMochaError,
|
|
32
|
+
constants: errorConstants
|
|
33
|
+
} = require('./errors');
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Non-enumerable globals.
|
|
@@ -128,54 +130,82 @@ var constants = utils.defineConstants(
|
|
|
128
130
|
}
|
|
129
131
|
);
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
if (typeof opts === 'boolean') {
|
|
149
|
-
this._delay = opts;
|
|
150
|
-
opts = {};
|
|
151
|
-
} else {
|
|
152
|
-
this._delay = opts.delay;
|
|
153
|
-
}
|
|
154
|
-
var self = this;
|
|
155
|
-
this._globals = [];
|
|
156
|
-
this._abort = false;
|
|
157
|
-
this.suite = suite;
|
|
158
|
-
this._opts = opts;
|
|
159
|
-
this.state = constants.STATE_IDLE;
|
|
160
|
-
this.total = suite.total();
|
|
161
|
-
this.failures = 0;
|
|
162
|
-
this._eventListeners = [];
|
|
163
|
-
this.on(constants.EVENT_TEST_END, function(test) {
|
|
164
|
-
if (test.type === 'test' && test.retriedTest() && test.parent) {
|
|
165
|
-
var idx =
|
|
166
|
-
test.parent.tests && test.parent.tests.indexOf(test.retriedTest());
|
|
167
|
-
if (idx > -1) test.parent.tests[idx] = test;
|
|
133
|
+
class Runner extends EventEmitter {
|
|
134
|
+
/**
|
|
135
|
+
* Initialize a `Runner` at the Root {@link Suite}, which represents a hierarchy of {@link Suite|Suites} and {@link Test|Tests}.
|
|
136
|
+
*
|
|
137
|
+
* @extends external:EventEmitter
|
|
138
|
+
* @public
|
|
139
|
+
* @class
|
|
140
|
+
* @param {Suite} suite - Root suite
|
|
141
|
+
* @param {Object|boolean} [opts] - Options. If `boolean`, whether or not to delay execution of root suite until ready (for backwards compatibility).
|
|
142
|
+
* @param {boolean} [opts.delay] - Whether to delay execution of root suite until ready.
|
|
143
|
+
* @param {boolean} [opts.cleanReferencesAfterRun] - Whether to clean references to test fns and hooks when a suite is done.
|
|
144
|
+
*/
|
|
145
|
+
constructor(suite, opts) {
|
|
146
|
+
super();
|
|
147
|
+
if (opts === undefined) {
|
|
148
|
+
opts = {};
|
|
168
149
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
150
|
+
if (typeof opts === 'boolean') {
|
|
151
|
+
// TODO: deprecate this
|
|
152
|
+
this._delay = opts;
|
|
153
|
+
opts = {};
|
|
154
|
+
} else {
|
|
155
|
+
this._delay = opts.delay;
|
|
156
|
+
}
|
|
157
|
+
var self = this;
|
|
158
|
+
this._globals = [];
|
|
159
|
+
this._abort = false;
|
|
160
|
+
this.suite = suite;
|
|
161
|
+
this._opts = opts;
|
|
162
|
+
this.state = constants.STATE_IDLE;
|
|
163
|
+
this.total = suite.total();
|
|
164
|
+
this.failures = 0;
|
|
165
|
+
/**
|
|
166
|
+
* @type {Map<EventEmitter,Map<string,Set<EventListener>>>}
|
|
167
|
+
*/
|
|
168
|
+
this._eventListeners = new Map();
|
|
169
|
+
this.on(constants.EVENT_TEST_END, function(test) {
|
|
170
|
+
if (test.type === 'test' && test.retriedTest() && test.parent) {
|
|
171
|
+
var idx =
|
|
172
|
+
test.parent.tests && test.parent.tests.indexOf(test.retriedTest());
|
|
173
|
+
if (idx > -1) test.parent.tests[idx] = test;
|
|
174
|
+
}
|
|
175
|
+
self.checkGlobals(test);
|
|
176
|
+
});
|
|
177
|
+
this.on(constants.EVENT_HOOK_END, function(hook) {
|
|
178
|
+
self.checkGlobals(hook);
|
|
179
|
+
});
|
|
180
|
+
this._defaultGrep = /.*/;
|
|
181
|
+
this.grep(this._defaultGrep);
|
|
182
|
+
this.globals(this.globalProps());
|
|
183
|
+
|
|
184
|
+
this.uncaught = this._uncaught.bind(this);
|
|
185
|
+
this.unhandled = (reason, promise) => {
|
|
186
|
+
if (isMochaError(reason)) {
|
|
187
|
+
debug(
|
|
188
|
+
'trapped unhandled rejection coming out of Mocha; forwarding to uncaught handler:',
|
|
189
|
+
reason
|
|
190
|
+
);
|
|
191
|
+
this.uncaught(reason);
|
|
192
|
+
} else {
|
|
193
|
+
debug(
|
|
194
|
+
'trapped unhandled rejection from (probably) user code; re-emitting on process'
|
|
195
|
+
);
|
|
196
|
+
this._removeEventListener(
|
|
197
|
+
process,
|
|
198
|
+
'unhandledRejection',
|
|
199
|
+
this.unhandled
|
|
200
|
+
);
|
|
201
|
+
try {
|
|
202
|
+
process.emit('unhandledRejection', reason, promise);
|
|
203
|
+
} finally {
|
|
204
|
+
this._addEventListener(process, 'unhandledRejection', this.unhandled);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
179
209
|
}
|
|
180
210
|
|
|
181
211
|
/**
|
|
@@ -186,11 +216,6 @@ function Runner(suite, opts) {
|
|
|
186
216
|
*/
|
|
187
217
|
Runner.immediately = global.setImmediate || process.nextTick;
|
|
188
218
|
|
|
189
|
-
/**
|
|
190
|
-
* Inherit from `EventEmitter.prototype`.
|
|
191
|
-
*/
|
|
192
|
-
inherits(Runner, EventEmitter);
|
|
193
|
-
|
|
194
219
|
/**
|
|
195
220
|
* Replacement for `target.on(eventName, listener)` that does bookkeeping to remove them when this runner instance is disposed.
|
|
196
221
|
* @param {EventEmitter} target - The `EventEmitter`
|
|
@@ -199,33 +224,62 @@ inherits(Runner, EventEmitter);
|
|
|
199
224
|
* @private
|
|
200
225
|
*/
|
|
201
226
|
Runner.prototype._addEventListener = function(target, eventName, listener) {
|
|
227
|
+
debug(
|
|
228
|
+
'_addEventListener(): adding for event %s; %d current listeners',
|
|
229
|
+
eventName,
|
|
230
|
+
target.listenerCount(eventName)
|
|
231
|
+
);
|
|
232
|
+
/* istanbul ignore next */
|
|
233
|
+
if (
|
|
234
|
+
this._eventListeners.has(target) &&
|
|
235
|
+
this._eventListeners.get(target).has(eventName) &&
|
|
236
|
+
this._eventListeners
|
|
237
|
+
.get(target)
|
|
238
|
+
.get(eventName)
|
|
239
|
+
.has(listener)
|
|
240
|
+
) {
|
|
241
|
+
debug(
|
|
242
|
+
'warning: tried to attach duplicate event listener for %s',
|
|
243
|
+
eventName
|
|
244
|
+
);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
202
247
|
target.on(eventName, listener);
|
|
203
|
-
this._eventListeners.
|
|
248
|
+
const targetListeners = this._eventListeners.has(target)
|
|
249
|
+
? this._eventListeners.get(target)
|
|
250
|
+
: new Map();
|
|
251
|
+
const targetEventListeners = targetListeners.has(eventName)
|
|
252
|
+
? targetListeners.get(eventName)
|
|
253
|
+
: new Set();
|
|
254
|
+
targetEventListeners.add(listener);
|
|
255
|
+
targetListeners.set(eventName, targetEventListeners);
|
|
256
|
+
this._eventListeners.set(target, targetListeners);
|
|
204
257
|
};
|
|
205
258
|
|
|
206
259
|
/**
|
|
207
260
|
* Replacement for `target.removeListener(eventName, listener)` that also updates the bookkeeping.
|
|
208
261
|
* @param {EventEmitter} target - The `EventEmitter`
|
|
209
|
-
* @param {string} eventName - The event
|
|
262
|
+
* @param {string} eventName - The event name
|
|
210
263
|
* @param {function} listener - Listener function
|
|
211
264
|
* @private
|
|
212
265
|
*/
|
|
213
266
|
Runner.prototype._removeEventListener = function(target, eventName, listener) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
267
|
+
target.removeListener(eventName, listener);
|
|
268
|
+
|
|
269
|
+
if (this._eventListeners.has(target)) {
|
|
270
|
+
const targetListeners = this._eventListeners.get(target);
|
|
271
|
+
if (targetListeners.has(eventName)) {
|
|
272
|
+
const targetEventListeners = targetListeners.get(eventName);
|
|
273
|
+
targetEventListeners.delete(listener);
|
|
274
|
+
if (!targetEventListeners.size) {
|
|
275
|
+
targetListeners.delete(eventName);
|
|
276
|
+
}
|
|
224
277
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
278
|
+
if (!targetListeners.size) {
|
|
279
|
+
this._eventListeners.delete(target);
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
debug('trying to remove listener for untracked object %s', target);
|
|
229
283
|
}
|
|
230
284
|
};
|
|
231
285
|
|
|
@@ -235,12 +289,14 @@ Runner.prototype._removeEventListener = function(target, eventName, listener) {
|
|
|
235
289
|
*/
|
|
236
290
|
Runner.prototype.dispose = function() {
|
|
237
291
|
this.removeAllListeners();
|
|
238
|
-
this._eventListeners.forEach(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
292
|
+
this._eventListeners.forEach((targetListeners, target) => {
|
|
293
|
+
targetListeners.forEach((targetEventListeners, eventName) => {
|
|
294
|
+
targetEventListeners.forEach(listener => {
|
|
295
|
+
target.removeListener(eventName, listener);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
243
298
|
});
|
|
299
|
+
this._eventListeners.clear();
|
|
244
300
|
};
|
|
245
301
|
|
|
246
302
|
/**
|
|
@@ -384,7 +440,7 @@ Runner.prototype.fail = function(test, err, force) {
|
|
|
384
440
|
return;
|
|
385
441
|
}
|
|
386
442
|
if (this.state === constants.STATE_STOPPED) {
|
|
387
|
-
if (err.code ===
|
|
443
|
+
if (err.code === errorConstants.MULTIPLE_DONE) {
|
|
388
444
|
throw err;
|
|
389
445
|
}
|
|
390
446
|
throw createFatalError(
|
|
@@ -976,73 +1032,117 @@ Runner.prototype._uncaught = function(err) {
|
|
|
976
1032
|
* @memberof Runner
|
|
977
1033
|
* @param {Function} fn - Callback when finished
|
|
978
1034
|
* @param {{files: string[], options: Options}} [opts] - For subclasses
|
|
979
|
-
* @
|
|
1035
|
+
* @returns {Runner} Runner instance.
|
|
980
1036
|
*/
|
|
981
|
-
Runner.prototype.run = function(fn, opts) {
|
|
982
|
-
var self = this;
|
|
1037
|
+
Runner.prototype.run = function(fn, opts = {}) {
|
|
983
1038
|
var rootSuite = this.suite;
|
|
1039
|
+
var options = opts.options || {};
|
|
984
1040
|
|
|
1041
|
+
debug('run(): got options: %O', options);
|
|
985
1042
|
fn = fn || function() {};
|
|
986
1043
|
|
|
987
|
-
|
|
1044
|
+
const end = () => {
|
|
1045
|
+
debug('run(): root suite completed; emitting %s', constants.EVENT_RUN_END);
|
|
1046
|
+
this.emit(constants.EVENT_RUN_END);
|
|
1047
|
+
};
|
|
1048
|
+
|
|
1049
|
+
const begin = () => {
|
|
1050
|
+
debug('run(): emitting %s', constants.EVENT_RUN_BEGIN);
|
|
1051
|
+
this.emit(constants.EVENT_RUN_BEGIN);
|
|
1052
|
+
debug('run(): emitted %s', constants.EVENT_RUN_BEGIN);
|
|
1053
|
+
|
|
1054
|
+
this.runSuite(rootSuite, end);
|
|
1055
|
+
};
|
|
1056
|
+
|
|
1057
|
+
const prepare = () => {
|
|
988
1058
|
debug('run(): starting');
|
|
989
1059
|
// If there is an `only` filter
|
|
990
1060
|
if (rootSuite.hasOnly()) {
|
|
991
1061
|
rootSuite.filterOnly();
|
|
992
1062
|
debug('run(): filtered exclusive Runnables');
|
|
993
1063
|
}
|
|
994
|
-
|
|
995
|
-
if (
|
|
996
|
-
|
|
1064
|
+
this.state = constants.STATE_RUNNING;
|
|
1065
|
+
if (this._delay) {
|
|
1066
|
+
this.emit(constants.EVENT_DELAY_END);
|
|
997
1067
|
debug('run(): "delay" ended');
|
|
998
1068
|
}
|
|
999
|
-
debug('run(): emitting %s', constants.EVENT_RUN_BEGIN);
|
|
1000
|
-
self.emit(constants.EVENT_RUN_BEGIN);
|
|
1001
|
-
debug('run(): emitted %s', constants.EVENT_RUN_BEGIN);
|
|
1002
1069
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
'run(): root suite completed; emitting %s',
|
|
1006
|
-
constants.EVENT_RUN_END
|
|
1007
|
-
);
|
|
1008
|
-
self.emit(constants.EVENT_RUN_END);
|
|
1009
|
-
debug('run(): emitted %s', constants.EVENT_RUN_END);
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1070
|
+
return begin();
|
|
1071
|
+
};
|
|
1012
1072
|
|
|
1013
1073
|
// references cleanup to avoid memory leaks
|
|
1014
1074
|
if (this._opts.cleanReferencesAfterRun) {
|
|
1015
|
-
this.on(constants.EVENT_SUITE_END,
|
|
1075
|
+
this.on(constants.EVENT_SUITE_END, suite => {
|
|
1016
1076
|
suite.cleanReferences();
|
|
1017
1077
|
});
|
|
1018
1078
|
}
|
|
1019
1079
|
|
|
1020
1080
|
// callback
|
|
1021
1081
|
this.on(constants.EVENT_RUN_END, function() {
|
|
1022
|
-
|
|
1023
|
-
debug(constants.EVENT_RUN_END);
|
|
1082
|
+
this.state = constants.STATE_STOPPED;
|
|
1024
1083
|
debug('run(): emitted %s', constants.EVENT_RUN_END);
|
|
1025
|
-
fn(
|
|
1084
|
+
fn(this.failures);
|
|
1026
1085
|
});
|
|
1027
1086
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1087
|
+
this._removeEventListener(process, 'uncaughtException', this.uncaught);
|
|
1088
|
+
this._removeEventListener(process, 'unhandledRejection', this.unhandled);
|
|
1089
|
+
this._addEventListener(process, 'uncaughtException', this.uncaught);
|
|
1090
|
+
this._addEventListener(process, 'unhandledRejection', this.unhandled);
|
|
1030
1091
|
|
|
1031
1092
|
if (this._delay) {
|
|
1032
1093
|
// for reporters, I guess.
|
|
1033
1094
|
// might be nice to debounce some dots while we wait.
|
|
1034
1095
|
this.emit(constants.EVENT_DELAY_BEGIN, rootSuite);
|
|
1035
|
-
rootSuite.once(EVENT_ROOT_SUITE_RUN,
|
|
1096
|
+
rootSuite.once(EVENT_ROOT_SUITE_RUN, prepare);
|
|
1036
1097
|
debug('run(): waiting for green light due to --delay');
|
|
1037
1098
|
} else {
|
|
1038
|
-
Runner.immediately(
|
|
1039
|
-
start();
|
|
1040
|
-
});
|
|
1099
|
+
Runner.immediately(prepare);
|
|
1041
1100
|
}
|
|
1042
1101
|
|
|
1043
1102
|
return this;
|
|
1044
1103
|
};
|
|
1045
1104
|
|
|
1105
|
+
/**
|
|
1106
|
+
* Toggle partial object linking behavior; used for building object references from
|
|
1107
|
+
* unique ID's. Does nothing in serial mode, because the object references already exist.
|
|
1108
|
+
* Subclasses can implement this (e.g., `ParallelBufferedRunner`)
|
|
1109
|
+
* @abstract
|
|
1110
|
+
* @param {boolean} [value] - If `true`, enable partial object linking, otherwise disable
|
|
1111
|
+
* @returns {Runner}
|
|
1112
|
+
* @chainable
|
|
1113
|
+
* @public
|
|
1114
|
+
* @example
|
|
1115
|
+
* // this reporter needs proper object references when run in parallel mode
|
|
1116
|
+
* class MyReporter() {
|
|
1117
|
+
* constructor(runner) {
|
|
1118
|
+
* this.runner.linkPartialObjects(true)
|
|
1119
|
+
* .on(EVENT_SUITE_BEGIN, suite => {
|
|
1120
|
+
// this Suite may be the same object...
|
|
1121
|
+
* })
|
|
1122
|
+
* .on(EVENT_TEST_BEGIN, test => {
|
|
1123
|
+
* // ...as the `test.parent` property
|
|
1124
|
+
* });
|
|
1125
|
+
* }
|
|
1126
|
+
* }
|
|
1127
|
+
*/
|
|
1128
|
+
Runner.prototype.linkPartialObjects = function(value) {
|
|
1129
|
+
return this;
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
/*
|
|
1133
|
+
* Like {@link Runner#run}, but does not accept a callback and returns a `Promise` instead of a `Runner`.
|
|
1134
|
+
* This function cannot reject; an `unhandledRejection` event will bubble up to the `process` object instead.
|
|
1135
|
+
* @public
|
|
1136
|
+
* @memberof Runner
|
|
1137
|
+
* @param {Object} [opts] - Options for {@link Runner#run}
|
|
1138
|
+
* @returns {Promise<number>} Failure count
|
|
1139
|
+
*/
|
|
1140
|
+
Runner.prototype.runAsync = async function runAsync(opts = {}) {
|
|
1141
|
+
return new Promise(resolve => {
|
|
1142
|
+
this.run(resolve, opts);
|
|
1143
|
+
});
|
|
1144
|
+
};
|
|
1145
|
+
|
|
1046
1146
|
/**
|
|
1047
1147
|
* Cleanly abort execution.
|
|
1048
1148
|
*
|
|
@@ -1057,6 +1157,31 @@ Runner.prototype.abort = function() {
|
|
|
1057
1157
|
return this;
|
|
1058
1158
|
};
|
|
1059
1159
|
|
|
1160
|
+
/**
|
|
1161
|
+
* Returns `true` if Mocha is running in parallel mode. For reporters.
|
|
1162
|
+
*
|
|
1163
|
+
* Subclasses should return an appropriate value.
|
|
1164
|
+
* @public
|
|
1165
|
+
* @returns {false}
|
|
1166
|
+
*/
|
|
1167
|
+
Runner.prototype.isParallelMode = function isParallelMode() {
|
|
1168
|
+
return false;
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1171
|
+
/**
|
|
1172
|
+
* Configures an alternate reporter for worker processes to use. Subclasses
|
|
1173
|
+
* using worker processes should implement this.
|
|
1174
|
+
* @public
|
|
1175
|
+
* @param {string} path - Absolute path to alternate reporter for worker processes to use
|
|
1176
|
+
* @returns {Runner}
|
|
1177
|
+
* @throws When in serial mode
|
|
1178
|
+
* @chainable
|
|
1179
|
+
* @abstract
|
|
1180
|
+
*/
|
|
1181
|
+
Runner.prototype.workerReporter = function() {
|
|
1182
|
+
throw createUnsupportedError('workerReporter() not supported in serial mode');
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1060
1185
|
/**
|
|
1061
1186
|
* Filter leaks with the given globals flagged as `ok`.
|
|
1062
1187
|
*
|
|
@@ -1122,7 +1247,9 @@ function isError(err) {
|
|
|
1122
1247
|
*/
|
|
1123
1248
|
function thrown2Error(err) {
|
|
1124
1249
|
return new Error(
|
|
1125
|
-
|
|
1250
|
+
`the ${utils.canonicalType(err)} ${stringify(
|
|
1251
|
+
err
|
|
1252
|
+
)} was thrown, throw an Error :)`
|
|
1126
1253
|
);
|
|
1127
1254
|
}
|
|
1128
1255
|
|
|
@@ -1133,3 +1260,5 @@ Runner.constants = constants;
|
|
|
1133
1260
|
* @external EventEmitter
|
|
1134
1261
|
* @see {@link https://nodejs.org/api/events.html#events_class_eventemitter}
|
|
1135
1262
|
*/
|
|
1263
|
+
|
|
1264
|
+
module.exports = Runner;
|
package/lib/suite.js
CHANGED
|
@@ -4,14 +4,23 @@
|
|
|
4
4
|
* Module dependencies.
|
|
5
5
|
* @private
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
const {EventEmitter} = require('events');
|
|
8
|
+
const Hook = require('./hook');
|
|
9
|
+
var {
|
|
10
|
+
assignNewMochaID,
|
|
11
|
+
clamp,
|
|
12
|
+
constants: utilsConstants,
|
|
13
|
+
createMap,
|
|
14
|
+
defineConstants,
|
|
15
|
+
getMochaID,
|
|
16
|
+
inherits,
|
|
17
|
+
isString
|
|
18
|
+
} = require('./utils');
|
|
19
|
+
const debug = require('debug')('mocha:suite');
|
|
20
|
+
const milliseconds = require('ms');
|
|
21
|
+
const errors = require('./errors');
|
|
22
|
+
|
|
23
|
+
const {MOCHA_ID_PROP_NAME} = utilsConstants;
|
|
15
24
|
|
|
16
25
|
/**
|
|
17
26
|
* Expose `Suite`.
|
|
@@ -47,8 +56,8 @@ Suite.create = function(parent, title) {
|
|
|
47
56
|
* @param {boolean} [isRoot=false] - Whether this is the root suite.
|
|
48
57
|
*/
|
|
49
58
|
function Suite(title, parentContext, isRoot) {
|
|
50
|
-
if (!
|
|
51
|
-
throw createInvalidArgumentTypeError(
|
|
59
|
+
if (!isString(title)) {
|
|
60
|
+
throw errors.createInvalidArgumentTypeError(
|
|
52
61
|
'Suite argument "title" must be a string. Received type "' +
|
|
53
62
|
typeof title +
|
|
54
63
|
'"',
|
|
@@ -74,11 +83,19 @@ function Suite(title, parentContext, isRoot) {
|
|
|
74
83
|
this._bail = false;
|
|
75
84
|
this._onlyTests = [];
|
|
76
85
|
this._onlySuites = [];
|
|
86
|
+
assignNewMochaID(this);
|
|
87
|
+
|
|
88
|
+
Object.defineProperty(this, 'id', {
|
|
89
|
+
get() {
|
|
90
|
+
return getMochaID(this);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
77
94
|
this.reset();
|
|
78
95
|
|
|
79
96
|
this.on('newListener', function(event) {
|
|
80
97
|
if (deprecatedEvents[event]) {
|
|
81
|
-
|
|
98
|
+
errors.deprecate(
|
|
82
99
|
'Event "' +
|
|
83
100
|
event +
|
|
84
101
|
'" is deprecated. Please let the Mocha team know about your use case: https://git.io/v6Lwm'
|
|
@@ -145,7 +162,7 @@ Suite.prototype.timeout = function(ms) {
|
|
|
145
162
|
// Clamp to range
|
|
146
163
|
var INT_MAX = Math.pow(2, 31) - 1;
|
|
147
164
|
var range = [0, INT_MAX];
|
|
148
|
-
ms =
|
|
165
|
+
ms = clamp(ms, range);
|
|
149
166
|
|
|
150
167
|
debug('timeout %d', ms);
|
|
151
168
|
this._timeout = parseInt(ms, 10);
|
|
@@ -579,11 +596,13 @@ Suite.prototype.serialize = function serialize() {
|
|
|
579
596
|
$$fullTitle: this.fullTitle(),
|
|
580
597
|
$$isPending: this.isPending(),
|
|
581
598
|
root: this.root,
|
|
582
|
-
title: this.title
|
|
599
|
+
title: this.title,
|
|
600
|
+
id: this.id,
|
|
601
|
+
parent: this.parent ? {[MOCHA_ID_PROP_NAME]: this.parent.id} : null
|
|
583
602
|
};
|
|
584
603
|
};
|
|
585
604
|
|
|
586
|
-
var constants =
|
|
605
|
+
var constants = defineConstants(
|
|
587
606
|
/**
|
|
588
607
|
* {@link Suite}-related constants.
|
|
589
608
|
* @public
|
|
@@ -671,6 +690,6 @@ var deprecatedEvents = Object.keys(constants)
|
|
|
671
690
|
.reduce(function(acc, constant) {
|
|
672
691
|
acc[constants[constant]] = true;
|
|
673
692
|
return acc;
|
|
674
|
-
},
|
|
693
|
+
}, createMap());
|
|
675
694
|
|
|
676
695
|
Suite.constants = constants;
|
package/lib/test.js
CHANGED
|
@@ -5,6 +5,8 @@ var errors = require('./errors');
|
|
|
5
5
|
var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError;
|
|
6
6
|
var isString = utils.isString;
|
|
7
7
|
|
|
8
|
+
const {MOCHA_ID_PROP_NAME} = utils.constants;
|
|
9
|
+
|
|
8
10
|
module.exports = Test;
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -98,12 +100,14 @@ Test.prototype.serialize = function serialize() {
|
|
|
98
100
|
duration: this.duration,
|
|
99
101
|
err: this.err,
|
|
100
102
|
parent: {
|
|
101
|
-
$$fullTitle: this.parent.fullTitle()
|
|
103
|
+
$$fullTitle: this.parent.fullTitle(),
|
|
104
|
+
[MOCHA_ID_PROP_NAME]: this.parent.id
|
|
102
105
|
},
|
|
103
106
|
speed: this.speed,
|
|
104
107
|
state: this.state,
|
|
105
108
|
title: this.title,
|
|
106
109
|
type: this.type,
|
|
107
|
-
file: this.file
|
|
110
|
+
file: this.file,
|
|
111
|
+
[MOCHA_ID_PROP_NAME]: this.id
|
|
108
112
|
};
|
|
109
113
|
};
|