mocha 9.1.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +1015 -0
  2. package/LICENSE +22 -0
  3. package/README.md +70 -0
  4. package/assets/growl/error.png +0 -0
  5. package/assets/growl/ok.png +0 -0
  6. package/bin/_mocha +10 -0
  7. package/bin/mocha +142 -0
  8. package/browser-entry.js +216 -0
  9. package/index.js +3 -0
  10. package/lib/browser/growl.js +169 -0
  11. package/lib/browser/highlight-tags.js +39 -0
  12. package/lib/browser/parse-query.js +24 -0
  13. package/lib/browser/progress.js +123 -0
  14. package/lib/browser/template.html +20 -0
  15. package/lib/cli/cli.js +89 -0
  16. package/lib/cli/collect-files.js +92 -0
  17. package/lib/cli/commands.js +13 -0
  18. package/lib/cli/config.js +105 -0
  19. package/lib/cli/index.js +3 -0
  20. package/lib/cli/init.js +36 -0
  21. package/lib/cli/lookup-files.js +145 -0
  22. package/lib/cli/node-flags.js +85 -0
  23. package/lib/cli/one-and-dones.js +69 -0
  24. package/lib/cli/options.js +261 -0
  25. package/lib/cli/run-helpers.js +243 -0
  26. package/lib/cli/run-option-metadata.js +117 -0
  27. package/lib/cli/run.js +379 -0
  28. package/lib/cli/watch-run.js +380 -0
  29. package/lib/context.js +86 -0
  30. package/lib/errors.js +563 -0
  31. package/lib/hook.js +89 -0
  32. package/lib/interfaces/bdd.js +111 -0
  33. package/lib/interfaces/common.js +193 -0
  34. package/lib/interfaces/exports.js +60 -0
  35. package/lib/interfaces/index.js +6 -0
  36. package/lib/interfaces/qunit.js +98 -0
  37. package/lib/interfaces/tdd.js +106 -0
  38. package/lib/mocha.js +1374 -0
  39. package/lib/mocharc.json +10 -0
  40. package/lib/nodejs/buffered-worker-pool.js +172 -0
  41. package/lib/nodejs/esm-utils.js +109 -0
  42. package/lib/nodejs/file-unloader.js +15 -0
  43. package/lib/nodejs/growl.js +137 -0
  44. package/lib/nodejs/parallel-buffered-runner.js +433 -0
  45. package/lib/nodejs/reporters/parallel-buffered.js +165 -0
  46. package/lib/nodejs/serializer.js +412 -0
  47. package/lib/nodejs/worker.js +151 -0
  48. package/lib/pending.js +16 -0
  49. package/lib/plugin-loader.js +286 -0
  50. package/lib/reporters/base.js +537 -0
  51. package/lib/reporters/doc.js +95 -0
  52. package/lib/reporters/dot.js +81 -0
  53. package/lib/reporters/html.js +390 -0
  54. package/lib/reporters/index.js +19 -0
  55. package/lib/reporters/json-stream.js +92 -0
  56. package/lib/reporters/json.js +162 -0
  57. package/lib/reporters/landing.js +116 -0
  58. package/lib/reporters/list.js +78 -0
  59. package/lib/reporters/markdown.js +112 -0
  60. package/lib/reporters/min.js +52 -0
  61. package/lib/reporters/nyan.js +276 -0
  62. package/lib/reporters/progress.js +104 -0
  63. package/lib/reporters/spec.js +99 -0
  64. package/lib/reporters/tap.js +293 -0
  65. package/lib/reporters/xunit.js +217 -0
  66. package/lib/runnable.js +476 -0
  67. package/lib/runner.js +1269 -0
  68. package/lib/stats-collector.js +83 -0
  69. package/lib/suite.js +695 -0
  70. package/lib/test.js +113 -0
  71. package/lib/utils.js +641 -0
  72. package/mocha-es2018.js +19816 -0
  73. package/mocha.css +325 -0
  74. package/mocha.js +30844 -0
  75. package/mocha.js.map +1 -0
  76. package/package.json +200 -0
