mocha-compat 3.6.4 → 10.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.
- package/LICENSE +1 -1
- package/README.md +61 -110
- package/bin/_mocha +10 -0
- package/bin/mocha.js +142 -0
- package/browser-entry.js +61 -22
- package/lib/browser/highlight-tags.js +39 -0
- package/lib/browser/parse-query.js +24 -0
- package/lib/{template.html → browser/template.html} +7 -5
- package/lib/cli/cli.js +89 -0
- package/lib/cli/collect-files.js +137 -0
- package/lib/cli/commands.js +14 -0
- package/lib/cli/config.js +100 -0
- package/lib/cli/index.js +3 -0
- package/lib/cli/init.js +36 -0
- package/lib/cli/lookup-files.js +150 -0
- package/lib/cli/node-flags.js +85 -0
- package/lib/cli/one-and-dones.js +69 -0
- package/lib/cli/options.js +284 -0
- package/lib/cli/run-helpers.js +304 -0
- package/lib/cli/run-option-metadata.js +116 -0
- package/lib/cli/run.js +380 -0
- package/lib/cli/watch-run.js +377 -0
- package/lib/context.js +16 -42
- package/lib/errors.js +563 -0
- package/lib/hook.js +50 -9
- package/lib/interfaces/bdd.js +28 -29
- package/lib/interfaces/common.js +56 -21
- package/lib/interfaces/exports.js +4 -7
- package/lib/interfaces/qunit.js +10 -11
- package/lib/interfaces/tdd.js +15 -15
- package/lib/mocha.js +1073 -292
- package/lib/mocharc.json +10 -0
- package/lib/nodejs/buffered-worker-pool.js +188 -0
- package/lib/nodejs/esm-utils.js +106 -0
- package/lib/nodejs/file-unloader.js +15 -0
- package/lib/nodejs/parallel-buffered-runner.js +433 -0
- package/lib/nodejs/reporters/parallel-buffered.js +165 -0
- package/lib/nodejs/serializer.js +414 -0
- package/lib/nodejs/worker.js +151 -0
- package/lib/pending.js +3 -3
- package/lib/plugin-loader.js +286 -0
- package/lib/reporters/base.js +305 -205
- package/lib/reporters/doc.js +52 -21
- package/lib/reporters/dot.js +31 -18
- package/lib/reporters/html.js +153 -81
- package/lib/reporters/json-stream.js +53 -24
- package/lib/reporters/json.js +88 -18
- package/lib/reporters/landing.js +38 -16
- package/lib/reporters/list.js +34 -19
- package/lib/reporters/markdown.js +28 -15
- package/lib/reporters/min.js +22 -8
- package/lib/reporters/nyan.js +62 -58
- package/lib/reporters/progress.js +32 -19
- package/lib/reporters/spec.js +41 -23
- package/lib/reporters/tap.js +255 -32
- package/lib/reporters/xunit.js +89 -39
- package/lib/runnable.js +233 -148
- package/lib/runner.js +679 -380
- package/lib/stats-collector.js +83 -0
- package/lib/suite.js +376 -112
- package/lib/test.js +82 -21
- package/lib/utils.js +364 -477
- package/mocha.css +183 -54
- package/mocha.js +19840 -15846
- package/mocha.js.map +1 -0
- package/package.json +163 -336
- package/{lib/to-iso-string → vendor/serialize-javascript}/LICENSE +8 -6
- package/vendor/serialize-javascript/README.md +10 -0
- package/vendor/serialize-javascript/index.js +349 -0
- package/bin/_mocha-compat +0 -572
- package/bin/mocha-compat +0 -87
- package/bin/options.js +0 -41
- package/bower.json +0 -38
- package/images/error.png +0 -0
- package/images/ok.png +0 -0
- package/lib/browser/.eslintrc.yaml +0 -4
- package/lib/browser/debug.js +0 -7
- package/lib/browser/events.js +0 -195
- package/lib/browser/progress.js +0 -119
- package/lib/browser/tty.js +0 -13
- package/lib/ms.js +0 -130
- package/lib/to-iso-string/index.js +0 -37
- package/vendor/glob/LICENSE +0 -15
- package/vendor/glob/README.md +0 -399
- package/vendor/glob/common.js +0 -244
- package/vendor/glob/glob.js +0 -788
- package/vendor/glob/package.json +0 -55
- package/vendor/glob/sync.js +0 -486
- package/vendor/inflight/LICENSE +0 -15
- package/vendor/inflight/README.md +0 -37
- package/vendor/inflight/inflight.js +0 -54
- package/vendor/inflight/package.json +0 -29
package/lib/runner.js
CHANGED
|
@@ -2,28 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Module dependencies.
|
|
5
|
+
* @private
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
7
|
var EventEmitter = require('events').EventEmitter;
|
|
8
8
|
var Pending = require('./pending');
|
|
9
9
|
var utils = require('./utils');
|
|
10
|
-
var inherits = utils.inherits;
|
|
11
10
|
var debug = require('debug')('mocha:runner');
|
|
12
11
|
var Runnable = require('./runnable');
|
|
13
|
-
var
|
|
14
|
-
var
|
|
15
|
-
var
|
|
16
|
-
var
|
|
12
|
+
var Suite = require('./suite');
|
|
13
|
+
var HOOK_TYPE_BEFORE_EACH = Suite.constants.HOOK_TYPE_BEFORE_EACH;
|
|
14
|
+
var HOOK_TYPE_AFTER_EACH = Suite.constants.HOOK_TYPE_AFTER_EACH;
|
|
15
|
+
var HOOK_TYPE_AFTER_ALL = Suite.constants.HOOK_TYPE_AFTER_ALL;
|
|
16
|
+
var HOOK_TYPE_BEFORE_ALL = Suite.constants.HOOK_TYPE_BEFORE_ALL;
|
|
17
|
+
var EVENT_ROOT_SUITE_RUN = Suite.constants.EVENT_ROOT_SUITE_RUN;
|
|
18
|
+
var STATE_FAILED = Runnable.constants.STATE_FAILED;
|
|
19
|
+
var STATE_PASSED = Runnable.constants.STATE_PASSED;
|
|
20
|
+
var STATE_PENDING = Runnable.constants.STATE_PENDING;
|
|
17
21
|
var stackFilter = utils.stackTraceFilter();
|
|
18
22
|
var stringify = utils.stringify;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
createInvalidExceptionError,
|
|
26
|
+
createUnsupportedError,
|
|
27
|
+
createFatalError,
|
|
28
|
+
isMochaError,
|
|
29
|
+
constants: errorConstants
|
|
30
|
+
} = require('./errors');
|
|
22
31
|
|
|
23
32
|
/**
|
|
24
33
|
* Non-enumerable globals.
|
|
34
|
+
* @private
|
|
35
|
+
* @readonly
|
|
25
36
|
*/
|
|
26
|
-
|
|
27
37
|
var globals = [
|
|
28
38
|
'setTimeout',
|
|
29
39
|
'clearTimeout',
|
|
@@ -35,81 +45,259 @@ var globals = [
|
|
|
35
45
|
'clearImmediate'
|
|
36
46
|
];
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
48
|
+
var constants = utils.defineConstants(
|
|
49
|
+
/**
|
|
50
|
+
* {@link Runner}-related constants.
|
|
51
|
+
* @public
|
|
52
|
+
* @memberof Runner
|
|
53
|
+
* @readonly
|
|
54
|
+
* @alias constants
|
|
55
|
+
* @static
|
|
56
|
+
* @enum {string}
|
|
57
|
+
*/
|
|
58
|
+
{
|
|
59
|
+
/**
|
|
60
|
+
* Emitted when {@link Hook} execution begins
|
|
61
|
+
*/
|
|
62
|
+
EVENT_HOOK_BEGIN: 'hook',
|
|
63
|
+
/**
|
|
64
|
+
* Emitted when {@link Hook} execution ends
|
|
65
|
+
*/
|
|
66
|
+
EVENT_HOOK_END: 'hook end',
|
|
67
|
+
/**
|
|
68
|
+
* Emitted when Root {@link Suite} execution begins (all files have been parsed and hooks/tests are ready for execution)
|
|
69
|
+
*/
|
|
70
|
+
EVENT_RUN_BEGIN: 'start',
|
|
71
|
+
/**
|
|
72
|
+
* Emitted when Root {@link Suite} execution has been delayed via `delay` option
|
|
73
|
+
*/
|
|
74
|
+
EVENT_DELAY_BEGIN: 'waiting',
|
|
75
|
+
/**
|
|
76
|
+
* Emitted when delayed Root {@link Suite} execution is triggered by user via `global.run()`
|
|
77
|
+
*/
|
|
78
|
+
EVENT_DELAY_END: 'ready',
|
|
79
|
+
/**
|
|
80
|
+
* Emitted when Root {@link Suite} execution ends
|
|
81
|
+
*/
|
|
82
|
+
EVENT_RUN_END: 'end',
|
|
83
|
+
/**
|
|
84
|
+
* Emitted when {@link Suite} execution begins
|
|
85
|
+
*/
|
|
86
|
+
EVENT_SUITE_BEGIN: 'suite',
|
|
87
|
+
/**
|
|
88
|
+
* Emitted when {@link Suite} execution ends
|
|
89
|
+
*/
|
|
90
|
+
EVENT_SUITE_END: 'suite end',
|
|
91
|
+
/**
|
|
92
|
+
* Emitted when {@link Test} execution begins
|
|
93
|
+
*/
|
|
94
|
+
EVENT_TEST_BEGIN: 'test',
|
|
95
|
+
/**
|
|
96
|
+
* Emitted when {@link Test} execution ends
|
|
97
|
+
*/
|
|
98
|
+
EVENT_TEST_END: 'test end',
|
|
99
|
+
/**
|
|
100
|
+
* Emitted when {@link Test} execution fails
|
|
101
|
+
*/
|
|
102
|
+
EVENT_TEST_FAIL: 'fail',
|
|
103
|
+
/**
|
|
104
|
+
* Emitted when {@link Test} execution succeeds
|
|
105
|
+
*/
|
|
106
|
+
EVENT_TEST_PASS: 'pass',
|
|
107
|
+
/**
|
|
108
|
+
* Emitted when {@link Test} becomes pending
|
|
109
|
+
*/
|
|
110
|
+
EVENT_TEST_PENDING: 'pending',
|
|
111
|
+
/**
|
|
112
|
+
* Emitted when {@link Test} execution has failed, but will retry
|
|
113
|
+
*/
|
|
114
|
+
EVENT_TEST_RETRY: 'retry',
|
|
115
|
+
/**
|
|
116
|
+
* Initial state of Runner
|
|
117
|
+
*/
|
|
118
|
+
STATE_IDLE: 'idle',
|
|
119
|
+
/**
|
|
120
|
+
* State set to this value when the Runner has started running
|
|
121
|
+
*/
|
|
122
|
+
STATE_RUNNING: 'running',
|
|
123
|
+
/**
|
|
124
|
+
* State set to this value when the Runner has stopped
|
|
125
|
+
*/
|
|
126
|
+
STATE_STOPPED: 'stopped'
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
class Runner extends EventEmitter {
|
|
131
|
+
/**
|
|
132
|
+
* Initialize a `Runner` at the Root {@link Suite}, which represents a hierarchy of {@link Suite|Suites} and {@link Test|Tests}.
|
|
133
|
+
*
|
|
134
|
+
* @extends external:EventEmitter
|
|
135
|
+
* @public
|
|
136
|
+
* @class
|
|
137
|
+
* @param {Suite} suite - Root suite
|
|
138
|
+
* @param {Object} [opts] - Settings object
|
|
139
|
+
* @param {boolean} [opts.cleanReferencesAfterRun] - Whether to clean references to test fns and hooks when a suite is done.
|
|
140
|
+
* @param {boolean} [opts.delay] - Whether to delay execution of root suite until ready.
|
|
141
|
+
* @param {boolean} [opts.dryRun] - Whether to report tests without running them.
|
|
142
|
+
* @param {boolean} [opts.failZero] - Whether to fail test run if zero tests encountered.
|
|
143
|
+
*/
|
|
144
|
+
constructor(suite, opts = {}) {
|
|
145
|
+
super();
|
|
146
|
+
|
|
147
|
+
var self = this;
|
|
148
|
+
this._globals = [];
|
|
149
|
+
this._abort = false;
|
|
150
|
+
this.suite = suite;
|
|
151
|
+
this._opts = opts;
|
|
152
|
+
this.state = constants.STATE_IDLE;
|
|
153
|
+
this.total = suite.total();
|
|
154
|
+
this.failures = 0;
|
|
155
|
+
/**
|
|
156
|
+
* @type {Map<EventEmitter,Map<string,Set<EventListener>>>}
|
|
157
|
+
*/
|
|
158
|
+
this._eventListeners = new Map();
|
|
159
|
+
this.on(constants.EVENT_TEST_END, function (test) {
|
|
160
|
+
if (test.type === 'test' && test.retriedTest() && test.parent) {
|
|
161
|
+
var idx =
|
|
162
|
+
test.parent.tests && test.parent.tests.indexOf(test.retriedTest());
|
|
163
|
+
if (idx > -1) test.parent.tests[idx] = test;
|
|
164
|
+
}
|
|
165
|
+
self.checkGlobals(test);
|
|
166
|
+
});
|
|
167
|
+
this.on(constants.EVENT_HOOK_END, function (hook) {
|
|
168
|
+
self.checkGlobals(hook);
|
|
169
|
+
});
|
|
170
|
+
this._defaultGrep = /.*/;
|
|
171
|
+
this.grep(this._defaultGrep);
|
|
172
|
+
this.globals(this.globalProps());
|
|
173
|
+
|
|
174
|
+
this.uncaught = this._uncaught.bind(this);
|
|
175
|
+
this.unhandled = (reason, promise) => {
|
|
176
|
+
if (isMochaError(reason)) {
|
|
177
|
+
debug(
|
|
178
|
+
'trapped unhandled rejection coming out of Mocha; forwarding to uncaught handler:',
|
|
179
|
+
reason
|
|
180
|
+
);
|
|
181
|
+
this.uncaught(reason);
|
|
182
|
+
} else {
|
|
183
|
+
debug(
|
|
184
|
+
'trapped unhandled rejection from (probably) user code; re-emitting on process'
|
|
185
|
+
);
|
|
186
|
+
this._removeEventListener(
|
|
187
|
+
process,
|
|
188
|
+
'unhandledRejection',
|
|
189
|
+
this.unhandled
|
|
190
|
+
);
|
|
191
|
+
try {
|
|
192
|
+
process.emit('unhandledRejection', reason, promise);
|
|
193
|
+
} finally {
|
|
194
|
+
this._addEventListener(process, 'unhandledRejection', this.unhandled);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
84
199
|
}
|
|
85
200
|
|
|
86
201
|
/**
|
|
87
202
|
* Wrapper for setImmediate, process.nextTick, or browser polyfill.
|
|
88
203
|
*
|
|
89
204
|
* @param {Function} fn
|
|
90
|
-
* @
|
|
205
|
+
* @private
|
|
91
206
|
*/
|
|
92
207
|
Runner.immediately = global.setImmediate || process.nextTick;
|
|
93
208
|
|
|
94
209
|
/**
|
|
95
|
-
*
|
|
210
|
+
* Replacement for `target.on(eventName, listener)` that does bookkeeping to remove them when this runner instance is disposed.
|
|
211
|
+
* @param {EventEmitter} target - The `EventEmitter`
|
|
212
|
+
* @param {string} eventName - The event name
|
|
213
|
+
* @param {string} fn - Listener function
|
|
214
|
+
* @private
|
|
215
|
+
*/
|
|
216
|
+
Runner.prototype._addEventListener = function (target, eventName, listener) {
|
|
217
|
+
debug(
|
|
218
|
+
'_addEventListener(): adding for event %s; %d current listeners',
|
|
219
|
+
eventName,
|
|
220
|
+
target.listenerCount(eventName)
|
|
221
|
+
);
|
|
222
|
+
/* istanbul ignore next */
|
|
223
|
+
if (
|
|
224
|
+
this._eventListeners.has(target) &&
|
|
225
|
+
this._eventListeners.get(target).has(eventName) &&
|
|
226
|
+
this._eventListeners.get(target).get(eventName).has(listener)
|
|
227
|
+
) {
|
|
228
|
+
debug(
|
|
229
|
+
'warning: tried to attach duplicate event listener for %s',
|
|
230
|
+
eventName
|
|
231
|
+
);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
target.on(eventName, listener);
|
|
235
|
+
const targetListeners = this._eventListeners.has(target)
|
|
236
|
+
? this._eventListeners.get(target)
|
|
237
|
+
: new Map();
|
|
238
|
+
const targetEventListeners = targetListeners.has(eventName)
|
|
239
|
+
? targetListeners.get(eventName)
|
|
240
|
+
: new Set();
|
|
241
|
+
targetEventListeners.add(listener);
|
|
242
|
+
targetListeners.set(eventName, targetEventListeners);
|
|
243
|
+
this._eventListeners.set(target, targetListeners);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Replacement for `target.removeListener(eventName, listener)` that also updates the bookkeeping.
|
|
248
|
+
* @param {EventEmitter} target - The `EventEmitter`
|
|
249
|
+
* @param {string} eventName - The event name
|
|
250
|
+
* @param {function} listener - Listener function
|
|
251
|
+
* @private
|
|
96
252
|
*/
|
|
97
|
-
|
|
253
|
+
Runner.prototype._removeEventListener = function (target, eventName, listener) {
|
|
254
|
+
target.removeListener(eventName, listener);
|
|
255
|
+
|
|
256
|
+
if (this._eventListeners.has(target)) {
|
|
257
|
+
const targetListeners = this._eventListeners.get(target);
|
|
258
|
+
if (targetListeners.has(eventName)) {
|
|
259
|
+
const targetEventListeners = targetListeners.get(eventName);
|
|
260
|
+
targetEventListeners.delete(listener);
|
|
261
|
+
if (!targetEventListeners.size) {
|
|
262
|
+
targetListeners.delete(eventName);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (!targetListeners.size) {
|
|
266
|
+
this._eventListeners.delete(target);
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
debug('trying to remove listener for untracked object %s', target);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Removes all event handlers set during a run on this instance.
|
|
275
|
+
* Remark: this does _not_ clean/dispose the tests or suites themselves.
|
|
276
|
+
*/
|
|
277
|
+
Runner.prototype.dispose = function () {
|
|
278
|
+
this.removeAllListeners();
|
|
279
|
+
this._eventListeners.forEach((targetListeners, target) => {
|
|
280
|
+
targetListeners.forEach((targetEventListeners, eventName) => {
|
|
281
|
+
targetEventListeners.forEach(listener => {
|
|
282
|
+
target.removeListener(eventName, listener);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
this._eventListeners.clear();
|
|
287
|
+
};
|
|
98
288
|
|
|
99
289
|
/**
|
|
100
290
|
* Run tests with full titles matching `re`. Updates runner.total
|
|
101
291
|
* with number of tests matched.
|
|
102
292
|
*
|
|
103
|
-
* @
|
|
104
|
-
* @
|
|
105
|
-
* @return {Runner} for chaining
|
|
106
|
-
* @api public
|
|
293
|
+
* @public
|
|
294
|
+
* @memberof Runner
|
|
107
295
|
* @param {RegExp} re
|
|
108
296
|
* @param {boolean} invert
|
|
109
297
|
* @return {Runner} Runner instance.
|
|
110
298
|
*/
|
|
111
299
|
Runner.prototype.grep = function (re, invert) {
|
|
112
|
-
debug('grep %s', re);
|
|
300
|
+
debug('grep(): setting to %s', re);
|
|
113
301
|
this._grep = re;
|
|
114
302
|
this._invert = invert;
|
|
115
303
|
this.total = this.grepTotal(this.suite);
|
|
@@ -120,9 +308,8 @@ Runner.prototype.grep = function (re, invert) {
|
|
|
120
308
|
* Returns the number of tests matching the grep search for the
|
|
121
309
|
* given suite.
|
|
122
310
|
*
|
|
123
|
-
* @
|
|
124
|
-
* @
|
|
125
|
-
* @api public
|
|
311
|
+
* @memberof Runner
|
|
312
|
+
* @public
|
|
126
313
|
* @param {Suite} suite
|
|
127
314
|
* @return {number}
|
|
128
315
|
*/
|
|
@@ -147,14 +334,14 @@ Runner.prototype.grepTotal = function (suite) {
|
|
|
147
334
|
* Return a list of global properties.
|
|
148
335
|
*
|
|
149
336
|
* @return {Array}
|
|
150
|
-
* @
|
|
337
|
+
* @private
|
|
151
338
|
*/
|
|
152
339
|
Runner.prototype.globalProps = function () {
|
|
153
|
-
var props = keys(global);
|
|
340
|
+
var props = Object.keys(global);
|
|
154
341
|
|
|
155
342
|
// non-enumerables
|
|
156
343
|
for (var i = 0; i < globals.length; ++i) {
|
|
157
|
-
if (~indexOf(
|
|
344
|
+
if (~props.indexOf(globals[i])) {
|
|
158
345
|
continue;
|
|
159
346
|
}
|
|
160
347
|
props.push(globals[i]);
|
|
@@ -166,9 +353,8 @@ Runner.prototype.globalProps = function () {
|
|
|
166
353
|
/**
|
|
167
354
|
* Allow the given `arr` of globals.
|
|
168
355
|
*
|
|
169
|
-
* @
|
|
170
|
-
* @
|
|
171
|
-
* @api public
|
|
356
|
+
* @public
|
|
357
|
+
* @memberof Runner
|
|
172
358
|
* @param {Array} arr
|
|
173
359
|
* @return {Runner} Runner instance.
|
|
174
360
|
*/
|
|
@@ -176,7 +362,7 @@ Runner.prototype.globals = function (arr) {
|
|
|
176
362
|
if (!arguments.length) {
|
|
177
363
|
return this._globals;
|
|
178
364
|
}
|
|
179
|
-
debug('globals %
|
|
365
|
+
debug('globals(): setting to %O', arr);
|
|
180
366
|
this._globals = this._globals.concat(arr);
|
|
181
367
|
return this;
|
|
182
368
|
};
|
|
@@ -184,10 +370,10 @@ Runner.prototype.globals = function (arr) {
|
|
|
184
370
|
/**
|
|
185
371
|
* Check for global variable leaks.
|
|
186
372
|
*
|
|
187
|
-
* @
|
|
373
|
+
* @private
|
|
188
374
|
*/
|
|
189
375
|
Runner.prototype.checkGlobals = function (test) {
|
|
190
|
-
if (this.
|
|
376
|
+
if (!this.checkLeaks) {
|
|
191
377
|
return;
|
|
192
378
|
}
|
|
193
379
|
var ok = this._globals;
|
|
@@ -207,132 +393,177 @@ Runner.prototype.checkGlobals = function (test) {
|
|
|
207
393
|
leaks = filterLeaks(ok, globals);
|
|
208
394
|
this._globals = this._globals.concat(leaks);
|
|
209
395
|
|
|
210
|
-
if (leaks.length
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.fail(test, new Error('global leak detected: ' + leaks[0]));
|
|
396
|
+
if (leaks.length) {
|
|
397
|
+
var msg = `global leak(s) detected: ${leaks.map(e => `'${e}'`).join(', ')}`;
|
|
398
|
+
this.fail(test, new Error(msg));
|
|
214
399
|
}
|
|
215
400
|
};
|
|
216
401
|
|
|
217
402
|
/**
|
|
218
403
|
* Fail the given `test`.
|
|
219
404
|
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*/
|
|
224
|
-
Runner.prototype.fail = function (test, err) {
|
|
225
|
-
if (test.isPending()) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
++this.failures;
|
|
230
|
-
test.state = 'failed';
|
|
231
|
-
|
|
232
|
-
if (!(err instanceof Error || err && typeof err.message === 'string')) {
|
|
233
|
-
err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
err.stack = (this.fullStackTrace || !err.stack)
|
|
238
|
-
? err.stack
|
|
239
|
-
: stackFilter(err.stack);
|
|
240
|
-
} catch (ignored) {
|
|
241
|
-
// some environments do not take kindly to monkeying with the stack
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
this.emit('fail', test, err);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Fail the given `hook` with `err`.
|
|
249
|
-
*
|
|
250
|
-
* Hook failures work in the following pattern:
|
|
251
|
-
* - If bail, then exit
|
|
405
|
+
* If `test` is a hook, failures work in the following pattern:
|
|
406
|
+
* - If bail, run corresponding `after each` and `after` hooks,
|
|
407
|
+
* then exit
|
|
252
408
|
* - Failed `before` hook skips all tests in a suite and subsuites,
|
|
253
409
|
* but jumps to corresponding `after` hook
|
|
254
410
|
* - Failed `before each` hook skips remaining tests in a
|
|
255
411
|
* suite and jumps to corresponding `after each` hook,
|
|
256
412
|
* which is run only once
|
|
257
|
-
* - Failed `after` hook does not alter
|
|
258
|
-
* execution order
|
|
413
|
+
* - Failed `after` hook does not alter execution order
|
|
259
414
|
* - Failed `after each` hook skips remaining tests in a
|
|
260
415
|
* suite and subsuites, but executes other `after each`
|
|
261
416
|
* hooks
|
|
262
417
|
*
|
|
263
|
-
* @
|
|
264
|
-
* @param {
|
|
418
|
+
* @private
|
|
419
|
+
* @param {Runnable} test
|
|
265
420
|
* @param {Error} err
|
|
421
|
+
* @param {boolean} [force=false] - Whether to fail a pending test.
|
|
266
422
|
*/
|
|
267
|
-
Runner.prototype.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
423
|
+
Runner.prototype.fail = function (test, err, force) {
|
|
424
|
+
force = force === true;
|
|
425
|
+
if (test.isPending() && !force) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (this.state === constants.STATE_STOPPED) {
|
|
429
|
+
if (err.code === errorConstants.MULTIPLE_DONE) {
|
|
430
|
+
throw err;
|
|
431
|
+
}
|
|
432
|
+
throw createFatalError(
|
|
433
|
+
'Test failed after root suite execution completed!',
|
|
434
|
+
err
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
++this.failures;
|
|
439
|
+
debug('total number of failures: %d', this.failures);
|
|
440
|
+
test.state = STATE_FAILED;
|
|
441
|
+
|
|
442
|
+
if (!isError(err)) {
|
|
443
|
+
err = thrown2Error(err);
|
|
271
444
|
}
|
|
272
445
|
|
|
273
|
-
|
|
274
|
-
if (this.
|
|
275
|
-
|
|
446
|
+
// Filter the stack traces
|
|
447
|
+
if (!this.fullStackTrace) {
|
|
448
|
+
const alreadyFiltered = new Set();
|
|
449
|
+
let currentErr = err;
|
|
450
|
+
|
|
451
|
+
while (currentErr && currentErr.stack && !alreadyFiltered.has(currentErr)) {
|
|
452
|
+
alreadyFiltered.add(currentErr);
|
|
453
|
+
|
|
454
|
+
try {
|
|
455
|
+
currentErr.stack = stackFilter(currentErr.stack);
|
|
456
|
+
} catch (ignore) {
|
|
457
|
+
// some environments do not take kindly to monkeying with the stack
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
currentErr = currentErr.cause;
|
|
461
|
+
}
|
|
276
462
|
}
|
|
463
|
+
|
|
464
|
+
this.emit(constants.EVENT_TEST_FAIL, test, err);
|
|
277
465
|
};
|
|
278
466
|
|
|
279
467
|
/**
|
|
280
468
|
* Run hook `name` callbacks and then invoke `fn()`.
|
|
281
469
|
*
|
|
282
|
-
* @
|
|
470
|
+
* @private
|
|
283
471
|
* @param {string} name
|
|
284
472
|
* @param {Function} fn
|
|
285
473
|
*/
|
|
286
474
|
|
|
287
475
|
Runner.prototype.hook = function (name, fn) {
|
|
476
|
+
if (this._opts.dryRun) return fn();
|
|
477
|
+
|
|
288
478
|
var suite = this.suite;
|
|
289
|
-
var hooks = suite
|
|
479
|
+
var hooks = suite.getHooks(name);
|
|
290
480
|
var self = this;
|
|
291
481
|
|
|
292
|
-
function next
|
|
482
|
+
function next(i) {
|
|
293
483
|
var hook = hooks[i];
|
|
294
484
|
if (!hook) {
|
|
295
485
|
return fn();
|
|
296
486
|
}
|
|
297
487
|
self.currentRunnable = hook;
|
|
298
488
|
|
|
299
|
-
|
|
489
|
+
if (name === HOOK_TYPE_BEFORE_ALL) {
|
|
490
|
+
hook.ctx.currentTest = hook.parent.tests[0];
|
|
491
|
+
} else if (name === HOOK_TYPE_AFTER_ALL) {
|
|
492
|
+
hook.ctx.currentTest = hook.parent.tests[hook.parent.tests.length - 1];
|
|
493
|
+
} else {
|
|
494
|
+
hook.ctx.currentTest = self.test;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
setHookTitle(hook);
|
|
300
498
|
|
|
301
|
-
self.
|
|
499
|
+
hook.allowUncaught = self.allowUncaught;
|
|
500
|
+
|
|
501
|
+
self.emit(constants.EVENT_HOOK_BEGIN, hook);
|
|
302
502
|
|
|
303
503
|
if (!hook.listeners('error').length) {
|
|
304
|
-
|
|
305
|
-
self.
|
|
504
|
+
self._addEventListener(hook, 'error', function (err) {
|
|
505
|
+
self.fail(hook, err);
|
|
306
506
|
});
|
|
307
507
|
}
|
|
308
508
|
|
|
309
|
-
hook.run(function (err) {
|
|
509
|
+
hook.run(function cbHookRun(err) {
|
|
310
510
|
var testError = hook.error();
|
|
311
511
|
if (testError) {
|
|
312
512
|
self.fail(self.test, testError);
|
|
313
513
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
514
|
+
// conditional skip
|
|
515
|
+
if (hook.pending) {
|
|
516
|
+
if (name === HOOK_TYPE_AFTER_EACH) {
|
|
517
|
+
// TODO define and implement use case
|
|
518
|
+
if (self.test) {
|
|
317
519
|
self.test.pending = true;
|
|
318
|
-
} else {
|
|
319
|
-
utils.forEach(suite.tests, function (test) {
|
|
320
|
-
test.pending = true;
|
|
321
|
-
});
|
|
322
|
-
// a pending hook won't be executed twice.
|
|
323
|
-
hook.pending = true;
|
|
324
520
|
}
|
|
521
|
+
} else if (name === HOOK_TYPE_BEFORE_EACH) {
|
|
522
|
+
if (self.test) {
|
|
523
|
+
self.test.pending = true;
|
|
524
|
+
}
|
|
525
|
+
self.emit(constants.EVENT_HOOK_END, hook);
|
|
526
|
+
hook.pending = false; // activates hook for next test
|
|
527
|
+
return fn(new Error('abort hookDown'));
|
|
528
|
+
} else if (name === HOOK_TYPE_BEFORE_ALL) {
|
|
529
|
+
suite.tests.forEach(function (test) {
|
|
530
|
+
test.pending = true;
|
|
531
|
+
});
|
|
532
|
+
suite.suites.forEach(function (suite) {
|
|
533
|
+
suite.pending = true;
|
|
534
|
+
});
|
|
535
|
+
hooks = [];
|
|
325
536
|
} else {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return fn(
|
|
537
|
+
hook.pending = false;
|
|
538
|
+
var errForbid = createUnsupportedError('`this.skip` forbidden');
|
|
539
|
+
self.fail(hook, errForbid);
|
|
540
|
+
return fn(errForbid);
|
|
330
541
|
}
|
|
542
|
+
} else if (err) {
|
|
543
|
+
self.fail(hook, err);
|
|
544
|
+
// stop executing hooks, notify callee of hook err
|
|
545
|
+
return fn(err);
|
|
331
546
|
}
|
|
332
|
-
self.emit(
|
|
547
|
+
self.emit(constants.EVENT_HOOK_END, hook);
|
|
333
548
|
delete hook.ctx.currentTest;
|
|
549
|
+
setHookTitle(hook);
|
|
334
550
|
next(++i);
|
|
335
551
|
});
|
|
552
|
+
|
|
553
|
+
function setHookTitle(hook) {
|
|
554
|
+
hook.originalTitle = hook.originalTitle || hook.title;
|
|
555
|
+
if (hook.ctx && hook.ctx.currentTest) {
|
|
556
|
+
hook.title = `${hook.originalTitle} for "${hook.ctx.currentTest.title}"`;
|
|
557
|
+
} else {
|
|
558
|
+
var parentTitle;
|
|
559
|
+
if (hook.parent.title) {
|
|
560
|
+
parentTitle = hook.parent.title;
|
|
561
|
+
} else {
|
|
562
|
+
parentTitle = hook.parent.root ? '{root}' : '';
|
|
563
|
+
}
|
|
564
|
+
hook.title = `${hook.originalTitle} in "${parentTitle}"`;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
336
567
|
}
|
|
337
568
|
|
|
338
569
|
Runner.immediately(function () {
|
|
@@ -344,7 +575,7 @@ Runner.prototype.hook = function (name, fn) {
|
|
|
344
575
|
* Run hook `name` for the given array of `suites`
|
|
345
576
|
* in order, and callback `fn(err, errSuite)`.
|
|
346
577
|
*
|
|
347
|
-
* @
|
|
578
|
+
* @private
|
|
348
579
|
* @param {string} name
|
|
349
580
|
* @param {Array} suites
|
|
350
581
|
* @param {Function} fn
|
|
@@ -353,7 +584,7 @@ Runner.prototype.hooks = function (name, suites, fn) {
|
|
|
353
584
|
var self = this;
|
|
354
585
|
var orig = this.suite;
|
|
355
586
|
|
|
356
|
-
function next
|
|
587
|
+
function next(suite) {
|
|
357
588
|
self.suite = suite;
|
|
358
589
|
|
|
359
590
|
if (!suite) {
|
|
@@ -376,11 +607,11 @@ Runner.prototype.hooks = function (name, suites, fn) {
|
|
|
376
607
|
};
|
|
377
608
|
|
|
378
609
|
/**
|
|
379
|
-
* Run hooks from
|
|
610
|
+
* Run 'afterEach' hooks from bottom up.
|
|
380
611
|
*
|
|
381
612
|
* @param {String} name
|
|
382
613
|
* @param {Function} fn
|
|
383
|
-
* @
|
|
614
|
+
* @private
|
|
384
615
|
*/
|
|
385
616
|
Runner.prototype.hookUp = function (name, fn) {
|
|
386
617
|
var suites = [this.suite].concat(this.parents()).reverse();
|
|
@@ -388,11 +619,11 @@ Runner.prototype.hookUp = function (name, fn) {
|
|
|
388
619
|
};
|
|
389
620
|
|
|
390
621
|
/**
|
|
391
|
-
* Run hooks from
|
|
622
|
+
* Run 'beforeEach' hooks from top level down.
|
|
392
623
|
*
|
|
393
624
|
* @param {String} name
|
|
394
625
|
* @param {Function} fn
|
|
395
|
-
* @
|
|
626
|
+
* @private
|
|
396
627
|
*/
|
|
397
628
|
Runner.prototype.hookDown = function (name, fn) {
|
|
398
629
|
var suites = [this.suite].concat(this.parents());
|
|
@@ -404,7 +635,7 @@ Runner.prototype.hookDown = function (name, fn) {
|
|
|
404
635
|
* closest to furthest.
|
|
405
636
|
*
|
|
406
637
|
* @return {Array}
|
|
407
|
-
* @
|
|
638
|
+
* @private
|
|
408
639
|
*/
|
|
409
640
|
Runner.prototype.parents = function () {
|
|
410
641
|
var suite = this.suite;
|
|
@@ -420,19 +651,22 @@ Runner.prototype.parents = function () {
|
|
|
420
651
|
* Run the current test and callback `fn(err)`.
|
|
421
652
|
*
|
|
422
653
|
* @param {Function} fn
|
|
423
|
-
* @
|
|
654
|
+
* @private
|
|
424
655
|
*/
|
|
425
656
|
Runner.prototype.runTest = function (fn) {
|
|
657
|
+
if (this._opts.dryRun) return Runner.immediately(fn);
|
|
658
|
+
|
|
426
659
|
var self = this;
|
|
427
660
|
var test = this.test;
|
|
428
661
|
|
|
429
662
|
if (!test) {
|
|
430
663
|
return;
|
|
431
664
|
}
|
|
665
|
+
|
|
432
666
|
if (this.asyncOnly) {
|
|
433
667
|
test.asyncOnly = true;
|
|
434
668
|
}
|
|
435
|
-
|
|
669
|
+
this._addEventListener(test, 'error', function (err) {
|
|
436
670
|
self.fail(test, err);
|
|
437
671
|
});
|
|
438
672
|
if (this.allowUncaught) {
|
|
@@ -449,7 +683,7 @@ Runner.prototype.runTest = function (fn) {
|
|
|
449
683
|
/**
|
|
450
684
|
* Run tests in the given `suite` and invoke the callback `fn()` when complete.
|
|
451
685
|
*
|
|
452
|
-
* @
|
|
686
|
+
* @private
|
|
453
687
|
* @param {Suite} suite
|
|
454
688
|
* @param {Function} fn
|
|
455
689
|
*/
|
|
@@ -458,7 +692,7 @@ Runner.prototype.runTests = function (suite, fn) {
|
|
|
458
692
|
var tests = suite.tests.slice();
|
|
459
693
|
var test;
|
|
460
694
|
|
|
461
|
-
function hookErr
|
|
695
|
+
function hookErr(_, errSuite, after) {
|
|
462
696
|
// before/after Each hook for errSuite failed:
|
|
463
697
|
var orig = self.suite;
|
|
464
698
|
|
|
@@ -467,8 +701,7 @@ Runner.prototype.runTests = function (suite, fn) {
|
|
|
467
701
|
self.suite = after ? errSuite.parent : errSuite;
|
|
468
702
|
|
|
469
703
|
if (self.suite) {
|
|
470
|
-
|
|
471
|
-
self.hookUp('afterEach', function (err2, errSuite2) {
|
|
704
|
+
self.hookUp(HOOK_TYPE_AFTER_EACH, function (err2, errSuite2) {
|
|
472
705
|
self.suite = orig;
|
|
473
706
|
// some hooks may fail even now
|
|
474
707
|
if (err2) {
|
|
@@ -484,10 +717,10 @@ Runner.prototype.runTests = function (suite, fn) {
|
|
|
484
717
|
}
|
|
485
718
|
}
|
|
486
719
|
|
|
487
|
-
function next
|
|
720
|
+
function next(err, errSuite) {
|
|
488
721
|
// if we bail after first err
|
|
489
722
|
if (self.failures && suite._bail) {
|
|
490
|
-
|
|
723
|
+
tests = [];
|
|
491
724
|
}
|
|
492
725
|
|
|
493
726
|
if (self._abort) {
|
|
@@ -528,19 +761,37 @@ Runner.prototype.runTests = function (suite, fn) {
|
|
|
528
761
|
return;
|
|
529
762
|
}
|
|
530
763
|
|
|
764
|
+
// static skip, no hooks are executed
|
|
531
765
|
if (test.isPending()) {
|
|
532
|
-
self.
|
|
533
|
-
|
|
766
|
+
if (self.forbidPending) {
|
|
767
|
+
self.fail(test, new Error('Pending test forbidden'), true);
|
|
768
|
+
} else {
|
|
769
|
+
test.state = STATE_PENDING;
|
|
770
|
+
self.emit(constants.EVENT_TEST_PENDING, test);
|
|
771
|
+
}
|
|
772
|
+
self.emit(constants.EVENT_TEST_END, test);
|
|
534
773
|
return next();
|
|
535
774
|
}
|
|
536
775
|
|
|
537
776
|
// execute test and hook(s)
|
|
538
|
-
self.emit(
|
|
539
|
-
self.hookDown(
|
|
777
|
+
self.emit(constants.EVENT_TEST_BEGIN, (self.test = test));
|
|
778
|
+
self.hookDown(HOOK_TYPE_BEFORE_EACH, function (err, errSuite) {
|
|
779
|
+
// conditional skip within beforeEach
|
|
540
780
|
if (test.isPending()) {
|
|
541
|
-
self.
|
|
542
|
-
|
|
543
|
-
|
|
781
|
+
if (self.forbidPending) {
|
|
782
|
+
self.fail(test, new Error('Pending test forbidden'), true);
|
|
783
|
+
} else {
|
|
784
|
+
test.state = STATE_PENDING;
|
|
785
|
+
self.emit(constants.EVENT_TEST_PENDING, test);
|
|
786
|
+
}
|
|
787
|
+
self.emit(constants.EVENT_TEST_END, test);
|
|
788
|
+
// skip inner afterEach hooks below errSuite level
|
|
789
|
+
var origSuite = self.suite;
|
|
790
|
+
self.suite = errSuite || self.suite;
|
|
791
|
+
return self.hookUp(HOOK_TYPE_AFTER_EACH, function (e, eSuite) {
|
|
792
|
+
self.suite = origSuite;
|
|
793
|
+
next(e, eSuite);
|
|
794
|
+
});
|
|
544
795
|
}
|
|
545
796
|
if (err) {
|
|
546
797
|
return hookErr(err, errSuite, false);
|
|
@@ -548,35 +799,39 @@ Runner.prototype.runTests = function (suite, fn) {
|
|
|
548
799
|
self.currentRunnable = self.test;
|
|
549
800
|
self.runTest(function (err) {
|
|
550
801
|
test = self.test;
|
|
551
|
-
|
|
802
|
+
// conditional skip within it
|
|
803
|
+
if (test.pending) {
|
|
804
|
+
if (self.forbidPending) {
|
|
805
|
+
self.fail(test, new Error('Pending test forbidden'), true);
|
|
806
|
+
} else {
|
|
807
|
+
test.state = STATE_PENDING;
|
|
808
|
+
self.emit(constants.EVENT_TEST_PENDING, test);
|
|
809
|
+
}
|
|
810
|
+
self.emit(constants.EVENT_TEST_END, test);
|
|
811
|
+
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
|
|
812
|
+
} else if (err) {
|
|
552
813
|
var retry = test.currentRetry();
|
|
553
|
-
if (
|
|
554
|
-
test.pending = true;
|
|
555
|
-
self.emit('pending', test);
|
|
556
|
-
} else if (retry < test.retries()) {
|
|
814
|
+
if (retry < test.retries()) {
|
|
557
815
|
var clonedTest = test.clone();
|
|
558
816
|
clonedTest.currentRetry(retry + 1);
|
|
559
817
|
tests.unshift(clonedTest);
|
|
560
818
|
|
|
819
|
+
self.emit(constants.EVENT_TEST_RETRY, test, err);
|
|
820
|
+
|
|
561
821
|
// Early return + hook trigger so that it doesn't
|
|
562
822
|
// increment the count wrong
|
|
563
|
-
return self.hookUp(
|
|
823
|
+
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
|
|
564
824
|
} else {
|
|
565
825
|
self.fail(test, err);
|
|
566
826
|
}
|
|
567
|
-
self.emit(
|
|
568
|
-
|
|
569
|
-
if (err instanceof Pending) {
|
|
570
|
-
return next();
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
return self.hookUp('afterEach', next);
|
|
827
|
+
self.emit(constants.EVENT_TEST_END, test);
|
|
828
|
+
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
|
|
574
829
|
}
|
|
575
830
|
|
|
576
|
-
test.state =
|
|
577
|
-
self.emit(
|
|
578
|
-
self.emit(
|
|
579
|
-
self.hookUp(
|
|
831
|
+
test.state = STATE_PASSED;
|
|
832
|
+
self.emit(constants.EVENT_TEST_PASS, test);
|
|
833
|
+
self.emit(constants.EVENT_TEST_END, test);
|
|
834
|
+
self.hookUp(HOOK_TYPE_AFTER_EACH, next);
|
|
580
835
|
});
|
|
581
836
|
});
|
|
582
837
|
}
|
|
@@ -589,7 +844,7 @@ Runner.prototype.runTests = function (suite, fn) {
|
|
|
589
844
|
/**
|
|
590
845
|
* Run the given `suite` and invoke the callback `fn()` when complete.
|
|
591
846
|
*
|
|
592
|
-
* @
|
|
847
|
+
* @private
|
|
593
848
|
* @param {Suite} suite
|
|
594
849
|
* @param {Function} fn
|
|
595
850
|
*/
|
|
@@ -597,17 +852,17 @@ Runner.prototype.runSuite = function (suite, fn) {
|
|
|
597
852
|
var i = 0;
|
|
598
853
|
var self = this;
|
|
599
854
|
var total = this.grepTotal(suite);
|
|
600
|
-
var afterAllHookCalled = false;
|
|
601
855
|
|
|
602
|
-
debug('
|
|
856
|
+
debug('runSuite(): running %s', suite.fullTitle());
|
|
603
857
|
|
|
604
858
|
if (!total || (self.failures && suite._bail)) {
|
|
859
|
+
debug('runSuite(): bailing');
|
|
605
860
|
return fn();
|
|
606
861
|
}
|
|
607
862
|
|
|
608
|
-
this.emit(
|
|
863
|
+
this.emit(constants.EVENT_SUITE_BEGIN, (this.suite = suite));
|
|
609
864
|
|
|
610
|
-
function next
|
|
865
|
+
function next(errSuite) {
|
|
611
866
|
if (errSuite) {
|
|
612
867
|
// current suite failed on a hook from errSuite
|
|
613
868
|
if (errSuite === suite) {
|
|
@@ -641,30 +896,22 @@ Runner.prototype.runSuite = function (suite, fn) {
|
|
|
641
896
|
}
|
|
642
897
|
}
|
|
643
898
|
|
|
644
|
-
function done
|
|
899
|
+
function done(errSuite) {
|
|
645
900
|
self.suite = suite;
|
|
646
901
|
self.nextSuite = next;
|
|
647
902
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
} else {
|
|
651
|
-
// mark that the afterAll block has been called once
|
|
652
|
-
// and so can be skipped if there is an error in it.
|
|
653
|
-
afterAllHookCalled = true;
|
|
654
|
-
|
|
655
|
-
// remove reference to test
|
|
656
|
-
delete self.test;
|
|
903
|
+
// remove reference to test
|
|
904
|
+
delete self.test;
|
|
657
905
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
}
|
|
906
|
+
self.hook(HOOK_TYPE_AFTER_ALL, function () {
|
|
907
|
+
self.emit(constants.EVENT_SUITE_END, suite);
|
|
908
|
+
fn(errSuite);
|
|
909
|
+
});
|
|
663
910
|
}
|
|
664
911
|
|
|
665
912
|
this.nextSuite = next;
|
|
666
913
|
|
|
667
|
-
this.hook(
|
|
914
|
+
this.hook(HOOK_TYPE_BEFORE_ALL, function (err) {
|
|
668
915
|
if (err) {
|
|
669
916
|
return done();
|
|
670
917
|
}
|
|
@@ -673,19 +920,60 @@ Runner.prototype.runSuite = function (suite, fn) {
|
|
|
673
920
|
};
|
|
674
921
|
|
|
675
922
|
/**
|
|
676
|
-
* Handle uncaught exceptions.
|
|
923
|
+
* Handle uncaught exceptions within runner.
|
|
677
924
|
*
|
|
678
|
-
*
|
|
679
|
-
*
|
|
925
|
+
* This function is bound to the instance as `Runner#uncaught` at instantiation
|
|
926
|
+
* time. It's intended to be listening on the `Process.uncaughtException` event.
|
|
927
|
+
* In order to not leak EE listeners, we need to ensure no more than a single
|
|
928
|
+
* `uncaughtException` listener exists per `Runner`. The only way to do
|
|
929
|
+
* this--because this function needs the context (and we don't have lambdas)--is
|
|
930
|
+
* to use `Function.prototype.bind`. We need strict equality to unregister and
|
|
931
|
+
* _only_ unregister the _one_ listener we set from the
|
|
932
|
+
* `Process.uncaughtException` event; would be poor form to just remove
|
|
933
|
+
* everything. See {@link Runner#run} for where the event listener is registered
|
|
934
|
+
* and unregistered.
|
|
935
|
+
* @param {Error} err - Some uncaught error
|
|
936
|
+
* @private
|
|
680
937
|
*/
|
|
681
|
-
Runner.prototype.
|
|
938
|
+
Runner.prototype._uncaught = function (err) {
|
|
939
|
+
// this is defensive to prevent future developers from mis-calling this function.
|
|
940
|
+
// it's more likely that it'd be called with the incorrect context--say, the global
|
|
941
|
+
// `process` object--than it would to be called with a context that is not a "subclass"
|
|
942
|
+
// of `Runner`.
|
|
943
|
+
if (!(this instanceof Runner)) {
|
|
944
|
+
throw createFatalError(
|
|
945
|
+
'Runner#uncaught() called with invalid context',
|
|
946
|
+
this
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
if (err instanceof Pending) {
|
|
950
|
+
debug('uncaught(): caught a Pending');
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
// browser does not exit script when throwing in global.onerror()
|
|
954
|
+
if (this.allowUncaught && !utils.isBrowser()) {
|
|
955
|
+
debug('uncaught(): bubbling exception due to --allow-uncaught');
|
|
956
|
+
throw err;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
if (this.state === constants.STATE_STOPPED) {
|
|
960
|
+
debug('uncaught(): throwing after run has completed!');
|
|
961
|
+
throw err;
|
|
962
|
+
}
|
|
963
|
+
|
|
682
964
|
if (err) {
|
|
683
|
-
debug('uncaught exception %
|
|
684
|
-
return this;
|
|
685
|
-
}.call(err)) ? (err.message || err) : err);
|
|
965
|
+
debug('uncaught(): got truthy exception %O', err);
|
|
686
966
|
} else {
|
|
687
|
-
debug('uncaught undefined exception');
|
|
688
|
-
err =
|
|
967
|
+
debug('uncaught(): undefined/falsy exception');
|
|
968
|
+
err = createInvalidExceptionError(
|
|
969
|
+
'Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger',
|
|
970
|
+
err
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (!isError(err)) {
|
|
975
|
+
err = thrown2Error(err);
|
|
976
|
+
debug('uncaught(): converted "error" %o to Error', err);
|
|
689
977
|
}
|
|
690
978
|
err.uncaught = true;
|
|
691
979
|
|
|
@@ -693,15 +981,18 @@ Runner.prototype.uncaught = function (err) {
|
|
|
693
981
|
|
|
694
982
|
if (!runnable) {
|
|
695
983
|
runnable = new Runnable('Uncaught error outside test suite');
|
|
984
|
+
debug('uncaught(): no current Runnable; created a phony one');
|
|
696
985
|
runnable.parent = this.suite;
|
|
697
986
|
|
|
698
|
-
if (this.
|
|
987
|
+
if (this.state === constants.STATE_RUNNING) {
|
|
988
|
+
debug('uncaught(): failing gracefully');
|
|
699
989
|
this.fail(runnable, err);
|
|
700
990
|
} else {
|
|
701
991
|
// Can't recover from this failure
|
|
702
|
-
|
|
992
|
+
debug('uncaught(): test run has not yet started; unrecoverable');
|
|
993
|
+
this.emit(constants.EVENT_RUN_BEGIN);
|
|
703
994
|
this.fail(runnable, err);
|
|
704
|
-
this.emit(
|
|
995
|
+
this.emit(constants.EVENT_RUN_END);
|
|
705
996
|
}
|
|
706
997
|
|
|
707
998
|
return;
|
|
@@ -709,208 +1000,201 @@ Runner.prototype.uncaught = function (err) {
|
|
|
709
1000
|
|
|
710
1001
|
runnable.clearTimeout();
|
|
711
1002
|
|
|
712
|
-
|
|
713
|
-
|
|
1003
|
+
if (runnable.isFailed()) {
|
|
1004
|
+
debug('uncaught(): Runnable has already failed');
|
|
1005
|
+
// Ignore error if already failed
|
|
714
1006
|
return;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (runnable.type === 'test') {
|
|
720
|
-
this.emit('test end', runnable);
|
|
721
|
-
this.hookUp('afterEach', this.next);
|
|
1007
|
+
} else if (runnable.isPending()) {
|
|
1008
|
+
debug('uncaught(): pending Runnable wound up failing!');
|
|
1009
|
+
// report 'pending test' retrospectively as failed
|
|
1010
|
+
this.fail(runnable, err, true);
|
|
722
1011
|
return;
|
|
723
1012
|
}
|
|
724
1013
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
return this.hookErr(err, errSuite, false);
|
|
735
|
-
}
|
|
736
|
-
// if hook failure is in after or before blocks
|
|
737
|
-
return this.nextSuite(errSuite);
|
|
1014
|
+
// we cannot recover gracefully if a Runnable has already passed
|
|
1015
|
+
// then fails asynchronously
|
|
1016
|
+
if (runnable.isPassed()) {
|
|
1017
|
+
debug('uncaught(): Runnable has already passed; bailing gracefully');
|
|
1018
|
+
this.fail(runnable, err);
|
|
1019
|
+
this.abort();
|
|
1020
|
+
} else {
|
|
1021
|
+
debug('uncaught(): forcing Runnable to complete with Error');
|
|
1022
|
+
return runnable.callback(err);
|
|
738
1023
|
}
|
|
739
|
-
|
|
740
|
-
// bail
|
|
741
|
-
this.emit('end');
|
|
742
1024
|
};
|
|
743
1025
|
|
|
744
|
-
/**
|
|
745
|
-
* Cleans up the references to all the deferred functions
|
|
746
|
-
* (before/after/beforeEach/afterEach) and tests of a Suite.
|
|
747
|
-
* These must be deleted otherwise a memory leak can happen,
|
|
748
|
-
* as those functions may reference variables from closures,
|
|
749
|
-
* thus those variables can never be garbage collected as long
|
|
750
|
-
* as the deferred functions exist.
|
|
751
|
-
*
|
|
752
|
-
* @param {Suite} suite
|
|
753
|
-
*/
|
|
754
|
-
function cleanSuiteReferences (suite) {
|
|
755
|
-
function cleanArrReferences (arr) {
|
|
756
|
-
for (var i = 0; i < arr.length; i++) {
|
|
757
|
-
delete arr[i].fn;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (isArray(suite._beforeAll)) {
|
|
762
|
-
cleanArrReferences(suite._beforeAll);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
if (isArray(suite._beforeEach)) {
|
|
766
|
-
cleanArrReferences(suite._beforeEach);
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
if (isArray(suite._afterAll)) {
|
|
770
|
-
cleanArrReferences(suite._afterAll);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
if (isArray(suite._afterEach)) {
|
|
774
|
-
cleanArrReferences(suite._afterEach);
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
for (var i = 0; i < suite.tests.length; i++) {
|
|
778
|
-
delete suite.tests[i].fn;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
|
|
782
1026
|
/**
|
|
783
1027
|
* Run the root suite and invoke `fn(failures)`
|
|
784
1028
|
* on completion.
|
|
785
1029
|
*
|
|
786
|
-
* @
|
|
787
|
-
* @
|
|
788
|
-
* @
|
|
789
|
-
* @param {
|
|
790
|
-
* @
|
|
1030
|
+
* @public
|
|
1031
|
+
* @memberof Runner
|
|
1032
|
+
* @param {Function} fn - Callback when finished
|
|
1033
|
+
* @param {Object} [opts] - For subclasses
|
|
1034
|
+
* @param {string[]} opts.files - Files to run
|
|
1035
|
+
* @param {Options} opts.options - command-line options
|
|
1036
|
+
* @returns {Runner} Runner instance.
|
|
791
1037
|
*/
|
|
792
|
-
Runner.prototype.run = function (fn) {
|
|
793
|
-
var self = this;
|
|
1038
|
+
Runner.prototype.run = function (fn, opts = {}) {
|
|
794
1039
|
var rootSuite = this.suite;
|
|
1040
|
+
var options = opts.options || {};
|
|
795
1041
|
|
|
796
|
-
|
|
797
|
-
if (this.hasOnly) {
|
|
798
|
-
filterOnly(rootSuite);
|
|
799
|
-
}
|
|
800
|
-
|
|
1042
|
+
debug('run(): got options: %O', options);
|
|
801
1043
|
fn = fn || function () {};
|
|
802
1044
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
}
|
|
1045
|
+
const end = () => {
|
|
1046
|
+
if (!this.total && this._opts.failZero) this.failures = 1;
|
|
806
1047
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
self.runSuite(rootSuite, function () {
|
|
811
|
-
debug('finished running');
|
|
812
|
-
self.emit('end');
|
|
813
|
-
});
|
|
814
|
-
}
|
|
1048
|
+
debug('run(): root suite completed; emitting %s', constants.EVENT_RUN_END);
|
|
1049
|
+
this.emit(constants.EVENT_RUN_END);
|
|
1050
|
+
};
|
|
815
1051
|
|
|
816
|
-
|
|
1052
|
+
const begin = () => {
|
|
1053
|
+
debug('run(): emitting %s', constants.EVENT_RUN_BEGIN);
|
|
1054
|
+
this.emit(constants.EVENT_RUN_BEGIN);
|
|
1055
|
+
debug('run(): emitted %s', constants.EVENT_RUN_BEGIN);
|
|
817
1056
|
|
|
818
|
-
|
|
819
|
-
|
|
1057
|
+
this.runSuite(rootSuite, end);
|
|
1058
|
+
};
|
|
820
1059
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1060
|
+
const prepare = () => {
|
|
1061
|
+
debug('run(): starting');
|
|
1062
|
+
// If there is an `only` filter
|
|
1063
|
+
if (rootSuite.hasOnly()) {
|
|
1064
|
+
rootSuite.filterOnly();
|
|
1065
|
+
debug('run(): filtered exclusive Runnables');
|
|
825
1066
|
}
|
|
826
|
-
|
|
827
|
-
|
|
1067
|
+
this.state = constants.STATE_RUNNING;
|
|
1068
|
+
if (this._opts.delay) {
|
|
1069
|
+
this.emit(constants.EVENT_DELAY_END);
|
|
1070
|
+
debug('run(): "delay" ended');
|
|
828
1071
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1072
|
+
|
|
1073
|
+
return begin();
|
|
1074
|
+
};
|
|
1075
|
+
|
|
1076
|
+
// references cleanup to avoid memory leaks
|
|
1077
|
+
if (this._opts.cleanReferencesAfterRun) {
|
|
1078
|
+
this.on(constants.EVENT_SUITE_END, suite => {
|
|
1079
|
+
suite.cleanReferences();
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// callback
|
|
1084
|
+
this.on(constants.EVENT_RUN_END, function () {
|
|
1085
|
+
this.state = constants.STATE_STOPPED;
|
|
1086
|
+
debug('run(): emitted %s', constants.EVENT_RUN_END);
|
|
1087
|
+
fn(this.failures);
|
|
832
1088
|
});
|
|
833
1089
|
|
|
834
|
-
|
|
835
|
-
|
|
1090
|
+
this._removeEventListener(process, 'uncaughtException', this.uncaught);
|
|
1091
|
+
this._removeEventListener(process, 'unhandledRejection', this.unhandled);
|
|
1092
|
+
this._addEventListener(process, 'uncaughtException', this.uncaught);
|
|
1093
|
+
this._addEventListener(process, 'unhandledRejection', this.unhandled);
|
|
836
1094
|
|
|
837
|
-
if (this.
|
|
1095
|
+
if (this._opts.delay) {
|
|
838
1096
|
// for reporters, I guess.
|
|
839
1097
|
// might be nice to debounce some dots while we wait.
|
|
840
|
-
this.emit(
|
|
841
|
-
rootSuite.once(
|
|
1098
|
+
this.emit(constants.EVENT_DELAY_BEGIN, rootSuite);
|
|
1099
|
+
rootSuite.once(EVENT_ROOT_SUITE_RUN, prepare);
|
|
1100
|
+
debug('run(): waiting for green light due to --delay');
|
|
842
1101
|
} else {
|
|
843
|
-
|
|
1102
|
+
Runner.immediately(prepare);
|
|
844
1103
|
}
|
|
845
1104
|
|
|
846
1105
|
return this;
|
|
847
1106
|
};
|
|
848
1107
|
|
|
1108
|
+
/**
|
|
1109
|
+
* Toggle partial object linking behavior; used for building object references from
|
|
1110
|
+
* unique ID's. Does nothing in serial mode, because the object references already exist.
|
|
1111
|
+
* Subclasses can implement this (e.g., `ParallelBufferedRunner`)
|
|
1112
|
+
* @abstract
|
|
1113
|
+
* @param {boolean} [value] - If `true`, enable partial object linking, otherwise disable
|
|
1114
|
+
* @returns {Runner}
|
|
1115
|
+
* @chainable
|
|
1116
|
+
* @public
|
|
1117
|
+
* @example
|
|
1118
|
+
* // this reporter needs proper object references when run in parallel mode
|
|
1119
|
+
* class MyReporter() {
|
|
1120
|
+
* constructor(runner) {
|
|
1121
|
+
* this.runner.linkPartialObjects(true)
|
|
1122
|
+
* .on(EVENT_SUITE_BEGIN, suite => {
|
|
1123
|
+
// this Suite may be the same object...
|
|
1124
|
+
* })
|
|
1125
|
+
* .on(EVENT_TEST_BEGIN, test => {
|
|
1126
|
+
* // ...as the `test.parent` property
|
|
1127
|
+
* });
|
|
1128
|
+
* }
|
|
1129
|
+
* }
|
|
1130
|
+
*/
|
|
1131
|
+
Runner.prototype.linkPartialObjects = function (value) {
|
|
1132
|
+
return this;
|
|
1133
|
+
};
|
|
1134
|
+
|
|
1135
|
+
/*
|
|
1136
|
+
* Like {@link Runner#run}, but does not accept a callback and returns a `Promise` instead of a `Runner`.
|
|
1137
|
+
* This function cannot reject; an `unhandledRejection` event will bubble up to the `process` object instead.
|
|
1138
|
+
* @public
|
|
1139
|
+
* @memberof Runner
|
|
1140
|
+
* @param {Object} [opts] - Options for {@link Runner#run}
|
|
1141
|
+
* @returns {Promise<number>} Failure count
|
|
1142
|
+
*/
|
|
1143
|
+
Runner.prototype.runAsync = async function runAsync(opts = {}) {
|
|
1144
|
+
return new Promise(resolve => {
|
|
1145
|
+
this.run(resolve, opts);
|
|
1146
|
+
});
|
|
1147
|
+
};
|
|
1148
|
+
|
|
849
1149
|
/**
|
|
850
1150
|
* Cleanly abort execution.
|
|
851
1151
|
*
|
|
852
|
-
* @
|
|
1152
|
+
* @memberof Runner
|
|
1153
|
+
* @public
|
|
853
1154
|
* @return {Runner} Runner instance.
|
|
854
1155
|
*/
|
|
855
1156
|
Runner.prototype.abort = function () {
|
|
856
|
-
debug('aborting');
|
|
1157
|
+
debug('abort(): aborting');
|
|
857
1158
|
this._abort = true;
|
|
858
1159
|
|
|
859
1160
|
return this;
|
|
860
1161
|
};
|
|
861
1162
|
|
|
862
1163
|
/**
|
|
863
|
-
*
|
|
1164
|
+
* Returns `true` if Mocha is running in parallel mode. For reporters.
|
|
864
1165
|
*
|
|
865
|
-
*
|
|
866
|
-
* @
|
|
867
|
-
* @
|
|
1166
|
+
* Subclasses should return an appropriate value.
|
|
1167
|
+
* @public
|
|
1168
|
+
* @returns {false}
|
|
868
1169
|
*/
|
|
869
|
-
function
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
suite.tests = suite._onlyTests;
|
|
873
|
-
suite.suites = [];
|
|
874
|
-
} else {
|
|
875
|
-
// Otherwise, do not run any of the tests in this suite.
|
|
876
|
-
suite.tests = [];
|
|
877
|
-
utils.forEach(suite._onlySuites, function (onlySuite) {
|
|
878
|
-
// If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite.
|
|
879
|
-
// Otherwise, all of the tests on this `only` suite should be run, so don't filter it.
|
|
880
|
-
if (hasOnly(onlySuite)) {
|
|
881
|
-
filterOnly(onlySuite);
|
|
882
|
-
}
|
|
883
|
-
});
|
|
884
|
-
// Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants.
|
|
885
|
-
suite.suites = filter(suite.suites, function (childSuite) {
|
|
886
|
-
return indexOf(suite._onlySuites, childSuite) !== -1 || filterOnly(childSuite);
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
// Keep the suite only if there is something to run
|
|
890
|
-
return suite.tests.length || suite.suites.length;
|
|
891
|
-
}
|
|
1170
|
+
Runner.prototype.isParallelMode = function isParallelMode() {
|
|
1171
|
+
return false;
|
|
1172
|
+
};
|
|
892
1173
|
|
|
893
1174
|
/**
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
* @
|
|
897
|
-
* @
|
|
898
|
-
* @
|
|
1175
|
+
* Configures an alternate reporter for worker processes to use. Subclasses
|
|
1176
|
+
* using worker processes should implement this.
|
|
1177
|
+
* @public
|
|
1178
|
+
* @param {string} path - Absolute path to alternate reporter for worker processes to use
|
|
1179
|
+
* @returns {Runner}
|
|
1180
|
+
* @throws When in serial mode
|
|
1181
|
+
* @chainable
|
|
1182
|
+
* @abstract
|
|
899
1183
|
*/
|
|
900
|
-
function
|
|
901
|
-
|
|
902
|
-
}
|
|
1184
|
+
Runner.prototype.workerReporter = function () {
|
|
1185
|
+
throw createUnsupportedError('workerReporter() not supported in serial mode');
|
|
1186
|
+
};
|
|
903
1187
|
|
|
904
1188
|
/**
|
|
905
1189
|
* Filter leaks with the given globals flagged as `ok`.
|
|
906
1190
|
*
|
|
907
|
-
* @
|
|
1191
|
+
* @private
|
|
908
1192
|
* @param {Array} ok
|
|
909
1193
|
* @param {Array} globals
|
|
910
1194
|
* @return {Array}
|
|
911
1195
|
*/
|
|
912
|
-
function filterLeaks
|
|
913
|
-
return filter(
|
|
1196
|
+
function filterLeaks(ok, globals) {
|
|
1197
|
+
return globals.filter(function (key) {
|
|
914
1198
|
// Firefox and Chrome exposes iframes as index inside the window object
|
|
915
1199
|
if (/^\d+/.test(key)) {
|
|
916
1200
|
return false;
|
|
@@ -919,13 +1203,13 @@ function filterLeaks (ok, globals) {
|
|
|
919
1203
|
// in firefox
|
|
920
1204
|
// if runner runs in an iframe, this iframe's window.getInterface method
|
|
921
1205
|
// not init at first it is assigned in some seconds
|
|
922
|
-
if (global.navigator &&
|
|
1206
|
+
if (global.navigator && /^getInterface/.test(key)) {
|
|
923
1207
|
return false;
|
|
924
1208
|
}
|
|
925
1209
|
|
|
926
1210
|
// an iframe could be approached by window[iframeIndex]
|
|
927
1211
|
// in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
|
|
928
|
-
if (global.navigator &&
|
|
1212
|
+
if (global.navigator && /^\d+/.test(key)) {
|
|
929
1213
|
return false;
|
|
930
1214
|
}
|
|
931
1215
|
|
|
@@ -934,7 +1218,7 @@ function filterLeaks (ok, globals) {
|
|
|
934
1218
|
return false;
|
|
935
1219
|
}
|
|
936
1220
|
|
|
937
|
-
var matched = filter(
|
|
1221
|
+
var matched = ok.filter(function (ok) {
|
|
938
1222
|
if (~ok.indexOf('*')) {
|
|
939
1223
|
return key.indexOf(ok.split('*')[0]) === 0;
|
|
940
1224
|
}
|
|
@@ -945,24 +1229,39 @@ function filterLeaks (ok, globals) {
|
|
|
945
1229
|
}
|
|
946
1230
|
|
|
947
1231
|
/**
|
|
948
|
-
*
|
|
1232
|
+
* Check if argument is an instance of Error object or a duck-typed equivalent.
|
|
949
1233
|
*
|
|
950
|
-
* @
|
|
951
|
-
* @
|
|
1234
|
+
* @private
|
|
1235
|
+
* @param {Object} err - object to check
|
|
1236
|
+
* @param {string} err.message - error message
|
|
1237
|
+
* @returns {boolean}
|
|
952
1238
|
*/
|
|
953
|
-
function
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
var nodeVersion = utils.reduce(parts, function (a, v) {
|
|
957
|
-
return a << 8 | v;
|
|
958
|
-
});
|
|
1239
|
+
function isError(err) {
|
|
1240
|
+
return err instanceof Error || (err && typeof err.message === 'string');
|
|
1241
|
+
}
|
|
959
1242
|
|
|
960
|
-
|
|
1243
|
+
/**
|
|
1244
|
+
*
|
|
1245
|
+
* Converts thrown non-extensible type into proper Error.
|
|
1246
|
+
*
|
|
1247
|
+
* @private
|
|
1248
|
+
* @param {*} thrown - Non-extensible type thrown by code
|
|
1249
|
+
* @return {Error}
|
|
1250
|
+
*/
|
|
1251
|
+
function thrown2Error(err) {
|
|
1252
|
+
return new Error(
|
|
1253
|
+
`the ${utils.canonicalType(err)} ${stringify(
|
|
1254
|
+
err
|
|
1255
|
+
)} was thrown, throw an Error :)`
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
961
1258
|
|
|
962
|
-
|
|
963
|
-
return ['errno'];
|
|
964
|
-
}
|
|
965
|
-
}
|
|
1259
|
+
Runner.constants = constants;
|
|
966
1260
|
|
|
967
|
-
|
|
968
|
-
|
|
1261
|
+
/**
|
|
1262
|
+
* Node.js' `EventEmitter`
|
|
1263
|
+
* @external EventEmitter
|
|
1264
|
+
* @see {@link https://nodejs.org/api/events.html#events_class_eventemitter}
|
|
1265
|
+
*/
|
|
1266
|
+
|
|
1267
|
+
module.exports = Runner;
|