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
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2011-2021 OpenJS Foundation and contributors, https://openjsf.org
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ <p align="center">
2
+ <img src="https://cldup.com/xFVFxOioAU.svg" alt="Mocha test framework"/>
3
+ </p>
4
+
5
+ <p align="center">☕️ Simple, flexible, fun JavaScript test framework for Node.js & The Browser ☕️</p>
6
+
7
+ <p align="center">
8
+ <a href="https://github.com/mochajs/mocha/actions?query=workflow%3ATests+branch%3Amaster"><img src="https://github.com/mochajs/mocha/workflows/Tests/badge.svg?branch=master" alt="GitHub Actions Build Status"></a>
9
+ <a href="https://coveralls.io/github/mochajs/mocha"><img src="https://coveralls.io/repos/github/mochajs/mocha/badge.svg" alt="Coverage Status"></a>
10
+ <a href="https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha?ref=badge_shield"><img src="https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha.svg?type=shield" alt="FOSSA Status"></a>
11
+ <a href="https://gitter.im/mochajs/mocha?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter"></a>
12
+ <a href="https://github.com/mochajs/mocha#sponsors"><img src="https://opencollective.com/mochajs/tiers/sponsors/badge.svg" alt="OpenCollective"></a>
13
+ <a href="https://github.com/mochajs/mocha#backers"><img src="https://opencollective.com/mochajs/tiers/backers/badge.svg" alt="OpenCollective"></a>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="https://www.npmjs.com/package/mocha"><img src="https://img.shields.io/npm/v/mocha.svg" alt="NPM Version"></a>
18
+ <a href="https://github.com/mochajs/mocha"><img src="https://img.shields.io/node/v/mocha.svg" alt="Node Version"></a>
19
+ </p>
20
+
21
+ <p align="center"><br><img alt="Mocha Browser Support h/t SauceLabs" src="https://saucelabs.com/browser-matrix/mochajs.svg" width="354"></p>
22
+
23
+ ## Links
24
+
25
+ - **[Documentation](https://mochajs.org/)**
26
+ - **[Release Notes / History / Changes](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)**
27
+ - [Code of Conduct](https://github.com/mochajs/mocha/blob/master/.github/CODE_OF_CONDUCT.md)
28
+ - [Contributing](https://github.com/mochajs/mocha/blob/master/.github/CONTRIBUTING.md)
29
+ - [Gitter Chatroom](https://gitter.im/mochajs/mocha) (ask questions here!)
30
+ - [Issue Tracker](https://github.com/mochajs/mocha/issues)
31
+
32
+ ## Backers
33
+
34
+ [Become a backer](https://opencollective.com/mochajs) and show your support to our open source project on [our site](https://mochajs.org/#backers).
35
+
36
+ <a href="https://opencollective.com/mochajs"><img src="https://opencollective.com/mochajs/tiers/backers.svg?limit=30&button=false&avatarHeight=46&width=750"></a>
37
+
38
+ ## Sponsors
39
+
40
+ Does your company use Mocha? Ask your manager or marketing team if your company would be interested in supporting our project. Support will allow the maintainers to dedicate more time for maintenance and new features for everyone. Also, your company's logo will show [on GitHub](https://github.com/mochajs/mocha#readme) and on [our site](https://mochajs.org#sponsors) - who doesn't want a little extra exposure? [Here's the info](https://opencollective.com/mochajs).
41
+
42
+ [![MochaJS Sponsor](https://opencollective.com/mochajs/tiers/sponsors/0/avatar)](https://opencollective.com/mochajs/tiers/sponsors/0/website)
43
+ [![MochaJS Sponsor](https://opencollective.com/mochajs/tiers/sponsors/1/avatar)](https://opencollective.com/mochajs/tiers/sponsors/1/website)
44
+ [![MochaJS Sponsor](https://opencollective.com/mochajs/tiers/sponsors/2/avatar)](https://opencollective.com/mochajs/tiers/sponsors/2/website)
45
+ [![MochaJS Sponsor](https://opencollective.com/mochajs/tiers/sponsors/3/avatar)](https://opencollective.com/mochajs/tiers/sponsors/3/website)
46
+
47
+ ## Development
48
+
49
+ You might want to know that:
50
+
51
+ - Mocha is one of the _most-depended-upon_ modules on npm (source: [libraries.io](https://libraries.io/search?order=desc&platforms=NPM&sort=dependents_count)), and
52
+ - Mocha is an _independent_ open-source project, maintained exclusively by volunteers.
53
+
54
+ You might want to help:
55
+
56
+ - New to contributing to Mocha? Check out this list of [good first issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue)
57
+ - Mocha could use a hand with [these issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
58
+ - The [maintainer's handbook](https://github.com/mochajs/mocha/blob/master/MAINTAINERS.md) explains how things get done
59
+
60
+ Finally, come [chat with the maintainers](https://gitter.im/mochajs/contributors) on Gitter if you want to help with:
61
+
62
+ - Triaging issues, answering questions
63
+ - Review, merging, and closing pull requests
64
+ - Other project-maintenance-y things
65
+
66
+ ## License
67
+
68
+ Copyright 2011-2021 OpenJS Foundation and contributors. Licensed [MIT](https://github.com/mochajs/mocha/blob/master/LICENSE).
69
+
70
+ [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha?ref=badge_large)
Binary file
Binary file
package/bin/_mocha ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * This file remains for backwards compatibility only.
6
+ * Don't put stuff in this file.
7
+ * @see module:lib/cli
8
+ */
9
+
10
+ require('../lib/cli').main();
package/bin/mocha ADDED
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ /**
6
+ * This wrapper executable checks for known node flags and appends them when found,
7
+ * before invoking the "real" executable (`lib/cli/cli.js`)
8
+ *
9
+ * @module bin/mocha
10
+ * @private
11
+ */
12
+
13
+ const {loadOptions} = require('../lib/cli/options');
14
+ const {
15
+ unparseNodeFlags,
16
+ isNodeFlag,
17
+ impliesNoTimeouts
18
+ } = require('../lib/cli/node-flags');
19
+ const unparse = require('yargs-unparser');
20
+ const debug = require('debug')('mocha:cli:mocha');
21
+ const {aliases} = require('../lib/cli/run-option-metadata');
22
+
23
+ const mochaArgs = {};
24
+ const nodeArgs = {};
25
+ let hasInspect = false;
26
+
27
+ const opts = loadOptions(process.argv.slice(2));
28
+ debug('loaded opts', opts);
29
+
30
+ /**
31
+ * Given option/command `value`, disable timeouts if applicable
32
+ * @param {string} [value] - Value to check
33
+ * @ignore
34
+ */
35
+ const disableTimeouts = value => {
36
+ if (impliesNoTimeouts(value)) {
37
+ debug('option %s disabled timeouts', value);
38
+ mochaArgs.timeout = 0;
39
+ }
40
+ };
41
+
42
+ /**
43
+ * If `value` begins with `v8-` and is not explicitly `v8-options`, remove prefix
44
+ * @param {string} [value] - Value to check
45
+ * @returns {string} `value` with prefix (maybe) removed
46
+ * @ignore
47
+ */
48
+ const trimV8Option = value =>
49
+ value !== 'v8-options' && /^v8-/.test(value) ? value.slice(3) : value;
50
+
51
+ // sort options into "node" and "mocha" buckets
52
+ Object.keys(opts).forEach(opt => {
53
+ if (isNodeFlag(opt)) {
54
+ nodeArgs[trimV8Option(opt)] = opts[opt];
55
+ } else {
56
+ mochaArgs[opt] = opts[opt];
57
+ }
58
+ });
59
+
60
+ // disable 'timeout' for debugFlags
61
+ Object.keys(nodeArgs).forEach(opt => disableTimeouts(opt));
62
+ mochaArgs['node-option'] &&
63
+ mochaArgs['node-option'].forEach(opt => disableTimeouts(opt));
64
+
65
+ // Native debugger handling
66
+ // see https://nodejs.org/api/debugger.html#debugger_debugger
67
+ // look for 'inspect' that would launch this debugger,
68
+ // remove it from Mocha's opts and prepend it to Node's opts.
69
+ // A deprecation warning will be printed by node, if applicable.
70
+ // (mochaArgs._ are "positional" arguments, not prefixed with - or --)
71
+ if (mochaArgs._) {
72
+ const i = mochaArgs._.findIndex(val => val === 'inspect');
73
+ if (i > -1) {
74
+ mochaArgs._.splice(i, 1);
75
+ disableTimeouts('inspect');
76
+ hasInspect = true;
77
+ }
78
+ }
79
+
80
+ if (mochaArgs['node-option'] || Object.keys(nodeArgs).length || hasInspect) {
81
+ const {spawn} = require('child_process');
82
+ const mochaPath = require.resolve('../lib/cli/cli.js');
83
+
84
+ const nodeArgv =
85
+ (mochaArgs['node-option'] && mochaArgs['node-option'].map(v => '--' + v)) ||
86
+ unparseNodeFlags(nodeArgs);
87
+
88
+ if (hasInspect) nodeArgv.unshift('inspect');
89
+ delete mochaArgs['node-option'];
90
+
91
+ debug('final node argv', nodeArgv);
92
+
93
+ const args = [].concat(
94
+ nodeArgv,
95
+ mochaPath,
96
+ unparse(mochaArgs, {alias: aliases})
97
+ );
98
+
99
+ debug(
100
+ 'forking child process via command: %s %s',
101
+ process.execPath,
102
+ args.join(' ')
103
+ );
104
+
105
+ const proc = spawn(process.execPath, args, {
106
+ stdio: 'inherit'
107
+ });
108
+
109
+ proc.on('exit', (code, signal) => {
110
+ process.on('exit', () => {
111
+ if (signal) {
112
+ process.kill(process.pid, signal);
113
+ } else {
114
+ process.exit(code);
115
+ }
116
+ });
117
+ });
118
+
119
+ // terminate children.
120
+ process.on('SIGINT', () => {
121
+ // XXX: a previous comment said this would abort the runner, but I can't see that it does
122
+ // anything with the default runner.
123
+ debug('main process caught SIGINT');
124
+ proc.kill('SIGINT');
125
+ // if running in parallel mode, we will have a proper SIGINT handler, so the below won't
126
+ // be needed.
127
+ if (!args.parallel || args.jobs < 2) {
128
+ // win32 does not support SIGTERM, so use next best thing.
129
+ if (require('os').platform() === 'win32') {
130
+ proc.kill('SIGKILL');
131
+ } else {
132
+ // using SIGKILL won't cleanly close the output streams, which can result
133
+ // in cut-off text or a befouled terminal.
134
+ debug('sending SIGTERM to child process');
135
+ proc.kill('SIGTERM');
136
+ }
137
+ }
138
+ });
139
+ } else {
140
+ debug('running Mocha in-process');
141
+ require('../lib/cli/cli').main([], mochaArgs);
142
+ }
@@ -0,0 +1,216 @@
1
+ 'use strict';
2
+
3
+ /* eslint no-unused-vars: off */
4
+ /* eslint-env commonjs */
5
+
6
+ /**
7
+ * Shim process.stdout.
8
+ */
9
+
10
+ process.stdout = require('browser-stdout')({label: false});
11
+
12
+ var parseQuery = require('./lib/browser/parse-query');
13
+ var highlightTags = require('./lib/browser/highlight-tags');
14
+ var Mocha = require('./lib/mocha');
15
+
16
+ /**
17
+ * Create a Mocha instance.
18
+ *
19
+ * @return {undefined}
20
+ */
21
+
22
+ var mocha = new Mocha({reporter: 'html'});
23
+
24
+ /**
25
+ * Save timer references to avoid Sinon interfering (see GH-237).
26
+ */
27
+
28
+ var Date = global.Date;
29
+ var setTimeout = global.setTimeout;
30
+ var setInterval = global.setInterval;
31
+ var clearTimeout = global.clearTimeout;
32
+ var clearInterval = global.clearInterval;
33
+
34
+ var uncaughtExceptionHandlers = [];
35
+
36
+ var originalOnerrorHandler = global.onerror;
37
+
38
+ /**
39
+ * Remove uncaughtException listener.
40
+ * Revert to original onerror handler if previously defined.
41
+ */
42
+
43
+ process.removeListener = function(e, fn) {
44
+ if (e === 'uncaughtException') {
45
+ if (originalOnerrorHandler) {
46
+ global.onerror = originalOnerrorHandler;
47
+ } else {
48
+ global.onerror = function() {};
49
+ }
50
+ var i = uncaughtExceptionHandlers.indexOf(fn);
51
+ if (i !== -1) {
52
+ uncaughtExceptionHandlers.splice(i, 1);
53
+ }
54
+ }
55
+ };
56
+
57
+ /**
58
+ * Implements listenerCount for 'uncaughtException'.
59
+ */
60
+
61
+ process.listenerCount = function(name) {
62
+ if (name === 'uncaughtException') {
63
+ return uncaughtExceptionHandlers.length;
64
+ }
65
+ return 0;
66
+ };
67
+
68
+ /**
69
+ * Implements uncaughtException listener.
70
+ */
71
+
72
+ process.on = function(e, fn) {
73
+ if (e === 'uncaughtException') {
74
+ global.onerror = function(err, url, line) {
75
+ fn(new Error(err + ' (' + url + ':' + line + ')'));
76
+ return !mocha.options.allowUncaught;
77
+ };
78
+ uncaughtExceptionHandlers.push(fn);
79
+ }
80
+ };
81
+
82
+ process.listeners = function(e) {
83
+ if (e === 'uncaughtException') {
84
+ return uncaughtExceptionHandlers;
85
+ }
86
+ return [];
87
+ };
88
+
89
+ // The BDD UI is registered by default, but no UI will be functional in the
90
+ // browser without an explicit call to the overridden `mocha.ui` (see below).
91
+ // Ensure that this default UI does not expose its methods to the global scope.
92
+ mocha.suite.removeAllListeners('pre-require');
93
+
94
+ var immediateQueue = [];
95
+ var immediateTimeout;
96
+
97
+ function timeslice() {
98
+ var immediateStart = new Date().getTime();
99
+ while (immediateQueue.length && new Date().getTime() - immediateStart < 100) {
100
+ immediateQueue.shift()();
101
+ }
102
+ if (immediateQueue.length) {
103
+ immediateTimeout = setTimeout(timeslice, 0);
104
+ } else {
105
+ immediateTimeout = null;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * High-performance override of Runner.immediately.
111
+ */
112
+
113
+ Mocha.Runner.immediately = function(callback) {
114
+ immediateQueue.push(callback);
115
+ if (!immediateTimeout) {
116
+ immediateTimeout = setTimeout(timeslice, 0);
117
+ }
118
+ };
119
+
120
+ /**
121
+ * Function to allow assertion libraries to throw errors directly into mocha.
122
+ * This is useful when running tests in a browser because window.onerror will
123
+ * only receive the 'message' attribute of the Error.
124
+ */
125
+ mocha.throwError = function(err) {
126
+ uncaughtExceptionHandlers.forEach(function(fn) {
127
+ fn(err);
128
+ });
129
+ throw err;
130
+ };
131
+
132
+ /**
133
+ * Override ui to ensure that the ui functions are initialized.
134
+ * Normally this would happen in Mocha.prototype.loadFiles.
135
+ */
136
+
137
+ mocha.ui = function(ui) {
138
+ Mocha.prototype.ui.call(this, ui);
139
+ this.suite.emit('pre-require', global, null, this);
140
+ return this;
141
+ };
142
+
143
+ /**
144
+ * Setup mocha with the given setting options.
145
+ */
146
+
147
+ mocha.setup = function(opts) {
148
+ if (typeof opts === 'string') {
149
+ opts = {ui: opts};
150
+ }
151
+ if (opts.delay === true) {
152
+ this.delay();
153
+ }
154
+ var self = this;
155
+ Object.keys(opts)
156
+ .filter(function(opt) {
157
+ return opt !== 'delay';
158
+ })
159
+ .forEach(function(opt) {
160
+ if (Object.prototype.hasOwnProperty.call(opts, opt)) {
161
+ self[opt](opts[opt]);
162
+ }
163
+ });
164
+ return this;
165
+ };
166
+
167
+ /**
168
+ * Run mocha, returning the Runner.
169
+ */
170
+
171
+ mocha.run = function(fn) {
172
+ var options = mocha.options;
173
+ mocha.globals('location');
174
+
175
+ var query = parseQuery(global.location.search || '');
176
+ if (query.grep) {
177
+ mocha.grep(query.grep);
178
+ }
179
+ if (query.fgrep) {
180
+ mocha.fgrep(query.fgrep);
181
+ }
182
+ if (query.invert) {
183
+ mocha.invert();
184
+ }
185
+
186
+ return Mocha.prototype.run.call(mocha, function(err) {
187
+ // The DOM Document is not available in Web Workers.
188
+ var document = global.document;
189
+ if (
190
+ document &&
191
+ document.getElementById('mocha') &&
192
+ options.noHighlighting !== true
193
+ ) {
194
+ highlightTags('code');
195
+ }
196
+ if (fn) {
197
+ fn(err);
198
+ }
199
+ });
200
+ };
201
+
202
+ /**
203
+ * Expose the process shim.
204
+ * https://github.com/mochajs/mocha/pull/916
205
+ */
206
+
207
+ Mocha.process = process;
208
+
209
+ /**
210
+ * Expose mocha.
211
+ */
212
+
213
+ global.Mocha = Mocha;
214
+ global.mocha = mocha;
215
+
216
+ module.exports = mocha;
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./lib/mocha');
@@ -0,0 +1,169 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Web Notifications module.
5
+ * @module Growl
6
+ */
7
+
8
+ /**
9
+ * Save timer references to avoid Sinon interfering (see GH-237).
10
+ */
11
+ var Date = global.Date;
12
+ var setTimeout = global.setTimeout;
13
+ var EVENT_RUN_END = require('../runner').constants.EVENT_RUN_END;
14
+ var isBrowser = require('../utils').isBrowser;
15
+
16
+ /**
17
+ * Checks if browser notification support exists.
18
+ *
19
+ * @public
20
+ * @see {@link https://caniuse.com/#feat=notifications|Browser support (notifications)}
21
+ * @see {@link https://caniuse.com/#feat=promises|Browser support (promises)}
22
+ * @see {@link Mocha#growl}
23
+ * @see {@link Mocha#isGrowlCapable}
24
+ * @return {boolean} whether browser notification support exists
25
+ */
26
+ exports.isCapable = function() {
27
+ var hasNotificationSupport = 'Notification' in window;
28
+ var hasPromiseSupport = typeof Promise === 'function';
29
+ return isBrowser() && hasNotificationSupport && hasPromiseSupport;
30
+ };
31
+
32
+ /**
33
+ * Implements browser notifications as a pseudo-reporter.
34
+ *
35
+ * @public
36
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/notification|Notification API}
37
+ * @see {@link https://developers.google.com/web/fundamentals/push-notifications/display-a-notification|Displaying a Notification}
38
+ * @see {@link Growl#isPermitted}
39
+ * @see {@link Mocha#_growl}
40
+ * @param {Runner} runner - Runner instance.
41
+ */
42
+ exports.notify = function(runner) {
43
+ var promise = isPermitted();
44
+
45
+ /**
46
+ * Attempt notification.
47
+ */
48
+ var sendNotification = function() {
49
+ // If user hasn't responded yet... "No notification for you!" (Seinfeld)
50
+ Promise.race([promise, Promise.resolve(undefined)])
51
+ .then(canNotify)
52
+ .then(function() {
53
+ display(runner);
54
+ })
55
+ .catch(notPermitted);
56
+ };
57
+
58
+ runner.once(EVENT_RUN_END, sendNotification);
59
+ };
60
+
61
+ /**
62
+ * Checks if browser notification is permitted by user.
63
+ *
64
+ * @private
65
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Notification/permission|Notification.permission}
66
+ * @see {@link Mocha#growl}
67
+ * @see {@link Mocha#isGrowlPermitted}
68
+ * @returns {Promise<boolean>} promise determining if browser notification
69
+ * permissible when fulfilled.
70
+ */
71
+ function isPermitted() {
72
+ var permitted = {
73
+ granted: function allow() {
74
+ return Promise.resolve(true);
75
+ },
76
+ denied: function deny() {
77
+ return Promise.resolve(false);
78
+ },
79
+ default: function ask() {
80
+ return Notification.requestPermission().then(function(permission) {
81
+ return permission === 'granted';
82
+ });
83
+ }
84
+ };
85
+
86
+ return permitted[Notification.permission]();
87
+ }
88
+
89
+ /**
90
+ * @summary
91
+ * Determines if notification should proceed.
92
+ *
93
+ * @description
94
+ * Notification shall <strong>not</strong> proceed unless `value` is true.
95
+ *
96
+ * `value` will equal one of:
97
+ * <ul>
98
+ * <li><code>true</code> (from `isPermitted`)</li>
99
+ * <li><code>false</code> (from `isPermitted`)</li>
100
+ * <li><code>undefined</code> (from `Promise.race`)</li>
101
+ * </ul>
102
+ *
103
+ * @private
104
+ * @param {boolean|undefined} value - Determines if notification permissible.
105
+ * @returns {Promise<undefined>} Notification can proceed
106
+ */
107
+ function canNotify(value) {
108
+ if (!value) {
109
+ var why = value === false ? 'blocked' : 'unacknowledged';
110
+ var reason = 'not permitted by user (' + why + ')';
111
+ return Promise.reject(new Error(reason));
112
+ }
113
+ return Promise.resolve();
114
+ }
115
+
116
+ /**
117
+ * Displays the notification.
118
+ *
119
+ * @private
120
+ * @param {Runner} runner - Runner instance.
121
+ */
122
+ function display(runner) {
123
+ var stats = runner.stats;
124
+ var symbol = {
125
+ cross: '\u274C',
126
+ tick: '\u2705'
127
+ };
128
+ var logo = require('../../package.json').notifyLogo;
129
+ var _message;
130
+ var message;
131
+ var title;
132
+
133
+ if (stats.failures) {
134
+ _message = stats.failures + ' of ' + stats.tests + ' tests failed';
135
+ message = symbol.cross + ' ' + _message;
136
+ title = 'Failed';
137
+ } else {
138
+ _message = stats.passes + ' tests passed in ' + stats.duration + 'ms';
139
+ message = symbol.tick + ' ' + _message;
140
+ title = 'Passed';
141
+ }
142
+
143
+ // Send notification
144
+ var options = {
145
+ badge: logo,
146
+ body: message,
147
+ dir: 'ltr',
148
+ icon: logo,
149
+ lang: 'en-US',
150
+ name: 'mocha',
151
+ requireInteraction: false,
152
+ timestamp: Date.now()
153
+ };
154
+ var notification = new Notification(title, options);
155
+
156
+ // Autoclose after brief delay (makes various browsers act same)
157
+ var FORCE_DURATION = 4000;
158
+ setTimeout(notification.close.bind(notification), FORCE_DURATION);
159
+ }
160
+
161
+ /**
162
+ * As notifications are tangential to our purpose, just log the error.
163
+ *
164
+ * @private
165
+ * @param {Error} err - Why notification didn't happen.
166
+ */
167
+ function notPermitted(err) {
168
+ console.error('notification error:', err.message);
169
+ }
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Highlight the given string of `js`.
5
+ *
6
+ * @private
7
+ * @param {string} js
8
+ * @return {string}
9
+ */
10
+ function highlight(js) {
11
+ return js
12
+ .replace(/</g, '&lt;')
13
+ .replace(/>/g, '&gt;')
14
+ .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
15
+ .replace(/('.*?')/gm, '<span class="string">$1</span>')
16
+ .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
17
+ .replace(/(\d+)/gm, '<span class="number">$1</span>')
18
+ .replace(
19
+ /\bnew[ \t]+(\w+)/gm,
20
+ '<span class="keyword">new</span> <span class="init">$1</span>'
21
+ )
22
+ .replace(
23
+ /\b(function|new|throw|return|var|if|else)\b/gm,
24
+ '<span class="keyword">$1</span>'
25
+ );
26
+ }
27
+
28
+ /**
29
+ * Highlight the contents of tag `name`.
30
+ *
31
+ * @private
32
+ * @param {string} name
33
+ */
34
+ module.exports = function highlightTags(name) {
35
+ var code = document.getElementById('mocha').getElementsByTagName(name);
36
+ for (var i = 0, len = code.length; i < len; ++i) {
37
+ code[i].innerHTML = highlight(code[i].innerHTML);
38
+ }
39
+ };