@@ -0,0 +1,10 @@
1
+ {
2
+ "diff": true,
3
+ "extension": ["js", "cjs", "mjs"],
4
+ "package": "./package.json",
5
+ "reporter": "spec",
6
+ "slow": 75,
7
+ "timeout": 2000,
8
+ "ui": "bdd",
9
+ "watch-ignore": ["node_modules", ".git"]
10
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * A wrapper around a third-party child process worker pool implementation.
3
+ * Used by {@link module:buffered-runner}.
4
+ * @private
5
+ * @module buffered-worker-pool
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const serializeJavascript = require('serialize-javascript');
11
+ const workerpool = require('workerpool');
12
+ const {deserialize} = require('./serializer');
13
+ const debug = require('debug')('mocha:parallel:buffered-worker-pool');
14
+ const {createInvalidArgumentTypeError} = require('../errors');
15
+
16
+ const WORKER_PATH = require.resolve('./worker.js');
17
+
18
+ /**
19
+ * A mapping of Mocha `Options` objects to serialized values.
20
+ *
21
+ * This is helpful because we tend to same the same options over and over
22
+ * over IPC.
23
+ * @type {WeakMap<Options,string>}
24
+ */
25
+ let optionsCache = new WeakMap();
26
+
27
+ /**
28
+ * These options are passed into the [workerpool](https://npm.im/workerpool) module.
29
+ * @type {Partial<WorkerPoolOptions>}
30
+ */
31
+ const WORKER_POOL_DEFAULT_OPTS = {
32
+ // use child processes, not worker threads!
33
+ workerType: 'process',
34
+ // ensure the same flags sent to `node` for this `mocha` invocation are passed
35
+ // along to children
36
+ forkOpts: {execArgv: process.execArgv},
37
+ maxWorkers: workerpool.cpus - 1
38
+ };
39
+
40
+ /**
41
+ * A wrapper around a third-party worker pool implementation.
42
+ * @private
43
+ */
44
+ class BufferedWorkerPool {
45
+ /**
46
+ * Creates an underlying worker pool instance; determines max worker count
47
+ * @param {Partial<WorkerPoolOptions>} [opts] - Options
48
+ */
49
+ constructor(opts = {}) {
50
+ const maxWorkers = Math.max(
51
+ 1,
52
+ typeof opts.maxWorkers === 'undefined'
53
+ ? WORKER_POOL_DEFAULT_OPTS.maxWorkers
54
+ : opts.maxWorkers
55
+ );
56
+
57
+ /* istanbul ignore next */
58
+ if (workerpool.cpus < 2) {
59
+ // TODO: decide whether we should warn
60
+ debug(
61
+ 'not enough CPU cores available to run multiple jobs; avoid --parallel on this machine'
62
+ );
63
+ } else if (maxWorkers >= workerpool.cpus) {
64
+ // TODO: decide whether we should warn
65
+ debug(
66
+ '%d concurrent job(s) requested, but only %d core(s) available',
67
+ maxWorkers,
68
+ workerpool.cpus
69
+ );
70
+ }
71
+ /* istanbul ignore next */
72
+ debug(
73
+ 'run(): starting worker pool of max size %d, using node args: %s',
74
+ maxWorkers,
75
+ process.execArgv.join(' ')
76
+ );
77
+
78
+ this.options = {...WORKER_POOL_DEFAULT_OPTS, opts, maxWorkers};
79
+ this._pool = workerpool.pool(WORKER_PATH, this.options);
80
+ }
81
+
82
+ /**
83
+ * Terminates all workers in the pool.
84
+ * @param {boolean} [force] - Whether to force-kill workers. By default, lets workers finish their current task before termination.
85
+ * @private
86
+ * @returns {Promise<void>}
87
+ */
88
+ async terminate(force = false) {
89
+ /* istanbul ignore next */
90
+ debug('terminate(): terminating with force = %s', force);
91
+ return this._pool.terminate(force);
92
+ }
93
+
94
+ /**
95
+ * Adds a test file run to the worker pool queue for execution by a worker process.
96
+ *
97
+ * Handles serialization/deserialization.
98
+ *
99
+ * @param {string} filepath - Filepath of test
100
+ * @param {Options} [options] - Options for Mocha instance
101
+ * @private
102
+ * @returns {Promise<SerializedWorkerResult>}
103
+ */
104
+ async run(filepath, options = {}) {
105
+ if (!filepath || typeof filepath !== 'string') {
106
+ throw createInvalidArgumentTypeError(
107
+ 'Expected a non-empty filepath',
108
+ 'filepath',
109
+ 'string'
110
+ );
111
+ }
112
+ const serializedOptions = BufferedWorkerPool.serializeOptions(options);
113
+ const result = await this._pool.exec('run', [filepath, serializedOptions]);
114
+ return deserialize(result);
115
+ }
116
+
117
+ /**
118
+ * Returns stats about the state of the worker processes in the pool.
119
+ *
120
+ * Used for debugging.
121
+ *
122
+ * @private
123
+ */
124
+ stats() {
125
+ return this._pool.stats();
126
+ }
127
+
128
+ /**
129
+ * Instantiates a {@link WorkerPool}.
130
+ * @private
131
+ */
132
+ static create(...args) {
133
+ return new BufferedWorkerPool(...args);
134
+ }
135
+
136
+ /**
137
+ * Given Mocha options object `opts`, serialize into a format suitable for
138
+ * transmission over IPC.
139
+ *
140
+ * @param {Options} [opts] - Mocha options
141
+ * @private
142
+ * @returns {string} Serialized options
143
+ */
144
+ static serializeOptions(opts = {}) {
145
+ if (!optionsCache.has(opts)) {
146
+ const serialized = serializeJavascript(opts, {
147
+ unsafe: true, // this means we don't care about XSS
148
+ ignoreFunction: true // do not serialize functions
149
+ });
150
+ optionsCache.set(opts, serialized);
151
+ /* istanbul ignore next */
152
+ debug(
153
+ 'serializeOptions(): serialized options %O to: %s',
154
+ opts,
155
+ serialized
156
+ );
157
+ }
158
+ return optionsCache.get(opts);
159
+ }
160
+
161
+ /**
162
+ * Resets internal cache of serialized options objects.
163
+ *
164
+ * For testing/debugging
165
+ * @private
166
+ */
167
+ static resetOptionsCache() {
168
+ optionsCache = new WeakMap();
169
+ }
170
+ }
171
+
172
+ exports.BufferedWorkerPool = BufferedWorkerPool;
@@ -0,0 +1,109 @@
1
+ const path = require('path');
2
+ const url = require('url');
3
+
4
+ const formattedImport = async file => {
5
+ if (path.isAbsolute(file)) {
6
+ try {
7
+ return await import(url.pathToFileURL(file));
8
+ } catch (err) {
9
+ // This is a hack created because ESM in Node.js (at least in Node v15.5.1) does not emit
10
+ // the location of the syntax error in the error thrown.
11
+ // This is problematic because the user can't see what file has the problem,
12
+ // so we add the file location to the error.
13
+ // This `if` should be removed once Node.js fixes the problem.
14
+ if (
15
+ err instanceof SyntaxError &&
16
+ err.message &&
17
+ err.stack &&
18
+ !err.stack.includes(file)
19
+ ) {
20
+ const newErrorWithFilename = new SyntaxError(err.message);
21
+ newErrorWithFilename.stack = err.stack.replace(
22
+ /^SyntaxError/,
23
+ `SyntaxError[ @${file} ]`
24
+ );
25
+ throw newErrorWithFilename;
26
+ }
27
+ throw err;
28
+ }
29
+ }
30
+ return import(file);
31
+ };
32
+
33
+ const hasStableEsmImplementation = (() => {
34
+ const [major, minor] = process.version.split('.');
35
+ // ESM is stable from v12.22.0 onward
36
+ // https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules
37
+ const majorNumber = parseInt(major.slice(1), 10);
38
+ const minorNumber = parseInt(minor, 10);
39
+ return majorNumber > 12 || (majorNumber === 12 && minorNumber >= 22);
40
+ })();
41
+
42
+ exports.requireOrImport = hasStableEsmImplementation
43
+ ? async file => {
44
+ if (path.extname(file) === '.mjs') {
45
+ return formattedImport(file);
46
+ }
47
+ try {
48
+ return dealWithExports(await formattedImport(file));
49
+ } catch (err) {
50
+ if (
51
+ err.code === 'ERR_MODULE_NOT_FOUND' ||
52
+ err.code === 'ERR_UNKNOWN_FILE_EXTENSION' ||
53
+ err.code === 'ERR_UNSUPPORTED_DIR_IMPORT'
54
+ ) {
55
+ try {
56
+ return require(file);
57
+ } catch (requireErr) {
58
+ if (requireErr.code === 'ERR_REQUIRE_ESM') {
59
+ // This happens when the test file is a JS file, but via type:module is actually ESM,
60
+ // AND has an import to a file that doesn't exist.
61
+ // This throws an `ERR_MODULE_NOT_FOUND` // error above,
62
+ // and when we try to `require` it here, it throws an `ERR_REQUIRE_ESM`.
63
+ // What we want to do is throw the original error (the `ERR_MODULE_NOT_FOUND`),
64
+ // and not the `ERR_REQUIRE_ESM` error, which is a red herring.
65
+ throw err;
66
+ } else {
67
+ throw requireErr;
68
+ }
69
+ }
70
+ } else {
71
+ throw err;
72
+ }
73
+ }
74
+ }
75
+ : implementationOfRequireOrImportForUnstableEsm;
76
+
77
+ function dealWithExports(module) {
78
+ if (module.default) {
79
+ return module.default;
80
+ } else {
81
+ return {...module, default: undefined};
82
+ }
83
+ }
84
+
85
+ exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => {
86
+ for (const file of files) {
87
+ preLoadFunc(file);
88
+ const result = await exports.requireOrImport(path.resolve(file));
89
+ postLoadFunc(file, result);
90
+ }
91
+ };
92
+
93
+ /* istanbul ignore next */
94
+ async function implementationOfRequireOrImportForUnstableEsm(file) {
95
+ if (path.extname(file) === '.mjs') {
96
+ return formattedImport(file);
97
+ }
98
+ // This is currently the only known way of figuring out whether a file is CJS or ESM in
99
+ // Node.js that doesn't necessitate calling `import` first.
100
+ try {
101
+ return require(file);
102
+ } catch (err) {
103
+ if (err.code === 'ERR_REQUIRE_ESM') {
104
+ return formattedImport(file);
105
+ } else {
106
+ throw err;
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * This module should not be in the browser bundle, so it's here.
5
+ * @private
6
+ * @module
7
+ */
8
+
9
+ /**
10
+ * Deletes a file from the `require` cache.
11
+ * @param {string} file - File
12
+ */
13
+ exports.unloadFile = file => {
14
+ delete require.cache[require.resolve(file)];
15
+ };
@@ -0,0 +1,137 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Desktop Notifications module.
5
+ * @module Growl
6
+ */
7
+
8
+ const os = require('os');
9
+ const path = require('path');
10
+ const {sync: which} = require('which');
11
+ const {EVENT_RUN_END} = require('../runner').constants;
12
+ const {isBrowser} = require('../utils');
13
+
14
+ /**
15
+ * @summary
16
+ * Checks if Growl notification support seems likely.
17
+ *
18
+ * @description
19
+ * Glosses over the distinction between an unsupported platform
20
+ * and one that lacks prerequisite software installations.
21
+ *
22
+ * @public
23
+ * @see {@link https://github.com/tj/node-growl/blob/master/README.md|Prerequisite Installs}
24
+ * @see {@link Mocha#growl}
25
+ * @see {@link Mocha#isGrowlCapable}
26
+ * @return {boolean} whether Growl notification support can be expected
27
+ */
28
+ exports.isCapable = () => {
29
+ if (!isBrowser()) {
30
+ return getSupportBinaries().reduce(
31
+ (acc, binary) => acc || Boolean(which(binary, {nothrow: true})),
32
+ false
33
+ );
34
+ }
35
+ return false;
36
+ };
37
+
38
+ /**
39
+ * Implements desktop notifications as a pseudo-reporter.
40
+ *
41
+ * @public
42
+ * @see {@link Mocha#_growl}
43
+ * @param {Runner} runner - Runner instance.
44
+ */
45
+ exports.notify = runner => {
46
+ runner.once(EVENT_RUN_END, () => {
47
+ display(runner);
48
+ });
49
+ };
50
+
51
+ /**
52
+ * Displays the notification.
53
+ *
54
+ * @private
55
+ * @param {Runner} runner - Runner instance.
56
+ */
57
+ const display = runner => {
58
+ const growl = require('growl');
59
+ const stats = runner.stats;
60
+ const symbol = {
61
+ cross: '\u274C',
62
+ tick: '\u2705'
63
+ };
64
+ let _message;
65
+ let message;
66
+ let title;
67
+
68
+ if (stats.failures) {
69
+ _message = `${stats.failures} of ${stats.tests} tests failed`;
70
+ message = `${symbol.cross} ${_message}`;
71
+ title = 'Failed';
72
+ } else {
73
+ _message = `${stats.passes} tests passed in ${stats.duration}ms`;
74
+ message = `${symbol.tick} ${_message}`;
75
+ title = 'Passed';
76
+ }
77
+
78
+ // Send notification
79
+ const options = {
80
+ image: logo(),
81
+ name: 'mocha',
82
+ title
83
+ };
84
+ growl(message, options, onCompletion);
85
+ };
86
+
87
+ /**
88
+ * @summary
89
+ * Callback for result of attempted Growl notification.
90
+ *
91
+ * @description
92
+ * Despite its appearance, this is <strong>not</strong> an Error-first
93
+ * callback -- all parameters are populated regardless of success.
94
+ *
95
+ * @private
96
+ * @callback Growl~growlCB
97
+ * @param {*} err - Error object, or <code>null</code> if successful.
98
+ */
99
+ function onCompletion(err) {
100
+ if (err) {
101
+ // As notifications are tangential to our purpose, just log the error.
102
+ const message =
103
+ err.code === 'ENOENT' ? 'prerequisite software not found' : err.message;
104
+ console.error('notification error:', message);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Returns Mocha logo image path.
110
+ *
111
+ * @private
112
+ * @return {string} Pathname of Mocha logo
113
+ */
114
+ const logo = () => {
115
+ return path.join(__dirname, '..', 'assets', 'mocha-logo-96.png');
116
+ };
117
+
118
+ /**
119
+ * @summary
120
+ * Gets platform-specific Growl support binaries.
121
+ *
122
+ * @description
123
+ * Somewhat brittle dependency on `growl` package implementation, but it
124
+ * rarely changes.
125
+ *
126
+ * @private
127
+ * @see {@link https://github.com/tj/node-growl/blob/master/lib/growl.js#L28-L126|setupCmd}
128
+ * @return {string[]} names of Growl support binaries
129
+ */
130
+ const getSupportBinaries = () => {
131
+ const binaries = {
132
+ Darwin: ['terminal-notifier', 'growlnotify'],
133
+ Linux: ['notify-send', 'growl'],
134
+ Windows_NT: ['growlnotify.exe']
135
+ };
136
+ return binaries[os.type()] || [];
137
+ };