mirror of
https://github.com/LukeHagar/plex-api-oauth.git
synced 2025-12-09 20:47:44 +00:00
Big Boy Updates
This commit is contained in:
22
node_modules/mocha/LICENSE
generated
vendored
Normal file
22
node_modules/mocha/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011-2022 OpenJS Foundation and contributors, https://openjsf.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
70
node_modules/mocha/README.md
generated
vendored
Normal file
70
node_modules/mocha/README.md
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<p align="center">
|
||||
<img src="https://cldup.com/xFVFxOioAU.svg" alt="Mocha test framework"/>
|
||||
</p>
|
||||
|
||||
<p align="center">☕️ Simple, flexible, fun JavaScript test framework for Node.js & The Browser ☕️</p>
|
||||
|
||||
<p align="center">
|
||||
<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>
|
||||
<a href="https://coveralls.io/github/mochajs/mocha"><img src="https://coveralls.io/repos/github/mochajs/mocha/badge.svg" alt="Coverage Status"></a>
|
||||
<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>
|
||||
<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>
|
||||
<a href="https://github.com/mochajs/mocha#sponsors"><img src="https://opencollective.com/mochajs/tiers/sponsors/badge.svg" alt="OpenCollective"></a>
|
||||
<a href="https://github.com/mochajs/mocha#backers"><img src="https://opencollective.com/mochajs/tiers/backers/badge.svg" alt="OpenCollective"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/mocha"><img src="https://img.shields.io/npm/v/mocha.svg" alt="NPM Version"></a>
|
||||
<a href="https://github.com/mochajs/mocha"><img src="https://img.shields.io/node/v/mocha.svg" alt="Node Version"></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><br><img alt="Mocha Browser Support h/t SauceLabs" src="https://saucelabs.com/browser-matrix/mochajs.svg" width="354"></p>
|
||||
|
||||
## Links
|
||||
|
||||
- **[Documentation](https://mochajs.org/)**
|
||||
- **[Release Notes / History / Changes](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)**
|
||||
- [Code of Conduct](https://github.com/mochajs/mocha/blob/master/.github/CODE_OF_CONDUCT.md)
|
||||
- [Contributing](https://github.com/mochajs/mocha/blob/master/.github/CONTRIBUTING.md)
|
||||
- [Gitter Chatroom](https://gitter.im/mochajs/mocha) (ask questions here!)
|
||||
- [Issue Tracker](https://github.com/mochajs/mocha/issues)
|
||||
|
||||
## Backers
|
||||
|
||||
[Become a backer](https://opencollective.com/mochajs) and show your support to our open source project on [our site](https://mochajs.org/#backers).
|
||||
|
||||
<a href="https://opencollective.com/mochajs"><img src="https://opencollective.com/mochajs/tiers/backers.svg?limit=30&button=false&avatarHeight=46&width=750"></a>
|
||||
|
||||
## Sponsors
|
||||
|
||||
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).
|
||||
|
||||
[](https://opencollective.com/mochajs/tiers/sponsors/0/website)
|
||||
[](https://opencollective.com/mochajs/tiers/sponsors/1/website)
|
||||
[](https://opencollective.com/mochajs/tiers/sponsors/2/website)
|
||||
[](https://opencollective.com/mochajs/tiers/sponsors/3/website)
|
||||
|
||||
## Development
|
||||
|
||||
You might want to know that:
|
||||
|
||||
- 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
|
||||
- Mocha is an _independent_ open-source project, maintained exclusively by volunteers.
|
||||
|
||||
You might want to help:
|
||||
|
||||
- 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)
|
||||
- Mocha could use a hand with [these issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
|
||||
- The [maintainer's handbook](https://github.com/mochajs/mocha/blob/master/MAINTAINERS.md) explains how things get done
|
||||
|
||||
Finally, come [chat with the maintainers](https://gitter.im/mochajs/contributors) on Gitter if you want to help with:
|
||||
|
||||
- Triaging issues, answering questions
|
||||
- Review, merging, and closing pull requests
|
||||
- Other project-maintenance-y things
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2011-2022 OpenJS Foundation and contributors. Licensed [MIT](https://github.com/mochajs/mocha/blob/master/LICENSE).
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha?ref=badge_large)
|
||||
10
node_modules/mocha/bin/_mocha
generated
vendored
Executable file
10
node_modules/mocha/bin/_mocha
generated
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This file remains for backwards compatibility only.
|
||||
* Don't put stuff in this file.
|
||||
* @see module:lib/cli
|
||||
*/
|
||||
|
||||
require('../lib/cli').main();
|
||||
142
node_modules/mocha/bin/mocha.js
generated
vendored
Executable file
142
node_modules/mocha/bin/mocha.js
generated
vendored
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This wrapper executable checks for known node flags and appends them when found,
|
||||
* before invoking the "real" executable (`lib/cli/cli.js`)
|
||||
*
|
||||
* @module bin/mocha
|
||||
* @private
|
||||
*/
|
||||
|
||||
const {loadOptions} = require('../lib/cli/options');
|
||||
const {
|
||||
unparseNodeFlags,
|
||||
isNodeFlag,
|
||||
impliesNoTimeouts
|
||||
} = require('../lib/cli/node-flags');
|
||||
const unparse = require('yargs-unparser');
|
||||
const debug = require('debug')('mocha:cli:mocha');
|
||||
const {aliases} = require('../lib/cli/run-option-metadata');
|
||||
|
||||
const mochaArgs = {};
|
||||
const nodeArgs = {};
|
||||
let hasInspect = false;
|
||||
|
||||
const opts = loadOptions(process.argv.slice(2));
|
||||
debug('loaded opts', opts);
|
||||
|
||||
/**
|
||||
* Given option/command `value`, disable timeouts if applicable
|
||||
* @param {string} [value] - Value to check
|
||||
* @ignore
|
||||
*/
|
||||
const disableTimeouts = value => {
|
||||
if (impliesNoTimeouts(value)) {
|
||||
debug('option %s disabled timeouts', value);
|
||||
mochaArgs.timeout = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If `value` begins with `v8-` and is not explicitly `v8-options`, remove prefix
|
||||
* @param {string} [value] - Value to check
|
||||
* @returns {string} `value` with prefix (maybe) removed
|
||||
* @ignore
|
||||
*/
|
||||
const trimV8Option = value =>
|
||||
value !== 'v8-options' && /^v8-/.test(value) ? value.slice(3) : value;
|
||||
|
||||
// sort options into "node" and "mocha" buckets
|
||||
Object.keys(opts).forEach(opt => {
|
||||
if (isNodeFlag(opt)) {
|
||||
nodeArgs[trimV8Option(opt)] = opts[opt];
|
||||
} else {
|
||||
mochaArgs[opt] = opts[opt];
|
||||
}
|
||||
});
|
||||
|
||||
// disable 'timeout' for debugFlags
|
||||
Object.keys(nodeArgs).forEach(opt => disableTimeouts(opt));
|
||||
mochaArgs['node-option'] &&
|
||||
mochaArgs['node-option'].forEach(opt => disableTimeouts(opt));
|
||||
|
||||
// Native debugger handling
|
||||
// see https://nodejs.org/api/debugger.html#debugger_debugger
|
||||
// look for 'inspect' that would launch this debugger,
|
||||
// remove it from Mocha's opts and prepend it to Node's opts.
|
||||
// A deprecation warning will be printed by node, if applicable.
|
||||
// (mochaArgs._ are "positional" arguments, not prefixed with - or --)
|
||||
if (mochaArgs._) {
|
||||
const i = mochaArgs._.findIndex(val => val === 'inspect');
|
||||
if (i > -1) {
|
||||
mochaArgs._.splice(i, 1);
|
||||
disableTimeouts('inspect');
|
||||
hasInspect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mochaArgs['node-option'] || Object.keys(nodeArgs).length || hasInspect) {
|
||||
const {spawn} = require('child_process');
|
||||
const mochaPath = require.resolve('../lib/cli/cli.js');
|
||||
|
||||
const nodeArgv =
|
||||
(mochaArgs['node-option'] && mochaArgs['node-option'].map(v => '--' + v)) ||
|
||||
unparseNodeFlags(nodeArgs);
|
||||
|
||||
if (hasInspect) nodeArgv.unshift('inspect');
|
||||
delete mochaArgs['node-option'];
|
||||
|
||||
debug('final node argv', nodeArgv);
|
||||
|
||||
const args = [].concat(
|
||||
nodeArgv,
|
||||
mochaPath,
|
||||
unparse(mochaArgs, {alias: aliases})
|
||||
);
|
||||
|
||||
debug(
|
||||
'forking child process via command: %s %s',
|
||||
process.execPath,
|
||||
args.join(' ')
|
||||
);
|
||||
|
||||
const proc = spawn(process.execPath, args, {
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
proc.on('exit', (code, signal) => {
|
||||
process.on('exit', () => {
|
||||
if (signal) {
|
||||
process.kill(process.pid, signal);
|
||||
} else {
|
||||
process.exit(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// terminate children.
|
||||
process.on('SIGINT', () => {
|
||||
// XXX: a previous comment said this would abort the runner, but I can't see that it does
|
||||
// anything with the default runner.
|
||||
debug('main process caught SIGINT');
|
||||
proc.kill('SIGINT');
|
||||
// if running in parallel mode, we will have a proper SIGINT handler, so the below won't
|
||||
// be needed.
|
||||
if (!args.parallel || args.jobs < 2) {
|
||||
// win32 does not support SIGTERM, so use next best thing.
|
||||
if (require('os').platform() === 'win32') {
|
||||
proc.kill('SIGKILL');
|
||||
} else {
|
||||
// using SIGKILL won't cleanly close the output streams, which can result
|
||||
// in cut-off text or a befouled terminal.
|
||||
debug('sending SIGTERM to child process');
|
||||
proc.kill('SIGTERM');
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
debug('running Mocha in-process');
|
||||
require('../lib/cli/cli').main([], mochaArgs);
|
||||
}
|
||||
226
node_modules/mocha/browser-entry.js
generated
vendored
Normal file
226
node_modules/mocha/browser-entry.js
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint no-unused-vars: off */
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/**
|
||||
* Shim process.stdout.
|
||||
*/
|
||||
|
||||
process.stdout = require('browser-stdout')({label: false});
|
||||
|
||||
var parseQuery = require('./lib/browser/parse-query');
|
||||
var highlightTags = require('./lib/browser/highlight-tags');
|
||||
var Mocha = require('./lib/mocha');
|
||||
|
||||
/**
|
||||
* Create a Mocha instance.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
|
||||
var mocha = new Mocha({reporter: 'html'});
|
||||
|
||||
/**
|
||||
* Save timer references to avoid Sinon interfering (see GH-237).
|
||||
*/
|
||||
|
||||
var Date = global.Date;
|
||||
var setTimeout = global.setTimeout;
|
||||
var setInterval = global.setInterval;
|
||||
var clearTimeout = global.clearTimeout;
|
||||
var clearInterval = global.clearInterval;
|
||||
|
||||
var uncaughtExceptionHandlers = [];
|
||||
|
||||
var originalOnerrorHandler = global.onerror;
|
||||
|
||||
/**
|
||||
* Remove uncaughtException listener.
|
||||
* Revert to original onerror handler if previously defined.
|
||||
*/
|
||||
|
||||
process.removeListener = function (e, fn) {
|
||||
if (e === 'uncaughtException') {
|
||||
if (originalOnerrorHandler) {
|
||||
global.onerror = originalOnerrorHandler;
|
||||
} else {
|
||||
global.onerror = function () {};
|
||||
}
|
||||
var i = uncaughtExceptionHandlers.indexOf(fn);
|
||||
if (i !== -1) {
|
||||
uncaughtExceptionHandlers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements listenerCount for 'uncaughtException'.
|
||||
*/
|
||||
|
||||
process.listenerCount = function (name) {
|
||||
if (name === 'uncaughtException') {
|
||||
return uncaughtExceptionHandlers.length;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements uncaughtException listener.
|
||||
*/
|
||||
|
||||
process.on = function (e, fn) {
|
||||
if (e === 'uncaughtException') {
|
||||
global.onerror = function (err, url, line) {
|
||||
fn(new Error(err + ' (' + url + ':' + line + ')'));
|
||||
return !mocha.options.allowUncaught;
|
||||
};
|
||||
uncaughtExceptionHandlers.push(fn);
|
||||
}
|
||||
};
|
||||
|
||||
process.listeners = function (e) {
|
||||
if (e === 'uncaughtException') {
|
||||
return uncaughtExceptionHandlers;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
// The BDD UI is registered by default, but no UI will be functional in the
|
||||
// browser without an explicit call to the overridden `mocha.ui` (see below).
|
||||
// Ensure that this default UI does not expose its methods to the global scope.
|
||||
mocha.suite.removeAllListeners('pre-require');
|
||||
|
||||
var immediateQueue = [];
|
||||
var immediateTimeout;
|
||||
|
||||
function timeslice() {
|
||||
var immediateStart = new Date().getTime();
|
||||
while (immediateQueue.length && new Date().getTime() - immediateStart < 100) {
|
||||
immediateQueue.shift()();
|
||||
}
|
||||
if (immediateQueue.length) {
|
||||
immediateTimeout = setTimeout(timeslice, 0);
|
||||
} else {
|
||||
immediateTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* High-performance override of Runner.immediately.
|
||||
*/
|
||||
|
||||
Mocha.Runner.immediately = function (callback) {
|
||||
immediateQueue.push(callback);
|
||||
if (!immediateTimeout) {
|
||||
immediateTimeout = setTimeout(timeslice, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to allow assertion libraries to throw errors directly into mocha.
|
||||
* This is useful when running tests in a browser because window.onerror will
|
||||
* only receive the 'message' attribute of the Error.
|
||||
*/
|
||||
mocha.throwError = function (err) {
|
||||
uncaughtExceptionHandlers.forEach(function (fn) {
|
||||
fn(err);
|
||||
});
|
||||
throw err;
|
||||
};
|
||||
|
||||
/**
|
||||
* Override ui to ensure that the ui functions are initialized.
|
||||
* Normally this would happen in Mocha.prototype.loadFiles.
|
||||
*/
|
||||
|
||||
mocha.ui = function (ui) {
|
||||
Mocha.prototype.ui.call(this, ui);
|
||||
this.suite.emit('pre-require', global, null, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup mocha with the given setting options.
|
||||
*/
|
||||
|
||||
mocha.setup = function (opts) {
|
||||
if (typeof opts === 'string') {
|
||||
opts = {ui: opts};
|
||||
}
|
||||
if (opts.delay === true) {
|
||||
this.delay();
|
||||
}
|
||||
var self = this;
|
||||
Object.keys(opts)
|
||||
.filter(function (opt) {
|
||||
return opt !== 'delay';
|
||||
})
|
||||
.forEach(function (opt) {
|
||||
if (Object.prototype.hasOwnProperty.call(opts, opt)) {
|
||||
self[opt](opts[opt]);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run mocha, returning the Runner.
|
||||
*/
|
||||
|
||||
mocha.run = function (fn) {
|
||||
var options = mocha.options;
|
||||
mocha.globals('location');
|
||||
|
||||
var query = parseQuery(global.location.search || '');
|
||||
if (query.grep) {
|
||||
mocha.grep(query.grep);
|
||||
}
|
||||
if (query.fgrep) {
|
||||
mocha.fgrep(query.fgrep);
|
||||
}
|
||||
if (query.invert) {
|
||||
mocha.invert();
|
||||
}
|
||||
|
||||
return Mocha.prototype.run.call(mocha, function (err) {
|
||||
// The DOM Document is not available in Web Workers.
|
||||
var document = global.document;
|
||||
if (
|
||||
document &&
|
||||
document.getElementById('mocha') &&
|
||||
options.noHighlighting !== true
|
||||
) {
|
||||
highlightTags('code');
|
||||
}
|
||||
if (fn) {
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the process shim.
|
||||
* https://github.com/mochajs/mocha/pull/916
|
||||
*/
|
||||
|
||||
Mocha.process = process;
|
||||
|
||||
/**
|
||||
* Expose mocha.
|
||||
*/
|
||||
global.Mocha = Mocha;
|
||||
global.mocha = mocha;
|
||||
|
||||
// for bundlers: enable `import {describe, it} from 'mocha'`
|
||||
// `bdd` interface only
|
||||
// prettier-ignore
|
||||
[
|
||||
'describe', 'context', 'it', 'specify',
|
||||
'xdescribe', 'xcontext', 'xit', 'xspecify',
|
||||
'before', 'beforeEach', 'afterEach', 'after'
|
||||
].forEach(function(key) {
|
||||
mocha[key] = global[key];
|
||||
});
|
||||
|
||||
module.exports = mocha;
|
||||
3
node_modules/mocha/index.js
generated
vendored
Normal file
3
node_modules/mocha/index.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./lib/mocha');
|
||||
39
node_modules/mocha/lib/browser/highlight-tags.js
generated
vendored
Normal file
39
node_modules/mocha/lib/browser/highlight-tags.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Highlight the given string of `js`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} js
|
||||
* @return {string}
|
||||
*/
|
||||
function highlight(js) {
|
||||
return js
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
|
||||
.replace(/('.*?')/gm, '<span class="string">$1</span>')
|
||||
.replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
|
||||
.replace(/(\d+)/gm, '<span class="number">$1</span>')
|
||||
.replace(
|
||||
/\bnew[ \t]+(\w+)/gm,
|
||||
'<span class="keyword">new</span> <span class="init">$1</span>'
|
||||
)
|
||||
.replace(
|
||||
/\b(function|new|throw|return|var|if|else)\b/gm,
|
||||
'<span class="keyword">$1</span>'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight the contents of tag `name`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} name
|
||||
*/
|
||||
module.exports = function highlightTags(name) {
|
||||
var code = document.getElementById('mocha').getElementsByTagName(name);
|
||||
for (var i = 0, len = code.length; i < len; ++i) {
|
||||
code[i].innerHTML = highlight(code[i].innerHTML);
|
||||
}
|
||||
};
|
||||
24
node_modules/mocha/lib/browser/parse-query.js
generated
vendored
Normal file
24
node_modules/mocha/lib/browser/parse-query.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Parse the given `qs`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} qs
|
||||
* @return {Object<string, string>}
|
||||
*/
|
||||
module.exports = function parseQuery(qs) {
|
||||
return qs
|
||||
.replace('?', '')
|
||||
.split('&')
|
||||
.reduce(function (obj, pair) {
|
||||
var i = pair.indexOf('=');
|
||||
var key = pair.slice(0, i);
|
||||
var val = pair.slice(++i);
|
||||
|
||||
// Due to how the URLSearchParams API treats spaces
|
||||
obj[key] = decodeURIComponent(val.replace(/\+/g, '%20'));
|
||||
|
||||
return obj;
|
||||
}, {});
|
||||
};
|
||||
123
node_modules/mocha/lib/browser/progress.js
generated
vendored
Normal file
123
node_modules/mocha/lib/browser/progress.js
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@module browser/Progress
|
||||
*/
|
||||
|
||||
/**
|
||||
* Expose `Progress`.
|
||||
*/
|
||||
|
||||
module.exports = Progress;
|
||||
|
||||
/**
|
||||
* Initialize a new `Progress` indicator.
|
||||
*/
|
||||
function Progress() {
|
||||
this.percent = 0;
|
||||
this.size(0);
|
||||
this.fontSize(11);
|
||||
this.font('helvetica, arial, sans-serif');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set progress size to `size`.
|
||||
*
|
||||
* @public
|
||||
* @param {number} size
|
||||
* @return {Progress} Progress instance.
|
||||
*/
|
||||
Progress.prototype.size = function (size) {
|
||||
this._size = size;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set text to `text`.
|
||||
*
|
||||
* @public
|
||||
* @param {string} text
|
||||
* @return {Progress} Progress instance.
|
||||
*/
|
||||
Progress.prototype.text = function (text) {
|
||||
this._text = text;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set font size to `size`.
|
||||
*
|
||||
* @public
|
||||
* @param {number} size
|
||||
* @return {Progress} Progress instance.
|
||||
*/
|
||||
Progress.prototype.fontSize = function (size) {
|
||||
this._fontSize = size;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set font to `family`.
|
||||
*
|
||||
* @param {string} family
|
||||
* @return {Progress} Progress instance.
|
||||
*/
|
||||
Progress.prototype.font = function (family) {
|
||||
this._font = family;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update percentage to `n`.
|
||||
*
|
||||
* @param {number} n
|
||||
* @return {Progress} Progress instance.
|
||||
*/
|
||||
Progress.prototype.update = function (n) {
|
||||
this.percent = n;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw on `ctx`.
|
||||
*
|
||||
* @param {CanvasRenderingContext2d} ctx
|
||||
* @return {Progress} Progress instance.
|
||||
*/
|
||||
Progress.prototype.draw = function (ctx) {
|
||||
try {
|
||||
var percent = Math.min(this.percent, 100);
|
||||
var size = this._size;
|
||||
var half = size / 2;
|
||||
var x = half;
|
||||
var y = half;
|
||||
var rad = half - 1;
|
||||
var fontSize = this._fontSize;
|
||||
|
||||
ctx.font = fontSize + 'px ' + this._font;
|
||||
|
||||
var angle = Math.PI * 2 * (percent / 100);
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
|
||||
// outer circle
|
||||
ctx.strokeStyle = '#9f9f9f';
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, rad, 0, angle, false);
|
||||
ctx.stroke();
|
||||
|
||||
// inner circle
|
||||
ctx.strokeStyle = '#eee';
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, rad - 1, 0, angle, true);
|
||||
ctx.stroke();
|
||||
|
||||
// text
|
||||
var text = this._text || (percent | 0) + '%';
|
||||
var w = ctx.measureText(text).width;
|
||||
|
||||
ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1);
|
||||
} catch (ignore) {
|
||||
// don't fail if we can't render progress
|
||||
}
|
||||
return this;
|
||||
};
|
||||
20
node_modules/mocha/lib/browser/template.html
generated
vendored
Normal file
20
node_modules/mocha/lib/browser/template.html
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Mocha</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="mocha.js"></script>
|
||||
<script>
|
||||
mocha.setup('bdd');
|
||||
</script>
|
||||
<script src="tests.spec.js"></script>
|
||||
<script>
|
||||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
89
node_modules/mocha/lib/cli/cli.js
generated
vendored
Executable file
89
node_modules/mocha/lib/cli/cli.js
generated
vendored
Executable file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Contains CLI entry point and public API for programmatic usage in Node.js.
|
||||
* - Option parsing is handled by {@link https://npm.im/yargs yargs}.
|
||||
* - If executed via `node`, this module will run {@linkcode module:lib/cli.main main()}.
|
||||
* @public
|
||||
* @module lib/cli
|
||||
*/
|
||||
|
||||
const debug = require('debug')('mocha:cli:cli');
|
||||
const symbols = require('log-symbols');
|
||||
const yargs = require('yargs/yargs');
|
||||
const path = require('path');
|
||||
const {
|
||||
loadRc,
|
||||
loadPkgRc,
|
||||
loadOptions,
|
||||
YARGS_PARSER_CONFIG
|
||||
} = require('./options');
|
||||
const lookupFiles = require('./lookup-files');
|
||||
const commands = require('./commands');
|
||||
const ansi = require('ansi-colors');
|
||||
const {repository, homepage, version, gitter} = require('../../package.json');
|
||||
const {cwd} = require('../utils');
|
||||
|
||||
/**
|
||||
* - Accepts an `Array` of arguments
|
||||
* - Modifies {@link https://nodejs.org/api/modules.html#modules_module_paths Node.js' search path} for easy loading of consumer modules
|
||||
* - Sets {@linkcode https://nodejs.org/api/errors.html#errors_error_stacktracelimit Error.stackTraceLimit} to `Infinity`
|
||||
* @public
|
||||
* @summary Mocha's main command-line entry-point.
|
||||
* @param {string[]} argv - Array of arguments to parse, or by default the lovely `process.argv.slice(2)`
|
||||
* @param {object} [mochaArgs] - Object of already parsed Mocha arguments (by bin/mocha)
|
||||
*/
|
||||
exports.main = (argv = process.argv.slice(2), mochaArgs) => {
|
||||
debug('entered main with raw args', argv);
|
||||
// ensure we can require() from current working directory
|
||||
if (typeof module.paths !== 'undefined') {
|
||||
module.paths.push(cwd(), path.resolve('node_modules'));
|
||||
}
|
||||
|
||||
Error.stackTraceLimit = Infinity; // configurable via --stack-trace-limit?
|
||||
|
||||
var args = mochaArgs || loadOptions(argv);
|
||||
|
||||
yargs()
|
||||
.scriptName('mocha')
|
||||
.command(commands.run)
|
||||
.command(commands.init)
|
||||
.updateStrings({
|
||||
'Positionals:': 'Positional Arguments',
|
||||
'Options:': 'Other Options',
|
||||
'Commands:': 'Commands'
|
||||
})
|
||||
.fail((msg, err, yargs) => {
|
||||
debug('caught error sometime before command handler: %O', err);
|
||||
yargs.showHelp();
|
||||
console.error(`\n${symbols.error} ${ansi.red('ERROR:')} ${msg}`);
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.help('help', 'Show usage information & exit')
|
||||
.alias('help', 'h')
|
||||
.version('version', 'Show version number & exit', version)
|
||||
.alias('version', 'V')
|
||||
.wrap(process.stdout.columns ? Math.min(process.stdout.columns, 80) : 80)
|
||||
.epilog(
|
||||
`Mocha Resources
|
||||
Chat: ${ansi.magenta(gitter)}
|
||||
GitHub: ${ansi.blue(repository.url)}
|
||||
Docs: ${ansi.yellow(homepage)}
|
||||
`
|
||||
)
|
||||
.parserConfiguration(YARGS_PARSER_CONFIG)
|
||||
.config(args)
|
||||
.parse(args._);
|
||||
};
|
||||
|
||||
exports.lookupFiles = lookupFiles;
|
||||
exports.loadOptions = loadOptions;
|
||||
exports.loadPkgRc = loadPkgRc;
|
||||
exports.loadRc = loadRc;
|
||||
|
||||
// allow direct execution
|
||||
if (require.main === module) {
|
||||
exports.main();
|
||||
}
|
||||
92
node_modules/mocha/lib/cli/collect-files.js
generated
vendored
Normal file
92
node_modules/mocha/lib/cli/collect-files.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const ansi = require('ansi-colors');
|
||||
const debug = require('debug')('mocha:cli:run:helpers');
|
||||
const minimatch = require('minimatch');
|
||||
const {NO_FILES_MATCH_PATTERN} = require('../errors').constants;
|
||||
const lookupFiles = require('./lookup-files');
|
||||
const {castArray} = require('../utils');
|
||||
|
||||
/**
|
||||
* Exports a function that collects test files from CLI parameters.
|
||||
* @see module:lib/cli/run-helpers
|
||||
* @see module:lib/cli/watch-run
|
||||
* @module
|
||||
* @private
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smash together an array of test files in the correct order
|
||||
* @param {FileCollectionOptions} [opts] - Options
|
||||
* @returns {string[]} List of files to test
|
||||
* @private
|
||||
*/
|
||||
module.exports = ({
|
||||
ignore,
|
||||
extension,
|
||||
file: fileArgs,
|
||||
recursive,
|
||||
sort,
|
||||
spec
|
||||
} = {}) => {
|
||||
const unmatched = [];
|
||||
const specFiles = spec.reduce((specFiles, arg) => {
|
||||
try {
|
||||
const moreSpecFiles = castArray(lookupFiles(arg, extension, recursive))
|
||||
.filter(filename =>
|
||||
ignore.every(pattern => !minimatch(filename, pattern))
|
||||
)
|
||||
.map(filename => path.resolve(filename));
|
||||
return [...specFiles, ...moreSpecFiles];
|
||||
} catch (err) {
|
||||
if (err.code === NO_FILES_MATCH_PATTERN) {
|
||||
unmatched.push({message: err.message, pattern: err.pattern});
|
||||
return specFiles;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// ensure we don't sort the stuff from fileArgs; order is important!
|
||||
if (sort) {
|
||||
specFiles.sort();
|
||||
}
|
||||
|
||||
// add files given through --file to be ran first
|
||||
const files = [
|
||||
...fileArgs.map(filepath => path.resolve(filepath)),
|
||||
...specFiles
|
||||
];
|
||||
debug('test files (in order): ', files);
|
||||
|
||||
if (!files.length) {
|
||||
// give full message details when only 1 file is missing
|
||||
const noneFoundMsg =
|
||||
unmatched.length === 1
|
||||
? `Error: No test files found: ${JSON.stringify(unmatched[0].pattern)}` // stringify to print escaped characters raw
|
||||
: 'Error: No test files found';
|
||||
console.error(ansi.red(noneFoundMsg));
|
||||
process.exit(1);
|
||||
} else {
|
||||
// print messages as a warning
|
||||
unmatched.forEach(warning => {
|
||||
console.warn(ansi.yellow(`Warning: ${warning.message}`));
|
||||
});
|
||||
}
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
/**
|
||||
* An object to configure how Mocha gathers test files
|
||||
* @private
|
||||
* @typedef {Object} FileCollectionOptions
|
||||
* @property {string[]} extension - File extensions to use
|
||||
* @property {string[]} spec - Files, dirs, globs to run
|
||||
* @property {string[]} ignore - Files, dirs, globs to ignore
|
||||
* @property {string[]} file - List of additional files to include
|
||||
* @property {boolean} recursive - Find files recursively
|
||||
* @property {boolean} sort - Sort test files
|
||||
*/
|
||||
13
node_modules/mocha/lib/cli/commands.js
generated
vendored
Normal file
13
node_modules/mocha/lib/cli/commands.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Exports Yargs commands
|
||||
* @see https://github.com/yargs/yargs/blob/main/docs/advanced.md
|
||||
* @private
|
||||
* @module
|
||||
*/
|
||||
|
||||
exports.init = require('./init');
|
||||
|
||||
// default command
|
||||
exports.run = require('./run');
|
||||
100
node_modules/mocha/lib/cli/config.js
generated
vendored
Normal file
100
node_modules/mocha/lib/cli/config.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Responsible for loading / finding Mocha's "rc" files.
|
||||
*
|
||||
* @private
|
||||
* @module
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const debug = require('debug')('mocha:cli:config');
|
||||
const findUp = require('find-up');
|
||||
const {createUnparsableFileError} = require('../errors');
|
||||
const utils = require('../utils');
|
||||
|
||||
/**
|
||||
* These are the valid config files, in order of precedence;
|
||||
* e.g., if `.mocharc.js` is present, then `.mocharc.yaml` and the rest
|
||||
* will be ignored.
|
||||
* The user should still be able to explicitly specify a file.
|
||||
* @private
|
||||
*/
|
||||
exports.CONFIG_FILES = [
|
||||
'.mocharc.cjs',
|
||||
'.mocharc.js',
|
||||
'.mocharc.yaml',
|
||||
'.mocharc.yml',
|
||||
'.mocharc.jsonc',
|
||||
'.mocharc.json'
|
||||
];
|
||||
|
||||
/**
|
||||
* Parsers for various config filetypes. Each accepts a filepath and
|
||||
* returns an object (but could throw)
|
||||
*/
|
||||
const parsers = (exports.parsers = {
|
||||
yaml: filepath => require('js-yaml').load(fs.readFileSync(filepath, 'utf8')),
|
||||
js: filepath => {
|
||||
let cwdFilepath;
|
||||
try {
|
||||
debug('parsers: load cwd-relative path: "%s"', path.resolve(filepath));
|
||||
cwdFilepath = require.resolve(path.resolve(filepath)); // evtl. throws
|
||||
return require(cwdFilepath);
|
||||
} catch (err) {
|
||||
if (cwdFilepath) throw err;
|
||||
|
||||
debug('parsers: retry load as module-relative path: "%s"', filepath);
|
||||
return require(filepath);
|
||||
}
|
||||
},
|
||||
json: filepath =>
|
||||
JSON.parse(
|
||||
require('strip-json-comments')(fs.readFileSync(filepath, 'utf8'))
|
||||
)
|
||||
});
|
||||
|
||||
/**
|
||||
* Loads and parses, based on file extension, a config file.
|
||||
* "JSON" files may have comments.
|
||||
*
|
||||
* @private
|
||||
* @param {string} filepath - Config file path to load
|
||||
* @returns {Object} Parsed config object
|
||||
*/
|
||||
exports.loadConfig = filepath => {
|
||||
let config = {};
|
||||
debug('loadConfig: trying to parse config at %s', filepath);
|
||||
|
||||
const ext = path.extname(filepath);
|
||||
try {
|
||||
if (ext === '.yml' || ext === '.yaml') {
|
||||
config = parsers.yaml(filepath);
|
||||
} else if (ext === '.js' || ext === '.cjs') {
|
||||
config = parsers.js(filepath);
|
||||
} else {
|
||||
config = parsers.json(filepath);
|
||||
}
|
||||
} catch (err) {
|
||||
throw createUnparsableFileError(
|
||||
`Unable to read/parse ${filepath}: ${err}`,
|
||||
filepath
|
||||
);
|
||||
}
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find ("find up") config file starting at `cwd`
|
||||
*
|
||||
* @param {string} [cwd] - Current working directory
|
||||
* @returns {string|null} Filepath to config, if found
|
||||
*/
|
||||
exports.findConfig = (cwd = utils.cwd()) => {
|
||||
const filepath = findUp.sync(exports.CONFIG_FILES, {cwd});
|
||||
if (filepath) {
|
||||
debug('findConfig: found config file %s', filepath);
|
||||
}
|
||||
return filepath;
|
||||
};
|
||||
3
node_modules/mocha/lib/cli/index.js
generated
vendored
Normal file
3
node_modules/mocha/lib/cli/index.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./cli');
|
||||
36
node_modules/mocha/lib/cli/init.js
generated
vendored
Normal file
36
node_modules/mocha/lib/cli/init.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Command module for "init" command
|
||||
*
|
||||
* @private
|
||||
* @module
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
exports.command = 'init <path>';
|
||||
|
||||
exports.description = 'create a client-side Mocha setup at <path>';
|
||||
|
||||
exports.builder = yargs =>
|
||||
yargs.positional('path', {
|
||||
type: 'string',
|
||||
normalize: true
|
||||
});
|
||||
|
||||
exports.handler = argv => {
|
||||
const destdir = argv.path;
|
||||
const srcdir = path.join(__dirname, '..', '..');
|
||||
fs.mkdirSync(destdir, {recursive: true});
|
||||
const css = fs.readFileSync(path.join(srcdir, 'mocha.css'));
|
||||
const js = fs.readFileSync(path.join(srcdir, 'mocha.js'));
|
||||
const tmpl = fs.readFileSync(
|
||||
path.join(srcdir, 'lib', 'browser', 'template.html')
|
||||
);
|
||||
fs.writeFileSync(path.join(destdir, 'mocha.css'), css);
|
||||
fs.writeFileSync(path.join(destdir, 'mocha.js'), js);
|
||||
fs.writeFileSync(path.join(destdir, 'tests.spec.js'), '');
|
||||
fs.writeFileSync(path.join(destdir, 'index.html'), tmpl);
|
||||
};
|
||||
145
node_modules/mocha/lib/cli/lookup-files.js
generated
vendored
Normal file
145
node_modules/mocha/lib/cli/lookup-files.js
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
'use strict';
|
||||
/**
|
||||
* Contains `lookupFiles`, which takes some globs/dirs/options and returns a list of files.
|
||||
* @module
|
||||
* @private
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var glob = require('glob');
|
||||
var errors = require('../errors');
|
||||
var createNoFilesMatchPatternError = errors.createNoFilesMatchPatternError;
|
||||
var createMissingArgumentError = errors.createMissingArgumentError;
|
||||
const debug = require('debug')('mocha:cli:lookup-files');
|
||||
|
||||
/**
|
||||
* Determines if pathname would be a "hidden" file (or directory) on UN*X.
|
||||
*
|
||||
* @description
|
||||
* On UN*X, pathnames beginning with a full stop (aka dot) are hidden during
|
||||
* typical usage. Dotfiles, plain-text configuration files, are prime examples.
|
||||
*
|
||||
* @see {@link http://xahlee.info/UnixResource_dir/writ/unix_origin_of_dot_filename.html|Origin of Dot File Names}
|
||||
*
|
||||
* @private
|
||||
* @param {string} pathname - Pathname to check for match.
|
||||
* @return {boolean} whether pathname would be considered a hidden file.
|
||||
* @example
|
||||
* isHiddenOnUnix('.profile'); // => true
|
||||
*/
|
||||
const isHiddenOnUnix = pathname => path.basename(pathname).startsWith('.');
|
||||
|
||||
/**
|
||||
* Determines if pathname has a matching file extension.
|
||||
*
|
||||
* Supports multi-part extensions.
|
||||
*
|
||||
* @private
|
||||
* @param {string} pathname - Pathname to check for match.
|
||||
* @param {string[]} exts - List of file extensions, w/-or-w/o leading period
|
||||
* @return {boolean} `true` if file extension matches.
|
||||
* @example
|
||||
* hasMatchingExtname('foo.html', ['js', 'css']); // false
|
||||
* hasMatchingExtname('foo.js', ['.js']); // true
|
||||
* hasMatchingExtname('foo.js', ['js']); // ture
|
||||
*/
|
||||
const hasMatchingExtname = (pathname, exts = []) =>
|
||||
exts
|
||||
.map(ext => (ext.startsWith('.') ? ext : `.${ext}`))
|
||||
.some(ext => pathname.endsWith(ext));
|
||||
|
||||
/**
|
||||
* Lookup file names at the given `path`.
|
||||
*
|
||||
* @description
|
||||
* Filenames are returned in _traversal_ order by the OS/filesystem.
|
||||
* **Make no assumption that the names will be sorted in any fashion.**
|
||||
*
|
||||
* @public
|
||||
* @alias module:lib/cli.lookupFiles
|
||||
* @param {string} filepath - Base path to start searching from.
|
||||
* @param {string[]} [extensions=[]] - File extensions to look for.
|
||||
* @param {boolean} [recursive=false] - Whether to recurse into subdirectories.
|
||||
* @return {string[]} An array of paths.
|
||||
* @throws {Error} if no files match pattern.
|
||||
* @throws {TypeError} if `filepath` is directory and `extensions` not provided.
|
||||
*/
|
||||
module.exports = function lookupFiles(
|
||||
filepath,
|
||||
extensions = [],
|
||||
recursive = false
|
||||
) {
|
||||
const files = [];
|
||||
let stat;
|
||||
|
||||
if (!fs.existsSync(filepath)) {
|
||||
let pattern;
|
||||
if (glob.hasMagic(filepath)) {
|
||||
// Handle glob as is without extensions
|
||||
pattern = filepath;
|
||||
} else {
|
||||
// glob pattern e.g. 'filepath+(.js|.ts)'
|
||||
const strExtensions = extensions
|
||||
.map(ext => (ext.startsWith('.') ? ext : `.${ext}`))
|
||||
.join('|');
|
||||
pattern = `${filepath}+(${strExtensions})`;
|
||||
debug('looking for files using glob pattern: %s', pattern);
|
||||
}
|
||||
files.push(...glob.sync(pattern, {nodir: true}));
|
||||
if (!files.length) {
|
||||
throw createNoFilesMatchPatternError(
|
||||
`Cannot find any files matching pattern "${filepath}"`,
|
||||
filepath
|
||||
);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
// Handle file
|
||||
try {
|
||||
stat = fs.statSync(filepath);
|
||||
if (stat.isFile()) {
|
||||
return filepath;
|
||||
}
|
||||
} catch (err) {
|
||||
// ignore error
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle directory
|
||||
fs.readdirSync(filepath).forEach(dirent => {
|
||||
const pathname = path.join(filepath, dirent);
|
||||
let stat;
|
||||
|
||||
try {
|
||||
stat = fs.statSync(pathname);
|
||||
if (stat.isDirectory()) {
|
||||
if (recursive) {
|
||||
files.push(...lookupFiles(pathname, extensions, recursive));
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (ignored) {
|
||||
return;
|
||||
}
|
||||
if (!extensions.length) {
|
||||
throw createMissingArgumentError(
|
||||
`Argument '${extensions}' required when argument '${filepath}' is a directory`,
|
||||
'extensions',
|
||||
'array'
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!stat.isFile() ||
|
||||
!hasMatchingExtname(pathname, extensions) ||
|
||||
isHiddenOnUnix(pathname)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
files.push(pathname);
|
||||
});
|
||||
|
||||
return files;
|
||||
};
|
||||
85
node_modules/mocha/lib/cli/node-flags.js
generated
vendored
Normal file
85
node_modules/mocha/lib/cli/node-flags.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Some settings and code related to Mocha's handling of Node.js/V8 flags.
|
||||
* @private
|
||||
* @module
|
||||
*/
|
||||
|
||||
const nodeFlags = process.allowedNodeEnvironmentFlags;
|
||||
const {isMochaFlag} = require('./run-option-metadata');
|
||||
const unparse = require('yargs-unparser');
|
||||
|
||||
/**
|
||||
* These flags are considered "debug" flags.
|
||||
* @see {@link impliesNoTimeouts}
|
||||
* @private
|
||||
*/
|
||||
const debugFlags = new Set(['inspect', 'inspect-brk']);
|
||||
|
||||
/**
|
||||
* Mocha has historical support for various `node` and V8 flags which might not
|
||||
* appear in `process.allowedNodeEnvironmentFlags`.
|
||||
* These include:
|
||||
* - `--preserve-symlinks`
|
||||
* - `--harmony-*`
|
||||
* - `--gc-global`
|
||||
* - `--trace-*`
|
||||
* - `--es-staging`
|
||||
* - `--use-strict`
|
||||
* - `--v8-*` (but *not* `--v8-options`)
|
||||
* @summary Whether or not to pass a flag along to the `node` executable.
|
||||
* @param {string} flag - Flag to test
|
||||
* @param {boolean} [bareword=true] - If `false`, we expect `flag` to have one or two leading dashes.
|
||||
* @returns {boolean} If the flag is considered a "Node" flag.
|
||||
* @private
|
||||
*/
|
||||
exports.isNodeFlag = (flag, bareword = true) => {
|
||||
if (!bareword) {
|
||||
// check if the flag begins with dashes; if not, not a node flag.
|
||||
if (!/^--?/.test(flag)) {
|
||||
return false;
|
||||
}
|
||||
// strip the leading dashes to match against subsequent checks
|
||||
flag = flag.replace(/^--?/, '');
|
||||
}
|
||||
return (
|
||||
// check actual node flags from `process.allowedNodeEnvironmentFlags`,
|
||||
// then historical support for various V8 and non-`NODE_OPTIONS` flags
|
||||
// and also any V8 flags with `--v8-` prefix
|
||||
(!isMochaFlag(flag) && nodeFlags && nodeFlags.has(flag)) ||
|
||||
debugFlags.has(flag) ||
|
||||
/(?:preserve-symlinks(?:-main)?|harmony(?:[_-]|$)|(?:trace[_-].+$)|gc[_-]global$|es[_-]staging$|use[_-]strict$|v8[_-](?!options).+?$)/.test(
|
||||
flag
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns `true` if the flag is a "debug-like" flag. These require timeouts
|
||||
* to be suppressed, or pausing the debugger on breakpoints will cause test failures.
|
||||
* @param {string} flag - Flag to test
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
exports.impliesNoTimeouts = flag => debugFlags.has(flag);
|
||||
|
||||
/**
|
||||
* All non-strictly-boolean arguments to node--those with values--must specify those values using `=`, e.g., `--inspect=0.0.0.0`.
|
||||
* Unparse these arguments using `yargs-unparser` (which would result in `--inspect 0.0.0.0`), then supply `=` where we have values.
|
||||
* There's probably an easier or more robust way to do this; fixes welcome
|
||||
* @param {Object} opts - Arguments object
|
||||
* @returns {string[]} Unparsed arguments using `=` to specify values
|
||||
* @private
|
||||
*/
|
||||
exports.unparseNodeFlags = opts => {
|
||||
var args = unparse(opts);
|
||||
return args.length
|
||||
? args
|
||||
.join(' ')
|
||||
.split(/\b/)
|
||||
.map(arg => (arg === ' ' ? '=' : arg))
|
||||
.join('')
|
||||
.split(' ')
|
||||
: [];
|
||||
};
|
||||
69
node_modules/mocha/lib/cli/one-and-dones.js
generated
vendored
Normal file
69
node_modules/mocha/lib/cli/one-and-dones.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Contains "command" code for "one-and-dones"--options passed
|
||||
* to Mocha which cause it to just dump some info and exit.
|
||||
* See {@link module:lib/cli/one-and-dones.ONE_AND_DONE_ARGS ONE_AND_DONE_ARGS} for more info.
|
||||
* @module
|
||||
* @private
|
||||
*/
|
||||
|
||||
const Mocha = require('../mocha');
|
||||
|
||||
/**
|
||||
* Dumps a sorted list of the enumerable, lower-case keys of some object
|
||||
* to `STDOUT`.
|
||||
* @param {Object} obj - Object, ostensibly having some enumerable keys
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const showKeys = obj => {
|
||||
console.log();
|
||||
const keys = Object.keys(obj);
|
||||
const maxKeyLength = keys.reduce((max, key) => Math.max(max, key.length), 0);
|
||||
keys
|
||||
.filter(
|
||||
key => /^[a-z]/.test(key) && !obj[key].browserOnly && !obj[key].abstract
|
||||
)
|
||||
.sort()
|
||||
.forEach(key => {
|
||||
const description = obj[key].description;
|
||||
console.log(
|
||||
` ${key.padEnd(maxKeyLength + 1)}${
|
||||
description ? `- ${description}` : ''
|
||||
}`
|
||||
);
|
||||
});
|
||||
console.log();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handlers for one-and-done options
|
||||
* @namespace
|
||||
* @private
|
||||
*/
|
||||
exports.ONE_AND_DONES = {
|
||||
/**
|
||||
* Dump list of built-in interfaces
|
||||
* @private
|
||||
*/
|
||||
'list-interfaces': () => {
|
||||
showKeys(Mocha.interfaces);
|
||||
},
|
||||
/**
|
||||
* Dump list of built-in reporters
|
||||
* @private
|
||||
*/
|
||||
'list-reporters': () => {
|
||||
showKeys(Mocha.reporters);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A Set of all one-and-done options
|
||||
* @type Set<string>
|
||||
* @private
|
||||
*/
|
||||
exports.ONE_AND_DONE_ARGS = new Set(
|
||||
['help', 'h', 'version', 'V'].concat(Object.keys(exports.ONE_AND_DONES))
|
||||
);
|
||||
261
node_modules/mocha/lib/cli/options.js
generated
vendored
Normal file
261
node_modules/mocha/lib/cli/options.js
generated
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Main entry point for handling filesystem-based configuration,
|
||||
* whether that's a config file or `package.json` or whatever.
|
||||
* @module lib/cli/options
|
||||
* @private
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const ansi = require('ansi-colors');
|
||||
const yargsParser = require('yargs-parser');
|
||||
const {types, aliases} = require('./run-option-metadata');
|
||||
const {ONE_AND_DONE_ARGS} = require('./one-and-dones');
|
||||
const mocharc = require('../mocharc.json');
|
||||
const {list} = require('./run-helpers');
|
||||
const {loadConfig, findConfig} = require('./config');
|
||||
const findUp = require('find-up');
|
||||
const debug = require('debug')('mocha:cli:options');
|
||||
const {isNodeFlag} = require('./node-flags');
|
||||
const {createUnparsableFileError} = require('../errors');
|
||||
|
||||
/**
|
||||
* The `yargs-parser` namespace
|
||||
* @external yargsParser
|
||||
* @see {@link https://npm.im/yargs-parser}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object returned by a configured `yargs-parser` representing arguments
|
||||
* @memberof external:yargsParser
|
||||
* @interface Arguments
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base yargs parser configuration
|
||||
* @private
|
||||
*/
|
||||
const YARGS_PARSER_CONFIG = {
|
||||
'combine-arrays': true,
|
||||
'short-option-groups': false,
|
||||
'dot-notation': false,
|
||||
'strip-aliased': true
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the config pulled from the `yargs` property of Mocha's
|
||||
* `package.json`, but it also disables camel case expansion as to
|
||||
* avoid outputting non-canonical keynames, as we need to do some
|
||||
* lookups.
|
||||
* @private
|
||||
* @ignore
|
||||
*/
|
||||
const configuration = Object.assign({}, YARGS_PARSER_CONFIG, {
|
||||
'camel-case-expansion': false
|
||||
});
|
||||
|
||||
/**
|
||||
* This is a really fancy way to:
|
||||
* - `array`-type options: ensure unique values and evtl. split comma-delimited lists
|
||||
* - `boolean`/`number`/`string`- options: use last element when given multiple times
|
||||
* This is passed as the `coerce` option to `yargs-parser`
|
||||
* @private
|
||||
* @ignore
|
||||
*/
|
||||
const globOptions = ['spec', 'ignore'];
|
||||
const coerceOpts = Object.assign(
|
||||
types.array.reduce(
|
||||
(acc, arg) =>
|
||||
Object.assign(acc, {
|
||||
[arg]: v => Array.from(new Set(globOptions.includes(arg) ? v : list(v)))
|
||||
}),
|
||||
{}
|
||||
),
|
||||
types.boolean
|
||||
.concat(types.string, types.number)
|
||||
.reduce(
|
||||
(acc, arg) =>
|
||||
Object.assign(acc, {[arg]: v => (Array.isArray(v) ? v.pop() : v)}),
|
||||
{}
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* We do not have a case when multiple arguments are ever allowed after a flag
|
||||
* (e.g., `--foo bar baz quux`), so we fix the number of arguments to 1 across
|
||||
* the board of non-boolean options.
|
||||
* This is passed as the `narg` option to `yargs-parser`
|
||||
* @private
|
||||
* @ignore
|
||||
*/
|
||||
const nargOpts = types.array
|
||||
.concat(types.string, types.number)
|
||||
.reduce((acc, arg) => Object.assign(acc, {[arg]: 1}), {});
|
||||
|
||||
/**
|
||||
* Wrapper around `yargs-parser` which applies our settings
|
||||
* @param {string|string[]} args - Arguments to parse
|
||||
* @param {Object} defaultValues - Default values of mocharc.json
|
||||
* @param {...Object} configObjects - `configObjects` for yargs-parser
|
||||
* @private
|
||||
* @ignore
|
||||
*/
|
||||
const parse = (args = [], defaultValues = {}, ...configObjects) => {
|
||||
// save node-specific args for special handling.
|
||||
// 1. when these args have a "=" they should be considered to have values
|
||||
// 2. if they don't, they just boolean flags
|
||||
// 3. to avoid explicitly defining the set of them, we tell yargs-parser they
|
||||
// are ALL boolean flags.
|
||||
// 4. we can then reapply the values after yargs-parser is done.
|
||||
const nodeArgs = (Array.isArray(args) ? args : args.split(' ')).reduce(
|
||||
(acc, arg) => {
|
||||
const pair = arg.split('=');
|
||||
let flag = pair[0];
|
||||
if (isNodeFlag(flag, false)) {
|
||||
flag = flag.replace(/^--?/, '');
|
||||
return arg.includes('=')
|
||||
? acc.concat([[flag, pair[1]]])
|
||||
: acc.concat([[flag, true]]);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const result = yargsParser.detailed(args, {
|
||||
configuration,
|
||||
configObjects,
|
||||
default: defaultValues,
|
||||
coerce: coerceOpts,
|
||||
narg: nargOpts,
|
||||
alias: aliases,
|
||||
string: types.string,
|
||||
array: types.array,
|
||||
number: types.number,
|
||||
boolean: types.boolean.concat(nodeArgs.map(pair => pair[0]))
|
||||
});
|
||||
if (result.error) {
|
||||
console.error(ansi.red(`Error: ${result.error.message}`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// reapply "=" arg values from above
|
||||
nodeArgs.forEach(([key, value]) => {
|
||||
result.argv[key] = value;
|
||||
});
|
||||
|
||||
return result.argv;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given path to config file in `args.config`, attempt to load & parse config file.
|
||||
* @param {Object} [args] - Arguments object
|
||||
* @param {string|boolean} [args.config] - Path to config file or `false` to skip
|
||||
* @public
|
||||
* @alias module:lib/cli.loadRc
|
||||
* @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.config` is `false`
|
||||
*/
|
||||
const loadRc = (args = {}) => {
|
||||
if (args.config !== false) {
|
||||
const config = args.config || findConfig();
|
||||
return config ? loadConfig(config) : {};
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.loadRc = loadRc;
|
||||
|
||||
/**
|
||||
* Given path to `package.json` in `args.package`, attempt to load config from `mocha` prop.
|
||||
* @param {Object} [args] - Arguments object
|
||||
* @param {string|boolean} [args.config] - Path to `package.json` or `false` to skip
|
||||
* @public
|
||||
* @alias module:lib/cli.loadPkgRc
|
||||
* @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.package` is `false`
|
||||
*/
|
||||
const loadPkgRc = (args = {}) => {
|
||||
let result;
|
||||
if (args.package === false) {
|
||||
return result;
|
||||
}
|
||||
result = {};
|
||||
const filepath = args.package || findUp.sync(mocharc.package);
|
||||
if (filepath) {
|
||||
try {
|
||||
const pkg = JSON.parse(fs.readFileSync(filepath, 'utf8'));
|
||||
if (pkg.mocha) {
|
||||
debug('`mocha` prop of package.json parsed: %O', pkg.mocha);
|
||||
result = pkg.mocha;
|
||||
} else {
|
||||
debug('no config found in %s', filepath);
|
||||
}
|
||||
} catch (err) {
|
||||
if (args.package) {
|
||||
throw createUnparsableFileError(
|
||||
`Unable to read/parse ${filepath}: ${err}`,
|
||||
filepath
|
||||
);
|
||||
}
|
||||
debug('failed to read default package.json at %s; ignoring', filepath);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports.loadPkgRc = loadPkgRc;
|
||||
|
||||
/**
|
||||
* Priority list:
|
||||
*
|
||||
* 1. Command-line args
|
||||
* 2. RC file (`.mocharc.c?js`, `.mocharc.ya?ml`, `mocharc.json`)
|
||||
* 3. `mocha` prop of `package.json`
|
||||
* 4. default configuration (`lib/mocharc.json`)
|
||||
*
|
||||
* If a {@link module:lib/cli/one-and-dones.ONE_AND_DONE_ARGS "one-and-done" option} is present in the `argv` array, no external config files will be read.
|
||||
* @summary Parses options read from `.mocharc.*` and `package.json`.
|
||||
* @param {string|string[]} [argv] - Arguments to parse
|
||||
* @public
|
||||
* @alias module:lib/cli.loadOptions
|
||||
* @returns {external:yargsParser.Arguments} Parsed args from everything
|
||||
*/
|
||||
const loadOptions = (argv = []) => {
|
||||
let args = parse(argv);
|
||||
// short-circuit: look for a flag that would abort loading of options
|
||||
if (
|
||||
Array.from(ONE_AND_DONE_ARGS).reduce(
|
||||
(acc, arg) => acc || arg in args,
|
||||
false
|
||||
)
|
||||
) {
|
||||
return args;
|
||||
}
|
||||
|
||||
const rcConfig = loadRc(args);
|
||||
const pkgConfig = loadPkgRc(args);
|
||||
|
||||
if (rcConfig) {
|
||||
args.config = false;
|
||||
args._ = args._.concat(rcConfig._ || []);
|
||||
}
|
||||
if (pkgConfig) {
|
||||
args.package = false;
|
||||
args._ = args._.concat(pkgConfig._ || []);
|
||||
}
|
||||
|
||||
args = parse(args._, mocharc, args, rcConfig || {}, pkgConfig || {});
|
||||
|
||||
// recombine positional arguments and "spec"
|
||||
if (args.spec) {
|
||||
args._ = args._.concat(args.spec);
|
||||
delete args.spec;
|
||||
}
|
||||
|
||||
// make unique
|
||||
args._ = Array.from(new Set(args._));
|
||||
|
||||
return args;
|
||||
};
|
||||
|
||||
module.exports.loadOptions = loadOptions;
|
||||
module.exports.YARGS_PARSER_CONFIG = YARGS_PARSER_CONFIG;
|
||||
243
node_modules/mocha/lib/cli/run-helpers.js
generated
vendored
Normal file
243
node_modules/mocha/lib/cli/run-helpers.js
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Helper scripts for the `run` command
|
||||
* @see module:lib/cli/run
|
||||
* @module
|
||||
* @private
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const debug = require('debug')('mocha:cli:run:helpers');
|
||||
const {watchRun, watchParallelRun} = require('./watch-run');
|
||||
const collectFiles = require('./collect-files');
|
||||
const {format} = require('util');
|
||||
const {createInvalidLegacyPluginError} = require('../errors');
|
||||
const {requireOrImport} = require('../nodejs/esm-utils');
|
||||
const PluginLoader = require('../plugin-loader');
|
||||
|
||||
/**
|
||||
* Exits Mocha when tests + code under test has finished execution (default)
|
||||
* @param {number} code - Exit code; typically # of failures
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const exitMochaLater = code => {
|
||||
process.on('exit', () => {
|
||||
process.exitCode = Math.min(code, 255);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Exits Mocha when Mocha itself has finished execution, regardless of
|
||||
* what the tests or code under test is doing.
|
||||
* @param {number} code - Exit code; typically # of failures
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const exitMocha = code => {
|
||||
const clampedCode = Math.min(code, 255);
|
||||
let draining = 0;
|
||||
|
||||
// Eagerly set the process's exit code in case stream.write doesn't
|
||||
// execute its callback before the process terminates.
|
||||
process.exitCode = clampedCode;
|
||||
|
||||
// flush output for Node.js Windows pipe bug
|
||||
// https://github.com/joyent/node/issues/6247 is just one bug example
|
||||
// https://github.com/visionmedia/mocha/issues/333 has a good discussion
|
||||
const done = () => {
|
||||
if (!draining--) {
|
||||
process.exit(clampedCode);
|
||||
}
|
||||
};
|
||||
|
||||
const streams = [process.stdout, process.stderr];
|
||||
|
||||
streams.forEach(stream => {
|
||||
// submit empty write request and wait for completion
|
||||
draining += 1;
|
||||
stream.write('', done);
|
||||
});
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
/**
|
||||
* Coerce a comma-delimited string (or array thereof) into a flattened array of
|
||||
* strings
|
||||
* @param {string|string[]} str - Value to coerce
|
||||
* @returns {string[]} Array of strings
|
||||
* @private
|
||||
*/
|
||||
exports.list = str =>
|
||||
Array.isArray(str) ? exports.list(str.join(',')) : str.split(/ *, */);
|
||||
|
||||
/**
|
||||
* `require()` the modules as required by `--require <require>`.
|
||||
*
|
||||
* Returns array of `mochaHooks` exports, if any.
|
||||
* @param {string[]} requires - Modules to require
|
||||
* @returns {Promise<object>} Plugin implementations
|
||||
* @private
|
||||
*/
|
||||
exports.handleRequires = async (requires = [], {ignoredPlugins = []} = {}) => {
|
||||
const pluginLoader = PluginLoader.create({ignore: ignoredPlugins});
|
||||
for await (const mod of requires) {
|
||||
let modpath = mod;
|
||||
// this is relative to cwd
|
||||
if (fs.existsSync(mod) || fs.existsSync(`${mod}.js`)) {
|
||||
modpath = path.resolve(mod);
|
||||
debug('resolved required file %s to %s', mod, modpath);
|
||||
}
|
||||
const requiredModule = await requireOrImport(modpath);
|
||||
if (requiredModule && typeof requiredModule === 'object') {
|
||||
if (pluginLoader.load(requiredModule)) {
|
||||
debug('found one or more plugin implementations in %s', modpath);
|
||||
}
|
||||
}
|
||||
debug('loaded required module "%s"', mod);
|
||||
}
|
||||
const plugins = await pluginLoader.finalize();
|
||||
if (Object.keys(plugins).length) {
|
||||
debug('finalized plugin implementations: %O', plugins);
|
||||
}
|
||||
return plugins;
|
||||
};
|
||||
|
||||
/**
|
||||
* Collect and load test files, then run mocha instance.
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @param {Options} [opts] - Command line options
|
||||
* @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete
|
||||
* @param {Object} fileCollectParams - Parameters that control test
|
||||
* file collection. See `lib/cli/collect-files.js`.
|
||||
* @returns {Promise<Runner>}
|
||||
* @private
|
||||
*/
|
||||
const singleRun = async (mocha, {exit}, fileCollectParams) => {
|
||||
const files = collectFiles(fileCollectParams);
|
||||
debug('single run with %d file(s)', files.length);
|
||||
mocha.files = files;
|
||||
|
||||
// handles ESM modules
|
||||
await mocha.loadFilesAsync();
|
||||
return mocha.run(exit ? exitMocha : exitMochaLater);
|
||||
};
|
||||
|
||||
/**
|
||||
* Collect files and run tests (using `BufferedRunner`).
|
||||
*
|
||||
* This is `async` for consistency.
|
||||
*
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @param {Options} options - Command line options
|
||||
* @param {Object} fileCollectParams - Parameters that control test
|
||||
* file collection. See `lib/cli/collect-files.js`.
|
||||
* @returns {Promise<BufferedRunner>}
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const parallelRun = async (mocha, options, fileCollectParams) => {
|
||||
const files = collectFiles(fileCollectParams);
|
||||
debug('executing %d test file(s) in parallel mode', files.length);
|
||||
mocha.files = files;
|
||||
|
||||
// note that we DO NOT load any files here; this is handled by the worker
|
||||
return mocha.run(options.exit ? exitMocha : exitMochaLater);
|
||||
};
|
||||
|
||||
/**
|
||||
* Actually run tests. Delegates to one of four different functions:
|
||||
* - `singleRun`: run tests in serial & exit
|
||||
* - `watchRun`: run tests in serial, rerunning as files change
|
||||
* - `parallelRun`: run tests in parallel & exit
|
||||
* - `watchParallelRun`: run tests in parallel, rerunning as files change
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @param {Options} opts - Command line options
|
||||
* @private
|
||||
* @returns {Promise<Runner>}
|
||||
*/
|
||||
exports.runMocha = async (mocha, options) => {
|
||||
const {
|
||||
watch = false,
|
||||
extension = [],
|
||||
ignore = [],
|
||||
file = [],
|
||||
parallel = false,
|
||||
recursive = false,
|
||||
sort = false,
|
||||
spec = []
|
||||
} = options;
|
||||
|
||||
const fileCollectParams = {
|
||||
ignore,
|
||||
extension,
|
||||
file,
|
||||
recursive,
|
||||
sort,
|
||||
spec
|
||||
};
|
||||
|
||||
let run;
|
||||
if (watch) {
|
||||
run = parallel ? watchParallelRun : watchRun;
|
||||
} else {
|
||||
run = parallel ? parallelRun : singleRun;
|
||||
}
|
||||
|
||||
return run(mocha, options, fileCollectParams);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for `--reporter` and `--ui`. Ensures there's only one, and asserts that
|
||||
* it actually exists. This must be run _after_ requires are processed (see
|
||||
* {@link handleRequires}), as it'll prevent interfaces from loading otherwise.
|
||||
* @param {Object} opts - Options object
|
||||
* @param {"reporter"|"ui"} pluginType - Type of plugin.
|
||||
* @param {Object} [map] - Used as a cache of sorts;
|
||||
* `Mocha.reporters` where each key corresponds to a reporter name,
|
||||
* `Mocha.interfaces` where each key corresponds to an interface name.
|
||||
* @private
|
||||
*/
|
||||
exports.validateLegacyPlugin = (opts, pluginType, map = {}) => {
|
||||
/**
|
||||
* This should be a unique identifier; either a string (present in `map`),
|
||||
* or a resolvable (via `require.resolve`) module ID/path.
|
||||
* @type {string}
|
||||
*/
|
||||
const pluginId = opts[pluginType];
|
||||
|
||||
if (Array.isArray(pluginId)) {
|
||||
throw createInvalidLegacyPluginError(
|
||||
`"--${pluginType}" can only be specified once`,
|
||||
pluginType
|
||||
);
|
||||
}
|
||||
|
||||
const createUnknownError = err =>
|
||||
createInvalidLegacyPluginError(
|
||||
format('Could not load %s "%s":\n\n %O', pluginType, pluginId, err),
|
||||
pluginType,
|
||||
pluginId
|
||||
);
|
||||
|
||||
// if this exists, then it's already loaded, so nothing more to do.
|
||||
if (!map[pluginId]) {
|
||||
let foundId;
|
||||
try {
|
||||
foundId = require.resolve(pluginId);
|
||||
map[pluginId] = require(foundId);
|
||||
} catch (err) {
|
||||
if (foundId) throw createUnknownError(err);
|
||||
|
||||
// Try to load reporters from a cwd-relative path
|
||||
try {
|
||||
map[pluginId] = require(path.resolve(pluginId));
|
||||
} catch (e) {
|
||||
throw createUnknownError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
115
node_modules/mocha/lib/cli/run-option-metadata.js
generated
vendored
Normal file
115
node_modules/mocha/lib/cli/run-option-metadata.js
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Metadata about various options of the `run` command
|
||||
* @see module:lib/cli/run
|
||||
* @module
|
||||
* @private
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dictionary of yargs option types to list of options having said type
|
||||
* @type {{string:string[]}}
|
||||
* @private
|
||||
*/
|
||||
const TYPES = (exports.types = {
|
||||
array: [
|
||||
'extension',
|
||||
'file',
|
||||
'global',
|
||||
'ignore',
|
||||
'node-option',
|
||||
'reporter-option',
|
||||
'require',
|
||||
'spec',
|
||||
'watch-files',
|
||||
'watch-ignore'
|
||||
],
|
||||
boolean: [
|
||||
'allow-uncaught',
|
||||
'async-only',
|
||||
'bail',
|
||||
'check-leaks',
|
||||
'color',
|
||||
'delay',
|
||||
'diff',
|
||||
'dry-run',
|
||||
'exit',
|
||||
'fail-zero',
|
||||
'forbid-only',
|
||||
'forbid-pending',
|
||||
'full-trace',
|
||||
'inline-diffs',
|
||||
'invert',
|
||||
'list-interfaces',
|
||||
'list-reporters',
|
||||
'no-colors',
|
||||
'parallel',
|
||||
'recursive',
|
||||
'sort',
|
||||
'watch'
|
||||
],
|
||||
number: ['retries', 'jobs'],
|
||||
string: [
|
||||
'config',
|
||||
'fgrep',
|
||||
'grep',
|
||||
'package',
|
||||
'reporter',
|
||||
'ui',
|
||||
'slow',
|
||||
'timeout'
|
||||
]
|
||||
});
|
||||
|
||||
/**
|
||||
* Option aliases keyed by canonical option name.
|
||||
* Arrays used to reduce
|
||||
* @type {{string:string[]}}
|
||||
* @private
|
||||
*/
|
||||
exports.aliases = {
|
||||
'async-only': ['A'],
|
||||
bail: ['b'],
|
||||
color: ['c', 'colors'],
|
||||
fgrep: ['f'],
|
||||
global: ['globals'],
|
||||
grep: ['g'],
|
||||
ignore: ['exclude'],
|
||||
invert: ['i'],
|
||||
jobs: ['j'],
|
||||
'no-colors': ['C'],
|
||||
'node-option': ['n'],
|
||||
parallel: ['p'],
|
||||
reporter: ['R'],
|
||||
'reporter-option': ['reporter-options', 'O'],
|
||||
require: ['r'],
|
||||
slow: ['s'],
|
||||
sort: ['S'],
|
||||
timeout: ['t', 'timeouts'],
|
||||
ui: ['u'],
|
||||
watch: ['w']
|
||||
};
|
||||
|
||||
const ALL_MOCHA_FLAGS = Object.keys(TYPES).reduce((acc, key) => {
|
||||
// gets all flags from each of the fields in `types`, adds those,
|
||||
// then adds aliases of each flag (if any)
|
||||
TYPES[key].forEach(flag => {
|
||||
acc.add(flag);
|
||||
const aliases = exports.aliases[flag] || [];
|
||||
aliases.forEach(alias => {
|
||||
acc.add(alias);
|
||||
});
|
||||
});
|
||||
return acc;
|
||||
}, new Set());
|
||||
|
||||
/**
|
||||
* Returns `true` if the provided `flag` is known to Mocha.
|
||||
* @param {string} flag - Flag to check
|
||||
* @returns {boolean} If `true`, this is a Mocha flag
|
||||
* @private
|
||||
*/
|
||||
exports.isMochaFlag = flag => {
|
||||
return ALL_MOCHA_FLAGS.has(flag.replace(/^--?/, ''));
|
||||
};
|
||||
375
node_modules/mocha/lib/cli/run.js
generated
vendored
Normal file
375
node_modules/mocha/lib/cli/run.js
generated
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Definition for Mocha's default ("run tests") command
|
||||
*
|
||||
* @module
|
||||
* @private
|
||||
*/
|
||||
|
||||
const symbols = require('log-symbols');
|
||||
const ansi = require('ansi-colors');
|
||||
const Mocha = require('../mocha');
|
||||
const {
|
||||
createUnsupportedError,
|
||||
createInvalidArgumentValueError,
|
||||
createMissingArgumentError
|
||||
} = require('../errors');
|
||||
|
||||
const {
|
||||
list,
|
||||
handleRequires,
|
||||
validateLegacyPlugin,
|
||||
runMocha
|
||||
} = require('./run-helpers');
|
||||
const {ONE_AND_DONES, ONE_AND_DONE_ARGS} = require('./one-and-dones');
|
||||
const debug = require('debug')('mocha:cli:run');
|
||||
const defaults = require('../mocharc');
|
||||
const {types, aliases} = require('./run-option-metadata');
|
||||
|
||||
/**
|
||||
* Logical option groups
|
||||
* @constant
|
||||
*/
|
||||
const GROUPS = {
|
||||
FILES: 'File Handling',
|
||||
FILTERS: 'Test Filters',
|
||||
NODEJS: 'Node.js & V8',
|
||||
OUTPUT: 'Reporting & Output',
|
||||
RULES: 'Rules & Behavior',
|
||||
CONFIG: 'Configuration'
|
||||
};
|
||||
|
||||
exports.command = ['$0 [spec..]', 'inspect'];
|
||||
|
||||
exports.describe = 'Run tests with Mocha';
|
||||
|
||||
exports.builder = yargs =>
|
||||
yargs
|
||||
.options({
|
||||
'allow-uncaught': {
|
||||
description: 'Allow uncaught errors to propagate',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
'async-only': {
|
||||
description:
|
||||
'Require all tests to use a callback (async) or return a Promise',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
bail: {
|
||||
description: 'Abort ("bail") after first test failure',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
'check-leaks': {
|
||||
description: 'Check for global variable leaks',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
color: {
|
||||
description: 'Force-enable color output',
|
||||
group: GROUPS.OUTPUT
|
||||
},
|
||||
config: {
|
||||
config: true,
|
||||
defaultDescription: '(nearest rc file)',
|
||||
description: 'Path to config file',
|
||||
group: GROUPS.CONFIG
|
||||
},
|
||||
delay: {
|
||||
description: 'Delay initial execution of root suite',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
diff: {
|
||||
default: true,
|
||||
description: 'Show diff on failure',
|
||||
group: GROUPS.OUTPUT
|
||||
},
|
||||
'dry-run': {
|
||||
description: 'Report tests without executing them',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
exit: {
|
||||
description: 'Force Mocha to quit after tests complete',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
extension: {
|
||||
default: defaults.extension,
|
||||
description: 'File extension(s) to load',
|
||||
group: GROUPS.FILES,
|
||||
requiresArg: true,
|
||||
coerce: list
|
||||
},
|
||||
'fail-zero': {
|
||||
description: 'Fail test run if no test(s) encountered',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
fgrep: {
|
||||
conflicts: 'grep',
|
||||
description: 'Only run tests containing this string',
|
||||
group: GROUPS.FILTERS,
|
||||
requiresArg: true
|
||||
},
|
||||
file: {
|
||||
defaultDescription: '(none)',
|
||||
description:
|
||||
'Specify file(s) to be loaded prior to root suite execution',
|
||||
group: GROUPS.FILES,
|
||||
normalize: true,
|
||||
requiresArg: true
|
||||
},
|
||||
'forbid-only': {
|
||||
description: 'Fail if exclusive test(s) encountered',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
'forbid-pending': {
|
||||
description: 'Fail if pending test(s) encountered',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
'full-trace': {
|
||||
description: 'Display full stack traces',
|
||||
group: GROUPS.OUTPUT
|
||||
},
|
||||
global: {
|
||||
coerce: list,
|
||||
description: 'List of allowed global variables',
|
||||
group: GROUPS.RULES,
|
||||
requiresArg: true
|
||||
},
|
||||
grep: {
|
||||
coerce: value => (!value ? null : value),
|
||||
conflicts: 'fgrep',
|
||||
description: 'Only run tests matching this string or regexp',
|
||||
group: GROUPS.FILTERS,
|
||||
requiresArg: true
|
||||
},
|
||||
ignore: {
|
||||
defaultDescription: '(none)',
|
||||
description: 'Ignore file(s) or glob pattern(s)',
|
||||
group: GROUPS.FILES,
|
||||
requiresArg: true
|
||||
},
|
||||
'inline-diffs': {
|
||||
description:
|
||||
'Display actual/expected differences inline within each string',
|
||||
group: GROUPS.OUTPUT
|
||||
},
|
||||
invert: {
|
||||
description: 'Inverts --grep and --fgrep matches',
|
||||
group: GROUPS.FILTERS
|
||||
},
|
||||
jobs: {
|
||||
description:
|
||||
'Number of concurrent jobs for --parallel; use 1 to run in serial',
|
||||
defaultDescription: '(number of CPU cores - 1)',
|
||||
requiresArg: true,
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
'list-interfaces': {
|
||||
conflicts: Array.from(ONE_AND_DONE_ARGS),
|
||||
description: 'List built-in user interfaces & exit'
|
||||
},
|
||||
'list-reporters': {
|
||||
conflicts: Array.from(ONE_AND_DONE_ARGS),
|
||||
description: 'List built-in reporters & exit'
|
||||
},
|
||||
'no-colors': {
|
||||
description: 'Force-disable color output',
|
||||
group: GROUPS.OUTPUT,
|
||||
hidden: true
|
||||
},
|
||||
'node-option': {
|
||||
description: 'Node or V8 option (no leading "--")',
|
||||
group: GROUPS.CONFIG
|
||||
},
|
||||
package: {
|
||||
description: 'Path to package.json for config',
|
||||
group: GROUPS.CONFIG,
|
||||
normalize: true,
|
||||
requiresArg: true
|
||||
},
|
||||
parallel: {
|
||||
description: 'Run tests in parallel',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
recursive: {
|
||||
description: 'Look for tests in subdirectories',
|
||||
group: GROUPS.FILES
|
||||
},
|
||||
reporter: {
|
||||
default: defaults.reporter,
|
||||
description: 'Specify reporter to use',
|
||||
group: GROUPS.OUTPUT,
|
||||
requiresArg: true
|
||||
},
|
||||
'reporter-option': {
|
||||
coerce: opts =>
|
||||
list(opts).reduce((acc, opt) => {
|
||||
const pair = opt.split('=');
|
||||
|
||||
if (pair.length > 2 || !pair.length) {
|
||||
throw createInvalidArgumentValueError(
|
||||
`invalid reporter option '${opt}'`,
|
||||
'--reporter-option',
|
||||
opt,
|
||||
'expected "key=value" format'
|
||||
);
|
||||
}
|
||||
|
||||
acc[pair[0]] = pair.length === 2 ? pair[1] : true;
|
||||
return acc;
|
||||
}, {}),
|
||||
description: 'Reporter-specific options (<k=v,[k1=v1,..]>)',
|
||||
group: GROUPS.OUTPUT,
|
||||
requiresArg: true
|
||||
},
|
||||
require: {
|
||||
defaultDescription: '(none)',
|
||||
description: 'Require module',
|
||||
group: GROUPS.FILES,
|
||||
requiresArg: true
|
||||
},
|
||||
retries: {
|
||||
description: 'Retry failed tests this many times',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
slow: {
|
||||
default: defaults.slow,
|
||||
description: 'Specify "slow" test threshold (in milliseconds)',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
sort: {
|
||||
description: 'Sort test files',
|
||||
group: GROUPS.FILES
|
||||
},
|
||||
timeout: {
|
||||
default: defaults.timeout,
|
||||
description: 'Specify test timeout threshold (in milliseconds)',
|
||||
group: GROUPS.RULES
|
||||
},
|
||||
ui: {
|
||||
default: defaults.ui,
|
||||
description: 'Specify user interface',
|
||||
group: GROUPS.RULES,
|
||||
requiresArg: true
|
||||
},
|
||||
watch: {
|
||||
description: 'Watch files in the current working directory for changes',
|
||||
group: GROUPS.FILES
|
||||
},
|
||||
'watch-files': {
|
||||
description: 'List of paths or globs to watch',
|
||||
group: GROUPS.FILES,
|
||||
requiresArg: true,
|
||||
coerce: list
|
||||
},
|
||||
'watch-ignore': {
|
||||
description: 'List of paths or globs to exclude from watching',
|
||||
group: GROUPS.FILES,
|
||||
requiresArg: true,
|
||||
coerce: list,
|
||||
default: defaults['watch-ignore']
|
||||
}
|
||||
})
|
||||
.positional('spec', {
|
||||
default: ['test'],
|
||||
description: 'One or more files, directories, or globs to test',
|
||||
type: 'array'
|
||||
})
|
||||
.check(argv => {
|
||||
// "one-and-dones"; let yargs handle help and version
|
||||
Object.keys(ONE_AND_DONES).forEach(opt => {
|
||||
if (argv[opt]) {
|
||||
ONE_AND_DONES[opt].call(null, yargs);
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
|
||||
// yargs.implies() isn't flexible enough to handle this
|
||||
if (argv.invert && !('fgrep' in argv || 'grep' in argv)) {
|
||||
throw createMissingArgumentError(
|
||||
'"--invert" requires one of "--fgrep <str>" or "--grep <regexp>"',
|
||||
'--fgrep|--grep',
|
||||
'string|regexp'
|
||||
);
|
||||
}
|
||||
|
||||
if (argv.parallel) {
|
||||
// yargs.conflicts() can't deal with `--file foo.js --no-parallel`, either
|
||||
if (argv.file) {
|
||||
throw createUnsupportedError(
|
||||
'--parallel runs test files in a non-deterministic order, and is mutually exclusive with --file'
|
||||
);
|
||||
}
|
||||
|
||||
// or this
|
||||
if (argv.sort) {
|
||||
throw createUnsupportedError(
|
||||
'--parallel runs test files in a non-deterministic order, and is mutually exclusive with --sort'
|
||||
);
|
||||
}
|
||||
|
||||
if (argv.reporter === 'progress') {
|
||||
throw createUnsupportedError(
|
||||
'--reporter=progress is mutually exclusive with --parallel'
|
||||
);
|
||||
}
|
||||
|
||||
if (argv.reporter === 'markdown') {
|
||||
throw createUnsupportedError(
|
||||
'--reporter=markdown is mutually exclusive with --parallel'
|
||||
);
|
||||
}
|
||||
|
||||
if (argv.reporter === 'json-stream') {
|
||||
throw createUnsupportedError(
|
||||
'--reporter=json-stream is mutually exclusive with --parallel'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (argv.compilers) {
|
||||
throw createUnsupportedError(
|
||||
`--compilers is DEPRECATED and no longer supported.
|
||||
See https://github.com/mochajs/mocha/wiki/compilers-deprecation for migration information.`
|
||||
);
|
||||
}
|
||||
|
||||
if (argv.opts) {
|
||||
throw createUnsupportedError(
|
||||
`--opts: configuring Mocha via 'mocha.opts' is DEPRECATED and no longer supported.
|
||||
Please use a configuration file instead.`
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.middleware(async (argv, yargs) => {
|
||||
// currently a failing middleware does not work nicely with yargs' `fail()`.
|
||||
try {
|
||||
// load requires first, because it can impact "plugin" validation
|
||||
const plugins = await handleRequires(argv.require);
|
||||
validateLegacyPlugin(argv, 'reporter', Mocha.reporters);
|
||||
validateLegacyPlugin(argv, 'ui', Mocha.interfaces);
|
||||
Object.assign(argv, plugins);
|
||||
} catch (err) {
|
||||
// this could be a bad --require, bad reporter, ui, etc.
|
||||
console.error(`\n${symbols.error} ${ansi.red('ERROR:')}`, err);
|
||||
yargs.exit(1);
|
||||
}
|
||||
})
|
||||
.array(types.array)
|
||||
.boolean(types.boolean)
|
||||
.string(types.string)
|
||||
.number(types.number)
|
||||
.alias(aliases);
|
||||
|
||||
exports.handler = async function (argv) {
|
||||
debug('post-yargs config', argv);
|
||||
const mocha = new Mocha(argv);
|
||||
|
||||
try {
|
||||
await runMocha(mocha, argv);
|
||||
} catch (err) {
|
||||
console.error('\n' + (err.stack || `Error: ${err.message || err}`));
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
377
node_modules/mocha/lib/cli/watch-run.js
generated
vendored
Normal file
377
node_modules/mocha/lib/cli/watch-run.js
generated
vendored
Normal file
@@ -0,0 +1,377 @@
|
||||
'use strict';
|
||||
|
||||
const logSymbols = require('log-symbols');
|
||||
const debug = require('debug')('mocha:cli:watch');
|
||||
const path = require('path');
|
||||
const chokidar = require('chokidar');
|
||||
const Context = require('../context');
|
||||
const collectFiles = require('./collect-files');
|
||||
|
||||
/**
|
||||
* Exports the `watchRun` function that runs mocha in "watch" mode.
|
||||
* @see module:lib/cli/run-helpers
|
||||
* @module
|
||||
* @private
|
||||
*/
|
||||
|
||||
/**
|
||||
* Run Mocha in parallel "watch" mode
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @param {Object} opts - Options
|
||||
* @param {string[]} [opts.watchFiles] - List of paths and patterns to
|
||||
* watch. If not provided all files with an extension included in
|
||||
* `fileCollectionParams.extension` are watched. See first argument of
|
||||
* `chokidar.watch`.
|
||||
* @param {string[]} opts.watchIgnore - List of paths and patterns to
|
||||
* exclude from watching. See `ignored` option of `chokidar`.
|
||||
* @param {FileCollectionOptions} fileCollectParams - Parameters that control test
|
||||
* @private
|
||||
*/
|
||||
exports.watchParallelRun = (
|
||||
mocha,
|
||||
{watchFiles, watchIgnore},
|
||||
fileCollectParams
|
||||
) => {
|
||||
debug('creating parallel watcher');
|
||||
|
||||
return createWatcher(mocha, {
|
||||
watchFiles,
|
||||
watchIgnore,
|
||||
beforeRun({mocha}) {
|
||||
// I don't know why we're cloning the root suite.
|
||||
const rootSuite = mocha.suite.clone();
|
||||
|
||||
// ensure we aren't leaking event listeners
|
||||
mocha.dispose();
|
||||
|
||||
// this `require` is needed because the require cache has been cleared. the dynamic
|
||||
// exports set via the below call to `mocha.ui()` won't work properly if a
|
||||
// test depends on this module.
|
||||
const Mocha = require('../mocha');
|
||||
|
||||
// ... and now that we've gotten a new module, we need to use it again due
|
||||
// to `mocha.ui()` call
|
||||
const newMocha = new Mocha(mocha.options);
|
||||
// don't know why this is needed
|
||||
newMocha.suite = rootSuite;
|
||||
// nor this
|
||||
newMocha.suite.ctx = new Context();
|
||||
|
||||
// reset the list of files
|
||||
newMocha.files = collectFiles(fileCollectParams);
|
||||
|
||||
// because we've swapped out the root suite (see the `run` inner function
|
||||
// in `createRerunner`), we need to call `mocha.ui()` again to set up the context/globals.
|
||||
newMocha.ui(newMocha.options.ui);
|
||||
|
||||
// we need to call `newMocha.rootHooks` to set up rootHooks for the new
|
||||
// suite
|
||||
newMocha.rootHooks(newMocha.options.rootHooks);
|
||||
|
||||
// in parallel mode, the main Mocha process doesn't actually load the
|
||||
// files. this flag prevents `mocha.run()` from autoloading.
|
||||
newMocha.lazyLoadFiles(true);
|
||||
return newMocha;
|
||||
},
|
||||
fileCollectParams
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Run Mocha in "watch" mode
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @param {Object} opts - Options
|
||||
* @param {string[]} [opts.watchFiles] - List of paths and patterns to
|
||||
* watch. If not provided all files with an extension included in
|
||||
* `fileCollectionParams.extension` are watched. See first argument of
|
||||
* `chokidar.watch`.
|
||||
* @param {string[]} opts.watchIgnore - List of paths and patterns to
|
||||
* exclude from watching. See `ignored` option of `chokidar`.
|
||||
* @param {FileCollectionOptions} fileCollectParams - Parameters that control test
|
||||
* file collection. See `lib/cli/collect-files.js`.
|
||||
* @private
|
||||
*/
|
||||
exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
|
||||
debug('creating serial watcher');
|
||||
|
||||
return createWatcher(mocha, {
|
||||
watchFiles,
|
||||
watchIgnore,
|
||||
beforeRun({mocha}) {
|
||||
mocha.unloadFiles();
|
||||
|
||||
// I don't know why we're cloning the root suite.
|
||||
const rootSuite = mocha.suite.clone();
|
||||
|
||||
// ensure we aren't leaking event listeners
|
||||
mocha.dispose();
|
||||
|
||||
// this `require` is needed because the require cache has been cleared. the dynamic
|
||||
// exports set via the below call to `mocha.ui()` won't work properly if a
|
||||
// test depends on this module.
|
||||
const Mocha = require('../mocha');
|
||||
|
||||
// ... and now that we've gotten a new module, we need to use it again due
|
||||
// to `mocha.ui()` call
|
||||
const newMocha = new Mocha(mocha.options);
|
||||
// don't know why this is needed
|
||||
newMocha.suite = rootSuite;
|
||||
// nor this
|
||||
newMocha.suite.ctx = new Context();
|
||||
|
||||
// reset the list of files
|
||||
newMocha.files = collectFiles(fileCollectParams);
|
||||
|
||||
// because we've swapped out the root suite (see the `run` inner function
|
||||
// in `createRerunner`), we need to call `mocha.ui()` again to set up the context/globals.
|
||||
newMocha.ui(newMocha.options.ui);
|
||||
|
||||
// we need to call `newMocha.rootHooks` to set up rootHooks for the new
|
||||
// suite
|
||||
newMocha.rootHooks(newMocha.options.rootHooks);
|
||||
|
||||
return newMocha;
|
||||
},
|
||||
fileCollectParams
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Bootstraps a chokidar watcher. Handles keyboard input & signals
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @param {Object} opts
|
||||
* @param {BeforeWatchRun} [opts.beforeRun] - Function to call before
|
||||
* `mocha.run()`
|
||||
* @param {string[]} [opts.watchFiles] - List of paths and patterns to watch. If
|
||||
* not provided all files with an extension included in
|
||||
* `fileCollectionParams.extension` are watched. See first argument of
|
||||
* `chokidar.watch`.
|
||||
* @param {string[]} [opts.watchIgnore] - List of paths and patterns to exclude
|
||||
* from watching. See `ignored` option of `chokidar`.
|
||||
* @param {FileCollectionOptions} opts.fileCollectParams - List of extensions to watch if `opts.watchFiles` is not given.
|
||||
* @returns {FSWatcher}
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const createWatcher = (
|
||||
mocha,
|
||||
{watchFiles, watchIgnore, beforeRun, fileCollectParams}
|
||||
) => {
|
||||
if (!watchFiles) {
|
||||
watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
|
||||
}
|
||||
|
||||
debug('ignoring files matching: %s', watchIgnore);
|
||||
let globalFixtureContext;
|
||||
|
||||
// we handle global fixtures manually
|
||||
mocha.enableGlobalSetup(false).enableGlobalTeardown(false);
|
||||
|
||||
const watcher = chokidar.watch(watchFiles, {
|
||||
ignored: watchIgnore,
|
||||
ignoreInitial: true
|
||||
});
|
||||
|
||||
const rerunner = createRerunner(mocha, watcher, {
|
||||
beforeRun
|
||||
});
|
||||
|
||||
watcher.on('ready', async () => {
|
||||
if (!globalFixtureContext) {
|
||||
debug('triggering global setup');
|
||||
globalFixtureContext = await mocha.runGlobalSetup();
|
||||
}
|
||||
rerunner.run();
|
||||
});
|
||||
|
||||
watcher.on('all', () => {
|
||||
rerunner.scheduleRun();
|
||||
});
|
||||
|
||||
hideCursor();
|
||||
process.on('exit', () => {
|
||||
showCursor();
|
||||
});
|
||||
|
||||
// this is for testing.
|
||||
// win32 cannot gracefully shutdown via a signal from a parent
|
||||
// process; a `SIGINT` from a parent will cause the process
|
||||
// to immediately exit. during normal course of operation, a user
|
||||
// will type Ctrl-C and the listener will be invoked, but this
|
||||
// is not possible in automated testing.
|
||||
// there may be another way to solve this, but it too will be a hack.
|
||||
// for our watch tests on win32 we must _fork_ mocha with an IPC channel
|
||||
if (process.connected) {
|
||||
process.on('message', msg => {
|
||||
if (msg === 'SIGINT') {
|
||||
process.emit('SIGINT');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let exiting = false;
|
||||
process.on('SIGINT', async () => {
|
||||
showCursor();
|
||||
console.error(`${logSymbols.warning} [mocha] cleaning up, please wait...`);
|
||||
if (!exiting) {
|
||||
exiting = true;
|
||||
if (mocha.hasGlobalTeardownFixtures()) {
|
||||
debug('running global teardown');
|
||||
try {
|
||||
await mocha.runGlobalTeardown(globalFixtureContext);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
process.exit(130);
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard shortcut for restarting when "rs\n" is typed (ala Nodemon)
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.on('data', data => {
|
||||
const str = data.toString().trim().toLowerCase();
|
||||
if (str === 'rs') rerunner.scheduleRun();
|
||||
});
|
||||
|
||||
return watcher;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an object that allows you to rerun tests on the mocha instance.
|
||||
*
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @param {FSWatcher} watcher - chokidar `FSWatcher` instance
|
||||
* @param {Object} [opts] - Options!
|
||||
* @param {BeforeWatchRun} [opts.beforeRun] - Function to call before `mocha.run()`
|
||||
* @returns {Rerunner}
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const createRerunner = (mocha, watcher, {beforeRun} = {}) => {
|
||||
// Set to a `Runner` when mocha is running. Set to `null` when mocha is not
|
||||
// running.
|
||||
let runner = null;
|
||||
|
||||
// true if a file has changed during a test run
|
||||
let rerunScheduled = false;
|
||||
|
||||
const run = () => {
|
||||
try {
|
||||
mocha = beforeRun ? beforeRun({mocha, watcher}) || mocha : mocha;
|
||||
runner = mocha.run(() => {
|
||||
debug('finished watch run');
|
||||
runner = null;
|
||||
blastCache(watcher);
|
||||
if (rerunScheduled) {
|
||||
rerun();
|
||||
} else {
|
||||
console.error(`${logSymbols.info} [mocha] waiting for changes...`);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
}
|
||||
};
|
||||
|
||||
const scheduleRun = () => {
|
||||
if (rerunScheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
rerunScheduled = true;
|
||||
if (runner) {
|
||||
runner.abort();
|
||||
} else {
|
||||
rerun();
|
||||
}
|
||||
};
|
||||
|
||||
const rerun = () => {
|
||||
rerunScheduled = false;
|
||||
eraseLine();
|
||||
run();
|
||||
};
|
||||
|
||||
return {
|
||||
scheduleRun,
|
||||
run
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the list of absolute paths watched by a chokidar watcher.
|
||||
*
|
||||
* @param watcher - Instance of a chokidar watcher
|
||||
* @return {string[]} - List of absolute paths
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const getWatchedFiles = watcher => {
|
||||
const watchedDirs = watcher.getWatched();
|
||||
return Object.keys(watchedDirs).reduce(
|
||||
(acc, dir) => [
|
||||
...acc,
|
||||
...watchedDirs[dir].map(file => path.join(dir, file))
|
||||
],
|
||||
[]
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the cursor.
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const hideCursor = () => {
|
||||
process.stdout.write('\u001b[?25l');
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the cursor.
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const showCursor = () => {
|
||||
process.stdout.write('\u001b[?25h');
|
||||
};
|
||||
|
||||
/**
|
||||
* Erases the line on stdout
|
||||
* @private
|
||||
*/
|
||||
const eraseLine = () => {
|
||||
process.stdout.write('\u001b[2K');
|
||||
};
|
||||
|
||||
/**
|
||||
* Blast all of the watched files out of `require.cache`
|
||||
* @param {FSWatcher} watcher - chokidar FSWatcher
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const blastCache = watcher => {
|
||||
const files = getWatchedFiles(watcher);
|
||||
files.forEach(file => {
|
||||
delete require.cache[file];
|
||||
});
|
||||
debug('deleted %d file(s) from the require cache', files.length);
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback to be run before `mocha.run()` is called.
|
||||
* Optionally, it can return a new `Mocha` instance.
|
||||
* @callback BeforeWatchRun
|
||||
* @private
|
||||
* @param {{mocha: Mocha, watcher: FSWatcher}} options
|
||||
* @returns {Mocha}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object containing run control methods
|
||||
* @typedef {Object} Rerunner
|
||||
* @private
|
||||
* @property {Function} run - Calls `mocha.run()`
|
||||
* @property {Function} scheduleRun - Schedules another call to `run`
|
||||
*/
|
||||
86
node_modules/mocha/lib/context.js
generated
vendored
Normal file
86
node_modules/mocha/lib/context.js
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Context
|
||||
*/
|
||||
/**
|
||||
* Expose `Context`.
|
||||
*/
|
||||
|
||||
module.exports = Context;
|
||||
|
||||
/**
|
||||
* Initialize a new `Context`.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function Context() {}
|
||||
|
||||
/**
|
||||
* Set or get the context `Runnable` to `runnable`.
|
||||
*
|
||||
* @private
|
||||
* @param {Runnable} runnable
|
||||
* @return {Context} context
|
||||
*/
|
||||
Context.prototype.runnable = function (runnable) {
|
||||
if (!arguments.length) {
|
||||
return this._runnable;
|
||||
}
|
||||
this.test = this._runnable = runnable;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get test timeout `ms`.
|
||||
*
|
||||
* @private
|
||||
* @param {number} ms
|
||||
* @return {Context} self
|
||||
*/
|
||||
Context.prototype.timeout = function (ms) {
|
||||
if (!arguments.length) {
|
||||
return this.runnable().timeout();
|
||||
}
|
||||
this.runnable().timeout(ms);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get test slowness threshold `ms`.
|
||||
*
|
||||
* @private
|
||||
* @param {number} ms
|
||||
* @return {Context} self
|
||||
*/
|
||||
Context.prototype.slow = function (ms) {
|
||||
if (!arguments.length) {
|
||||
return this.runnable().slow();
|
||||
}
|
||||
this.runnable().slow(ms);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark a test as skipped.
|
||||
*
|
||||
* @private
|
||||
* @throws Pending
|
||||
*/
|
||||
Context.prototype.skip = function () {
|
||||
this.runnable().skip();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get a number of allowed retries on failed tests
|
||||
*
|
||||
* @private
|
||||
* @param {number} n
|
||||
* @return {Context} self
|
||||
*/
|
||||
Context.prototype.retries = function (n) {
|
||||
if (!arguments.length) {
|
||||
return this.runnable().retries();
|
||||
}
|
||||
this.runnable().retries(n);
|
||||
return this;
|
||||
};
|
||||
563
node_modules/mocha/lib/errors.js
generated
vendored
Normal file
563
node_modules/mocha/lib/errors.js
generated
vendored
Normal file
@@ -0,0 +1,563 @@
|
||||
'use strict';
|
||||
|
||||
const {format} = require('util');
|
||||
|
||||
/**
|
||||
* Contains error codes, factory functions to create throwable error objects,
|
||||
* and warning/deprecation functions.
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* process.emitWarning or a polyfill
|
||||
* @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options
|
||||
* @ignore
|
||||
*/
|
||||
const emitWarning = (msg, type) => {
|
||||
if (process.emitWarning) {
|
||||
process.emitWarning(msg, type);
|
||||
} else {
|
||||
/* istanbul ignore next */
|
||||
process.nextTick(function () {
|
||||
console.warn(type + ': ' + msg);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show a deprecation warning. Each distinct message is only displayed once.
|
||||
* Ignores empty messages.
|
||||
*
|
||||
* @param {string} [msg] - Warning to print
|
||||
* @private
|
||||
*/
|
||||
const deprecate = msg => {
|
||||
msg = String(msg);
|
||||
if (msg && !deprecate.cache[msg]) {
|
||||
deprecate.cache[msg] = true;
|
||||
emitWarning(msg, 'DeprecationWarning');
|
||||
}
|
||||
};
|
||||
deprecate.cache = {};
|
||||
|
||||
/**
|
||||
* Show a generic warning.
|
||||
* Ignores empty messages.
|
||||
*
|
||||
* @param {string} [msg] - Warning to print
|
||||
* @private
|
||||
*/
|
||||
const warn = msg => {
|
||||
if (msg) {
|
||||
emitWarning(msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When Mocha throws exceptions (or rejects `Promise`s), it attempts to assign a `code` property to the `Error` object, for easier handling. These are the potential values of `code`.
|
||||
* @public
|
||||
* @namespace
|
||||
* @memberof module:lib/errors
|
||||
*/
|
||||
var constants = {
|
||||
/**
|
||||
* An unrecoverable error.
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FATAL: 'ERR_MOCHA_FATAL',
|
||||
|
||||
/**
|
||||
* The type of an argument to a function call is invalid
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INVALID_ARG_TYPE: 'ERR_MOCHA_INVALID_ARG_TYPE',
|
||||
|
||||
/**
|
||||
* The value of an argument to a function call is invalid
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INVALID_ARG_VALUE: 'ERR_MOCHA_INVALID_ARG_VALUE',
|
||||
|
||||
/**
|
||||
* Something was thrown, but it wasn't an `Error`
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INVALID_EXCEPTION: 'ERR_MOCHA_INVALID_EXCEPTION',
|
||||
|
||||
/**
|
||||
* An interface (e.g., `Mocha.interfaces`) is unknown or invalid
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INVALID_INTERFACE: 'ERR_MOCHA_INVALID_INTERFACE',
|
||||
|
||||
/**
|
||||
* A reporter (.e.g, `Mocha.reporters`) is unknown or invalid
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INVALID_REPORTER: 'ERR_MOCHA_INVALID_REPORTER',
|
||||
|
||||
/**
|
||||
* `done()` was called twice in a `Test` or `Hook` callback
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
MULTIPLE_DONE: 'ERR_MOCHA_MULTIPLE_DONE',
|
||||
|
||||
/**
|
||||
* No files matched the pattern provided by the user
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
NO_FILES_MATCH_PATTERN: 'ERR_MOCHA_NO_FILES_MATCH_PATTERN',
|
||||
|
||||
/**
|
||||
* Known, but unsupported behavior of some kind
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
UNSUPPORTED: 'ERR_MOCHA_UNSUPPORTED',
|
||||
|
||||
/**
|
||||
* Invalid state transition occurring in `Mocha` instance
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INSTANCE_ALREADY_RUNNING: 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING',
|
||||
|
||||
/**
|
||||
* Invalid state transition occurring in `Mocha` instance
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INSTANCE_ALREADY_DISPOSED: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED',
|
||||
|
||||
/**
|
||||
* Use of `only()` w/ `--forbid-only` results in this error.
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY',
|
||||
|
||||
/**
|
||||
* To be thrown when a user-defined plugin implementation (e.g., `mochaHooks`) is invalid
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INVALID_PLUGIN_IMPLEMENTATION: 'ERR_MOCHA_INVALID_PLUGIN_IMPLEMENTATION',
|
||||
|
||||
/**
|
||||
* To be thrown when a builtin or third-party plugin definition (the _definition_ of `mochaHooks`) is invalid
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
INVALID_PLUGIN_DEFINITION: 'ERR_MOCHA_INVALID_PLUGIN_DEFINITION',
|
||||
|
||||
/**
|
||||
* When a runnable exceeds its allowed run time.
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
TIMEOUT: 'ERR_MOCHA_TIMEOUT',
|
||||
|
||||
/**
|
||||
* Input file is not able to be parsed
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
UNPARSABLE_FILE: 'ERR_MOCHA_UNPARSABLE_FILE'
|
||||
};
|
||||
|
||||
/**
|
||||
* A set containing all string values of all Mocha error constants, for use by {@link isMochaError}.
|
||||
* @private
|
||||
*/
|
||||
const MOCHA_ERRORS = new Set(Object.values(constants));
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when no files to be tested could be found using specified pattern.
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @param {string} pattern - User-specified argument value.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createNoFilesMatchPatternError(message, pattern) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.NO_FILES_MATCH_PATTERN;
|
||||
err.pattern = pattern;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when the reporter specified in the options was not found.
|
||||
*
|
||||
* @public
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @param {string} reporter - User-specified reporter value.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createInvalidReporterError(message, reporter) {
|
||||
var err = new TypeError(message);
|
||||
err.code = constants.INVALID_REPORTER;
|
||||
err.reporter = reporter;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when the interface specified in the options was not found.
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @param {string} ui - User-specified interface value.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createInvalidInterfaceError(message, ui) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.INVALID_INTERFACE;
|
||||
err.interface = ui;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when a behavior, option, or parameter is unsupported.
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createUnsupportedError(message) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.UNSUPPORTED;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when an argument is missing.
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @param {string} argument - Argument name.
|
||||
* @param {string} expected - Expected argument datatype.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createMissingArgumentError(message, argument, expected) {
|
||||
return createInvalidArgumentTypeError(message, argument, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when an argument did not use the supported type
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @param {string} argument - Argument name.
|
||||
* @param {string} expected - Expected argument datatype.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createInvalidArgumentTypeError(message, argument, expected) {
|
||||
var err = new TypeError(message);
|
||||
err.code = constants.INVALID_ARG_TYPE;
|
||||
err.argument = argument;
|
||||
err.expected = expected;
|
||||
err.actual = typeof argument;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when an argument did not use the supported value
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @param {string} argument - Argument name.
|
||||
* @param {string} value - Argument value.
|
||||
* @param {string} [reason] - Why value is invalid.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createInvalidArgumentValueError(message, argument, value, reason) {
|
||||
var err = new TypeError(message);
|
||||
err.code = constants.INVALID_ARG_VALUE;
|
||||
err.argument = argument;
|
||||
err.value = value;
|
||||
err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when an exception was caught, but the `Error` is falsy or undefined.
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createInvalidExceptionError(message, value) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.INVALID_EXCEPTION;
|
||||
err.valueType = typeof value;
|
||||
err.value = value;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when an unrecoverable error occurs.
|
||||
*
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @returns {Error} instance detailing the error condition
|
||||
*/
|
||||
function createFatalError(message, value) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.FATAL;
|
||||
err.valueType = typeof value;
|
||||
err.value = value;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically creates a plugin-type-specific error based on plugin type
|
||||
* @param {string} message - Error message
|
||||
* @param {"reporter"|"ui"} pluginType - Plugin type. Future: expand as needed
|
||||
* @param {string} [pluginId] - Name/path of plugin, if any
|
||||
* @throws When `pluginType` is not known
|
||||
* @public
|
||||
* @static
|
||||
* @returns {Error}
|
||||
*/
|
||||
function createInvalidLegacyPluginError(message, pluginType, pluginId) {
|
||||
switch (pluginType) {
|
||||
case 'reporter':
|
||||
return createInvalidReporterError(message, pluginId);
|
||||
case 'ui':
|
||||
return createInvalidInterfaceError(message, pluginId);
|
||||
default:
|
||||
throw new Error('unknown pluginType "' + pluginType + '"');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* **DEPRECATED**. Use {@link createInvalidLegacyPluginError} instead Dynamically creates a plugin-type-specific error based on plugin type
|
||||
* @deprecated
|
||||
* @param {string} message - Error message
|
||||
* @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
|
||||
* @param {string} [pluginId] - Name/path of plugin, if any
|
||||
* @throws When `pluginType` is not known
|
||||
* @public
|
||||
* @static
|
||||
* @returns {Error}
|
||||
*/
|
||||
function createInvalidPluginError(...args) {
|
||||
deprecate('Use createInvalidLegacyPluginError() instead');
|
||||
return createInvalidLegacyPluginError(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
|
||||
* @param {string} message The error message to be displayed.
|
||||
* @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`
|
||||
* @param {Mocha} instance the mocha instance that throw this error
|
||||
* @static
|
||||
*/
|
||||
function createMochaInstanceAlreadyDisposedError(
|
||||
message,
|
||||
cleanReferencesAfterRun,
|
||||
instance
|
||||
) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.INSTANCE_ALREADY_DISPOSED;
|
||||
err.cleanReferencesAfterRun = cleanReferencesAfterRun;
|
||||
err.instance = instance;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.
|
||||
* @param {string} message The error message to be displayed.
|
||||
* @static
|
||||
* @public
|
||||
*/
|
||||
function createMochaInstanceAlreadyRunningError(message, instance) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.INSTANCE_ALREADY_RUNNING;
|
||||
err.instance = instance;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when done() is called multiple times in a test
|
||||
*
|
||||
* @public
|
||||
* @param {Runnable} runnable - Original runnable
|
||||
* @param {Error} [originalErr] - Original error, if any
|
||||
* @returns {Error} instance detailing the error condition
|
||||
* @static
|
||||
*/
|
||||
function createMultipleDoneError(runnable, originalErr) {
|
||||
var title;
|
||||
try {
|
||||
title = format('<%s>', runnable.fullTitle());
|
||||
if (runnable.parent.root) {
|
||||
title += ' (of root suite)';
|
||||
}
|
||||
} catch (ignored) {
|
||||
title = format('<%s> (of unknown suite)', runnable.title);
|
||||
}
|
||||
var message = format(
|
||||
'done() called multiple times in %s %s',
|
||||
runnable.type ? runnable.type : 'unknown runnable',
|
||||
title
|
||||
);
|
||||
if (runnable.file) {
|
||||
message += format(' of file %s', runnable.file);
|
||||
}
|
||||
if (originalErr) {
|
||||
message += format('; in addition, done() received error: %s', originalErr);
|
||||
}
|
||||
|
||||
var err = new Error(message);
|
||||
err.code = constants.MULTIPLE_DONE;
|
||||
err.valueType = typeof originalErr;
|
||||
err.value = originalErr;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when `.only()` is used with
|
||||
* `--forbid-only`.
|
||||
* @static
|
||||
* @public
|
||||
* @param {Mocha} mocha - Mocha instance
|
||||
* @returns {Error} Error with code {@link constants.FORBIDDEN_EXCLUSIVITY}
|
||||
*/
|
||||
function createForbiddenExclusivityError(mocha) {
|
||||
var err = new Error(
|
||||
mocha.isWorker
|
||||
? '`.only` is not supported in parallel mode'
|
||||
: '`.only` forbidden by --forbid-only'
|
||||
);
|
||||
err.code = constants.FORBIDDEN_EXCLUSIVITY;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when a plugin definition is invalid
|
||||
* @static
|
||||
* @param {string} msg - Error message
|
||||
* @param {PluginDefinition} [pluginDef] - Problematic plugin definition
|
||||
* @public
|
||||
* @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
|
||||
*/
|
||||
function createInvalidPluginDefinitionError(msg, pluginDef) {
|
||||
const err = new Error(msg);
|
||||
err.code = constants.INVALID_PLUGIN_DEFINITION;
|
||||
err.pluginDef = pluginDef;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when a plugin implementation (user code) is invalid
|
||||
* @static
|
||||
* @param {string} msg - Error message
|
||||
* @param {Object} [opts] - Plugin definition and user-supplied implementation
|
||||
* @param {PluginDefinition} [opts.pluginDef] - Plugin Definition
|
||||
* @param {*} [opts.pluginImpl] - Plugin Implementation (user-supplied)
|
||||
* @public
|
||||
* @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
|
||||
*/
|
||||
function createInvalidPluginImplementationError(
|
||||
msg,
|
||||
{pluginDef, pluginImpl} = {}
|
||||
) {
|
||||
const err = new Error(msg);
|
||||
err.code = constants.INVALID_PLUGIN_IMPLEMENTATION;
|
||||
err.pluginDef = pluginDef;
|
||||
err.pluginImpl = pluginImpl;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when a runnable exceeds its allowed run time.
|
||||
* @static
|
||||
* @param {string} msg - Error message
|
||||
* @param {number} [timeout] - Timeout in ms
|
||||
* @param {string} [file] - File, if given
|
||||
* @returns {MochaTimeoutError}
|
||||
*/
|
||||
function createTimeoutError(msg, timeout, file) {
|
||||
const err = new Error(msg);
|
||||
err.code = constants.TIMEOUT;
|
||||
err.timeout = timeout;
|
||||
err.file = file;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error object to be thrown when file is unparsable
|
||||
* @public
|
||||
* @static
|
||||
* @param {string} message - Error message to be displayed.
|
||||
* @param {string} filename - File name
|
||||
* @returns {Error} Error with code {@link constants.UNPARSABLE_FILE}
|
||||
*/
|
||||
function createUnparsableFileError(message, filename) {
|
||||
var err = new Error(message);
|
||||
err.code = constants.UNPARSABLE_FILE;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if an error came out of Mocha.
|
||||
* _Can suffer from false negatives, but not false positives._
|
||||
* @static
|
||||
* @public
|
||||
* @param {*} err - Error, or anything
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isMochaError = err =>
|
||||
Boolean(err && typeof err === 'object' && MOCHA_ERRORS.has(err.code));
|
||||
|
||||
module.exports = {
|
||||
constants,
|
||||
createFatalError,
|
||||
createForbiddenExclusivityError,
|
||||
createInvalidArgumentTypeError,
|
||||
createInvalidArgumentValueError,
|
||||
createInvalidExceptionError,
|
||||
createInvalidInterfaceError,
|
||||
createInvalidLegacyPluginError,
|
||||
createInvalidPluginDefinitionError,
|
||||
createInvalidPluginError,
|
||||
createInvalidPluginImplementationError,
|
||||
createInvalidReporterError,
|
||||
createMissingArgumentError,
|
||||
createMochaInstanceAlreadyDisposedError,
|
||||
createMochaInstanceAlreadyRunningError,
|
||||
createMultipleDoneError,
|
||||
createNoFilesMatchPatternError,
|
||||
createTimeoutError,
|
||||
createUnparsableFileError,
|
||||
createUnsupportedError,
|
||||
deprecate,
|
||||
isMochaError,
|
||||
warn
|
||||
};
|
||||
|
||||
/**
|
||||
* The error thrown when a Runnable times out
|
||||
* @memberof module:lib/errors
|
||||
* @typedef {Error} MochaTimeoutError
|
||||
* @property {constants.TIMEOUT} code - Error code
|
||||
* @property {number?} timeout Timeout in ms
|
||||
* @property {string?} file Filepath, if given
|
||||
*/
|
||||
89
node_modules/mocha/lib/hook.js
generated
vendored
Normal file
89
node_modules/mocha/lib/hook.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
'use strict';
|
||||
|
||||
var Runnable = require('./runnable');
|
||||
const {inherits, constants} = require('./utils');
|
||||
const {MOCHA_ID_PROP_NAME} = constants;
|
||||
|
||||
/**
|
||||
* Expose `Hook`.
|
||||
*/
|
||||
|
||||
module.exports = Hook;
|
||||
|
||||
/**
|
||||
* Initialize a new `Hook` with the given `title` and callback `fn`
|
||||
*
|
||||
* @class
|
||||
* @extends Runnable
|
||||
* @param {String} title
|
||||
* @param {Function} fn
|
||||
*/
|
||||
function Hook(title, fn) {
|
||||
Runnable.call(this, title, fn);
|
||||
this.type = 'hook';
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Runnable.prototype`.
|
||||
*/
|
||||
inherits(Hook, Runnable);
|
||||
|
||||
/**
|
||||
* Resets the state for a next run.
|
||||
*/
|
||||
Hook.prototype.reset = function () {
|
||||
Runnable.prototype.reset.call(this);
|
||||
delete this._error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get or set the test `err`.
|
||||
*
|
||||
* @memberof Hook
|
||||
* @public
|
||||
* @param {Error} err
|
||||
* @return {Error}
|
||||
*/
|
||||
Hook.prototype.error = function (err) {
|
||||
if (!arguments.length) {
|
||||
err = this._error;
|
||||
this._error = null;
|
||||
return err;
|
||||
}
|
||||
|
||||
this._error = err;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object suitable for IPC.
|
||||
* Functions are represented by keys beginning with `$$`.
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
Hook.prototype.serialize = function serialize() {
|
||||
return {
|
||||
$$currentRetry: this.currentRetry(),
|
||||
$$fullTitle: this.fullTitle(),
|
||||
$$isPending: Boolean(this.isPending()),
|
||||
$$titlePath: this.titlePath(),
|
||||
ctx:
|
||||
this.ctx && this.ctx.currentTest
|
||||
? {
|
||||
currentTest: {
|
||||
title: this.ctx.currentTest.title,
|
||||
[MOCHA_ID_PROP_NAME]: this.ctx.currentTest.id
|
||||
}
|
||||
}
|
||||
: {},
|
||||
duration: this.duration,
|
||||
file: this.file,
|
||||
parent: {
|
||||
$$fullTitle: this.parent.fullTitle(),
|
||||
[MOCHA_ID_PROP_NAME]: this.parent.id
|
||||
},
|
||||
state: this.state,
|
||||
title: this.title,
|
||||
type: this.type,
|
||||
[MOCHA_ID_PROP_NAME]: this.id
|
||||
};
|
||||
};
|
||||
114
node_modules/mocha/lib/interfaces/bdd.js
generated
vendored
Normal file
114
node_modules/mocha/lib/interfaces/bdd.js
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
'use strict';
|
||||
|
||||
var Test = require('../test');
|
||||
var EVENT_FILE_PRE_REQUIRE =
|
||||
require('../suite').constants.EVENT_FILE_PRE_REQUIRE;
|
||||
|
||||
/**
|
||||
* BDD-style interface:
|
||||
*
|
||||
* describe('Array', function() {
|
||||
* describe('#indexOf()', function() {
|
||||
* it('should return -1 when not present', function() {
|
||||
* // ...
|
||||
* });
|
||||
*
|
||||
* it('should return the index when present', function() {
|
||||
* // ...
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* @param {Suite} suite Root suite.
|
||||
*/
|
||||
module.exports = function bddInterface(suite) {
|
||||
var suites = [suite];
|
||||
|
||||
suite.on(EVENT_FILE_PRE_REQUIRE, function (context, file, mocha) {
|
||||
var common = require('./common')(suites, context, mocha);
|
||||
|
||||
context.before = common.before;
|
||||
context.after = common.after;
|
||||
context.beforeEach = common.beforeEach;
|
||||
context.afterEach = common.afterEach;
|
||||
context.run = mocha.options.delay && common.runWithSuite(suite);
|
||||
/**
|
||||
* Describe a "suite" with the given `title`
|
||||
* and callback `fn` containing nested suites
|
||||
* and/or tests.
|
||||
*/
|
||||
|
||||
context.describe = context.context = function (title, fn) {
|
||||
return common.suite.create({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: fn
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Pending describe.
|
||||
*/
|
||||
|
||||
context.xdescribe =
|
||||
context.xcontext =
|
||||
context.describe.skip =
|
||||
function (title, fn) {
|
||||
return common.suite.skip({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: fn
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclusive suite.
|
||||
*/
|
||||
|
||||
context.describe.only = function (title, fn) {
|
||||
return common.suite.only({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: fn
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Describe a specification or test-case
|
||||
* with the given `title` and callback `fn`
|
||||
* acting as a thunk.
|
||||
*/
|
||||
|
||||
context.it = context.specify = function (title, fn) {
|
||||
var suite = suites[0];
|
||||
if (suite.isPending()) {
|
||||
fn = null;
|
||||
}
|
||||
var test = new Test(title, fn);
|
||||
test.file = file;
|
||||
suite.addTest(test);
|
||||
return test;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclusive test-case.
|
||||
*/
|
||||
|
||||
context.it.only = function (title, fn) {
|
||||
return common.test.only(mocha, context.it(title, fn));
|
||||
};
|
||||
|
||||
/**
|
||||
* Pending test case.
|
||||
*/
|
||||
|
||||
context.xit =
|
||||
context.xspecify =
|
||||
context.it.skip =
|
||||
function (title) {
|
||||
return context.it(title);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.description = 'BDD or RSpec style [default]';
|
||||
193
node_modules/mocha/lib/interfaces/common.js
generated
vendored
Normal file
193
node_modules/mocha/lib/interfaces/common.js
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@module interfaces/common
|
||||
*/
|
||||
|
||||
var Suite = require('../suite');
|
||||
var errors = require('../errors');
|
||||
var createMissingArgumentError = errors.createMissingArgumentError;
|
||||
var createUnsupportedError = errors.createUnsupportedError;
|
||||
var createForbiddenExclusivityError = errors.createForbiddenExclusivityError;
|
||||
|
||||
/**
|
||||
* Functions common to more than one interface.
|
||||
*
|
||||
* @private
|
||||
* @param {Suite[]} suites
|
||||
* @param {Context} context
|
||||
* @param {Mocha} mocha
|
||||
* @return {Object} An object containing common functions.
|
||||
*/
|
||||
module.exports = function (suites, context, mocha) {
|
||||
/**
|
||||
* Check if the suite should be tested.
|
||||
*
|
||||
* @private
|
||||
* @param {Suite} suite - suite to check
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function shouldBeTested(suite) {
|
||||
return (
|
||||
!mocha.options.grep ||
|
||||
(mocha.options.grep &&
|
||||
mocha.options.grep.test(suite.fullTitle()) &&
|
||||
!mocha.options.invert)
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* This is only present if flag --delay is passed into Mocha. It triggers
|
||||
* root suite execution.
|
||||
*
|
||||
* @param {Suite} suite The root suite.
|
||||
* @return {Function} A function which runs the root suite
|
||||
*/
|
||||
runWithSuite: function runWithSuite(suite) {
|
||||
return function run() {
|
||||
suite.run();
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute before running tests.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {Function} fn
|
||||
*/
|
||||
before: function (name, fn) {
|
||||
suites[0].beforeAll(name, fn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute after running tests.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {Function} fn
|
||||
*/
|
||||
after: function (name, fn) {
|
||||
suites[0].afterAll(name, fn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute before each test case.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {Function} fn
|
||||
*/
|
||||
beforeEach: function (name, fn) {
|
||||
suites[0].beforeEach(name, fn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute after each test case.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {Function} fn
|
||||
*/
|
||||
afterEach: function (name, fn) {
|
||||
suites[0].afterEach(name, fn);
|
||||
},
|
||||
|
||||
suite: {
|
||||
/**
|
||||
* Create an exclusive Suite; convenience function
|
||||
* See docstring for create() below.
|
||||
*
|
||||
* @param {Object} opts
|
||||
* @returns {Suite}
|
||||
*/
|
||||
only: function only(opts) {
|
||||
if (mocha.options.forbidOnly) {
|
||||
throw createForbiddenExclusivityError(mocha);
|
||||
}
|
||||
opts.isOnly = true;
|
||||
return this.create(opts);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a Suite, but skip it; convenience function
|
||||
* See docstring for create() below.
|
||||
*
|
||||
* @param {Object} opts
|
||||
* @returns {Suite}
|
||||
*/
|
||||
skip: function skip(opts) {
|
||||
opts.pending = true;
|
||||
return this.create(opts);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a suite.
|
||||
*
|
||||
* @param {Object} opts Options
|
||||
* @param {string} opts.title Title of Suite
|
||||
* @param {Function} [opts.fn] Suite Function (not always applicable)
|
||||
* @param {boolean} [opts.pending] Is Suite pending?
|
||||
* @param {string} [opts.file] Filepath where this Suite resides
|
||||
* @param {boolean} [opts.isOnly] Is Suite exclusive?
|
||||
* @returns {Suite}
|
||||
*/
|
||||
create: function create(opts) {
|
||||
var suite = Suite.create(suites[0], opts.title);
|
||||
suite.pending = Boolean(opts.pending);
|
||||
suite.file = opts.file;
|
||||
suites.unshift(suite);
|
||||
if (opts.isOnly) {
|
||||
suite.markOnly();
|
||||
}
|
||||
if (
|
||||
suite.pending &&
|
||||
mocha.options.forbidPending &&
|
||||
shouldBeTested(suite)
|
||||
) {
|
||||
throw createUnsupportedError('Pending test forbidden');
|
||||
}
|
||||
if (typeof opts.fn === 'function') {
|
||||
opts.fn.call(suite);
|
||||
suites.shift();
|
||||
} else if (typeof opts.fn === 'undefined' && !suite.pending) {
|
||||
throw createMissingArgumentError(
|
||||
'Suite "' +
|
||||
suite.fullTitle() +
|
||||
'" was defined but no callback was supplied. ' +
|
||||
'Supply a callback or explicitly skip the suite.',
|
||||
'callback',
|
||||
'function'
|
||||
);
|
||||
} else if (!opts.fn && suite.pending) {
|
||||
suites.shift();
|
||||
}
|
||||
|
||||
return suite;
|
||||
}
|
||||
},
|
||||
|
||||
test: {
|
||||
/**
|
||||
* Exclusive test-case.
|
||||
*
|
||||
* @param {Object} mocha
|
||||
* @param {Function} test
|
||||
* @returns {*}
|
||||
*/
|
||||
only: function (mocha, test) {
|
||||
if (mocha.options.forbidOnly) {
|
||||
throw createForbiddenExclusivityError(mocha);
|
||||
}
|
||||
test.markOnly();
|
||||
return test;
|
||||
},
|
||||
|
||||
/**
|
||||
* Pending test case.
|
||||
*
|
||||
* @param {string} title
|
||||
*/
|
||||
skip: function (title) {
|
||||
context.test(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
60
node_modules/mocha/lib/interfaces/exports.js
generated
vendored
Normal file
60
node_modules/mocha/lib/interfaces/exports.js
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
var Suite = require('../suite');
|
||||
var Test = require('../test');
|
||||
|
||||
/**
|
||||
* Exports-style (as Node.js module) interface:
|
||||
*
|
||||
* exports.Array = {
|
||||
* '#indexOf()': {
|
||||
* 'should return -1 when the value is not present': function() {
|
||||
*
|
||||
* },
|
||||
*
|
||||
* 'should return the correct index when the value is present': function() {
|
||||
*
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* @param {Suite} suite Root suite.
|
||||
*/
|
||||
module.exports = function (suite) {
|
||||
var suites = [suite];
|
||||
|
||||
suite.on(Suite.constants.EVENT_FILE_REQUIRE, visit);
|
||||
|
||||
function visit(obj, file) {
|
||||
var suite;
|
||||
for (var key in obj) {
|
||||
if (typeof obj[key] === 'function') {
|
||||
var fn = obj[key];
|
||||
switch (key) {
|
||||
case 'before':
|
||||
suites[0].beforeAll(fn);
|
||||
break;
|
||||
case 'after':
|
||||
suites[0].afterAll(fn);
|
||||
break;
|
||||
case 'beforeEach':
|
||||
suites[0].beforeEach(fn);
|
||||
break;
|
||||
case 'afterEach':
|
||||
suites[0].afterEach(fn);
|
||||
break;
|
||||
default:
|
||||
var test = new Test(key, fn);
|
||||
test.file = file;
|
||||
suites[0].addTest(test);
|
||||
}
|
||||
} else {
|
||||
suite = Suite.create(suites[0], key);
|
||||
suites.unshift(suite);
|
||||
visit(obj[key], file);
|
||||
suites.shift();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.description = 'Node.js module ("exports") style';
|
||||
6
node_modules/mocha/lib/interfaces/index.js
generated
vendored
Normal file
6
node_modules/mocha/lib/interfaces/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
exports.bdd = require('./bdd');
|
||||
exports.tdd = require('./tdd');
|
||||
exports.qunit = require('./qunit');
|
||||
exports.exports = require('./exports');
|
||||
98
node_modules/mocha/lib/interfaces/qunit.js
generated
vendored
Normal file
98
node_modules/mocha/lib/interfaces/qunit.js
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
'use strict';
|
||||
|
||||
var Test = require('../test');
|
||||
var EVENT_FILE_PRE_REQUIRE =
|
||||
require('../suite').constants.EVENT_FILE_PRE_REQUIRE;
|
||||
|
||||
/**
|
||||
* QUnit-style interface:
|
||||
*
|
||||
* suite('Array');
|
||||
*
|
||||
* test('#length', function() {
|
||||
* var arr = [1,2,3];
|
||||
* ok(arr.length == 3);
|
||||
* });
|
||||
*
|
||||
* test('#indexOf()', function() {
|
||||
* var arr = [1,2,3];
|
||||
* ok(arr.indexOf(1) == 0);
|
||||
* ok(arr.indexOf(2) == 1);
|
||||
* ok(arr.indexOf(3) == 2);
|
||||
* });
|
||||
*
|
||||
* suite('String');
|
||||
*
|
||||
* test('#length', function() {
|
||||
* ok('foo'.length == 3);
|
||||
* });
|
||||
*
|
||||
* @param {Suite} suite Root suite.
|
||||
*/
|
||||
module.exports = function qUnitInterface(suite) {
|
||||
var suites = [suite];
|
||||
|
||||
suite.on(EVENT_FILE_PRE_REQUIRE, function (context, file, mocha) {
|
||||
var common = require('./common')(suites, context, mocha);
|
||||
|
||||
context.before = common.before;
|
||||
context.after = common.after;
|
||||
context.beforeEach = common.beforeEach;
|
||||
context.afterEach = common.afterEach;
|
||||
context.run = mocha.options.delay && common.runWithSuite(suite);
|
||||
/**
|
||||
* Describe a "suite" with the given `title`.
|
||||
*/
|
||||
|
||||
context.suite = function (title) {
|
||||
if (suites.length > 1) {
|
||||
suites.shift();
|
||||
}
|
||||
return common.suite.create({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: false
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclusive Suite.
|
||||
*/
|
||||
|
||||
context.suite.only = function (title) {
|
||||
if (suites.length > 1) {
|
||||
suites.shift();
|
||||
}
|
||||
return common.suite.only({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: false
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Describe a specification or test-case
|
||||
* with the given `title` and callback `fn`
|
||||
* acting as a thunk.
|
||||
*/
|
||||
|
||||
context.test = function (title, fn) {
|
||||
var test = new Test(title, fn);
|
||||
test.file = file;
|
||||
suites[0].addTest(test);
|
||||
return test;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclusive test-case.
|
||||
*/
|
||||
|
||||
context.test.only = function (title, fn) {
|
||||
return common.test.only(mocha, context.test(title, fn));
|
||||
};
|
||||
|
||||
context.test.skip = common.test.skip;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.description = 'QUnit style';
|
||||
106
node_modules/mocha/lib/interfaces/tdd.js
generated
vendored
Normal file
106
node_modules/mocha/lib/interfaces/tdd.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
'use strict';
|
||||
|
||||
var Test = require('../test');
|
||||
var EVENT_FILE_PRE_REQUIRE =
|
||||
require('../suite').constants.EVENT_FILE_PRE_REQUIRE;
|
||||
|
||||
/**
|
||||
* TDD-style interface:
|
||||
*
|
||||
* suite('Array', function() {
|
||||
* suite('#indexOf()', function() {
|
||||
* suiteSetup(function() {
|
||||
*
|
||||
* });
|
||||
*
|
||||
* test('should return -1 when not present', function() {
|
||||
*
|
||||
* });
|
||||
*
|
||||
* test('should return the index when present', function() {
|
||||
*
|
||||
* });
|
||||
*
|
||||
* suiteTeardown(function() {
|
||||
*
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* @param {Suite} suite Root suite.
|
||||
*/
|
||||
module.exports = function (suite) {
|
||||
var suites = [suite];
|
||||
|
||||
suite.on(EVENT_FILE_PRE_REQUIRE, function (context, file, mocha) {
|
||||
var common = require('./common')(suites, context, mocha);
|
||||
|
||||
context.setup = common.beforeEach;
|
||||
context.teardown = common.afterEach;
|
||||
context.suiteSetup = common.before;
|
||||
context.suiteTeardown = common.after;
|
||||
context.run = mocha.options.delay && common.runWithSuite(suite);
|
||||
|
||||
/**
|
||||
* Describe a "suite" with the given `title` and callback `fn` containing
|
||||
* nested suites and/or tests.
|
||||
*/
|
||||
context.suite = function (title, fn) {
|
||||
return common.suite.create({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: fn
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Pending suite.
|
||||
*/
|
||||
context.suite.skip = function (title, fn) {
|
||||
return common.suite.skip({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: fn
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclusive test-case.
|
||||
*/
|
||||
context.suite.only = function (title, fn) {
|
||||
return common.suite.only({
|
||||
title: title,
|
||||
file: file,
|
||||
fn: fn
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Describe a specification or test-case with the given `title` and
|
||||
* callback `fn` acting as a thunk.
|
||||
*/
|
||||
context.test = function (title, fn) {
|
||||
var suite = suites[0];
|
||||
if (suite.isPending()) {
|
||||
fn = null;
|
||||
}
|
||||
var test = new Test(title, fn);
|
||||
test.file = file;
|
||||
suite.addTest(test);
|
||||
return test;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclusive test-case.
|
||||
*/
|
||||
|
||||
context.test.only = function (title, fn) {
|
||||
return common.test.only(mocha, context.test(title, fn));
|
||||
};
|
||||
|
||||
context.test.skip = common.test.skip;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.description =
|
||||
'traditional "suite"/"test" instead of BDD\'s "describe"/"it"';
|
||||
1313
node_modules/mocha/lib/mocha.js
generated
vendored
Normal file
1313
node_modules/mocha/lib/mocha.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
node_modules/mocha/lib/mocharc.json
generated
vendored
Normal file
10
node_modules/mocha/lib/mocharc.json
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"diff": true,
|
||||
"extension": ["js", "cjs", "mjs"],
|
||||
"package": "./package.json",
|
||||
"reporter": "spec",
|
||||
"slow": 75,
|
||||
"timeout": 2000,
|
||||
"ui": "bdd",
|
||||
"watch-ignore": ["node_modules", ".git"]
|
||||
}
|
||||
188
node_modules/mocha/lib/nodejs/buffered-worker-pool.js
generated
vendored
Normal file
188
node_modules/mocha/lib/nodejs/buffered-worker-pool.js
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* A wrapper around a third-party child process worker pool implementation.
|
||||
* Used by {@link module:buffered-runner}.
|
||||
* @private
|
||||
* @module buffered-worker-pool
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const serializeJavascript = require('serialize-javascript');
|
||||
const workerpool = require('workerpool');
|
||||
const {deserialize} = require('./serializer');
|
||||
const debug = require('debug')('mocha:parallel:buffered-worker-pool');
|
||||
const {createInvalidArgumentTypeError} = require('../errors');
|
||||
|
||||
const WORKER_PATH = require.resolve('./worker.js');
|
||||
|
||||
/**
|
||||
* A mapping of Mocha `Options` objects to serialized values.
|
||||
*
|
||||
* This is helpful because we tend to same the same options over and over
|
||||
* over IPC.
|
||||
* @type {WeakMap<Options,string>}
|
||||
*/
|
||||
let optionsCache = new WeakMap();
|
||||
|
||||
/**
|
||||
* These options are passed into the [workerpool](https://npm.im/workerpool) module.
|
||||
* @type {Partial<WorkerPoolOptions>}
|
||||
*/
|
||||
const WORKER_POOL_DEFAULT_OPTS = {
|
||||
// use child processes, not worker threads!
|
||||
workerType: 'process',
|
||||
// ensure the same flags sent to `node` for this `mocha` invocation are passed
|
||||
// along to children
|
||||
forkOpts: {execArgv: process.execArgv},
|
||||
maxWorkers: workerpool.cpus - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper around a third-party worker pool implementation.
|
||||
* @private
|
||||
*/
|
||||
class BufferedWorkerPool {
|
||||
/**
|
||||
* Creates an underlying worker pool instance; determines max worker count
|
||||
* @param {Partial<WorkerPoolOptions>} [opts] - Options
|
||||
*/
|
||||
constructor(opts = {}) {
|
||||
const maxWorkers = Math.max(
|
||||
1,
|
||||
typeof opts.maxWorkers === 'undefined'
|
||||
? WORKER_POOL_DEFAULT_OPTS.maxWorkers
|
||||
: opts.maxWorkers
|
||||
);
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (workerpool.cpus < 2) {
|
||||
// TODO: decide whether we should warn
|
||||
debug(
|
||||
'not enough CPU cores available to run multiple jobs; avoid --parallel on this machine'
|
||||
);
|
||||
} else if (maxWorkers >= workerpool.cpus) {
|
||||
// TODO: decide whether we should warn
|
||||
debug(
|
||||
'%d concurrent job(s) requested, but only %d core(s) available',
|
||||
maxWorkers,
|
||||
workerpool.cpus
|
||||
);
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
debug(
|
||||
'run(): starting worker pool of max size %d, using node args: %s',
|
||||
maxWorkers,
|
||||
process.execArgv.join(' ')
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
const onCreateWorker = ({forkOpts}) => {
|
||||
return {
|
||||
forkOpts: {
|
||||
...forkOpts,
|
||||
// adds an incremental id to all workers, which can be useful to allocate resources for each process
|
||||
env: {...process.env, MOCHA_WORKER_ID: counter++}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
this.options = {
|
||||
...WORKER_POOL_DEFAULT_OPTS,
|
||||
...opts,
|
||||
maxWorkers,
|
||||
onCreateWorker
|
||||
};
|
||||
this._pool = workerpool.pool(WORKER_PATH, this.options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates all workers in the pool.
|
||||
* @param {boolean} [force] - Whether to force-kill workers. By default, lets workers finish their current task before termination.
|
||||
* @private
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async terminate(force = false) {
|
||||
/* istanbul ignore next */
|
||||
debug('terminate(): terminating with force = %s', force);
|
||||
return this._pool.terminate(force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a test file run to the worker pool queue for execution by a worker process.
|
||||
*
|
||||
* Handles serialization/deserialization.
|
||||
*
|
||||
* @param {string} filepath - Filepath of test
|
||||
* @param {Options} [options] - Options for Mocha instance
|
||||
* @private
|
||||
* @returns {Promise<SerializedWorkerResult>}
|
||||
*/
|
||||
async run(filepath, options = {}) {
|
||||
if (!filepath || typeof filepath !== 'string') {
|
||||
throw createInvalidArgumentTypeError(
|
||||
'Expected a non-empty filepath',
|
||||
'filepath',
|
||||
'string'
|
||||
);
|
||||
}
|
||||
const serializedOptions = BufferedWorkerPool.serializeOptions(options);
|
||||
const result = await this._pool.exec('run', [filepath, serializedOptions]);
|
||||
return deserialize(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns stats about the state of the worker processes in the pool.
|
||||
*
|
||||
* Used for debugging.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
stats() {
|
||||
return this._pool.stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link WorkerPool}.
|
||||
* @private
|
||||
*/
|
||||
static create(...args) {
|
||||
return new BufferedWorkerPool(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given Mocha options object `opts`, serialize into a format suitable for
|
||||
* transmission over IPC.
|
||||
*
|
||||
* @param {Options} [opts] - Mocha options
|
||||
* @private
|
||||
* @returns {string} Serialized options
|
||||
*/
|
||||
static serializeOptions(opts = {}) {
|
||||
if (!optionsCache.has(opts)) {
|
||||
const serialized = serializeJavascript(opts, {
|
||||
unsafe: true, // this means we don't care about XSS
|
||||
ignoreFunction: true // do not serialize functions
|
||||
});
|
||||
optionsCache.set(opts, serialized);
|
||||
/* istanbul ignore next */
|
||||
debug(
|
||||
'serializeOptions(): serialized options %O to: %s',
|
||||
opts,
|
||||
serialized
|
||||
);
|
||||
}
|
||||
return optionsCache.get(opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets internal cache of serialized options objects.
|
||||
*
|
||||
* For testing/debugging
|
||||
* @private
|
||||
*/
|
||||
static resetOptionsCache() {
|
||||
optionsCache = new WeakMap();
|
||||
}
|
||||
}
|
||||
|
||||
exports.BufferedWorkerPool = BufferedWorkerPool;
|
||||
94
node_modules/mocha/lib/nodejs/esm-utils.js
generated
vendored
Normal file
94
node_modules/mocha/lib/nodejs/esm-utils.js
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
|
||||
const formattedImport = async file => {
|
||||
if (path.isAbsolute(file)) {
|
||||
try {
|
||||
return await import(url.pathToFileURL(file));
|
||||
} catch (err) {
|
||||
// This is a hack created because ESM in Node.js (at least in Node v15.5.1) does not emit
|
||||
// the location of the syntax error in the error thrown.
|
||||
// This is problematic because the user can't see what file has the problem,
|
||||
// so we add the file location to the error.
|
||||
// TODO: remove once Node.js fixes the problem.
|
||||
if (
|
||||
err instanceof SyntaxError &&
|
||||
err.message &&
|
||||
err.stack &&
|
||||
!err.stack.includes(file)
|
||||
) {
|
||||
const newErrorWithFilename = new SyntaxError(err.message);
|
||||
newErrorWithFilename.stack = err.stack.replace(
|
||||
/^SyntaxError/,
|
||||
`SyntaxError[ @${file} ]`
|
||||
);
|
||||
throw newErrorWithFilename;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
return import(file);
|
||||
};
|
||||
|
||||
exports.requireOrImport = async file => {
|
||||
if (path.extname(file) === '.mjs') {
|
||||
return formattedImport(file);
|
||||
}
|
||||
try {
|
||||
return dealWithExports(await formattedImport(file));
|
||||
} catch (err) {
|
||||
if (
|
||||
err.code === 'ERR_MODULE_NOT_FOUND' ||
|
||||
err.code === 'ERR_UNKNOWN_FILE_EXTENSION' ||
|
||||
err.code === 'ERR_UNSUPPORTED_DIR_IMPORT'
|
||||
) {
|
||||
try {
|
||||
// Importing a file usually works, but the resolution of `import` is the ESM
|
||||
// resolution algorithm, and not the CJS resolution algorithm. We may have
|
||||
// failed because we tried the ESM resolution, so we try to `require` it.
|
||||
return require(file);
|
||||
} catch (requireErr) {
|
||||
if (
|
||||
requireErr.code === 'ERR_REQUIRE_ESM' ||
|
||||
(requireErr instanceof SyntaxError &&
|
||||
requireErr
|
||||
.toString()
|
||||
.includes('Cannot use import statement outside a module'))
|
||||
) {
|
||||
// ERR_REQUIRE_ESM happens when the test file is a JS file, but via type:module is actually ESM,
|
||||
// AND has an import to a file that doesn't exist.
|
||||
// This throws an `ERR_MODULE_NOT_FOUND` error above,
|
||||
// and when we try to `require` it here, it throws an `ERR_REQUIRE_ESM`.
|
||||
// What we want to do is throw the original error (the `ERR_MODULE_NOT_FOUND`),
|
||||
// and not the `ERR_REQUIRE_ESM` error, which is a red herring.
|
||||
//
|
||||
// SyntaxError happens when in an edge case: when we're using an ESM loader that loads
|
||||
// a `test.ts` file (i.e. unrecognized extension), and that file includes an unknown
|
||||
// import (which throws an ERR_MODULE_NOT_FOUND). `require`-ing it will throw the
|
||||
// syntax error, because we cannot require a file that has `import`-s.
|
||||
throw err;
|
||||
} else {
|
||||
throw requireErr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function dealWithExports(module) {
|
||||
if (module.default) {
|
||||
return module.default;
|
||||
} else {
|
||||
return {...module, default: undefined};
|
||||
}
|
||||
}
|
||||
|
||||
exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => {
|
||||
for (const file of files) {
|
||||
preLoadFunc(file);
|
||||
const result = await exports.requireOrImport(path.resolve(file));
|
||||
postLoadFunc(file, result);
|
||||
}
|
||||
};
|
||||
15
node_modules/mocha/lib/nodejs/file-unloader.js
generated
vendored
Normal file
15
node_modules/mocha/lib/nodejs/file-unloader.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This module should not be in the browser bundle, so it's here.
|
||||
* @private
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* Deletes a file from the `require` cache.
|
||||
* @param {string} file - File
|
||||
*/
|
||||
exports.unloadFile = file => {
|
||||
delete require.cache[require.resolve(file)];
|
||||
};
|
||||
434
node_modules/mocha/lib/nodejs/parallel-buffered-runner.js
generated
vendored
Normal file
434
node_modules/mocha/lib/nodejs/parallel-buffered-runner.js
generated
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
/**
|
||||
* A test Runner that uses a {@link module:buffered-worker-pool}.
|
||||
* @module parallel-buffered-runner
|
||||
* @private
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const allSettled = require('@ungap/promise-all-settled').bind(Promise);
|
||||
const Runner = require('../runner');
|
||||
const {EVENT_RUN_BEGIN, EVENT_RUN_END} = Runner.constants;
|
||||
const debug = require('debug')('mocha:parallel:parallel-buffered-runner');
|
||||
const {BufferedWorkerPool} = require('./buffered-worker-pool');
|
||||
const {setInterval, clearInterval} = global;
|
||||
const {createMap, constants} = require('../utils');
|
||||
const {MOCHA_ID_PROP_NAME} = constants;
|
||||
const {createFatalError} = require('../errors');
|
||||
|
||||
const DEFAULT_WORKER_REPORTER = require.resolve(
|
||||
'./reporters/parallel-buffered'
|
||||
);
|
||||
|
||||
/**
|
||||
* List of options to _not_ serialize for transmission to workers
|
||||
*/
|
||||
const DENY_OPTIONS = [
|
||||
'globalSetup',
|
||||
'globalTeardown',
|
||||
'parallel',
|
||||
'p',
|
||||
'jobs',
|
||||
'j'
|
||||
];
|
||||
|
||||
/**
|
||||
* Outputs a debug statement with worker stats
|
||||
* @param {BufferedWorkerPool} pool - Worker pool
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
const debugStats = pool => {
|
||||
const {totalWorkers, busyWorkers, idleWorkers, pendingTasks} = pool.stats();
|
||||
debug(
|
||||
'%d/%d busy workers; %d idle; %d tasks queued',
|
||||
busyWorkers,
|
||||
totalWorkers,
|
||||
idleWorkers,
|
||||
pendingTasks
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* The interval at which we will display stats for worker processes in debug mode
|
||||
*/
|
||||
const DEBUG_STATS_INTERVAL = 5000;
|
||||
|
||||
const ABORTED = 'ABORTED';
|
||||
const IDLE = 'IDLE';
|
||||
const ABORTING = 'ABORTING';
|
||||
const RUNNING = 'RUNNING';
|
||||
const BAILING = 'BAILING';
|
||||
const BAILED = 'BAILED';
|
||||
const COMPLETE = 'COMPLETE';
|
||||
|
||||
const states = createMap({
|
||||
[IDLE]: new Set([RUNNING, ABORTING]),
|
||||
[RUNNING]: new Set([COMPLETE, BAILING, ABORTING]),
|
||||
[COMPLETE]: new Set(),
|
||||
[ABORTED]: new Set(),
|
||||
[ABORTING]: new Set([ABORTED]),
|
||||
[BAILING]: new Set([BAILED, ABORTING]),
|
||||
[BAILED]: new Set([COMPLETE, ABORTING])
|
||||
});
|
||||
|
||||
/**
|
||||
* This `Runner` delegates tests runs to worker threads. Does not execute any
|
||||
* {@link Runnable}s by itself!
|
||||
* @public
|
||||
*/
|
||||
class ParallelBufferedRunner extends Runner {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
let state = IDLE;
|
||||
Object.defineProperty(this, '_state', {
|
||||
get() {
|
||||
return state;
|
||||
},
|
||||
set(newState) {
|
||||
if (states[state].has(newState)) {
|
||||
state = newState;
|
||||
} else {
|
||||
throw new Error(`invalid state transition: ${state} => ${newState}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this._workerReporter = DEFAULT_WORKER_REPORTER;
|
||||
this._linkPartialObjects = false;
|
||||
this._linkedObjectMap = new Map();
|
||||
|
||||
this.once(Runner.constants.EVENT_RUN_END, () => {
|
||||
this._state = COMPLETE;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mapping function to enqueue a file in the worker pool and return results of its execution.
|
||||
* @param {BufferedWorkerPool} pool - Worker pool
|
||||
* @param {Options} options - Mocha options
|
||||
* @returns {FileRunner} Mapping function
|
||||
* @private
|
||||
*/
|
||||
_createFileRunner(pool, options) {
|
||||
/**
|
||||
* Emits event and sets `BAILING` state, if necessary.
|
||||
* @param {Object} event - Event having `eventName`, maybe `data` and maybe `error`
|
||||
* @param {number} failureCount - Failure count
|
||||
*/
|
||||
const emitEvent = (event, failureCount) => {
|
||||
this.emit(event.eventName, event.data, event.error);
|
||||
if (
|
||||
this._state !== BAILING &&
|
||||
event.data &&
|
||||
event.data._bail &&
|
||||
(failureCount || event.error)
|
||||
) {
|
||||
debug('run(): nonzero failure count & found bail flag');
|
||||
// we need to let the events complete for this file, as the worker
|
||||
// should run any cleanup hooks
|
||||
this._state = BAILING;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an event, recursively find any objects in its data that have ID's, and create object references to already-seen objects.
|
||||
* @param {Object} event - Event having `eventName`, maybe `data` and maybe `error`
|
||||
*/
|
||||
const linkEvent = event => {
|
||||
const stack = [{parent: event, prop: 'data'}];
|
||||
while (stack.length) {
|
||||
const {parent, prop} = stack.pop();
|
||||
const obj = parent[prop];
|
||||
let newObj;
|
||||
if (obj && typeof obj === 'object') {
|
||||
if (obj[MOCHA_ID_PROP_NAME]) {
|
||||
const id = obj[MOCHA_ID_PROP_NAME];
|
||||
newObj = this._linkedObjectMap.has(id)
|
||||
? Object.assign(this._linkedObjectMap.get(id), obj)
|
||||
: obj;
|
||||
this._linkedObjectMap.set(id, newObj);
|
||||
parent[prop] = newObj;
|
||||
} else {
|
||||
throw createFatalError(
|
||||
'Object missing ID received in event data',
|
||||
obj
|
||||
);
|
||||
}
|
||||
}
|
||||
Object.keys(newObj).forEach(key => {
|
||||
const value = obj[key];
|
||||
if (value && typeof value === 'object' && value[MOCHA_ID_PROP_NAME]) {
|
||||
stack.push({obj: value, parent: newObj, prop: key});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return async file => {
|
||||
debug('run(): enqueueing test file %s', file);
|
||||
try {
|
||||
const {failureCount, events} = await pool.run(file, options);
|
||||
|
||||
if (this._state === BAILED) {
|
||||
// short-circuit after a graceful bail. if this happens,
|
||||
// some other worker has bailed.
|
||||
// TODO: determine if this is the desired behavior, or if we
|
||||
// should report the events of this run anyway.
|
||||
return;
|
||||
}
|
||||
debug(
|
||||
'run(): completed run of file %s; %d failures / %d events',
|
||||
file,
|
||||
failureCount,
|
||||
events.length
|
||||
);
|
||||
this.failures += failureCount; // can this ever be non-numeric?
|
||||
let event = events.shift();
|
||||
|
||||
if (this._linkPartialObjects) {
|
||||
while (event) {
|
||||
linkEvent(event);
|
||||
emitEvent(event, failureCount);
|
||||
event = events.shift();
|
||||
}
|
||||
} else {
|
||||
while (event) {
|
||||
emitEvent(event, failureCount);
|
||||
event = events.shift();
|
||||
}
|
||||
}
|
||||
if (this._state === BAILING) {
|
||||
debug('run(): terminating pool due to "bail" flag');
|
||||
this._state = BAILED;
|
||||
await pool.terminate();
|
||||
}
|
||||
} catch (err) {
|
||||
if (this._state === BAILED || this._state === ABORTING) {
|
||||
debug(
|
||||
'run(): worker pool terminated with intent; skipping file %s',
|
||||
file
|
||||
);
|
||||
} else {
|
||||
// this is an uncaught exception
|
||||
debug('run(): encountered uncaught exception: %O', err);
|
||||
if (this.allowUncaught) {
|
||||
// still have to clean up
|
||||
this._state = ABORTING;
|
||||
await pool.terminate(true);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
debug('run(): done running file %s', file);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen on `Process.SIGINT`; terminate pool if caught.
|
||||
* Returns the listener for later call to `process.removeListener()`.
|
||||
* @param {BufferedWorkerPool} pool - Worker pool
|
||||
* @returns {SigIntListener} Listener
|
||||
* @private
|
||||
*/
|
||||
_bindSigIntListener(pool) {
|
||||
const sigIntListener = async () => {
|
||||
debug('run(): caught a SIGINT');
|
||||
this._state = ABORTING;
|
||||
|
||||
try {
|
||||
debug('run(): force-terminating worker pool');
|
||||
await pool.terminate(true);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`Error while attempting to force-terminate worker pool: ${err}`
|
||||
);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
process.nextTick(() => {
|
||||
debug('run(): imminent death');
|
||||
this._state = ABORTED;
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
process.once('SIGINT', sigIntListener);
|
||||
|
||||
return sigIntListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs Mocha tests by creating a thread pool, then delegating work to the
|
||||
* worker threads.
|
||||
*
|
||||
* Each worker receives one file, and as workers become available, they take a
|
||||
* file from the queue and run it. The worker thread execution is treated like
|
||||
* an RPC--it returns a `Promise` containing serialized information about the
|
||||
* run. The information is processed as it's received, and emitted to a
|
||||
* {@link Reporter}, which is likely listening for these events.
|
||||
*
|
||||
* @param {Function} callback - Called with an exit code corresponding to
|
||||
* number of test failures.
|
||||
* @param {Object} [opts] - options
|
||||
* @param {string[]} opts.files - Files to run
|
||||
* @param {Options} opts.options - command-line options
|
||||
*/
|
||||
run(callback, {files, options = {}} = {}) {
|
||||
/**
|
||||
* Listener on `Process.SIGINT` which tries to cleanly terminate the worker pool.
|
||||
*/
|
||||
let sigIntListener;
|
||||
|
||||
// assign the reporter the worker will use, which will be different than the
|
||||
// main process' reporter
|
||||
options = {...options, reporter: this._workerReporter};
|
||||
|
||||
// This function should _not_ return a `Promise`; its parent (`Runner#run`)
|
||||
// returns this instance, so this should do the same. However, we want to make
|
||||
// use of `async`/`await`, so we use this IIFE.
|
||||
(async () => {
|
||||
/**
|
||||
* This is an interval that outputs stats about the worker pool every so often
|
||||
*/
|
||||
let debugInterval;
|
||||
|
||||
/**
|
||||
* @type {BufferedWorkerPool}
|
||||
*/
|
||||
let pool;
|
||||
|
||||
try {
|
||||
pool = BufferedWorkerPool.create({maxWorkers: options.jobs});
|
||||
|
||||
sigIntListener = this._bindSigIntListener(pool);
|
||||
|
||||
/* istanbul ignore next */
|
||||
debugInterval = setInterval(
|
||||
() => debugStats(pool),
|
||||
DEBUG_STATS_INTERVAL
|
||||
).unref();
|
||||
|
||||
// this is set for uncaught exception handling in `Runner#uncaught`
|
||||
// TODO: `Runner` should be using a state machine instead.
|
||||
this.started = true;
|
||||
this._state = RUNNING;
|
||||
|
||||
this.emit(EVENT_RUN_BEGIN);
|
||||
|
||||
options = {...options};
|
||||
DENY_OPTIONS.forEach(opt => {
|
||||
delete options[opt];
|
||||
});
|
||||
|
||||
const results = await allSettled(
|
||||
files.map(this._createFileRunner(pool, options))
|
||||
);
|
||||
|
||||
// note that pool may already be terminated due to --bail
|
||||
await pool.terminate();
|
||||
|
||||
results
|
||||
.filter(({status}) => status === 'rejected')
|
||||
.forEach(({reason}) => {
|
||||
if (this.allowUncaught) {
|
||||
// yep, just the first one.
|
||||
throw reason;
|
||||
}
|
||||
// "rejected" will correspond to uncaught exceptions.
|
||||
// unlike the serial runner, the parallel runner can always recover.
|
||||
this.uncaught(reason);
|
||||
});
|
||||
|
||||
if (this._state === ABORTING) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.emit(EVENT_RUN_END);
|
||||
debug('run(): completing with failure count %d', this.failures);
|
||||
callback(this.failures);
|
||||
} catch (err) {
|
||||
// this `nextTick` takes us out of the `Promise` scope, so the
|
||||
// exception will not be caught and returned as a rejected `Promise`,
|
||||
// which would lead to an `unhandledRejection` event.
|
||||
process.nextTick(() => {
|
||||
debug('run(): re-throwing uncaught exception');
|
||||
throw err;
|
||||
});
|
||||
} finally {
|
||||
clearInterval(debugInterval);
|
||||
process.removeListener('SIGINT', sigIntListener);
|
||||
}
|
||||
})();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle partial object linking behavior; used for building object references from
|
||||
* unique ID's.
|
||||
* @param {boolean} [value] - If `true`, enable partial object linking, otherwise disable
|
||||
* @returns {Runner}
|
||||
* @chainable
|
||||
* @public
|
||||
* @example
|
||||
* // this reporter needs proper object references when run in parallel mode
|
||||
* class MyReporter() {
|
||||
* constructor(runner) {
|
||||
* this.runner.linkPartialObjects(true)
|
||||
* .on(EVENT_SUITE_BEGIN, suite => {
|
||||
// this Suite may be the same object...
|
||||
* })
|
||||
* .on(EVENT_TEST_BEGIN, test => {
|
||||
* // ...as the `test.parent` property
|
||||
* });
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
linkPartialObjects(value) {
|
||||
this._linkPartialObjects = Boolean(value);
|
||||
return super.linkPartialObjects(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this class is the `Runner` in use, then this is going to return `true`.
|
||||
*
|
||||
* For use by reporters.
|
||||
* @returns {true}
|
||||
* @public
|
||||
*/
|
||||
isParallelMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures an alternate reporter for worker processes to use. Subclasses
|
||||
* using worker processes should implement this.
|
||||
* @public
|
||||
* @param {string} path - Absolute path to alternate reporter for worker processes to use
|
||||
* @returns {Runner}
|
||||
* @throws When in serial mode
|
||||
* @chainable
|
||||
*/
|
||||
workerReporter(reporter) {
|
||||
this._workerReporter = reporter;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ParallelBufferedRunner;
|
||||
|
||||
/**
|
||||
* Listener function intended to be bound to `Process.SIGINT` event
|
||||
* @private
|
||||
* @callback SigIntListener
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function accepting a test file path and returning the results of a test run
|
||||
* @private
|
||||
* @callback FileRunner
|
||||
* @param {string} filename - File to run
|
||||
* @returns {Promise<SerializedWorkerResult>}
|
||||
*/
|
||||
165
node_modules/mocha/lib/nodejs/reporters/parallel-buffered.js
generated
vendored
Normal file
165
node_modules/mocha/lib/nodejs/reporters/parallel-buffered.js
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* "Buffered" reporter used internally by a worker process when running in parallel mode.
|
||||
* @module nodejs/reporters/parallel-buffered
|
||||
* @public
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
const {
|
||||
EVENT_SUITE_BEGIN,
|
||||
EVENT_SUITE_END,
|
||||
EVENT_TEST_FAIL,
|
||||
EVENT_TEST_PASS,
|
||||
EVENT_TEST_PENDING,
|
||||
EVENT_TEST_BEGIN,
|
||||
EVENT_TEST_END,
|
||||
EVENT_TEST_RETRY,
|
||||
EVENT_DELAY_BEGIN,
|
||||
EVENT_DELAY_END,
|
||||
EVENT_HOOK_BEGIN,
|
||||
EVENT_HOOK_END,
|
||||
EVENT_RUN_END
|
||||
} = require('../../runner').constants;
|
||||
const {SerializableEvent, SerializableWorkerResult} = require('../serializer');
|
||||
const debug = require('debug')('mocha:reporters:buffered');
|
||||
const Base = require('../../reporters/base');
|
||||
|
||||
/**
|
||||
* List of events to listen to; these will be buffered and sent
|
||||
* when `Mocha#run` is complete (via {@link ParallelBuffered#done}).
|
||||
*/
|
||||
const EVENT_NAMES = [
|
||||
EVENT_SUITE_BEGIN,
|
||||
EVENT_SUITE_END,
|
||||
EVENT_TEST_BEGIN,
|
||||
EVENT_TEST_PENDING,
|
||||
EVENT_TEST_FAIL,
|
||||
EVENT_TEST_PASS,
|
||||
EVENT_TEST_RETRY,
|
||||
EVENT_TEST_END,
|
||||
EVENT_HOOK_BEGIN,
|
||||
EVENT_HOOK_END
|
||||
];
|
||||
|
||||
/**
|
||||
* Like {@link EVENT_NAMES}, except we expect these events to only be emitted
|
||||
* by the `Runner` once.
|
||||
*/
|
||||
const ONCE_EVENT_NAMES = [EVENT_DELAY_BEGIN, EVENT_DELAY_END];
|
||||
|
||||
/**
|
||||
* The `ParallelBuffered` reporter is used by each worker process in "parallel"
|
||||
* mode, by default. Instead of reporting to to `STDOUT`, etc., it retains a
|
||||
* list of events it receives and hands these off to the callback passed into
|
||||
* {@link Mocha#run}. That callback will then return the data to the main
|
||||
* process.
|
||||
* @public
|
||||
*/
|
||||
class ParallelBuffered extends Base {
|
||||
/**
|
||||
* Calls {@link ParallelBuffered#createListeners}
|
||||
* @param {Runner} runner
|
||||
*/
|
||||
constructor(runner, opts) {
|
||||
super(runner, opts);
|
||||
|
||||
/**
|
||||
* Retained list of events emitted from the {@link Runner} instance.
|
||||
* @type {BufferedEvent[]}
|
||||
* @public
|
||||
*/
|
||||
this.events = [];
|
||||
|
||||
/**
|
||||
* Map of `Runner` event names to listeners (for later teardown)
|
||||
* @public
|
||||
* @type {Map<string,EventListener>}
|
||||
*/
|
||||
this.listeners = new Map();
|
||||
|
||||
this.createListeners(runner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new listener which saves event data in memory to
|
||||
* {@link ParallelBuffered#events}. Listeners are indexed by `eventName` and stored
|
||||
* in {@link ParallelBuffered#listeners}. This is a defensive measure, so that we
|
||||
* don't a) leak memory or b) remove _other_ listeners that may not be
|
||||
* associated with this reporter.
|
||||
*
|
||||
* Subclasses could override this behavior.
|
||||
*
|
||||
* @public
|
||||
* @param {string} eventName - Name of event to create listener for
|
||||
* @returns {EventListener}
|
||||
*/
|
||||
createListener(eventName) {
|
||||
const listener = (runnable, err) => {
|
||||
this.events.push(SerializableEvent.create(eventName, runnable, err));
|
||||
};
|
||||
return this.listeners.set(eventName, listener).get(eventName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates event listeners (using {@link ParallelBuffered#createListener}) for each
|
||||
* reporter-relevant event emitted by a {@link Runner}. This array is drained when
|
||||
* {@link ParallelBuffered#done} is called by {@link Runner#run}.
|
||||
*
|
||||
* Subclasses could override this behavior.
|
||||
* @public
|
||||
* @param {Runner} runner - Runner instance
|
||||
* @returns {ParallelBuffered}
|
||||
* @chainable
|
||||
*/
|
||||
createListeners(runner) {
|
||||
EVENT_NAMES.forEach(evt => {
|
||||
runner.on(evt, this.createListener(evt));
|
||||
});
|
||||
ONCE_EVENT_NAMES.forEach(evt => {
|
||||
runner.once(evt, this.createListener(evt));
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, () => {
|
||||
debug('received EVENT_RUN_END');
|
||||
this.listeners.forEach((listener, evt) => {
|
||||
runner.removeListener(evt, listener);
|
||||
this.listeners.delete(evt);
|
||||
});
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the {@link Mocha#run} callback (`callback`) with the test failure
|
||||
* count and the array of {@link BufferedEvent} objects. Resets the array.
|
||||
*
|
||||
* This is called directly by `Runner#run` and should not be called by any other consumer.
|
||||
*
|
||||
* Subclasses could override this.
|
||||
*
|
||||
* @param {number} failures - Number of failed tests
|
||||
* @param {Function} callback - The callback passed to {@link Mocha#run}.
|
||||
* @public
|
||||
*/
|
||||
done(failures, callback) {
|
||||
callback(SerializableWorkerResult.create(this.events, failures));
|
||||
this.events = []; // defensive
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializable event data from a `Runner`. Keys of the `data` property
|
||||
* beginning with `__` will be converted into a function which returns the value
|
||||
* upon deserialization.
|
||||
* @typedef {Object} BufferedEvent
|
||||
* @property {string} name - Event name
|
||||
* @property {object} data - Event parameters
|
||||
*/
|
||||
|
||||
module.exports = ParallelBuffered;
|
||||
412
node_modules/mocha/lib/nodejs/serializer.js
generated
vendored
Normal file
412
node_modules/mocha/lib/nodejs/serializer.js
generated
vendored
Normal file
@@ -0,0 +1,412 @@
|
||||
/**
|
||||
* Serialization/deserialization classes and functions for communication between a main Mocha process and worker processes.
|
||||
* @module serializer
|
||||
* @private
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {type} = require('../utils');
|
||||
const {createInvalidArgumentTypeError} = require('../errors');
|
||||
// this is not named `mocha:parallel:serializer` because it's noisy and it's
|
||||
// helpful to be able to write `DEBUG=mocha:parallel*` and get everything else.
|
||||
const debug = require('debug')('mocha:serializer');
|
||||
|
||||
const SERIALIZABLE_RESULT_NAME = 'SerializableWorkerResult';
|
||||
const SERIALIZABLE_TYPES = new Set(['object', 'array', 'function', 'error']);
|
||||
|
||||
/**
|
||||
* The serializable result of a test file run from a worker.
|
||||
* @private
|
||||
*/
|
||||
class SerializableWorkerResult {
|
||||
/**
|
||||
* Creates instance props; of note, the `__type` prop.
|
||||
*
|
||||
* Note that the failure count is _redundant_ and could be derived from the
|
||||
* list of events; but since we're already doing the work, might as well use
|
||||
* it.
|
||||
* @param {SerializableEvent[]} [events=[]] - Events to eventually serialize
|
||||
* @param {number} [failureCount=0] - Failure count
|
||||
*/
|
||||
constructor(events = [], failureCount = 0) {
|
||||
/**
|
||||
* The number of failures in this run
|
||||
* @type {number}
|
||||
*/
|
||||
this.failureCount = failureCount;
|
||||
/**
|
||||
* All relevant events emitted from the {@link Runner}.
|
||||
* @type {SerializableEvent[]}
|
||||
*/
|
||||
this.events = events;
|
||||
|
||||
/**
|
||||
* Symbol-like value needed to distinguish when attempting to deserialize
|
||||
* this object (once it's been received over IPC).
|
||||
* @type {Readonly<"SerializableWorkerResult">}
|
||||
*/
|
||||
Object.defineProperty(this, '__type', {
|
||||
value: SERIALIZABLE_RESULT_NAME,
|
||||
enumerable: true,
|
||||
writable: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new {@link SerializableWorkerResult}.
|
||||
* @param {...any} args - Args to constructor
|
||||
* @returns {SerializableWorkerResult}
|
||||
*/
|
||||
static create(...args) {
|
||||
return new SerializableWorkerResult(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes each {@link SerializableEvent} in our `events` prop;
|
||||
* makes this object read-only.
|
||||
* @returns {Readonly<SerializableWorkerResult>}
|
||||
*/
|
||||
serialize() {
|
||||
this.events.forEach(event => {
|
||||
event.serialize();
|
||||
});
|
||||
return Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a {@link SerializedWorkerResult} into something reporters can
|
||||
* use; calls {@link SerializableEvent.deserialize} on each item in its
|
||||
* `events` prop.
|
||||
* @param {SerializedWorkerResult} obj
|
||||
* @returns {SerializedWorkerResult}
|
||||
*/
|
||||
static deserialize(obj) {
|
||||
obj.events.forEach(event => {
|
||||
SerializableEvent.deserialize(event);
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if this is a {@link SerializedWorkerResult} or a
|
||||
* {@link SerializableWorkerResult}.
|
||||
* @param {*} value - A value to check
|
||||
* @returns {boolean} If true, it's deserializable
|
||||
*/
|
||||
static isSerializedWorkerResult(value) {
|
||||
return (
|
||||
value instanceof SerializableWorkerResult ||
|
||||
(type(value) === 'object' && value.__type === SERIALIZABLE_RESULT_NAME)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an event, emitted by a {@link Runner}, which is to be transmitted
|
||||
* over IPC.
|
||||
*
|
||||
* Due to the contents of the event data, it's not possible to send them
|
||||
* verbatim. When received by the main process--and handled by reporters--these
|
||||
* objects are expected to contain {@link Runnable} instances. This class
|
||||
* provides facilities to perform the translation via serialization and
|
||||
* deserialization.
|
||||
* @private
|
||||
*/
|
||||
class SerializableEvent {
|
||||
/**
|
||||
* Constructs a `SerializableEvent`, throwing if we receive unexpected data.
|
||||
*
|
||||
* Practically, events emitted from `Runner` have a minumum of zero (0)
|
||||
* arguments-- (for example, {@link Runnable.constants.EVENT_RUN_BEGIN}) and a
|
||||
* maximum of two (2) (for example,
|
||||
* {@link Runnable.constants.EVENT_TEST_FAIL}, where the second argument is an
|
||||
* `Error`). The first argument, if present, is a {@link Runnable}. This
|
||||
* constructor's arguments adhere to this convention.
|
||||
* @param {string} eventName - A non-empty event name.
|
||||
* @param {any} [originalValue] - Some data. Corresponds to extra arguments
|
||||
* passed to `EventEmitter#emit`.
|
||||
* @param {Error} [originalError] - An error, if there's an error.
|
||||
* @throws If `eventName` is empty, or `originalValue` is a non-object.
|
||||
*/
|
||||
constructor(eventName, originalValue, originalError) {
|
||||
if (!eventName) {
|
||||
throw createInvalidArgumentTypeError(
|
||||
'Empty `eventName` string argument',
|
||||
'eventName',
|
||||
'string'
|
||||
);
|
||||
}
|
||||
/**
|
||||
* The event name.
|
||||
* @memberof SerializableEvent
|
||||
*/
|
||||
this.eventName = eventName;
|
||||
const originalValueType = type(originalValue);
|
||||
if (originalValueType !== 'object' && originalValueType !== 'undefined') {
|
||||
throw createInvalidArgumentTypeError(
|
||||
`Expected object but received ${originalValueType}`,
|
||||
'originalValue',
|
||||
'object'
|
||||
);
|
||||
}
|
||||
/**
|
||||
* An error, if present.
|
||||
* @memberof SerializableEvent
|
||||
*/
|
||||
Object.defineProperty(this, 'originalError', {
|
||||
value: originalError,
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
/**
|
||||
* The raw value.
|
||||
*
|
||||
* We don't want this value sent via IPC; making it non-enumerable will do that.
|
||||
*
|
||||
* @memberof SerializableEvent
|
||||
*/
|
||||
Object.defineProperty(this, 'originalValue', {
|
||||
value: originalValue,
|
||||
enumerable: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* In case you hated using `new` (I do).
|
||||
*
|
||||
* @param {...any} args - Args for {@link SerializableEvent#constructor}.
|
||||
* @returns {SerializableEvent} A new `SerializableEvent`
|
||||
*/
|
||||
static create(...args) {
|
||||
return new SerializableEvent(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally by {@link SerializableEvent#serialize}.
|
||||
* @ignore
|
||||
* @param {Array<object|string>} pairs - List of parent/key tuples to process; modified in-place. This JSDoc type is an approximation
|
||||
* @param {object} parent - Some parent object
|
||||
* @param {string} key - Key to inspect
|
||||
* @param {WeakSet<Object>} seenObjects - For avoiding circular references
|
||||
*/
|
||||
static _serialize(pairs, parent, key, seenObjects) {
|
||||
let value = parent[key];
|
||||
if (seenObjects.has(value)) {
|
||||
parent[key] = Object.create(null);
|
||||
return;
|
||||
}
|
||||
let _type = type(value);
|
||||
if (_type === 'error') {
|
||||
// we need to reference the stack prop b/c it's lazily-loaded.
|
||||
// `__type` is necessary for deserialization to create an `Error` later.
|
||||
// `message` is apparently not enumerable, so we must handle it specifically.
|
||||
value = Object.assign(Object.create(null), value, {
|
||||
stack: value.stack,
|
||||
message: value.message,
|
||||
__type: 'Error'
|
||||
});
|
||||
parent[key] = value;
|
||||
// after this, set the result of type(value) to be `object`, and we'll throw
|
||||
// whatever other junk is in the original error into the new `value`.
|
||||
_type = 'object';
|
||||
}
|
||||
switch (_type) {
|
||||
case 'object':
|
||||
if (type(value.serialize) === 'function') {
|
||||
parent[key] = value.serialize();
|
||||
} else {
|
||||
// by adding props to the `pairs` array, we will process it further
|
||||
pairs.push(
|
||||
...Object.keys(value)
|
||||
.filter(key => SERIALIZABLE_TYPES.has(type(value[key])))
|
||||
.map(key => [value, key])
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'function':
|
||||
// we _may_ want to dig in to functions for some assertion libraries
|
||||
// that might put a usable property on a function.
|
||||
// for now, just zap it.
|
||||
delete parent[key];
|
||||
break;
|
||||
case 'array':
|
||||
pairs.push(
|
||||
...value
|
||||
.filter(value => SERIALIZABLE_TYPES.has(type(value)))
|
||||
.map((value, index) => [value, index])
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies this object *in place* (for theoretical memory consumption &
|
||||
* performance reasons); serializes `SerializableEvent#originalValue` (placing
|
||||
* the result in `SerializableEvent#data`) and `SerializableEvent#error`.
|
||||
* Freezes this object. The result is an object that can be transmitted over
|
||||
* IPC.
|
||||
* If this quickly becomes unmaintainable, we will want to move towards immutable
|
||||
* objects post-haste.
|
||||
*/
|
||||
serialize() {
|
||||
// given a parent object and a key, inspect the value and decide whether
|
||||
// to replace it, remove it, or add it to our `pairs` array to further process.
|
||||
// this is recursion in loop form.
|
||||
const originalValue = this.originalValue;
|
||||
const result = Object.assign(Object.create(null), {
|
||||
data:
|
||||
type(originalValue) === 'object' &&
|
||||
type(originalValue.serialize) === 'function'
|
||||
? originalValue.serialize()
|
||||
: originalValue,
|
||||
error: this.originalError
|
||||
});
|
||||
|
||||
const pairs = Object.keys(result).map(key => [result, key]);
|
||||
const seenObjects = new WeakSet();
|
||||
|
||||
let pair;
|
||||
while ((pair = pairs.shift())) {
|
||||
SerializableEvent._serialize(pairs, ...pair, seenObjects);
|
||||
seenObjects.add(pair[0]);
|
||||
}
|
||||
|
||||
this.data = result.data;
|
||||
this.error = result.error;
|
||||
|
||||
return Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally by {@link SerializableEvent.deserialize}; creates an `Error`
|
||||
* from an `Error`-like (serialized) object
|
||||
* @ignore
|
||||
* @param {Object} value - An Error-like value
|
||||
* @returns {Error} Real error
|
||||
*/
|
||||
static _deserializeError(value) {
|
||||
const error = new Error(value.message);
|
||||
error.stack = value.stack;
|
||||
Object.assign(error, value);
|
||||
delete error.__type;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally by {@link SerializableEvent.deserialize}; recursively
|
||||
* deserializes an object in-place.
|
||||
* @param {object|Array} parent - Some object or array
|
||||
* @param {string|number} key - Some prop name or array index within `parent`
|
||||
*/
|
||||
static _deserializeObject(parent, key) {
|
||||
if (key === '__proto__') {
|
||||
delete parent[key];
|
||||
return;
|
||||
}
|
||||
const value = parent[key];
|
||||
// keys beginning with `$$` are converted into functions returning the value
|
||||
// and renamed, stripping the `$$` prefix.
|
||||
// functions defined this way cannot be array members!
|
||||
if (type(key) === 'string' && key.startsWith('$$')) {
|
||||
const newKey = key.slice(2);
|
||||
parent[newKey] = () => value;
|
||||
delete parent[key];
|
||||
key = newKey;
|
||||
}
|
||||
if (type(value) === 'array') {
|
||||
value.forEach((_, idx) => {
|
||||
SerializableEvent._deserializeObject(value, idx);
|
||||
});
|
||||
} else if (type(value) === 'object') {
|
||||
if (value.__type === 'Error') {
|
||||
parent[key] = SerializableEvent._deserializeError(value);
|
||||
} else {
|
||||
Object.keys(value).forEach(key => {
|
||||
SerializableEvent._deserializeObject(value, key);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize value returned from a worker into something more useful.
|
||||
* Does not return the same object.
|
||||
* @todo do this in a loop instead of with recursion (if necessary)
|
||||
* @param {SerializedEvent} obj - Object returned from worker
|
||||
* @returns {SerializedEvent} Deserialized result
|
||||
*/
|
||||
static deserialize(obj) {
|
||||
if (!obj) {
|
||||
throw createInvalidArgumentTypeError('Expected value', obj);
|
||||
}
|
||||
|
||||
obj = Object.assign(Object.create(null), obj);
|
||||
|
||||
if (obj.data) {
|
||||
Object.keys(obj.data).forEach(key => {
|
||||
SerializableEvent._deserializeObject(obj.data, key);
|
||||
});
|
||||
}
|
||||
|
||||
if (obj.error) {
|
||||
obj.error = SerializableEvent._deserializeError(obj.error);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Serializes" a value for transmission over IPC as a message.
|
||||
*
|
||||
* If value is an object and has a `serialize()` method, call that method; otherwise return the object and hope for the best.
|
||||
*
|
||||
* @param {*} [value] - A value to serialize
|
||||
*/
|
||||
exports.serialize = function serialize(value) {
|
||||
const result =
|
||||
type(value) === 'object' && type(value.serialize) === 'function'
|
||||
? value.serialize()
|
||||
: value;
|
||||
debug('serialized: %O', result);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* "Deserializes" a "message" received over IPC.
|
||||
*
|
||||
* This could be expanded with other objects that need deserialization,
|
||||
* but at present time we only care about {@link SerializableWorkerResult} objects.
|
||||
*
|
||||
* @param {*} [value] - A "message" to deserialize
|
||||
*/
|
||||
exports.deserialize = function deserialize(value) {
|
||||
const result = SerializableWorkerResult.isSerializedWorkerResult(value)
|
||||
? SerializableWorkerResult.deserialize(value)
|
||||
: value;
|
||||
debug('deserialized: %O', result);
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.SerializableEvent = SerializableEvent;
|
||||
exports.SerializableWorkerResult = SerializableWorkerResult;
|
||||
|
||||
/**
|
||||
* The result of calling `SerializableEvent.serialize`, as received
|
||||
* by the deserializer.
|
||||
* @private
|
||||
* @typedef {Object} SerializedEvent
|
||||
* @property {object?} data - Optional serialized data
|
||||
* @property {object?} error - Optional serialized `Error`
|
||||
*/
|
||||
|
||||
/**
|
||||
* The result of calling `SerializableWorkerResult.serialize` as received
|
||||
* by the deserializer.
|
||||
* @private
|
||||
* @typedef {Object} SerializedWorkerResult
|
||||
* @property {number} failureCount - Number of failures
|
||||
* @property {SerializedEvent[]} events - Serialized events
|
||||
* @property {"SerializedWorkerResult"} __type - Symbol-like to denote the type of object this is
|
||||
*/
|
||||
151
node_modules/mocha/lib/nodejs/worker.js
generated
vendored
Normal file
151
node_modules/mocha/lib/nodejs/worker.js
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* A worker process. Consumes {@link module:reporters/parallel-buffered} reporter.
|
||||
* @module worker
|
||||
* @private
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
createInvalidArgumentTypeError,
|
||||
createInvalidArgumentValueError
|
||||
} = require('../errors');
|
||||
const workerpool = require('workerpool');
|
||||
const Mocha = require('../mocha');
|
||||
const {handleRequires, validateLegacyPlugin} = require('../cli/run-helpers');
|
||||
const d = require('debug');
|
||||
const debug = d.debug(`mocha:parallel:worker:${process.pid}`);
|
||||
const isDebugEnabled = d.enabled(`mocha:parallel:worker:${process.pid}`);
|
||||
const {serialize} = require('./serializer');
|
||||
const {setInterval, clearInterval} = global;
|
||||
|
||||
let rootHooks;
|
||||
|
||||
if (workerpool.isMainThread) {
|
||||
throw new Error(
|
||||
'This script is intended to be run as a worker (by the `workerpool` package).'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes some stuff on the first call to {@link run}.
|
||||
*
|
||||
* Handles `--require` and `--ui`. Does _not_ handle `--reporter`,
|
||||
* as only the `Buffered` reporter is used.
|
||||
*
|
||||
* **This function only runs once per worker**; it overwrites itself with a no-op
|
||||
* before returning.
|
||||
*
|
||||
* @param {Options} argv - Command-line options
|
||||
*/
|
||||
let bootstrap = async argv => {
|
||||
// globalSetup and globalTeardown do not run in workers
|
||||
const plugins = await handleRequires(argv.require, {
|
||||
ignoredPlugins: ['mochaGlobalSetup', 'mochaGlobalTeardown']
|
||||
});
|
||||
validateLegacyPlugin(argv, 'ui', Mocha.interfaces);
|
||||
|
||||
rootHooks = plugins.rootHooks;
|
||||
bootstrap = () => {};
|
||||
debug('bootstrap(): finished with args: %O', argv);
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs a single test file in a worker thread.
|
||||
* @param {string} filepath - Filepath of test file
|
||||
* @param {string} [serializedOptions] - **Serialized** options. This string will be eval'd!
|
||||
* @see https://npm.im/serialize-javascript
|
||||
* @returns {Promise<{failures: number, events: BufferedEvent[]}>} - Test
|
||||
* failure count and list of events.
|
||||
*/
|
||||
async function run(filepath, serializedOptions = '{}') {
|
||||
if (!filepath) {
|
||||
throw createInvalidArgumentTypeError(
|
||||
'Expected a non-empty "filepath" argument',
|
||||
'file',
|
||||
'string'
|
||||
);
|
||||
}
|
||||
|
||||
debug('run(): running test file %s', filepath);
|
||||
|
||||
if (typeof serializedOptions !== 'string') {
|
||||
throw createInvalidArgumentTypeError(
|
||||
'run() expects second parameter to be a string which was serialized by the `serialize-javascript` module',
|
||||
'serializedOptions',
|
||||
'string'
|
||||
);
|
||||
}
|
||||
let argv;
|
||||
try {
|
||||
// eslint-disable-next-line no-eval
|
||||
argv = eval('(' + serializedOptions + ')');
|
||||
} catch (err) {
|
||||
throw createInvalidArgumentValueError(
|
||||
'run() was unable to deserialize the options',
|
||||
'serializedOptions',
|
||||
serializedOptions
|
||||
);
|
||||
}
|
||||
|
||||
const opts = Object.assign({ui: 'bdd'}, argv, {
|
||||
// if this was true, it would cause infinite recursion.
|
||||
parallel: false,
|
||||
// this doesn't work in parallel mode
|
||||
forbidOnly: true,
|
||||
// it's useful for a Mocha instance to know if it's running in a worker process.
|
||||
isWorker: true
|
||||
});
|
||||
|
||||
await bootstrap(opts);
|
||||
|
||||
opts.rootHooks = rootHooks;
|
||||
|
||||
const mocha = new Mocha(opts).addFile(filepath);
|
||||
|
||||
try {
|
||||
await mocha.loadFilesAsync();
|
||||
} catch (err) {
|
||||
debug('run(): could not load file %s: %s', filepath, err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let debugInterval;
|
||||
/* istanbul ignore next */
|
||||
if (isDebugEnabled) {
|
||||
debugInterval = setInterval(() => {
|
||||
debug('run(): still running %s...', filepath);
|
||||
}, 5000).unref();
|
||||
}
|
||||
mocha.run(result => {
|
||||
// Runner adds these; if we don't remove them, we'll get a leak.
|
||||
process.removeAllListeners('uncaughtException');
|
||||
process.removeAllListeners('unhandledRejection');
|
||||
|
||||
try {
|
||||
const serialized = serialize(result);
|
||||
debug(
|
||||
'run(): completed run with %d test failures; returning to main process',
|
||||
typeof result.failures === 'number' ? result.failures : 0
|
||||
);
|
||||
resolve(serialized);
|
||||
} catch (err) {
|
||||
// TODO: figure out exactly what the sad path looks like here.
|
||||
// rejection should only happen if an error is "unrecoverable"
|
||||
debug('run(): serialization failed; rejecting: %O', err);
|
||||
reject(err);
|
||||
} finally {
|
||||
clearInterval(debugInterval);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// this registers the `run` function.
|
||||
workerpool.worker({run});
|
||||
|
||||
debug('started worker process');
|
||||
|
||||
// for testing
|
||||
exports.run = run;
|
||||
16
node_modules/mocha/lib/pending.js
generated
vendored
Normal file
16
node_modules/mocha/lib/pending.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@module Pending
|
||||
*/
|
||||
|
||||
module.exports = Pending;
|
||||
|
||||
/**
|
||||
* Initialize a new `Pending` error with the given message.
|
||||
*
|
||||
* @param {string} message
|
||||
*/
|
||||
function Pending(message) {
|
||||
this.message = message;
|
||||
}
|
||||
286
node_modules/mocha/lib/plugin-loader.js
generated
vendored
Normal file
286
node_modules/mocha/lib/plugin-loader.js
generated
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* Provides a way to load "plugins" as provided by the user.
|
||||
*
|
||||
* Currently supports:
|
||||
*
|
||||
* - Root hooks
|
||||
* - Global fixtures (setup/teardown)
|
||||
* @private
|
||||
* @module plugin
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const debug = require('debug')('mocha:plugin-loader');
|
||||
const {
|
||||
createInvalidPluginDefinitionError,
|
||||
createInvalidPluginImplementationError
|
||||
} = require('./errors');
|
||||
const {castArray} = require('./utils');
|
||||
|
||||
/**
|
||||
* Built-in plugin definitions.
|
||||
*/
|
||||
const MochaPlugins = [
|
||||
/**
|
||||
* Root hook plugin definition
|
||||
* @type {PluginDefinition}
|
||||
*/
|
||||
{
|
||||
exportName: 'mochaHooks',
|
||||
optionName: 'rootHooks',
|
||||
validate(value) {
|
||||
if (
|
||||
Array.isArray(value) ||
|
||||
(typeof value !== 'function' && typeof value !== 'object')
|
||||
) {
|
||||
throw createInvalidPluginImplementationError(
|
||||
`mochaHooks must be an object or a function returning (or fulfilling with) an object`
|
||||
);
|
||||
}
|
||||
},
|
||||
async finalize(rootHooks) {
|
||||
if (rootHooks.length) {
|
||||
const rootHookObjects = await Promise.all(
|
||||
rootHooks.map(async hook =>
|
||||
typeof hook === 'function' ? hook() : hook
|
||||
)
|
||||
);
|
||||
|
||||
return rootHookObjects.reduce(
|
||||
(acc, hook) => {
|
||||
hook = {
|
||||
beforeAll: [],
|
||||
beforeEach: [],
|
||||
afterAll: [],
|
||||
afterEach: [],
|
||||
...hook
|
||||
};
|
||||
return {
|
||||
beforeAll: [...acc.beforeAll, ...castArray(hook.beforeAll)],
|
||||
beforeEach: [...acc.beforeEach, ...castArray(hook.beforeEach)],
|
||||
afterAll: [...acc.afterAll, ...castArray(hook.afterAll)],
|
||||
afterEach: [...acc.afterEach, ...castArray(hook.afterEach)]
|
||||
};
|
||||
},
|
||||
{beforeAll: [], beforeEach: [], afterAll: [], afterEach: []}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Global setup fixture plugin definition
|
||||
* @type {PluginDefinition}
|
||||
*/
|
||||
{
|
||||
exportName: 'mochaGlobalSetup',
|
||||
optionName: 'globalSetup',
|
||||
validate(value) {
|
||||
let isValid = true;
|
||||
if (Array.isArray(value)) {
|
||||
if (value.some(item => typeof item !== 'function')) {
|
||||
isValid = false;
|
||||
}
|
||||
} else if (typeof value !== 'function') {
|
||||
isValid = false;
|
||||
}
|
||||
if (!isValid) {
|
||||
throw createInvalidPluginImplementationError(
|
||||
`mochaGlobalSetup must be a function or an array of functions`,
|
||||
{pluginDef: this, pluginImpl: value}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Global teardown fixture plugin definition
|
||||
* @type {PluginDefinition}
|
||||
*/
|
||||
{
|
||||
exportName: 'mochaGlobalTeardown',
|
||||
optionName: 'globalTeardown',
|
||||
validate(value) {
|
||||
let isValid = true;
|
||||
if (Array.isArray(value)) {
|
||||
if (value.some(item => typeof item !== 'function')) {
|
||||
isValid = false;
|
||||
}
|
||||
} else if (typeof value !== 'function') {
|
||||
isValid = false;
|
||||
}
|
||||
if (!isValid) {
|
||||
throw createInvalidPluginImplementationError(
|
||||
`mochaGlobalTeardown must be a function or an array of functions`,
|
||||
{pluginDef: this, pluginImpl: value}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Contains a registry of [plugin definitions]{@link PluginDefinition} and discovers plugin implementations in user-supplied code.
|
||||
*
|
||||
* - [load()]{@link #load} should be called for all required modules
|
||||
* - The result of [finalize()]{@link #finalize} should be merged into the options for the [Mocha]{@link Mocha} constructor.
|
||||
* @private
|
||||
*/
|
||||
class PluginLoader {
|
||||
/**
|
||||
* Initializes plugin names, plugin map, etc.
|
||||
* @param {PluginLoaderOptions} [opts] - Options
|
||||
*/
|
||||
constructor({pluginDefs = MochaPlugins, ignore = []} = {}) {
|
||||
/**
|
||||
* Map of registered plugin defs
|
||||
* @type {Map<string,PluginDefinition>}
|
||||
*/
|
||||
this.registered = new Map();
|
||||
|
||||
/**
|
||||
* Cache of known `optionName` values for checking conflicts
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
this.knownOptionNames = new Set();
|
||||
|
||||
/**
|
||||
* Cache of known `exportName` values for checking conflicts
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
this.knownExportNames = new Set();
|
||||
|
||||
/**
|
||||
* Map of user-supplied plugin implementations
|
||||
* @type {Map<string,Array<*>>}
|
||||
*/
|
||||
this.loaded = new Map();
|
||||
|
||||
/**
|
||||
* Set of ignored plugins by export name
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
this.ignoredExportNames = new Set(castArray(ignore));
|
||||
|
||||
castArray(pluginDefs).forEach(pluginDef => {
|
||||
this.register(pluginDef);
|
||||
});
|
||||
|
||||
debug(
|
||||
'registered %d plugin defs (%d ignored)',
|
||||
this.registered.size,
|
||||
this.ignoredExportNames.size
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a plugin
|
||||
* @param {PluginDefinition} pluginDef - Plugin definition
|
||||
*/
|
||||
register(pluginDef) {
|
||||
if (!pluginDef || typeof pluginDef !== 'object') {
|
||||
throw createInvalidPluginDefinitionError(
|
||||
'pluginDef is non-object or falsy',
|
||||
pluginDef
|
||||
);
|
||||
}
|
||||
if (!pluginDef.exportName) {
|
||||
throw createInvalidPluginDefinitionError(
|
||||
`exportName is expected to be a non-empty string`,
|
||||
pluginDef
|
||||
);
|
||||
}
|
||||
let {exportName} = pluginDef;
|
||||
if (this.ignoredExportNames.has(exportName)) {
|
||||
debug(
|
||||
'refusing to register ignored plugin with export name "%s"',
|
||||
exportName
|
||||
);
|
||||
return;
|
||||
}
|
||||
exportName = String(exportName);
|
||||
pluginDef.optionName = String(pluginDef.optionName || exportName);
|
||||
if (this.knownExportNames.has(exportName)) {
|
||||
throw createInvalidPluginDefinitionError(
|
||||
`Plugin definition conflict: ${exportName}; exportName must be unique`,
|
||||
pluginDef
|
||||
);
|
||||
}
|
||||
this.loaded.set(exportName, []);
|
||||
this.registered.set(exportName, pluginDef);
|
||||
this.knownExportNames.add(exportName);
|
||||
this.knownOptionNames.add(pluginDef.optionName);
|
||||
debug('registered plugin def "%s"', exportName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects a module's exports for known plugins and keeps them in memory.
|
||||
*
|
||||
* @param {*} requiredModule - The exports of a module loaded via `--require`
|
||||
* @returns {boolean} If one or more plugins was found, return `true`.
|
||||
*/
|
||||
load(requiredModule) {
|
||||
// we should explicitly NOT fail if other stuff is exported.
|
||||
// we only care about the plugins we know about.
|
||||
if (requiredModule && typeof requiredModule === 'object') {
|
||||
return Array.from(this.knownExportNames).reduce(
|
||||
(pluginImplFound, pluginName) => {
|
||||
const pluginImpl = requiredModule[pluginName];
|
||||
if (pluginImpl) {
|
||||
const plugin = this.registered.get(pluginName);
|
||||
if (typeof plugin.validate === 'function') {
|
||||
plugin.validate(pluginImpl);
|
||||
}
|
||||
this.loaded.set(pluginName, [
|
||||
...this.loaded.get(pluginName),
|
||||
...castArray(pluginImpl)
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
return pluginImplFound;
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the `finalize()` function of each known plugin definition on the plugins found by [load()]{@link PluginLoader#load}.
|
||||
*
|
||||
* Output suitable for passing as input into {@link Mocha} constructor.
|
||||
* @returns {Promise<object>} Object having keys corresponding to registered plugin definitions' `optionName` prop (or `exportName`, if none), and the values are the implementations as provided by a user.
|
||||
*/
|
||||
async finalize() {
|
||||
const finalizedPlugins = Object.create(null);
|
||||
|
||||
for await (const [exportName, pluginImpls] of this.loaded.entries()) {
|
||||
if (pluginImpls.length) {
|
||||
const plugin = this.registered.get(exportName);
|
||||
finalizedPlugins[plugin.optionName] =
|
||||
typeof plugin.finalize === 'function'
|
||||
? await plugin.finalize(pluginImpls)
|
||||
: pluginImpls;
|
||||
}
|
||||
}
|
||||
|
||||
debug('finalized plugins: %O', finalizedPlugins);
|
||||
return finalizedPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link PluginLoader}
|
||||
* @param {PluginLoaderOptions} [opts] - Plugin loader options
|
||||
*/
|
||||
static create({pluginDefs = MochaPlugins, ignore = []} = {}) {
|
||||
return new PluginLoader({pluginDefs, ignore});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PluginLoader;
|
||||
|
||||
/**
|
||||
* Options for {@link PluginLoader}
|
||||
* @typedef {Object} PluginLoaderOptions
|
||||
* @property {PluginDefinition[]} [pluginDefs] - Plugin definitions
|
||||
* @property {string[]} [ignore] - A list of plugins to ignore when loading
|
||||
*/
|
||||
550
node_modules/mocha/lib/reporters/base.js
generated
vendored
Normal file
550
node_modules/mocha/lib/reporters/base.js
generated
vendored
Normal file
@@ -0,0 +1,550 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Base
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var diff = require('diff');
|
||||
var milliseconds = require('ms');
|
||||
var utils = require('../utils');
|
||||
var supportsColor = require('supports-color');
|
||||
var symbols = require('log-symbols');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
|
||||
const isBrowser = utils.isBrowser();
|
||||
|
||||
function getBrowserWindowSize() {
|
||||
if ('innerHeight' in global) {
|
||||
return [global.innerHeight, global.innerWidth];
|
||||
}
|
||||
// In a Web Worker, the DOM Window is not available.
|
||||
return [640, 480];
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose `Base`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Base;
|
||||
|
||||
/**
|
||||
* Check if both stdio streams are associated with a tty.
|
||||
*/
|
||||
|
||||
var isatty = isBrowser || (process.stdout.isTTY && process.stderr.isTTY);
|
||||
|
||||
/**
|
||||
* Save log references to avoid tests interfering (see GH-3604).
|
||||
*/
|
||||
var consoleLog = console.log;
|
||||
|
||||
/**
|
||||
* Enable coloring by default, except in the browser interface.
|
||||
*/
|
||||
|
||||
exports.useColors =
|
||||
!isBrowser &&
|
||||
(supportsColor.stdout || process.env.MOCHA_COLORS !== undefined);
|
||||
|
||||
/**
|
||||
* Inline diffs instead of +/-
|
||||
*/
|
||||
|
||||
exports.inlineDiffs = false;
|
||||
|
||||
/**
|
||||
* Truncate diffs longer than this value to avoid slow performance
|
||||
*/
|
||||
exports.maxDiffSize = 8192;
|
||||
|
||||
/**
|
||||
* Default color map.
|
||||
*/
|
||||
|
||||
exports.colors = {
|
||||
pass: 90,
|
||||
fail: 31,
|
||||
'bright pass': 92,
|
||||
'bright fail': 91,
|
||||
'bright yellow': 93,
|
||||
pending: 36,
|
||||
suite: 0,
|
||||
'error title': 0,
|
||||
'error message': 31,
|
||||
'error stack': 90,
|
||||
checkmark: 32,
|
||||
fast: 90,
|
||||
medium: 33,
|
||||
slow: 31,
|
||||
green: 32,
|
||||
light: 90,
|
||||
'diff gutter': 90,
|
||||
'diff added': 32,
|
||||
'diff removed': 31,
|
||||
'diff added inline': '30;42',
|
||||
'diff removed inline': '30;41'
|
||||
};
|
||||
|
||||
/**
|
||||
* Default symbol map.
|
||||
*/
|
||||
|
||||
exports.symbols = {
|
||||
ok: symbols.success,
|
||||
err: symbols.error,
|
||||
dot: '.',
|
||||
comma: ',',
|
||||
bang: '!'
|
||||
};
|
||||
|
||||
/**
|
||||
* Color `str` with the given `type`,
|
||||
* allowing colors to be disabled,
|
||||
* as well as user-defined color
|
||||
* schemes.
|
||||
*
|
||||
* @private
|
||||
* @param {string} type
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
var color = (exports.color = function (type, str) {
|
||||
if (!exports.useColors) {
|
||||
return String(str);
|
||||
}
|
||||
return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
|
||||
});
|
||||
|
||||
/**
|
||||
* Expose term window size, with some defaults for when stderr is not a tty.
|
||||
*/
|
||||
|
||||
exports.window = {
|
||||
width: 75
|
||||
};
|
||||
|
||||
if (isatty) {
|
||||
if (isBrowser) {
|
||||
exports.window.width = getBrowserWindowSize()[1];
|
||||
} else {
|
||||
exports.window.width = process.stdout.getWindowSize(1)[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose some basic cursor interactions that are common among reporters.
|
||||
*/
|
||||
|
||||
exports.cursor = {
|
||||
hide: function () {
|
||||
isatty && process.stdout.write('\u001b[?25l');
|
||||
},
|
||||
|
||||
show: function () {
|
||||
isatty && process.stdout.write('\u001b[?25h');
|
||||
},
|
||||
|
||||
deleteLine: function () {
|
||||
isatty && process.stdout.write('\u001b[2K');
|
||||
},
|
||||
|
||||
beginningOfLine: function () {
|
||||
isatty && process.stdout.write('\u001b[0G');
|
||||
},
|
||||
|
||||
CR: function () {
|
||||
if (isatty) {
|
||||
exports.cursor.deleteLine();
|
||||
exports.cursor.beginningOfLine();
|
||||
} else {
|
||||
process.stdout.write('\r');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var showDiff = (exports.showDiff = function (err) {
|
||||
return (
|
||||
err &&
|
||||
err.showDiff !== false &&
|
||||
sameType(err.actual, err.expected) &&
|
||||
err.expected !== undefined
|
||||
);
|
||||
});
|
||||
|
||||
function stringifyDiffObjs(err) {
|
||||
if (!utils.isString(err.actual) || !utils.isString(err.expected)) {
|
||||
err.actual = utils.stringify(err.actual);
|
||||
err.expected = utils.stringify(err.expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a diff between 2 strings with coloured ANSI output.
|
||||
*
|
||||
* @description
|
||||
* The diff will be either inline or unified dependent on the value
|
||||
* of `Base.inlineDiff`.
|
||||
*
|
||||
* @param {string} actual
|
||||
* @param {string} expected
|
||||
* @return {string} Diff
|
||||
*/
|
||||
|
||||
var generateDiff = (exports.generateDiff = function (actual, expected) {
|
||||
try {
|
||||
var maxLen = exports.maxDiffSize;
|
||||
var skipped = 0;
|
||||
if (maxLen > 0) {
|
||||
skipped = Math.max(actual.length - maxLen, expected.length - maxLen);
|
||||
actual = actual.slice(0, maxLen);
|
||||
expected = expected.slice(0, maxLen);
|
||||
}
|
||||
let result = exports.inlineDiffs
|
||||
? inlineDiff(actual, expected)
|
||||
: unifiedDiff(actual, expected);
|
||||
if (skipped > 0) {
|
||||
result = `${result}\n [mocha] output truncated to ${maxLen} characters, see "maxDiffSize" reporter-option\n`;
|
||||
}
|
||||
return result;
|
||||
} catch (err) {
|
||||
var msg =
|
||||
'\n ' +
|
||||
color('diff added', '+ expected') +
|
||||
' ' +
|
||||
color('diff removed', '- actual: failed to generate Mocha diff') +
|
||||
'\n';
|
||||
return msg;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Outputs the given `failures` as a list.
|
||||
*
|
||||
* @public
|
||||
* @memberof Mocha.reporters.Base
|
||||
* @variation 1
|
||||
* @param {Object[]} failures - Each is Test instance with corresponding
|
||||
* Error property
|
||||
*/
|
||||
exports.list = function (failures) {
|
||||
var multipleErr, multipleTest;
|
||||
Base.consoleLog();
|
||||
failures.forEach(function (test, i) {
|
||||
// format
|
||||
var fmt =
|
||||
color('error title', ' %s) %s:\n') +
|
||||
color('error message', ' %s') +
|
||||
color('error stack', '\n%s\n');
|
||||
|
||||
// msg
|
||||
var msg;
|
||||
var err;
|
||||
if (test.err && test.err.multiple) {
|
||||
if (multipleTest !== test) {
|
||||
multipleTest = test;
|
||||
multipleErr = [test.err].concat(test.err.multiple);
|
||||
}
|
||||
err = multipleErr.shift();
|
||||
} else {
|
||||
err = test.err;
|
||||
}
|
||||
var message;
|
||||
if (typeof err.inspect === 'function') {
|
||||
message = err.inspect() + '';
|
||||
} else if (err.message && typeof err.message.toString === 'function') {
|
||||
message = err.message + '';
|
||||
} else {
|
||||
message = '';
|
||||
}
|
||||
var stack = err.stack || message;
|
||||
var index = message ? stack.indexOf(message) : -1;
|
||||
|
||||
if (index === -1) {
|
||||
msg = message;
|
||||
} else {
|
||||
index += message.length;
|
||||
msg = stack.slice(0, index);
|
||||
// remove msg from stack
|
||||
stack = stack.slice(index + 1);
|
||||
}
|
||||
|
||||
// uncaught
|
||||
if (err.uncaught) {
|
||||
msg = 'Uncaught ' + msg;
|
||||
}
|
||||
// explicitly show diff
|
||||
if (!exports.hideDiff && showDiff(err)) {
|
||||
stringifyDiffObjs(err);
|
||||
fmt =
|
||||
color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
|
||||
var match = message.match(/^([^:]+): expected/);
|
||||
msg = '\n ' + color('error message', match ? match[1] : msg);
|
||||
|
||||
msg += generateDiff(err.actual, err.expected);
|
||||
}
|
||||
|
||||
// indent stack trace
|
||||
stack = stack.replace(/^/gm, ' ');
|
||||
|
||||
// indented test title
|
||||
var testTitle = '';
|
||||
test.titlePath().forEach(function (str, index) {
|
||||
if (index !== 0) {
|
||||
testTitle += '\n ';
|
||||
}
|
||||
for (var i = 0; i < index; i++) {
|
||||
testTitle += ' ';
|
||||
}
|
||||
testTitle += str;
|
||||
});
|
||||
|
||||
Base.consoleLog(fmt, i + 1, testTitle, msg, stack);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new `Base` reporter instance.
|
||||
*
|
||||
* @description
|
||||
* All other reporters generally inherit from this reporter.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Base(runner, options) {
|
||||
var failures = (this.failures = []);
|
||||
|
||||
if (!runner) {
|
||||
throw new TypeError('Missing runner argument');
|
||||
}
|
||||
this.options = options || {};
|
||||
this.runner = runner;
|
||||
this.stats = runner.stats; // assigned so Reporters keep a closer reference
|
||||
|
||||
var maxDiffSizeOpt =
|
||||
this.options.reporterOption && this.options.reporterOption.maxDiffSize;
|
||||
if (maxDiffSizeOpt !== undefined && !isNaN(Number(maxDiffSizeOpt))) {
|
||||
exports.maxDiffSize = Number(maxDiffSizeOpt);
|
||||
}
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
if (test.duration > test.slow()) {
|
||||
test.speed = 'slow';
|
||||
} else if (test.duration > test.slow() / 2) {
|
||||
test.speed = 'medium';
|
||||
} else {
|
||||
test.speed = 'fast';
|
||||
}
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test, err) {
|
||||
if (showDiff(err)) {
|
||||
stringifyDiffObjs(err);
|
||||
}
|
||||
// more than one error per test
|
||||
if (test.err && err instanceof Error) {
|
||||
test.err.multiple = (test.err.multiple || []).concat(err);
|
||||
} else {
|
||||
test.err = err;
|
||||
}
|
||||
failures.push(test);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs common epilogue used by many of the bundled reporters.
|
||||
*
|
||||
* @public
|
||||
* @memberof Mocha.reporters
|
||||
*/
|
||||
Base.prototype.epilogue = function () {
|
||||
var stats = this.stats;
|
||||
var fmt;
|
||||
|
||||
Base.consoleLog();
|
||||
|
||||
// passes
|
||||
fmt =
|
||||
color('bright pass', ' ') +
|
||||
color('green', ' %d passing') +
|
||||
color('light', ' (%s)');
|
||||
|
||||
Base.consoleLog(fmt, stats.passes || 0, milliseconds(stats.duration));
|
||||
|
||||
// pending
|
||||
if (stats.pending) {
|
||||
fmt = color('pending', ' ') + color('pending', ' %d pending');
|
||||
|
||||
Base.consoleLog(fmt, stats.pending);
|
||||
}
|
||||
|
||||
// failures
|
||||
if (stats.failures) {
|
||||
fmt = color('fail', ' %d failing');
|
||||
|
||||
Base.consoleLog(fmt, stats.failures);
|
||||
|
||||
Base.list(this.failures);
|
||||
Base.consoleLog();
|
||||
}
|
||||
|
||||
Base.consoleLog();
|
||||
};
|
||||
|
||||
/**
|
||||
* Pads the given `str` to `len`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} str
|
||||
* @param {string} len
|
||||
* @return {string}
|
||||
*/
|
||||
function pad(str, len) {
|
||||
str = String(str);
|
||||
return Array(len - str.length + 1).join(' ') + str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns inline diff between 2 strings with coloured ANSI output.
|
||||
*
|
||||
* @private
|
||||
* @param {String} actual
|
||||
* @param {String} expected
|
||||
* @return {string} Diff
|
||||
*/
|
||||
function inlineDiff(actual, expected) {
|
||||
var msg = errorDiff(actual, expected);
|
||||
|
||||
// linenos
|
||||
var lines = msg.split('\n');
|
||||
if (lines.length > 4) {
|
||||
var width = String(lines.length).length;
|
||||
msg = lines
|
||||
.map(function (str, i) {
|
||||
return pad(++i, width) + ' |' + ' ' + str;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
// legend
|
||||
msg =
|
||||
'\n' +
|
||||
color('diff removed inline', 'actual') +
|
||||
' ' +
|
||||
color('diff added inline', 'expected') +
|
||||
'\n\n' +
|
||||
msg +
|
||||
'\n';
|
||||
|
||||
// indent
|
||||
msg = msg.replace(/^/gm, ' ');
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unified diff between two strings with coloured ANSI output.
|
||||
*
|
||||
* @private
|
||||
* @param {String} actual
|
||||
* @param {String} expected
|
||||
* @return {string} The diff.
|
||||
*/
|
||||
function unifiedDiff(actual, expected) {
|
||||
var indent = ' ';
|
||||
function cleanUp(line) {
|
||||
if (line[0] === '+') {
|
||||
return indent + colorLines('diff added', line);
|
||||
}
|
||||
if (line[0] === '-') {
|
||||
return indent + colorLines('diff removed', line);
|
||||
}
|
||||
if (line.match(/@@/)) {
|
||||
return '--';
|
||||
}
|
||||
if (line.match(/\\ No newline/)) {
|
||||
return null;
|
||||
}
|
||||
return indent + line;
|
||||
}
|
||||
function notBlank(line) {
|
||||
return typeof line !== 'undefined' && line !== null;
|
||||
}
|
||||
var msg = diff.createPatch('string', actual, expected);
|
||||
var lines = msg.split('\n').splice(5);
|
||||
return (
|
||||
'\n ' +
|
||||
colorLines('diff added', '+ expected') +
|
||||
' ' +
|
||||
colorLines('diff removed', '- actual') +
|
||||
'\n\n' +
|
||||
lines.map(cleanUp).filter(notBlank).join('\n')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns character diff for `err`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} actual
|
||||
* @param {String} expected
|
||||
* @return {string} the diff
|
||||
*/
|
||||
function errorDiff(actual, expected) {
|
||||
return diff
|
||||
.diffWordsWithSpace(actual, expected)
|
||||
.map(function (str) {
|
||||
if (str.added) {
|
||||
return colorLines('diff added inline', str.value);
|
||||
}
|
||||
if (str.removed) {
|
||||
return colorLines('diff removed inline', str.value);
|
||||
}
|
||||
return str.value;
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Colors lines for `str`, using the color `name`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} name
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
function colorLines(name, str) {
|
||||
return str
|
||||
.split('\n')
|
||||
.map(function (str) {
|
||||
return color(name, str);
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Object#toString reference.
|
||||
*/
|
||||
var objToString = Object.prototype.toString;
|
||||
|
||||
/**
|
||||
* Checks that a / b have the same type.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {boolean}
|
||||
*/
|
||||
function sameType(a, b) {
|
||||
return objToString.call(a) === objToString.call(b);
|
||||
}
|
||||
|
||||
Base.consoleLog = consoleLog;
|
||||
|
||||
Base.abstract = true;
|
||||
95
node_modules/mocha/lib/reporters/doc.js
generated
vendored
Normal file
95
node_modules/mocha/lib/reporters/doc.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Doc
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var utils = require('../utils');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
|
||||
var EVENT_SUITE_END = constants.EVENT_SUITE_END;
|
||||
|
||||
/**
|
||||
* Expose `Doc`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Doc;
|
||||
|
||||
/**
|
||||
* Constructs a new `Doc` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Doc(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var indents = 2;
|
||||
|
||||
function indent() {
|
||||
return Array(indents).join(' ');
|
||||
}
|
||||
|
||||
runner.on(EVENT_SUITE_BEGIN, function (suite) {
|
||||
if (suite.root) {
|
||||
return;
|
||||
}
|
||||
++indents;
|
||||
Base.consoleLog('%s<section class="suite">', indent());
|
||||
++indents;
|
||||
Base.consoleLog('%s<h1>%s</h1>', indent(), utils.escape(suite.title));
|
||||
Base.consoleLog('%s<dl>', indent());
|
||||
});
|
||||
|
||||
runner.on(EVENT_SUITE_END, function (suite) {
|
||||
if (suite.root) {
|
||||
return;
|
||||
}
|
||||
Base.consoleLog('%s</dl>', indent());
|
||||
--indents;
|
||||
Base.consoleLog('%s</section>', indent());
|
||||
--indents;
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.title));
|
||||
Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.file));
|
||||
var code = utils.escape(utils.clean(test.body));
|
||||
Base.consoleLog('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test, err) {
|
||||
Base.consoleLog(
|
||||
'%s <dt class="error">%s</dt>',
|
||||
indent(),
|
||||
utils.escape(test.title)
|
||||
);
|
||||
Base.consoleLog(
|
||||
'%s <dt class="error">%s</dt>',
|
||||
indent(),
|
||||
utils.escape(test.file)
|
||||
);
|
||||
var code = utils.escape(utils.clean(test.body));
|
||||
Base.consoleLog(
|
||||
'%s <dd class="error"><pre><code>%s</code></pre></dd>',
|
||||
indent(),
|
||||
code
|
||||
);
|
||||
Base.consoleLog(
|
||||
'%s <dd class="error">%s</dd>',
|
||||
indent(),
|
||||
utils.escape(err)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Doc.description = 'HTML documentation';
|
||||
81
node_modules/mocha/lib/reporters/dot.js
generated
vendored
Normal file
81
node_modules/mocha/lib/reporters/dot.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Dot
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var inherits = require('../utils').inherits;
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
|
||||
/**
|
||||
* Expose `Dot`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Dot;
|
||||
|
||||
/**
|
||||
* Constructs a new `Dot` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Dot(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var width = (Base.window.width * 0.75) | 0;
|
||||
var n = -1;
|
||||
|
||||
runner.on(EVENT_RUN_BEGIN, function () {
|
||||
process.stdout.write('\n');
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function () {
|
||||
if (++n % width === 0) {
|
||||
process.stdout.write('\n ');
|
||||
}
|
||||
process.stdout.write(Base.color('pending', Base.symbols.comma));
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
if (++n % width === 0) {
|
||||
process.stdout.write('\n ');
|
||||
}
|
||||
if (test.speed === 'slow') {
|
||||
process.stdout.write(Base.color('bright yellow', Base.symbols.dot));
|
||||
} else {
|
||||
process.stdout.write(Base.color(test.speed, Base.symbols.dot));
|
||||
}
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function () {
|
||||
if (++n % width === 0) {
|
||||
process.stdout.write('\n ');
|
||||
}
|
||||
process.stdout.write(Base.color('fail', Base.symbols.bang));
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
process.stdout.write('\n');
|
||||
self.epilogue();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(Dot, Base);
|
||||
|
||||
Dot.description = 'dot matrix representation';
|
||||
390
node_modules/mocha/lib/reporters/html.js
generated
vendored
Normal file
390
node_modules/mocha/lib/reporters/html.js
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-env browser */
|
||||
/**
|
||||
* @module HTML
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var utils = require('../utils');
|
||||
var Progress = require('../browser/progress');
|
||||
var escapeRe = require('escape-string-regexp');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
|
||||
var EVENT_SUITE_END = constants.EVENT_SUITE_END;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var escape = utils.escape;
|
||||
|
||||
/**
|
||||
* Save timer references to avoid Sinon interfering (see GH-237).
|
||||
*/
|
||||
|
||||
var Date = global.Date;
|
||||
|
||||
/**
|
||||
* Expose `HTML`.
|
||||
*/
|
||||
|
||||
exports = module.exports = HTML;
|
||||
|
||||
/**
|
||||
* Stats template.
|
||||
*/
|
||||
|
||||
var statsTemplate =
|
||||
'<ul id="mocha-stats">' +
|
||||
'<li class="progress"><canvas width="40" height="40"></canvas></li>' +
|
||||
'<li class="passes"><a href="javascript:void(0);">passes:</a> <em>0</em></li>' +
|
||||
'<li class="failures"><a href="javascript:void(0);">failures:</a> <em>0</em></li>' +
|
||||
'<li class="duration">duration: <em>0</em>s</li>' +
|
||||
'</ul>';
|
||||
|
||||
var playIcon = '‣';
|
||||
|
||||
/**
|
||||
* Constructs a new `HTML` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function HTML(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var stats = this.stats;
|
||||
var stat = fragment(statsTemplate);
|
||||
var items = stat.getElementsByTagName('li');
|
||||
var passes = items[1].getElementsByTagName('em')[0];
|
||||
var passesLink = items[1].getElementsByTagName('a')[0];
|
||||
var failures = items[2].getElementsByTagName('em')[0];
|
||||
var failuresLink = items[2].getElementsByTagName('a')[0];
|
||||
var duration = items[3].getElementsByTagName('em')[0];
|
||||
var canvas = stat.getElementsByTagName('canvas')[0];
|
||||
var report = fragment('<ul id="mocha-report"></ul>');
|
||||
var stack = [report];
|
||||
var progress;
|
||||
var ctx;
|
||||
var root = document.getElementById('mocha');
|
||||
|
||||
if (canvas.getContext) {
|
||||
var ratio = window.devicePixelRatio || 1;
|
||||
canvas.style.width = canvas.width;
|
||||
canvas.style.height = canvas.height;
|
||||
canvas.width *= ratio;
|
||||
canvas.height *= ratio;
|
||||
ctx = canvas.getContext('2d');
|
||||
ctx.scale(ratio, ratio);
|
||||
progress = new Progress();
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
return error('#mocha div missing, add it to your document');
|
||||
}
|
||||
|
||||
// pass toggle
|
||||
on(passesLink, 'click', function (evt) {
|
||||
evt.preventDefault();
|
||||
unhide();
|
||||
var name = /pass/.test(report.className) ? '' : ' pass';
|
||||
report.className = report.className.replace(/fail|pass/g, '') + name;
|
||||
if (report.className.trim()) {
|
||||
hideSuitesWithout('test pass');
|
||||
}
|
||||
});
|
||||
|
||||
// failure toggle
|
||||
on(failuresLink, 'click', function (evt) {
|
||||
evt.preventDefault();
|
||||
unhide();
|
||||
var name = /fail/.test(report.className) ? '' : ' fail';
|
||||
report.className = report.className.replace(/fail|pass/g, '') + name;
|
||||
if (report.className.trim()) {
|
||||
hideSuitesWithout('test fail');
|
||||
}
|
||||
});
|
||||
|
||||
root.appendChild(stat);
|
||||
root.appendChild(report);
|
||||
|
||||
if (progress) {
|
||||
progress.size(40);
|
||||
}
|
||||
|
||||
runner.on(EVENT_SUITE_BEGIN, function (suite) {
|
||||
if (suite.root) {
|
||||
return;
|
||||
}
|
||||
|
||||
// suite
|
||||
var url = self.suiteURL(suite);
|
||||
var el = fragment(
|
||||
'<li class="suite"><h1><a href="%s">%s</a></h1></li>',
|
||||
url,
|
||||
escape(suite.title)
|
||||
);
|
||||
|
||||
// container
|
||||
stack[0].appendChild(el);
|
||||
stack.unshift(document.createElement('ul'));
|
||||
el.appendChild(stack[0]);
|
||||
});
|
||||
|
||||
runner.on(EVENT_SUITE_END, function (suite) {
|
||||
if (suite.root) {
|
||||
updateStats();
|
||||
return;
|
||||
}
|
||||
stack.shift();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
var url = self.testURL(test);
|
||||
var markup =
|
||||
'<li class="test pass %e"><h2>%e<span class="duration">%ems</span> ' +
|
||||
'<a href="%s" class="replay">' +
|
||||
playIcon +
|
||||
'</a></h2></li>';
|
||||
var el = fragment(markup, test.speed, test.title, test.duration, url);
|
||||
self.addCodeToggle(el, test.body);
|
||||
appendToStack(el);
|
||||
updateStats();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test) {
|
||||
var el = fragment(
|
||||
'<li class="test fail"><h2>%e <a href="%e" class="replay">' +
|
||||
playIcon +
|
||||
'</a></h2></li>',
|
||||
test.title,
|
||||
self.testURL(test)
|
||||
);
|
||||
var stackString; // Note: Includes leading newline
|
||||
var message = test.err.toString();
|
||||
|
||||
// <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
|
||||
// check for the result of the stringifying.
|
||||
if (message === '[object Error]') {
|
||||
message = test.err.message;
|
||||
}
|
||||
|
||||
if (test.err.stack) {
|
||||
var indexOfMessage = test.err.stack.indexOf(test.err.message);
|
||||
if (indexOfMessage === -1) {
|
||||
stackString = test.err.stack;
|
||||
} else {
|
||||
stackString = test.err.stack.slice(
|
||||
test.err.message.length + indexOfMessage
|
||||
);
|
||||
}
|
||||
} else if (test.err.sourceURL && test.err.line !== undefined) {
|
||||
// Safari doesn't give you a stack. Let's at least provide a source line.
|
||||
stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')';
|
||||
}
|
||||
|
||||
stackString = stackString || '';
|
||||
|
||||
if (test.err.htmlMessage && stackString) {
|
||||
el.appendChild(
|
||||
fragment(
|
||||
'<div class="html-error">%s\n<pre class="error">%e</pre></div>',
|
||||
test.err.htmlMessage,
|
||||
stackString
|
||||
)
|
||||
);
|
||||
} else if (test.err.htmlMessage) {
|
||||
el.appendChild(
|
||||
fragment('<div class="html-error">%s</div>', test.err.htmlMessage)
|
||||
);
|
||||
} else {
|
||||
el.appendChild(
|
||||
fragment('<pre class="error">%e%e</pre>', message, stackString)
|
||||
);
|
||||
}
|
||||
|
||||
self.addCodeToggle(el, test.body);
|
||||
appendToStack(el);
|
||||
updateStats();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function (test) {
|
||||
var el = fragment(
|
||||
'<li class="test pass pending"><h2>%e</h2></li>',
|
||||
test.title
|
||||
);
|
||||
appendToStack(el);
|
||||
updateStats();
|
||||
});
|
||||
|
||||
function appendToStack(el) {
|
||||
// Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
|
||||
if (stack[0]) {
|
||||
stack[0].appendChild(el);
|
||||
}
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
// TODO: add to stats
|
||||
var percent = ((stats.tests / runner.total) * 100) | 0;
|
||||
if (progress) {
|
||||
progress.update(percent).draw(ctx);
|
||||
}
|
||||
|
||||
// update stats
|
||||
var ms = new Date() - stats.start;
|
||||
text(passes, stats.passes);
|
||||
text(failures, stats.failures);
|
||||
text(duration, (ms / 1000).toFixed(2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a URL, preserving querystring ("search") parameters.
|
||||
*
|
||||
* @param {string} s
|
||||
* @return {string} A new URL.
|
||||
*/
|
||||
function makeUrl(s) {
|
||||
var search = window.location.search;
|
||||
|
||||
// Remove previous grep query parameter if present
|
||||
if (search) {
|
||||
search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?');
|
||||
}
|
||||
|
||||
return (
|
||||
window.location.pathname +
|
||||
(search ? search + '&' : '?') +
|
||||
'grep=' +
|
||||
encodeURIComponent(escapeRe(s))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide suite URL.
|
||||
*
|
||||
* @param {Object} [suite]
|
||||
*/
|
||||
HTML.prototype.suiteURL = function (suite) {
|
||||
return makeUrl(suite.fullTitle());
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide test URL.
|
||||
*
|
||||
* @param {Object} [test]
|
||||
*/
|
||||
HTML.prototype.testURL = function (test) {
|
||||
return makeUrl(test.fullTitle());
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds code toggle functionality for the provided test's list element.
|
||||
*
|
||||
* @param {HTMLLIElement} el
|
||||
* @param {string} contents
|
||||
*/
|
||||
HTML.prototype.addCodeToggle = function (el, contents) {
|
||||
var h2 = el.getElementsByTagName('h2')[0];
|
||||
|
||||
on(h2, 'click', function () {
|
||||
pre.style.display = pre.style.display === 'none' ? 'block' : 'none';
|
||||
});
|
||||
|
||||
var pre = fragment('<pre><code>%e</code></pre>', utils.clean(contents));
|
||||
el.appendChild(pre);
|
||||
pre.style.display = 'none';
|
||||
};
|
||||
|
||||
/**
|
||||
* Display error `msg`.
|
||||
*
|
||||
* @param {string} msg
|
||||
*/
|
||||
function error(msg) {
|
||||
document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a DOM fragment from `html`.
|
||||
*
|
||||
* @param {string} html
|
||||
*/
|
||||
function fragment(html) {
|
||||
var args = arguments;
|
||||
var div = document.createElement('div');
|
||||
var i = 1;
|
||||
|
||||
div.innerHTML = html.replace(/%([se])/g, function (_, type) {
|
||||
switch (type) {
|
||||
case 's':
|
||||
return String(args[i++]);
|
||||
case 'e':
|
||||
return escape(args[i++]);
|
||||
// no default
|
||||
}
|
||||
});
|
||||
|
||||
return div.firstChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for suites that do not have elements
|
||||
* with `classname`, and hide them.
|
||||
*
|
||||
* @param {text} classname
|
||||
*/
|
||||
function hideSuitesWithout(classname) {
|
||||
var suites = document.getElementsByClassName('suite');
|
||||
for (var i = 0; i < suites.length; i++) {
|
||||
var els = suites[i].getElementsByClassName(classname);
|
||||
if (!els.length) {
|
||||
suites[i].className += ' hidden';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unhide .hidden suites.
|
||||
*/
|
||||
function unhide() {
|
||||
var els = document.getElementsByClassName('suite hidden');
|
||||
while (els.length > 0) {
|
||||
els[0].className = els[0].className.replace('suite hidden', 'suite');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an element's text contents.
|
||||
*
|
||||
* @param {HTMLElement} el
|
||||
* @param {string} contents
|
||||
*/
|
||||
function text(el, contents) {
|
||||
if (el.textContent) {
|
||||
el.textContent = contents;
|
||||
} else {
|
||||
el.innerText = contents;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen on `event` with callback `fn`.
|
||||
*/
|
||||
function on(el, event, fn) {
|
||||
if (el.addEventListener) {
|
||||
el.addEventListener(event, fn, false);
|
||||
} else {
|
||||
el.attachEvent('on' + event, fn);
|
||||
}
|
||||
}
|
||||
|
||||
HTML.browserOnly = true;
|
||||
19
node_modules/mocha/lib/reporters/index.js
generated
vendored
Normal file
19
node_modules/mocha/lib/reporters/index.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
// Alias exports to a their normalized format Mocha#reporter to prevent a need
|
||||
// for dynamic (try/catch) requires, which Browserify doesn't handle.
|
||||
exports.Base = exports.base = require('./base');
|
||||
exports.Dot = exports.dot = require('./dot');
|
||||
exports.Doc = exports.doc = require('./doc');
|
||||
exports.TAP = exports.tap = require('./tap');
|
||||
exports.JSON = exports.json = require('./json');
|
||||
exports.HTML = exports.html = require('./html');
|
||||
exports.List = exports.list = require('./list');
|
||||
exports.Min = exports.min = require('./min');
|
||||
exports.Spec = exports.spec = require('./spec');
|
||||
exports.Nyan = exports.nyan = require('./nyan');
|
||||
exports.XUnit = exports.xunit = require('./xunit');
|
||||
exports.Markdown = exports.markdown = require('./markdown');
|
||||
exports.Progress = exports.progress = require('./progress');
|
||||
exports.Landing = exports.landing = require('./landing');
|
||||
exports.JSONStream = exports['json-stream'] = require('./json-stream');
|
||||
92
node_modules/mocha/lib/reporters/json-stream.js
generated
vendored
Normal file
92
node_modules/mocha/lib/reporters/json-stream.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module JSONStream
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
|
||||
/**
|
||||
* Expose `JSONStream`.
|
||||
*/
|
||||
|
||||
exports = module.exports = JSONStream;
|
||||
|
||||
/**
|
||||
* Constructs a new `JSONStream` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function JSONStream(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var total = runner.total;
|
||||
|
||||
runner.once(EVENT_RUN_BEGIN, function () {
|
||||
writeEvent(['start', {total: total}]);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
writeEvent(['pass', clean(test)]);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test, err) {
|
||||
test = clean(test);
|
||||
test.err = err.message;
|
||||
test.stack = err.stack || null;
|
||||
writeEvent(['fail', test]);
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
writeEvent(['end', self.stats]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocha event to be written to the output stream.
|
||||
* @typedef {Array} JSONStream~MochaEvent
|
||||
*/
|
||||
|
||||
/**
|
||||
* Writes Mocha event to reporter output stream.
|
||||
*
|
||||
* @private
|
||||
* @param {JSONStream~MochaEvent} event - Mocha event to be output.
|
||||
*/
|
||||
function writeEvent(event) {
|
||||
process.stdout.write(JSON.stringify(event) + '\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object literal representation of `test`
|
||||
* free of cyclic properties, etc.
|
||||
*
|
||||
* @private
|
||||
* @param {Test} test - Instance used as data source.
|
||||
* @return {Object} object containing pared-down test instance data
|
||||
*/
|
||||
function clean(test) {
|
||||
return {
|
||||
title: test.title,
|
||||
fullTitle: test.fullTitle(),
|
||||
file: test.file,
|
||||
duration: test.duration,
|
||||
currentRetry: test.currentRetry(),
|
||||
speed: test.speed
|
||||
};
|
||||
}
|
||||
|
||||
JSONStream.description = 'newline delimited JSON events';
|
||||
162
node_modules/mocha/lib/reporters/json.js
generated
vendored
Normal file
162
node_modules/mocha/lib/reporters/json.js
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module JSON
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
const createUnsupportedError = require('../errors').createUnsupportedError;
|
||||
const utils = require('../utils');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_TEST_END = constants.EVENT_TEST_END;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
|
||||
/**
|
||||
* Expose `JSON`.
|
||||
*/
|
||||
|
||||
exports = module.exports = JSONReporter;
|
||||
|
||||
/**
|
||||
* Constructs a new `JSON` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class JSON
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function JSONReporter(runner, options = {}) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var tests = [];
|
||||
var pending = [];
|
||||
var failures = [];
|
||||
var passes = [];
|
||||
var output;
|
||||
|
||||
if (options.reporterOption && options.reporterOption.output) {
|
||||
if (utils.isBrowser()) {
|
||||
throw createUnsupportedError('file output not supported in browser');
|
||||
}
|
||||
output = options.reporterOption.output;
|
||||
}
|
||||
|
||||
runner.on(EVENT_TEST_END, function (test) {
|
||||
tests.push(test);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
passes.push(test);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test) {
|
||||
failures.push(test);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function (test) {
|
||||
pending.push(test);
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
var obj = {
|
||||
stats: self.stats,
|
||||
tests: tests.map(clean),
|
||||
pending: pending.map(clean),
|
||||
failures: failures.map(clean),
|
||||
passes: passes.map(clean)
|
||||
};
|
||||
|
||||
runner.testResults = obj;
|
||||
|
||||
var json = JSON.stringify(obj, null, 2);
|
||||
if (output) {
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(output), {recursive: true});
|
||||
fs.writeFileSync(output, json);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`${Base.symbols.err} [mocha] writing output to "${output}" failed: ${err.message}\n`
|
||||
);
|
||||
process.stdout.write(json);
|
||||
}
|
||||
} else {
|
||||
process.stdout.write(json);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a plain-object representation of `test`
|
||||
* free of cyclic properties etc.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} test
|
||||
* @return {Object}
|
||||
*/
|
||||
function clean(test) {
|
||||
var err = test.err || {};
|
||||
if (err instanceof Error) {
|
||||
err = errorJSON(err);
|
||||
}
|
||||
|
||||
return {
|
||||
title: test.title,
|
||||
fullTitle: test.fullTitle(),
|
||||
file: test.file,
|
||||
duration: test.duration,
|
||||
currentRetry: test.currentRetry(),
|
||||
speed: test.speed,
|
||||
err: cleanCycles(err)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces any circular references inside `obj` with '[object Object]'
|
||||
*
|
||||
* @private
|
||||
* @param {Object} obj
|
||||
* @return {Object}
|
||||
*/
|
||||
function cleanCycles(obj) {
|
||||
var cache = [];
|
||||
return JSON.parse(
|
||||
JSON.stringify(obj, function (key, value) {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (cache.indexOf(value) !== -1) {
|
||||
// Instead of going in a circle, we'll print [object Object]
|
||||
return '' + value;
|
||||
}
|
||||
cache.push(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an Error object into a JSON object.
|
||||
*
|
||||
* @private
|
||||
* @param {Error} err
|
||||
* @return {Object}
|
||||
*/
|
||||
function errorJSON(err) {
|
||||
var res = {};
|
||||
Object.getOwnPropertyNames(err).forEach(function (key) {
|
||||
res[key] = err[key];
|
||||
}, err);
|
||||
return res;
|
||||
}
|
||||
|
||||
JSONReporter.description = 'single JSON object';
|
||||
116
node_modules/mocha/lib/reporters/landing.js
generated
vendored
Normal file
116
node_modules/mocha/lib/reporters/landing.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Landing
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var inherits = require('../utils').inherits;
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_TEST_END = constants.EVENT_TEST_END;
|
||||
var STATE_FAILED = require('../runnable').constants.STATE_FAILED;
|
||||
|
||||
var cursor = Base.cursor;
|
||||
var color = Base.color;
|
||||
|
||||
/**
|
||||
* Expose `Landing`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Landing;
|
||||
|
||||
/**
|
||||
* Airplane color.
|
||||
*/
|
||||
|
||||
Base.colors.plane = 0;
|
||||
|
||||
/**
|
||||
* Airplane crash color.
|
||||
*/
|
||||
|
||||
Base.colors['plane crash'] = 31;
|
||||
|
||||
/**
|
||||
* Runway color.
|
||||
*/
|
||||
|
||||
Base.colors.runway = 90;
|
||||
|
||||
/**
|
||||
* Constructs a new `Landing` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Landing(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var width = (Base.window.width * 0.75) | 0;
|
||||
var stream = process.stdout;
|
||||
|
||||
var plane = color('plane', '✈');
|
||||
var crashed = -1;
|
||||
var n = 0;
|
||||
var total = 0;
|
||||
|
||||
function runway() {
|
||||
var buf = Array(width).join('-');
|
||||
return ' ' + color('runway', buf);
|
||||
}
|
||||
|
||||
runner.on(EVENT_RUN_BEGIN, function () {
|
||||
stream.write('\n\n\n ');
|
||||
cursor.hide();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_END, function (test) {
|
||||
// check if the plane crashed
|
||||
var col = crashed === -1 ? ((width * ++n) / ++total) | 0 : crashed;
|
||||
// show the crash
|
||||
if (test.state === STATE_FAILED) {
|
||||
plane = color('plane crash', '✈');
|
||||
crashed = col;
|
||||
}
|
||||
|
||||
// render landing strip
|
||||
stream.write('\u001b[' + (width + 1) + 'D\u001b[2A');
|
||||
stream.write(runway());
|
||||
stream.write('\n ');
|
||||
stream.write(color('runway', Array(col).join('⋅')));
|
||||
stream.write(plane);
|
||||
stream.write(color('runway', Array(width - col).join('⋅') + '\n'));
|
||||
stream.write(runway());
|
||||
stream.write('\u001b[0m');
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
cursor.show();
|
||||
process.stdout.write('\n');
|
||||
self.epilogue();
|
||||
});
|
||||
|
||||
// if cursor is hidden when we ctrl-C, then it will remain hidden unless...
|
||||
process.once('SIGINT', function () {
|
||||
cursor.show();
|
||||
process.nextTick(function () {
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(Landing, Base);
|
||||
|
||||
Landing.description = 'Unicode landing strip';
|
||||
78
node_modules/mocha/lib/reporters/list.js
generated
vendored
Normal file
78
node_modules/mocha/lib/reporters/list.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module List
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var inherits = require('../utils').inherits;
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_TEST_BEGIN = constants.EVENT_TEST_BEGIN;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var color = Base.color;
|
||||
var cursor = Base.cursor;
|
||||
|
||||
/**
|
||||
* Expose `List`.
|
||||
*/
|
||||
|
||||
exports = module.exports = List;
|
||||
|
||||
/**
|
||||
* Constructs a new `List` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function List(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var n = 0;
|
||||
|
||||
runner.on(EVENT_RUN_BEGIN, function () {
|
||||
Base.consoleLog();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_BEGIN, function (test) {
|
||||
process.stdout.write(color('pass', ' ' + test.fullTitle() + ': '));
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function (test) {
|
||||
var fmt = color('checkmark', ' -') + color('pending', ' %s');
|
||||
Base.consoleLog(fmt, test.fullTitle());
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
var fmt =
|
||||
color('checkmark', ' ' + Base.symbols.ok) +
|
||||
color('pass', ' %s: ') +
|
||||
color(test.speed, '%dms');
|
||||
cursor.CR();
|
||||
Base.consoleLog(fmt, test.fullTitle(), test.duration);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test) {
|
||||
cursor.CR();
|
||||
Base.consoleLog(color('fail', ' %d) %s'), ++n, test.fullTitle());
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, self.epilogue.bind(self));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(List, Base);
|
||||
|
||||
List.description = 'like "spec" reporter but flat';
|
||||
112
node_modules/mocha/lib/reporters/markdown.js
generated
vendored
Normal file
112
node_modules/mocha/lib/reporters/markdown.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Markdown
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var utils = require('../utils');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
|
||||
var EVENT_SUITE_END = constants.EVENT_SUITE_END;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
var SUITE_PREFIX = '$';
|
||||
|
||||
/**
|
||||
* Expose `Markdown`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Markdown;
|
||||
|
||||
/**
|
||||
* Constructs a new `Markdown` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Markdown(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var level = 0;
|
||||
var buf = '';
|
||||
|
||||
function title(str) {
|
||||
return Array(level).join('#') + ' ' + str;
|
||||
}
|
||||
|
||||
function mapTOC(suite, obj) {
|
||||
var ret = obj;
|
||||
var key = SUITE_PREFIX + suite.title;
|
||||
|
||||
obj = obj[key] = obj[key] || {suite: suite};
|
||||
suite.suites.forEach(function (suite) {
|
||||
mapTOC(suite, obj);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function stringifyTOC(obj, level) {
|
||||
++level;
|
||||
var buf = '';
|
||||
var link;
|
||||
for (var key in obj) {
|
||||
if (key === 'suite') {
|
||||
continue;
|
||||
}
|
||||
if (key !== SUITE_PREFIX) {
|
||||
link = ' - [' + key.substring(1) + ']';
|
||||
link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
|
||||
buf += Array(level).join(' ') + link;
|
||||
}
|
||||
buf += stringifyTOC(obj[key], level);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
function generateTOC(suite) {
|
||||
var obj = mapTOC(suite, {});
|
||||
return stringifyTOC(obj, 0);
|
||||
}
|
||||
|
||||
generateTOC(runner.suite);
|
||||
|
||||
runner.on(EVENT_SUITE_BEGIN, function (suite) {
|
||||
++level;
|
||||
var slug = utils.slug(suite.fullTitle());
|
||||
buf += '<a name="' + slug + '"></a>' + '\n';
|
||||
buf += title(suite.title) + '\n';
|
||||
});
|
||||
|
||||
runner.on(EVENT_SUITE_END, function () {
|
||||
--level;
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
var code = utils.clean(test.body);
|
||||
buf += test.title + '.\n';
|
||||
buf += '\n```js\n';
|
||||
buf += code + '\n';
|
||||
buf += '```\n\n';
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
process.stdout.write('# TOC\n');
|
||||
process.stdout.write(generateTOC(runner.suite));
|
||||
process.stdout.write(buf);
|
||||
});
|
||||
}
|
||||
|
||||
Markdown.description = 'GitHub Flavored Markdown';
|
||||
52
node_modules/mocha/lib/reporters/min.js
generated
vendored
Normal file
52
node_modules/mocha/lib/reporters/min.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Min
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var inherits = require('../utils').inherits;
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
|
||||
/**
|
||||
* Expose `Min`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Min;
|
||||
|
||||
/**
|
||||
* Constructs a new `Min` reporter instance.
|
||||
*
|
||||
* @description
|
||||
* This minimal test reporter is best used with '--watch'.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Min(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
runner.on(EVENT_RUN_BEGIN, function () {
|
||||
// clear screen
|
||||
process.stdout.write('\u001b[2J');
|
||||
// set cursor position
|
||||
process.stdout.write('\u001b[1;3H');
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, this.epilogue.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(Min, Base);
|
||||
|
||||
Min.description = 'essentially just a summary';
|
||||
276
node_modules/mocha/lib/reporters/nyan.js
generated
vendored
Normal file
276
node_modules/mocha/lib/reporters/nyan.js
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Nyan
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var constants = require('../runner').constants;
|
||||
var inherits = require('../utils').inherits;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
|
||||
/**
|
||||
* Expose `Dot`.
|
||||
*/
|
||||
|
||||
exports = module.exports = NyanCat;
|
||||
|
||||
/**
|
||||
* Constructs a new `Nyan` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class Nyan
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function NyanCat(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var width = (Base.window.width * 0.75) | 0;
|
||||
var nyanCatWidth = (this.nyanCatWidth = 11);
|
||||
|
||||
this.colorIndex = 0;
|
||||
this.numberOfLines = 4;
|
||||
this.rainbowColors = self.generateColors();
|
||||
this.scoreboardWidth = 5;
|
||||
this.tick = 0;
|
||||
this.trajectories = [[], [], [], []];
|
||||
this.trajectoryWidthMax = width - nyanCatWidth;
|
||||
|
||||
runner.on(EVENT_RUN_BEGIN, function () {
|
||||
Base.cursor.hide();
|
||||
self.draw();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function () {
|
||||
self.draw();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function () {
|
||||
self.draw();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function () {
|
||||
self.draw();
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
Base.cursor.show();
|
||||
for (var i = 0; i < self.numberOfLines; i++) {
|
||||
write('\n');
|
||||
}
|
||||
self.epilogue();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(NyanCat, Base);
|
||||
|
||||
/**
|
||||
* Draw the nyan cat
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
NyanCat.prototype.draw = function () {
|
||||
this.appendRainbow();
|
||||
this.drawScoreboard();
|
||||
this.drawRainbow();
|
||||
this.drawNyanCat();
|
||||
this.tick = !this.tick;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw the "scoreboard" showing the number
|
||||
* of passes, failures and pending tests.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
NyanCat.prototype.drawScoreboard = function () {
|
||||
var stats = this.stats;
|
||||
|
||||
function draw(type, n) {
|
||||
write(' ');
|
||||
write(Base.color(type, n));
|
||||
write('\n');
|
||||
}
|
||||
|
||||
draw('green', stats.passes);
|
||||
draw('fail', stats.failures);
|
||||
draw('pending', stats.pending);
|
||||
write('\n');
|
||||
|
||||
this.cursorUp(this.numberOfLines);
|
||||
};
|
||||
|
||||
/**
|
||||
* Append the rainbow.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
NyanCat.prototype.appendRainbow = function () {
|
||||
var segment = this.tick ? '_' : '-';
|
||||
var rainbowified = this.rainbowify(segment);
|
||||
|
||||
for (var index = 0; index < this.numberOfLines; index++) {
|
||||
var trajectory = this.trajectories[index];
|
||||
if (trajectory.length >= this.trajectoryWidthMax) {
|
||||
trajectory.shift();
|
||||
}
|
||||
trajectory.push(rainbowified);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw the rainbow.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
NyanCat.prototype.drawRainbow = function () {
|
||||
var self = this;
|
||||
|
||||
this.trajectories.forEach(function (line) {
|
||||
write('\u001b[' + self.scoreboardWidth + 'C');
|
||||
write(line.join(''));
|
||||
write('\n');
|
||||
});
|
||||
|
||||
this.cursorUp(this.numberOfLines);
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw the nyan cat
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
NyanCat.prototype.drawNyanCat = function () {
|
||||
var self = this;
|
||||
var startWidth = this.scoreboardWidth + this.trajectories[0].length;
|
||||
var dist = '\u001b[' + startWidth + 'C';
|
||||
var padding = '';
|
||||
|
||||
write(dist);
|
||||
write('_,------,');
|
||||
write('\n');
|
||||
|
||||
write(dist);
|
||||
padding = self.tick ? ' ' : ' ';
|
||||
write('_|' + padding + '/\\_/\\ ');
|
||||
write('\n');
|
||||
|
||||
write(dist);
|
||||
padding = self.tick ? '_' : '__';
|
||||
var tail = self.tick ? '~' : '^';
|
||||
write(tail + '|' + padding + this.face() + ' ');
|
||||
write('\n');
|
||||
|
||||
write(dist);
|
||||
padding = self.tick ? ' ' : ' ';
|
||||
write(padding + '"" "" ');
|
||||
write('\n');
|
||||
|
||||
this.cursorUp(this.numberOfLines);
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw nyan cat face.
|
||||
*
|
||||
* @private
|
||||
* @return {string}
|
||||
*/
|
||||
|
||||
NyanCat.prototype.face = function () {
|
||||
var stats = this.stats;
|
||||
if (stats.failures) {
|
||||
return '( x .x)';
|
||||
} else if (stats.pending) {
|
||||
return '( o .o)';
|
||||
} else if (stats.passes) {
|
||||
return '( ^ .^)';
|
||||
}
|
||||
return '( - .-)';
|
||||
};
|
||||
|
||||
/**
|
||||
* Move cursor up `n`.
|
||||
*
|
||||
* @private
|
||||
* @param {number} n
|
||||
*/
|
||||
|
||||
NyanCat.prototype.cursorUp = function (n) {
|
||||
write('\u001b[' + n + 'A');
|
||||
};
|
||||
|
||||
/**
|
||||
* Move cursor down `n`.
|
||||
*
|
||||
* @private
|
||||
* @param {number} n
|
||||
*/
|
||||
|
||||
NyanCat.prototype.cursorDown = function (n) {
|
||||
write('\u001b[' + n + 'B');
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate rainbow colors.
|
||||
*
|
||||
* @private
|
||||
* @return {Array}
|
||||
*/
|
||||
NyanCat.prototype.generateColors = function () {
|
||||
var colors = [];
|
||||
|
||||
for (var i = 0; i < 6 * 7; i++) {
|
||||
var pi3 = Math.floor(Math.PI / 3);
|
||||
var n = i * (1.0 / 6);
|
||||
var r = Math.floor(3 * Math.sin(n) + 3);
|
||||
var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);
|
||||
var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);
|
||||
colors.push(36 * r + 6 * g + b + 16);
|
||||
}
|
||||
|
||||
return colors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply rainbow to the given `str`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
NyanCat.prototype.rainbowify = function (str) {
|
||||
if (!Base.useColors) {
|
||||
return str;
|
||||
}
|
||||
var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
|
||||
this.colorIndex += 1;
|
||||
return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
|
||||
};
|
||||
|
||||
/**
|
||||
* Stdout helper.
|
||||
*
|
||||
* @param {string} string A message to write to stdout.
|
||||
*/
|
||||
function write(string) {
|
||||
process.stdout.write(string);
|
||||
}
|
||||
|
||||
NyanCat.description = '"nyan cat"';
|
||||
104
node_modules/mocha/lib/reporters/progress.js
generated
vendored
Normal file
104
node_modules/mocha/lib/reporters/progress.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Progress
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_TEST_END = constants.EVENT_TEST_END;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var inherits = require('../utils').inherits;
|
||||
var color = Base.color;
|
||||
var cursor = Base.cursor;
|
||||
|
||||
/**
|
||||
* Expose `Progress`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Progress;
|
||||
|
||||
/**
|
||||
* General progress bar color.
|
||||
*/
|
||||
|
||||
Base.colors.progress = 90;
|
||||
|
||||
/**
|
||||
* Constructs a new `Progress` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Progress(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var width = (Base.window.width * 0.5) | 0;
|
||||
var total = runner.total;
|
||||
var complete = 0;
|
||||
var lastN = -1;
|
||||
|
||||
// default chars
|
||||
options = options || {};
|
||||
var reporterOptions = options.reporterOptions || {};
|
||||
|
||||
options.open = reporterOptions.open || '[';
|
||||
options.complete = reporterOptions.complete || '▬';
|
||||
options.incomplete = reporterOptions.incomplete || Base.symbols.dot;
|
||||
options.close = reporterOptions.close || ']';
|
||||
options.verbose = reporterOptions.verbose || false;
|
||||
|
||||
// tests started
|
||||
runner.on(EVENT_RUN_BEGIN, function () {
|
||||
process.stdout.write('\n');
|
||||
cursor.hide();
|
||||
});
|
||||
|
||||
// tests complete
|
||||
runner.on(EVENT_TEST_END, function () {
|
||||
complete++;
|
||||
|
||||
var percent = complete / total;
|
||||
var n = (width * percent) | 0;
|
||||
var i = width - n;
|
||||
|
||||
if (n === lastN && !options.verbose) {
|
||||
// Don't re-render the line if it hasn't changed
|
||||
return;
|
||||
}
|
||||
lastN = n;
|
||||
|
||||
cursor.CR();
|
||||
process.stdout.write('\u001b[J');
|
||||
process.stdout.write(color('progress', ' ' + options.open));
|
||||
process.stdout.write(Array(n).join(options.complete));
|
||||
process.stdout.write(Array(i).join(options.incomplete));
|
||||
process.stdout.write(color('progress', options.close));
|
||||
if (options.verbose) {
|
||||
process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
|
||||
}
|
||||
});
|
||||
|
||||
// tests are complete, output some stats
|
||||
// and the failures if any
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
cursor.show();
|
||||
process.stdout.write('\n');
|
||||
self.epilogue();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(Progress, Base);
|
||||
|
||||
Progress.description = 'a progress bar';
|
||||
99
node_modules/mocha/lib/reporters/spec.js
generated
vendored
Normal file
99
node_modules/mocha/lib/reporters/spec.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module Spec
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
|
||||
var EVENT_SUITE_END = constants.EVENT_SUITE_END;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var inherits = require('../utils').inherits;
|
||||
var color = Base.color;
|
||||
|
||||
/**
|
||||
* Expose `Spec`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Spec;
|
||||
|
||||
/**
|
||||
* Constructs a new `Spec` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function Spec(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var indents = 0;
|
||||
var n = 0;
|
||||
|
||||
function indent() {
|
||||
return Array(indents).join(' ');
|
||||
}
|
||||
|
||||
runner.on(EVENT_RUN_BEGIN, function () {
|
||||
Base.consoleLog();
|
||||
});
|
||||
|
||||
runner.on(EVENT_SUITE_BEGIN, function (suite) {
|
||||
++indents;
|
||||
Base.consoleLog(color('suite', '%s%s'), indent(), suite.title);
|
||||
});
|
||||
|
||||
runner.on(EVENT_SUITE_END, function () {
|
||||
--indents;
|
||||
if (indents === 1) {
|
||||
Base.consoleLog();
|
||||
}
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function (test) {
|
||||
var fmt = indent() + color('pending', ' - %s');
|
||||
Base.consoleLog(fmt, test.title);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
var fmt;
|
||||
if (test.speed === 'fast') {
|
||||
fmt =
|
||||
indent() +
|
||||
color('checkmark', ' ' + Base.symbols.ok) +
|
||||
color('pass', ' %s');
|
||||
Base.consoleLog(fmt, test.title);
|
||||
} else {
|
||||
fmt =
|
||||
indent() +
|
||||
color('checkmark', ' ' + Base.symbols.ok) +
|
||||
color('pass', ' %s') +
|
||||
color(test.speed, ' (%dms)');
|
||||
Base.consoleLog(fmt, test.title, test.duration);
|
||||
}
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test) {
|
||||
Base.consoleLog(indent() + color('fail', ' %d) %s'), ++n, test.title);
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, self.epilogue.bind(self));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(Spec, Base);
|
||||
|
||||
Spec.description = 'hierarchical & verbose [default]';
|
||||
293
node_modules/mocha/lib/reporters/tap.js
generated
vendored
Normal file
293
node_modules/mocha/lib/reporters/tap.js
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module TAP
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var util = require('util');
|
||||
var Base = require('./base');
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var EVENT_TEST_END = constants.EVENT_TEST_END;
|
||||
var inherits = require('../utils').inherits;
|
||||
var sprintf = util.format;
|
||||
|
||||
/**
|
||||
* Expose `TAP`.
|
||||
*/
|
||||
|
||||
exports = module.exports = TAP;
|
||||
|
||||
/**
|
||||
* Constructs a new `TAP` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function TAP(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var self = this;
|
||||
var n = 1;
|
||||
|
||||
var tapVersion = '12';
|
||||
if (options && options.reporterOptions) {
|
||||
if (options.reporterOptions.tapVersion) {
|
||||
tapVersion = options.reporterOptions.tapVersion.toString();
|
||||
}
|
||||
}
|
||||
|
||||
this._producer = createProducer(tapVersion);
|
||||
|
||||
runner.once(EVENT_RUN_BEGIN, function () {
|
||||
self._producer.writeVersion();
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_END, function () {
|
||||
++n;
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function (test) {
|
||||
self._producer.writePending(n, test);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
self._producer.writePass(n, test);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test, err) {
|
||||
self._producer.writeFail(n, test, err);
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
self._producer.writeEpilogue(runner.stats);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(TAP, Base);
|
||||
|
||||
/**
|
||||
* Returns a TAP-safe title of `test`.
|
||||
*
|
||||
* @private
|
||||
* @param {Test} test - Test instance.
|
||||
* @return {String} title with any hash character removed
|
||||
*/
|
||||
function title(test) {
|
||||
return test.fullTitle().replace(/#/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes newline-terminated formatted string to reporter output stream.
|
||||
*
|
||||
* @private
|
||||
* @param {string} format - `printf`-like format string
|
||||
* @param {...*} [varArgs] - Format string arguments
|
||||
*/
|
||||
function println(format, varArgs) {
|
||||
var vargs = Array.from(arguments);
|
||||
vargs[0] += '\n';
|
||||
process.stdout.write(sprintf.apply(null, vargs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a `tapVersion`-appropriate TAP producer instance, if possible.
|
||||
*
|
||||
* @private
|
||||
* @param {string} tapVersion - Version of TAP specification to produce.
|
||||
* @returns {TAPProducer} specification-appropriate instance
|
||||
* @throws {Error} if specification version has no associated producer.
|
||||
*/
|
||||
function createProducer(tapVersion) {
|
||||
var producers = {
|
||||
12: new TAP12Producer(),
|
||||
13: new TAP13Producer()
|
||||
};
|
||||
var producer = producers[tapVersion];
|
||||
|
||||
if (!producer) {
|
||||
throw new Error(
|
||||
'invalid or unsupported TAP version: ' + JSON.stringify(tapVersion)
|
||||
);
|
||||
}
|
||||
|
||||
return producer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary
|
||||
* Constructs a new TAPProducer.
|
||||
*
|
||||
* @description
|
||||
* <em>Only</em> to be used as an abstract base class.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
*/
|
||||
function TAPProducer() {}
|
||||
|
||||
/**
|
||||
* Writes the TAP version to reporter output stream.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
TAPProducer.prototype.writeVersion = function () {};
|
||||
|
||||
/**
|
||||
* Writes the plan to reporter output stream.
|
||||
*
|
||||
* @abstract
|
||||
* @param {number} ntests - Number of tests that are planned to run.
|
||||
*/
|
||||
TAPProducer.prototype.writePlan = function (ntests) {
|
||||
println('%d..%d', 1, ntests);
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes that test passed to reporter output stream.
|
||||
*
|
||||
* @abstract
|
||||
* @param {number} n - Index of test that passed.
|
||||
* @param {Test} test - Instance containing test information.
|
||||
*/
|
||||
TAPProducer.prototype.writePass = function (n, test) {
|
||||
println('ok %d %s', n, title(test));
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes that test was skipped to reporter output stream.
|
||||
*
|
||||
* @abstract
|
||||
* @param {number} n - Index of test that was skipped.
|
||||
* @param {Test} test - Instance containing test information.
|
||||
*/
|
||||
TAPProducer.prototype.writePending = function (n, test) {
|
||||
println('ok %d %s # SKIP -', n, title(test));
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes that test failed to reporter output stream.
|
||||
*
|
||||
* @abstract
|
||||
* @param {number} n - Index of test that failed.
|
||||
* @param {Test} test - Instance containing test information.
|
||||
* @param {Error} err - Reason the test failed.
|
||||
*/
|
||||
TAPProducer.prototype.writeFail = function (n, test, err) {
|
||||
println('not ok %d %s', n, title(test));
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes the summary epilogue to reporter output stream.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Object} stats - Object containing run statistics.
|
||||
*/
|
||||
TAPProducer.prototype.writeEpilogue = function (stats) {
|
||||
// :TBD: Why is this not counting pending tests?
|
||||
println('# tests ' + (stats.passes + stats.failures));
|
||||
println('# pass ' + stats.passes);
|
||||
// :TBD: Why are we not showing pending results?
|
||||
println('# fail ' + stats.failures);
|
||||
this.writePlan(stats.passes + stats.failures + stats.pending);
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary
|
||||
* Constructs a new TAP12Producer.
|
||||
*
|
||||
* @description
|
||||
* Produces output conforming to the TAP12 specification.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @extends TAPProducer
|
||||
* @see {@link https://testanything.org/tap-specification.html|Specification}
|
||||
*/
|
||||
function TAP12Producer() {
|
||||
/**
|
||||
* Writes that test failed to reporter output stream, with error formatting.
|
||||
* @override
|
||||
*/
|
||||
this.writeFail = function (n, test, err) {
|
||||
TAPProducer.prototype.writeFail.call(this, n, test, err);
|
||||
if (err.message) {
|
||||
println(err.message.replace(/^/gm, ' '));
|
||||
}
|
||||
if (err.stack) {
|
||||
println(err.stack.replace(/^/gm, ' '));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `TAPProducer.prototype`.
|
||||
*/
|
||||
inherits(TAP12Producer, TAPProducer);
|
||||
|
||||
/**
|
||||
* @summary
|
||||
* Constructs a new TAP13Producer.
|
||||
*
|
||||
* @description
|
||||
* Produces output conforming to the TAP13 specification.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @extends TAPProducer
|
||||
* @see {@link https://testanything.org/tap-version-13-specification.html|Specification}
|
||||
*/
|
||||
function TAP13Producer() {
|
||||
/**
|
||||
* Writes the TAP version to reporter output stream.
|
||||
* @override
|
||||
*/
|
||||
this.writeVersion = function () {
|
||||
println('TAP version 13');
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes that test failed to reporter output stream, with error formatting.
|
||||
* @override
|
||||
*/
|
||||
this.writeFail = function (n, test, err) {
|
||||
TAPProducer.prototype.writeFail.call(this, n, test, err);
|
||||
var emitYamlBlock = err.message != null || err.stack != null;
|
||||
if (emitYamlBlock) {
|
||||
println(indent(1) + '---');
|
||||
if (err.message) {
|
||||
println(indent(2) + 'message: |-');
|
||||
println(err.message.replace(/^/gm, indent(3)));
|
||||
}
|
||||
if (err.stack) {
|
||||
println(indent(2) + 'stack: |-');
|
||||
println(err.stack.replace(/^/gm, indent(3)));
|
||||
}
|
||||
println(indent(1) + '...');
|
||||
}
|
||||
};
|
||||
|
||||
function indent(level) {
|
||||
return Array(level + 1).join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `TAPProducer.prototype`.
|
||||
*/
|
||||
inherits(TAP13Producer, TAPProducer);
|
||||
|
||||
TAP.description = 'TAP-compatible output';
|
||||
217
node_modules/mocha/lib/reporters/xunit.js
generated
vendored
Normal file
217
node_modules/mocha/lib/reporters/xunit.js
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @module XUnit
|
||||
*/
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('./base');
|
||||
var utils = require('../utils');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var errors = require('../errors');
|
||||
var createUnsupportedError = errors.createUnsupportedError;
|
||||
var constants = require('../runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var STATE_FAILED = require('../runnable').constants.STATE_FAILED;
|
||||
var inherits = utils.inherits;
|
||||
var escape = utils.escape;
|
||||
|
||||
/**
|
||||
* Save timer references to avoid Sinon interfering (see GH-237).
|
||||
*/
|
||||
var Date = global.Date;
|
||||
|
||||
/**
|
||||
* Expose `XUnit`.
|
||||
*/
|
||||
|
||||
exports = module.exports = XUnit;
|
||||
|
||||
/**
|
||||
* Constructs a new `XUnit` reporter instance.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @memberof Mocha.reporters
|
||||
* @extends Mocha.reporters.Base
|
||||
* @param {Runner} runner - Instance triggers reporter actions.
|
||||
* @param {Object} [options] - runner options
|
||||
*/
|
||||
function XUnit(runner, options) {
|
||||
Base.call(this, runner, options);
|
||||
|
||||
var stats = this.stats;
|
||||
var tests = [];
|
||||
var self = this;
|
||||
|
||||
// the name of the test suite, as it will appear in the resulting XML file
|
||||
var suiteName;
|
||||
|
||||
// the default name of the test suite if none is provided
|
||||
var DEFAULT_SUITE_NAME = 'Mocha Tests';
|
||||
|
||||
if (options && options.reporterOptions) {
|
||||
if (options.reporterOptions.output) {
|
||||
if (!fs.createWriteStream) {
|
||||
throw createUnsupportedError('file output not supported in browser');
|
||||
}
|
||||
|
||||
fs.mkdirSync(path.dirname(options.reporterOptions.output), {
|
||||
recursive: true
|
||||
});
|
||||
self.fileStream = fs.createWriteStream(options.reporterOptions.output);
|
||||
}
|
||||
|
||||
// get the suite name from the reporter options (if provided)
|
||||
suiteName = options.reporterOptions.suiteName;
|
||||
}
|
||||
|
||||
// fall back to the default suite name
|
||||
suiteName = suiteName || DEFAULT_SUITE_NAME;
|
||||
|
||||
runner.on(EVENT_TEST_PENDING, function (test) {
|
||||
tests.push(test);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_PASS, function (test) {
|
||||
tests.push(test);
|
||||
});
|
||||
|
||||
runner.on(EVENT_TEST_FAIL, function (test) {
|
||||
tests.push(test);
|
||||
});
|
||||
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
self.write(
|
||||
tag(
|
||||
'testsuite',
|
||||
{
|
||||
name: suiteName,
|
||||
tests: stats.tests,
|
||||
failures: 0,
|
||||
errors: stats.failures,
|
||||
skipped: stats.tests - stats.failures - stats.passes,
|
||||
timestamp: new Date().toUTCString(),
|
||||
time: stats.duration / 1000 || 0
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
tests.forEach(function (t) {
|
||||
self.test(t);
|
||||
});
|
||||
|
||||
self.write('</testsuite>');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
inherits(XUnit, Base);
|
||||
|
||||
/**
|
||||
* Override done to close the stream (if it's a file).
|
||||
*
|
||||
* @param failures
|
||||
* @param {Function} fn
|
||||
*/
|
||||
XUnit.prototype.done = function (failures, fn) {
|
||||
if (this.fileStream) {
|
||||
this.fileStream.end(function () {
|
||||
fn(failures);
|
||||
});
|
||||
} else {
|
||||
fn(failures);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Write out the given line.
|
||||
*
|
||||
* @param {string} line
|
||||
*/
|
||||
XUnit.prototype.write = function (line) {
|
||||
if (this.fileStream) {
|
||||
this.fileStream.write(line + '\n');
|
||||
} else if (typeof process === 'object' && process.stdout) {
|
||||
process.stdout.write(line + '\n');
|
||||
} else {
|
||||
Base.consoleLog(line);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Output tag for the given `test.`
|
||||
*
|
||||
* @param {Test} test
|
||||
*/
|
||||
XUnit.prototype.test = function (test) {
|
||||
Base.useColors = false;
|
||||
|
||||
var attrs = {
|
||||
classname: test.parent.fullTitle(),
|
||||
name: test.title,
|
||||
time: test.duration / 1000 || 0
|
||||
};
|
||||
|
||||
if (test.state === STATE_FAILED) {
|
||||
var err = test.err;
|
||||
var diff =
|
||||
!Base.hideDiff && Base.showDiff(err)
|
||||
? '\n' + Base.generateDiff(err.actual, err.expected)
|
||||
: '';
|
||||
this.write(
|
||||
tag(
|
||||
'testcase',
|
||||
attrs,
|
||||
false,
|
||||
tag(
|
||||
'failure',
|
||||
{},
|
||||
false,
|
||||
escape(err.message) + escape(diff) + '\n' + escape(err.stack)
|
||||
)
|
||||
)
|
||||
);
|
||||
} else if (test.isPending()) {
|
||||
this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
|
||||
} else {
|
||||
this.write(tag('testcase', attrs, true));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HTML tag helper.
|
||||
*
|
||||
* @param name
|
||||
* @param attrs
|
||||
* @param close
|
||||
* @param content
|
||||
* @return {string}
|
||||
*/
|
||||
function tag(name, attrs, close, content) {
|
||||
var end = close ? '/>' : '>';
|
||||
var pairs = [];
|
||||
var tag;
|
||||
|
||||
for (var key in attrs) {
|
||||
if (Object.prototype.hasOwnProperty.call(attrs, key)) {
|
||||
pairs.push(key + '="' + escape(attrs[key]) + '"');
|
||||
}
|
||||
}
|
||||
|
||||
tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
|
||||
if (content) {
|
||||
tag += content + '</' + name + end;
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
XUnit.description = 'XUnit-compatible XML output';
|
||||
476
node_modules/mocha/lib/runnable.js
generated
vendored
Normal file
476
node_modules/mocha/lib/runnable.js
generated
vendored
Normal file
@@ -0,0 +1,476 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Pending = require('./pending');
|
||||
var debug = require('debug')('mocha:runnable');
|
||||
var milliseconds = require('ms');
|
||||
var utils = require('./utils');
|
||||
const {
|
||||
createInvalidExceptionError,
|
||||
createMultipleDoneError,
|
||||
createTimeoutError
|
||||
} = require('./errors');
|
||||
|
||||
/**
|
||||
* Save timer references to avoid Sinon interfering (see GH-237).
|
||||
* @private
|
||||
*/
|
||||
var Date = global.Date;
|
||||
var setTimeout = global.setTimeout;
|
||||
var clearTimeout = global.clearTimeout;
|
||||
var toString = Object.prototype.toString;
|
||||
|
||||
module.exports = Runnable;
|
||||
|
||||
/**
|
||||
* Initialize a new `Runnable` with the given `title` and callback `fn`.
|
||||
*
|
||||
* @class
|
||||
* @extends external:EventEmitter
|
||||
* @public
|
||||
* @param {String} title
|
||||
* @param {Function} fn
|
||||
*/
|
||||
function Runnable(title, fn) {
|
||||
this.title = title;
|
||||
this.fn = fn;
|
||||
this.body = (fn || '').toString();
|
||||
this.async = fn && fn.length;
|
||||
this.sync = !this.async;
|
||||
this._timeout = 2000;
|
||||
this._slow = 75;
|
||||
this._retries = -1;
|
||||
utils.assignNewMochaID(this);
|
||||
Object.defineProperty(this, 'id', {
|
||||
get() {
|
||||
return utils.getMochaID(this);
|
||||
}
|
||||
});
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `EventEmitter.prototype`.
|
||||
*/
|
||||
utils.inherits(Runnable, EventEmitter);
|
||||
|
||||
/**
|
||||
* Resets the state initially or for a next run.
|
||||
*/
|
||||
Runnable.prototype.reset = function () {
|
||||
this.timedOut = false;
|
||||
this._currentRetry = 0;
|
||||
this.pending = false;
|
||||
delete this.state;
|
||||
delete this.err;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get current timeout value in msecs.
|
||||
*
|
||||
* @private
|
||||
* @returns {number} current timeout threshold value
|
||||
*/
|
||||
/**
|
||||
* @summary
|
||||
* Set timeout threshold value (msecs).
|
||||
*
|
||||
* @description
|
||||
* A string argument can use shorthand (e.g., "2s") and will be converted.
|
||||
* The value will be clamped to range [<code>0</code>, <code>2^<sup>31</sup>-1</code>].
|
||||
* If clamped value matches either range endpoint, timeouts will be disabled.
|
||||
*
|
||||
* @private
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Maximum_delay_value}
|
||||
* @param {number|string} ms - Timeout threshold value.
|
||||
* @returns {Runnable} this
|
||||
* @chainable
|
||||
*/
|
||||
Runnable.prototype.timeout = function (ms) {
|
||||
if (!arguments.length) {
|
||||
return this._timeout;
|
||||
}
|
||||
if (typeof ms === 'string') {
|
||||
ms = milliseconds(ms);
|
||||
}
|
||||
|
||||
// Clamp to range
|
||||
var INT_MAX = Math.pow(2, 31) - 1;
|
||||
var range = [0, INT_MAX];
|
||||
ms = utils.clamp(ms, range);
|
||||
|
||||
// see #1652 for reasoning
|
||||
if (ms === range[0] || ms === range[1]) {
|
||||
this._timeout = 0;
|
||||
} else {
|
||||
this._timeout = ms;
|
||||
}
|
||||
debug('timeout %d', this._timeout);
|
||||
|
||||
if (this.timer) {
|
||||
this.resetTimeout();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get slow `ms`.
|
||||
*
|
||||
* @private
|
||||
* @param {number|string} ms
|
||||
* @return {Runnable|number} ms or Runnable instance.
|
||||
*/
|
||||
Runnable.prototype.slow = function (ms) {
|
||||
if (!arguments.length || typeof ms === 'undefined') {
|
||||
return this._slow;
|
||||
}
|
||||
if (typeof ms === 'string') {
|
||||
ms = milliseconds(ms);
|
||||
}
|
||||
debug('slow %d', ms);
|
||||
this._slow = ms;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Halt and mark as pending.
|
||||
*
|
||||
* @memberof Mocha.Runnable
|
||||
* @public
|
||||
*/
|
||||
Runnable.prototype.skip = function () {
|
||||
this.pending = true;
|
||||
throw new Pending('sync skip; aborting execution');
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this runnable or its parent suite is marked as pending.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.isPending = function () {
|
||||
return this.pending || (this.parent && this.parent.isPending());
|
||||
};
|
||||
|
||||
/**
|
||||
* Return `true` if this Runnable has failed.
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.isFailed = function () {
|
||||
return !this.isPending() && this.state === constants.STATE_FAILED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return `true` if this Runnable has passed.
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.isPassed = function () {
|
||||
return !this.isPending() && this.state === constants.STATE_PASSED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get number of retries.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.retries = function (n) {
|
||||
if (!arguments.length) {
|
||||
return this._retries;
|
||||
}
|
||||
this._retries = n;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get current retry
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.currentRetry = function (n) {
|
||||
if (!arguments.length) {
|
||||
return this._currentRetry;
|
||||
}
|
||||
this._currentRetry = n;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the full title generated by recursively concatenating the parent's
|
||||
* full title.
|
||||
*
|
||||
* @memberof Mocha.Runnable
|
||||
* @public
|
||||
* @return {string}
|
||||
*/
|
||||
Runnable.prototype.fullTitle = function () {
|
||||
return this.titlePath().join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the title path generated by concatenating the parent's title path with the title.
|
||||
*
|
||||
* @memberof Mocha.Runnable
|
||||
* @public
|
||||
* @return {string}
|
||||
*/
|
||||
Runnable.prototype.titlePath = function () {
|
||||
return this.parent.titlePath().concat([this.title]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the timeout.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.clearTimeout = function () {
|
||||
clearTimeout(this.timer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the timeout.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.resetTimeout = function () {
|
||||
var self = this;
|
||||
var ms = this.timeout();
|
||||
|
||||
if (ms === 0) {
|
||||
return;
|
||||
}
|
||||
this.clearTimeout();
|
||||
this.timer = setTimeout(function () {
|
||||
if (self.timeout() === 0) {
|
||||
return;
|
||||
}
|
||||
self.callback(self._timeoutError(ms));
|
||||
self.timedOut = true;
|
||||
}, ms);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get a list of whitelisted globals for this test run.
|
||||
*
|
||||
* @private
|
||||
* @param {string[]} globals
|
||||
*/
|
||||
Runnable.prototype.globals = function (globals) {
|
||||
if (!arguments.length) {
|
||||
return this._allowedGlobals;
|
||||
}
|
||||
this._allowedGlobals = globals;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run the test and invoke `fn(err)`.
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype.run = function (fn) {
|
||||
var self = this;
|
||||
var start = new Date();
|
||||
var ctx = this.ctx;
|
||||
var finished;
|
||||
var errorWasHandled = false;
|
||||
|
||||
if (this.isPending()) return fn();
|
||||
|
||||
// Sometimes the ctx exists, but it is not runnable
|
||||
if (ctx && ctx.runnable) {
|
||||
ctx.runnable(this);
|
||||
}
|
||||
|
||||
// called multiple times
|
||||
function multiple(err) {
|
||||
if (errorWasHandled) {
|
||||
return;
|
||||
}
|
||||
errorWasHandled = true;
|
||||
self.emit('error', createMultipleDoneError(self, err));
|
||||
}
|
||||
|
||||
// finished
|
||||
function done(err) {
|
||||
var ms = self.timeout();
|
||||
if (self.timedOut) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (finished) {
|
||||
return multiple(err);
|
||||
}
|
||||
|
||||
self.clearTimeout();
|
||||
self.duration = new Date() - start;
|
||||
finished = true;
|
||||
if (!err && self.duration > ms && ms > 0) {
|
||||
err = self._timeoutError(ms);
|
||||
}
|
||||
fn(err);
|
||||
}
|
||||
|
||||
// for .resetTimeout() and Runner#uncaught()
|
||||
this.callback = done;
|
||||
|
||||
if (this.fn && typeof this.fn.call !== 'function') {
|
||||
done(
|
||||
new TypeError(
|
||||
'A runnable must be passed a function as its second argument.'
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// explicit async with `done` argument
|
||||
if (this.async) {
|
||||
this.resetTimeout();
|
||||
|
||||
// allows skip() to be used in an explicit async context
|
||||
this.skip = function asyncSkip() {
|
||||
this.pending = true;
|
||||
done();
|
||||
// halt execution, the uncaught handler will ignore the failure.
|
||||
throw new Pending('async skip; aborting execution');
|
||||
};
|
||||
|
||||
try {
|
||||
callFnAsync(this.fn);
|
||||
} catch (err) {
|
||||
// handles async runnables which actually run synchronously
|
||||
errorWasHandled = true;
|
||||
if (err instanceof Pending) {
|
||||
return; // done() is already called in this.skip()
|
||||
} else if (this.allowUncaught) {
|
||||
throw err;
|
||||
}
|
||||
done(Runnable.toValueOrError(err));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// sync or promise-returning
|
||||
try {
|
||||
callFn(this.fn);
|
||||
} catch (err) {
|
||||
errorWasHandled = true;
|
||||
if (err instanceof Pending) {
|
||||
return done();
|
||||
} else if (this.allowUncaught) {
|
||||
throw err;
|
||||
}
|
||||
done(Runnable.toValueOrError(err));
|
||||
}
|
||||
|
||||
function callFn(fn) {
|
||||
var result = fn.call(ctx);
|
||||
if (result && typeof result.then === 'function') {
|
||||
self.resetTimeout();
|
||||
result.then(
|
||||
function () {
|
||||
done();
|
||||
// Return null so libraries like bluebird do not warn about
|
||||
// subsequently constructed Promises.
|
||||
return null;
|
||||
},
|
||||
function (reason) {
|
||||
done(reason || new Error('Promise rejected with no or falsy reason'));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
if (self.asyncOnly) {
|
||||
return done(
|
||||
new Error(
|
||||
'--async-only option in use without declaring `done()` or returning a promise'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
function callFnAsync(fn) {
|
||||
var result = fn.call(ctx, function (err) {
|
||||
if (err instanceof Error || toString.call(err) === '[object Error]') {
|
||||
return done(err);
|
||||
}
|
||||
if (err) {
|
||||
if (Object.prototype.toString.call(err) === '[object Object]') {
|
||||
return done(
|
||||
new Error('done() invoked with non-Error: ' + JSON.stringify(err))
|
||||
);
|
||||
}
|
||||
return done(new Error('done() invoked with non-Error: ' + err));
|
||||
}
|
||||
if (result && utils.isPromise(result)) {
|
||||
return done(
|
||||
new Error(
|
||||
'Resolution method is overspecified. Specify a callback *or* return a Promise; not both.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a "timeout" error
|
||||
*
|
||||
* @param {number} ms - Timeout (in milliseconds)
|
||||
* @returns {Error} a "timeout" error
|
||||
* @private
|
||||
*/
|
||||
Runnable.prototype._timeoutError = function (ms) {
|
||||
let msg = `Timeout of ${ms}ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.`;
|
||||
if (this.file) {
|
||||
msg += ' (' + this.file + ')';
|
||||
}
|
||||
return createTimeoutError(msg, ms, this.file);
|
||||
};
|
||||
|
||||
var constants = utils.defineConstants(
|
||||
/**
|
||||
* {@link Runnable}-related constants.
|
||||
* @public
|
||||
* @memberof Runnable
|
||||
* @readonly
|
||||
* @static
|
||||
* @alias constants
|
||||
* @enum {string}
|
||||
*/
|
||||
{
|
||||
/**
|
||||
* Value of `state` prop when a `Runnable` has failed
|
||||
*/
|
||||
STATE_FAILED: 'failed',
|
||||
/**
|
||||
* Value of `state` prop when a `Runnable` has passed
|
||||
*/
|
||||
STATE_PASSED: 'passed',
|
||||
/**
|
||||
* Value of `state` prop when a `Runnable` has been skipped by user
|
||||
*/
|
||||
STATE_PENDING: 'pending'
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Given `value`, return identity if truthy, otherwise create an "invalid exception" error and return that.
|
||||
* @param {*} [value] - Value to return, if present
|
||||
* @returns {*|Error} `value`, otherwise an `Error`
|
||||
* @private
|
||||
*/
|
||||
Runnable.toValueOrError = function (value) {
|
||||
return (
|
||||
value ||
|
||||
createInvalidExceptionError(
|
||||
'Runnable failed with falsy or undefined exception. Please throw an Error instead.',
|
||||
value
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
Runnable.constants = constants;
|
||||
1256
node_modules/mocha/lib/runner.js
generated
vendored
Normal file
1256
node_modules/mocha/lib/runner.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
83
node_modules/mocha/lib/stats-collector.js
generated
vendored
Normal file
83
node_modules/mocha/lib/stats-collector.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Provides a factory function for a {@link StatsCollector} object.
|
||||
* @module
|
||||
*/
|
||||
|
||||
var constants = require('./runner').constants;
|
||||
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
||||
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
||||
var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
|
||||
var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
|
||||
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
||||
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
||||
var EVENT_TEST_END = constants.EVENT_TEST_END;
|
||||
|
||||
/**
|
||||
* Test statistics collector.
|
||||
*
|
||||
* @public
|
||||
* @typedef {Object} StatsCollector
|
||||
* @property {number} suites - integer count of suites run.
|
||||
* @property {number} tests - integer count of tests run.
|
||||
* @property {number} passes - integer count of passing tests.
|
||||
* @property {number} pending - integer count of pending tests.
|
||||
* @property {number} failures - integer count of failed tests.
|
||||
* @property {Date} start - time when testing began.
|
||||
* @property {Date} end - time when testing concluded.
|
||||
* @property {number} duration - number of msecs that testing took.
|
||||
*/
|
||||
|
||||
var Date = global.Date;
|
||||
|
||||
/**
|
||||
* Provides stats such as test duration, number of tests passed / failed etc., by listening for events emitted by `runner`.
|
||||
*
|
||||
* @private
|
||||
* @param {Runner} runner - Runner instance
|
||||
* @throws {TypeError} If falsy `runner`
|
||||
*/
|
||||
function createStatsCollector(runner) {
|
||||
/**
|
||||
* @type StatsCollector
|
||||
*/
|
||||
var stats = {
|
||||
suites: 0,
|
||||
tests: 0,
|
||||
passes: 0,
|
||||
pending: 0,
|
||||
failures: 0
|
||||
};
|
||||
|
||||
if (!runner) {
|
||||
throw new TypeError('Missing runner argument');
|
||||
}
|
||||
|
||||
runner.stats = stats;
|
||||
|
||||
runner.once(EVENT_RUN_BEGIN, function () {
|
||||
stats.start = new Date();
|
||||
});
|
||||
runner.on(EVENT_SUITE_BEGIN, function (suite) {
|
||||
suite.root || stats.suites++;
|
||||
});
|
||||
runner.on(EVENT_TEST_PASS, function () {
|
||||
stats.passes++;
|
||||
});
|
||||
runner.on(EVENT_TEST_FAIL, function () {
|
||||
stats.failures++;
|
||||
});
|
||||
runner.on(EVENT_TEST_PENDING, function () {
|
||||
stats.pending++;
|
||||
});
|
||||
runner.on(EVENT_TEST_END, function () {
|
||||
stats.tests++;
|
||||
});
|
||||
runner.once(EVENT_RUN_END, function () {
|
||||
stats.end = new Date();
|
||||
stats.duration = stats.end - stats.start;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = createStatsCollector;
|
||||
666
node_modules/mocha/lib/suite.js
generated
vendored
Normal file
666
node_modules/mocha/lib/suite.js
generated
vendored
Normal file
@@ -0,0 +1,666 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
const {EventEmitter} = require('events');
|
||||
const Hook = require('./hook');
|
||||
var {
|
||||
assignNewMochaID,
|
||||
clamp,
|
||||
constants: utilsConstants,
|
||||
defineConstants,
|
||||
getMochaID,
|
||||
inherits,
|
||||
isString
|
||||
} = require('./utils');
|
||||
const debug = require('debug')('mocha:suite');
|
||||
const milliseconds = require('ms');
|
||||
const errors = require('./errors');
|
||||
|
||||
const {MOCHA_ID_PROP_NAME} = utilsConstants;
|
||||
|
||||
/**
|
||||
* Expose `Suite`.
|
||||
*/
|
||||
|
||||
exports = module.exports = Suite;
|
||||
|
||||
/**
|
||||
* Create a new `Suite` with the given `title` and parent `Suite`.
|
||||
*
|
||||
* @public
|
||||
* @param {Suite} parent - Parent suite (required!)
|
||||
* @param {string} title - Title
|
||||
* @return {Suite}
|
||||
*/
|
||||
Suite.create = function (parent, title) {
|
||||
var suite = new Suite(title, parent.ctx);
|
||||
suite.parent = parent;
|
||||
title = suite.fullTitle();
|
||||
parent.addSuite(suite);
|
||||
return suite;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new `Suite` instance with the given `title`, `ctx`, and `isRoot`.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @extends EventEmitter
|
||||
* @see {@link https://nodejs.org/api/events.html#events_class_eventemitter|EventEmitter}
|
||||
* @param {string} title - Suite title.
|
||||
* @param {Context} parentContext - Parent context instance.
|
||||
* @param {boolean} [isRoot=false] - Whether this is the root suite.
|
||||
*/
|
||||
function Suite(title, parentContext, isRoot) {
|
||||
if (!isString(title)) {
|
||||
throw errors.createInvalidArgumentTypeError(
|
||||
'Suite argument "title" must be a string. Received type "' +
|
||||
typeof title +
|
||||
'"',
|
||||
'title',
|
||||
'string'
|
||||
);
|
||||
}
|
||||
this.title = title;
|
||||
function Context() {}
|
||||
Context.prototype = parentContext;
|
||||
this.ctx = new Context();
|
||||
this.suites = [];
|
||||
this.tests = [];
|
||||
this.root = isRoot === true;
|
||||
this.pending = false;
|
||||
this._retries = -1;
|
||||
this._beforeEach = [];
|
||||
this._beforeAll = [];
|
||||
this._afterEach = [];
|
||||
this._afterAll = [];
|
||||
this._timeout = 2000;
|
||||
this._slow = 75;
|
||||
this._bail = false;
|
||||
this._onlyTests = [];
|
||||
this._onlySuites = [];
|
||||
assignNewMochaID(this);
|
||||
|
||||
Object.defineProperty(this, 'id', {
|
||||
get() {
|
||||
return getMochaID(this);
|
||||
}
|
||||
});
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `EventEmitter.prototype`.
|
||||
*/
|
||||
inherits(Suite, EventEmitter);
|
||||
|
||||
/**
|
||||
* Resets the state initially or for a next run.
|
||||
*/
|
||||
Suite.prototype.reset = function () {
|
||||
this.delayed = false;
|
||||
function doReset(thingToReset) {
|
||||
thingToReset.reset();
|
||||
}
|
||||
this.suites.forEach(doReset);
|
||||
this.tests.forEach(doReset);
|
||||
this._beforeEach.forEach(doReset);
|
||||
this._afterEach.forEach(doReset);
|
||||
this._beforeAll.forEach(doReset);
|
||||
this._afterAll.forEach(doReset);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a clone of this `Suite`.
|
||||
*
|
||||
* @private
|
||||
* @return {Suite}
|
||||
*/
|
||||
Suite.prototype.clone = function () {
|
||||
var suite = new Suite(this.title);
|
||||
debug('clone');
|
||||
suite.ctx = this.ctx;
|
||||
suite.root = this.root;
|
||||
suite.timeout(this.timeout());
|
||||
suite.retries(this.retries());
|
||||
suite.slow(this.slow());
|
||||
suite.bail(this.bail());
|
||||
return suite;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get timeout `ms` or short-hand such as "2s".
|
||||
*
|
||||
* @private
|
||||
* @todo Do not attempt to set value if `ms` is undefined
|
||||
* @param {number|string} ms
|
||||
* @return {Suite|number} for chaining
|
||||
*/
|
||||
Suite.prototype.timeout = function (ms) {
|
||||
if (!arguments.length) {
|
||||
return this._timeout;
|
||||
}
|
||||
if (typeof ms === 'string') {
|
||||
ms = milliseconds(ms);
|
||||
}
|
||||
|
||||
// Clamp to range
|
||||
var INT_MAX = Math.pow(2, 31) - 1;
|
||||
var range = [0, INT_MAX];
|
||||
ms = clamp(ms, range);
|
||||
|
||||
debug('timeout %d', ms);
|
||||
this._timeout = parseInt(ms, 10);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get number of times to retry a failed test.
|
||||
*
|
||||
* @private
|
||||
* @param {number|string} n
|
||||
* @return {Suite|number} for chaining
|
||||
*/
|
||||
Suite.prototype.retries = function (n) {
|
||||
if (!arguments.length) {
|
||||
return this._retries;
|
||||
}
|
||||
debug('retries %d', n);
|
||||
this._retries = parseInt(n, 10) || 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get slow `ms` or short-hand such as "2s".
|
||||
*
|
||||
* @private
|
||||
* @param {number|string} ms
|
||||
* @return {Suite|number} for chaining
|
||||
*/
|
||||
Suite.prototype.slow = function (ms) {
|
||||
if (!arguments.length) {
|
||||
return this._slow;
|
||||
}
|
||||
if (typeof ms === 'string') {
|
||||
ms = milliseconds(ms);
|
||||
}
|
||||
debug('slow %d', ms);
|
||||
this._slow = ms;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get whether to bail after first error.
|
||||
*
|
||||
* @private
|
||||
* @param {boolean} bail
|
||||
* @return {Suite|number} for chaining
|
||||
*/
|
||||
Suite.prototype.bail = function (bail) {
|
||||
if (!arguments.length) {
|
||||
return this._bail;
|
||||
}
|
||||
debug('bail %s', bail);
|
||||
this._bail = bail;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this suite or its parent suite is marked as pending.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Suite.prototype.isPending = function () {
|
||||
return this.pending || (this.parent && this.parent.isPending());
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic hook-creator.
|
||||
* @private
|
||||
* @param {string} title - Title of hook
|
||||
* @param {Function} fn - Hook callback
|
||||
* @returns {Hook} A new hook
|
||||
*/
|
||||
Suite.prototype._createHook = function (title, fn) {
|
||||
var hook = new Hook(title, fn);
|
||||
hook.parent = this;
|
||||
hook.timeout(this.timeout());
|
||||
hook.retries(this.retries());
|
||||
hook.slow(this.slow());
|
||||
hook.ctx = this.ctx;
|
||||
hook.file = this.file;
|
||||
return hook;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run `fn(test[, done])` before running tests.
|
||||
*
|
||||
* @private
|
||||
* @param {string} title
|
||||
* @param {Function} fn
|
||||
* @return {Suite} for chaining
|
||||
*/
|
||||
Suite.prototype.beforeAll = function (title, fn) {
|
||||
if (this.isPending()) {
|
||||
return this;
|
||||
}
|
||||
if (typeof title === 'function') {
|
||||
fn = title;
|
||||
title = fn.name;
|
||||
}
|
||||
title = '"before all" hook' + (title ? ': ' + title : '');
|
||||
|
||||
var hook = this._createHook(title, fn);
|
||||
this._beforeAll.push(hook);
|
||||
this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_ALL, hook);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run `fn(test[, done])` after running tests.
|
||||
*
|
||||
* @private
|
||||
* @param {string} title
|
||||
* @param {Function} fn
|
||||
* @return {Suite} for chaining
|
||||
*/
|
||||
Suite.prototype.afterAll = function (title, fn) {
|
||||
if (this.isPending()) {
|
||||
return this;
|
||||
}
|
||||
if (typeof title === 'function') {
|
||||
fn = title;
|
||||
title = fn.name;
|
||||
}
|
||||
title = '"after all" hook' + (title ? ': ' + title : '');
|
||||
|
||||
var hook = this._createHook(title, fn);
|
||||
this._afterAll.push(hook);
|
||||
this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_ALL, hook);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run `fn(test[, done])` before each test case.
|
||||
*
|
||||
* @private
|
||||
* @param {string} title
|
||||
* @param {Function} fn
|
||||
* @return {Suite} for chaining
|
||||
*/
|
||||
Suite.prototype.beforeEach = function (title, fn) {
|
||||
if (this.isPending()) {
|
||||
return this;
|
||||
}
|
||||
if (typeof title === 'function') {
|
||||
fn = title;
|
||||
title = fn.name;
|
||||
}
|
||||
title = '"before each" hook' + (title ? ': ' + title : '');
|
||||
|
||||
var hook = this._createHook(title, fn);
|
||||
this._beforeEach.push(hook);
|
||||
this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_EACH, hook);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run `fn(test[, done])` after each test case.
|
||||
*
|
||||
* @private
|
||||
* @param {string} title
|
||||
* @param {Function} fn
|
||||
* @return {Suite} for chaining
|
||||
*/
|
||||
Suite.prototype.afterEach = function (title, fn) {
|
||||
if (this.isPending()) {
|
||||
return this;
|
||||
}
|
||||
if (typeof title === 'function') {
|
||||
fn = title;
|
||||
title = fn.name;
|
||||
}
|
||||
title = '"after each" hook' + (title ? ': ' + title : '');
|
||||
|
||||
var hook = this._createHook(title, fn);
|
||||
this._afterEach.push(hook);
|
||||
this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_EACH, hook);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a test `suite`.
|
||||
*
|
||||
* @private
|
||||
* @param {Suite} suite
|
||||
* @return {Suite} for chaining
|
||||
*/
|
||||
Suite.prototype.addSuite = function (suite) {
|
||||
suite.parent = this;
|
||||
suite.root = false;
|
||||
suite.timeout(this.timeout());
|
||||
suite.retries(this.retries());
|
||||
suite.slow(this.slow());
|
||||
suite.bail(this.bail());
|
||||
this.suites.push(suite);
|
||||
this.emit(constants.EVENT_SUITE_ADD_SUITE, suite);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a `test` to this suite.
|
||||
*
|
||||
* @private
|
||||
* @param {Test} test
|
||||
* @return {Suite} for chaining
|
||||
*/
|
||||
Suite.prototype.addTest = function (test) {
|
||||
test.parent = this;
|
||||
test.timeout(this.timeout());
|
||||
test.retries(this.retries());
|
||||
test.slow(this.slow());
|
||||
test.ctx = this.ctx;
|
||||
this.tests.push(test);
|
||||
this.emit(constants.EVENT_SUITE_ADD_TEST, test);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the full title generated by recursively concatenating the parent's
|
||||
* full title.
|
||||
*
|
||||
* @memberof Suite
|
||||
* @public
|
||||
* @return {string}
|
||||
*/
|
||||
Suite.prototype.fullTitle = function () {
|
||||
return this.titlePath().join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the title path generated by recursively concatenating the parent's
|
||||
* title path.
|
||||
*
|
||||
* @memberof Suite
|
||||
* @public
|
||||
* @return {string}
|
||||
*/
|
||||
Suite.prototype.titlePath = function () {
|
||||
var result = [];
|
||||
if (this.parent) {
|
||||
result = result.concat(this.parent.titlePath());
|
||||
}
|
||||
if (!this.root) {
|
||||
result.push(this.title);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the total number of tests.
|
||||
*
|
||||
* @memberof Suite
|
||||
* @public
|
||||
* @return {number}
|
||||
*/
|
||||
Suite.prototype.total = function () {
|
||||
return (
|
||||
this.suites.reduce(function (sum, suite) {
|
||||
return sum + suite.total();
|
||||
}, 0) + this.tests.length
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates through each suite recursively to find all tests. Applies a
|
||||
* function in the format `fn(test)`.
|
||||
*
|
||||
* @private
|
||||
* @param {Function} fn
|
||||
* @return {Suite}
|
||||
*/
|
||||
Suite.prototype.eachTest = function (fn) {
|
||||
this.tests.forEach(fn);
|
||||
this.suites.forEach(function (suite) {
|
||||
suite.eachTest(fn);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* This will run the root suite if we happen to be running in delayed mode.
|
||||
* @private
|
||||
*/
|
||||
Suite.prototype.run = function run() {
|
||||
if (this.root) {
|
||||
this.emit(constants.EVENT_ROOT_SUITE_RUN);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether a suite has an `only` test or suite as a descendant.
|
||||
*
|
||||
* @private
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Suite.prototype.hasOnly = function hasOnly() {
|
||||
return (
|
||||
this._onlyTests.length > 0 ||
|
||||
this._onlySuites.length > 0 ||
|
||||
this.suites.some(function (suite) {
|
||||
return suite.hasOnly();
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter suites based on `isOnly` logic.
|
||||
*
|
||||
* @private
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Suite.prototype.filterOnly = function filterOnly() {
|
||||
if (this._onlyTests.length) {
|
||||
// If the suite contains `only` tests, run those and ignore any nested suites.
|
||||
this.tests = this._onlyTests;
|
||||
this.suites = [];
|
||||
} else {
|
||||
// Otherwise, do not run any of the tests in this suite.
|
||||
this.tests = [];
|
||||
this._onlySuites.forEach(function (onlySuite) {
|
||||
// If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite.
|
||||
// Otherwise, all of the tests on this `only` suite should be run, so don't filter it.
|
||||
if (onlySuite.hasOnly()) {
|
||||
onlySuite.filterOnly();
|
||||
}
|
||||
});
|
||||
// Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants.
|
||||
var onlySuites = this._onlySuites;
|
||||
this.suites = this.suites.filter(function (childSuite) {
|
||||
return onlySuites.indexOf(childSuite) !== -1 || childSuite.filterOnly();
|
||||
});
|
||||
}
|
||||
// Keep the suite only if there is something to run
|
||||
return this.tests.length > 0 || this.suites.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a suite to the list of subsuites marked `only`.
|
||||
*
|
||||
* @private
|
||||
* @param {Suite} suite
|
||||
*/
|
||||
Suite.prototype.appendOnlySuite = function (suite) {
|
||||
this._onlySuites.push(suite);
|
||||
};
|
||||
|
||||
/**
|
||||
* Marks a suite to be `only`.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Suite.prototype.markOnly = function () {
|
||||
this.parent && this.parent.appendOnlySuite(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a test to the list of tests marked `only`.
|
||||
*
|
||||
* @private
|
||||
* @param {Test} test
|
||||
*/
|
||||
Suite.prototype.appendOnlyTest = function (test) {
|
||||
this._onlyTests.push(test);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the array of hooks by hook name; see `HOOK_TYPE_*` constants.
|
||||
* @private
|
||||
*/
|
||||
Suite.prototype.getHooks = function getHooks(name) {
|
||||
return this['_' + name];
|
||||
};
|
||||
|
||||
/**
|
||||
* cleans all references from this suite and all child suites.
|
||||
*/
|
||||
Suite.prototype.dispose = function () {
|
||||
this.suites.forEach(function (suite) {
|
||||
suite.dispose();
|
||||
});
|
||||
this.cleanReferences();
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleans up the references to all the deferred functions
|
||||
* (before/after/beforeEach/afterEach) and tests of a Suite.
|
||||
* These must be deleted otherwise a memory leak can happen,
|
||||
* as those functions may reference variables from closures,
|
||||
* thus those variables can never be garbage collected as long
|
||||
* as the deferred functions exist.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Suite.prototype.cleanReferences = function cleanReferences() {
|
||||
function cleanArrReferences(arr) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
delete arr[i].fn;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(this._beforeAll)) {
|
||||
cleanArrReferences(this._beforeAll);
|
||||
}
|
||||
|
||||
if (Array.isArray(this._beforeEach)) {
|
||||
cleanArrReferences(this._beforeEach);
|
||||
}
|
||||
|
||||
if (Array.isArray(this._afterAll)) {
|
||||
cleanArrReferences(this._afterAll);
|
||||
}
|
||||
|
||||
if (Array.isArray(this._afterEach)) {
|
||||
cleanArrReferences(this._afterEach);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.tests.length; i++) {
|
||||
delete this.tests[i].fn;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object suitable for IPC.
|
||||
* Functions are represented by keys beginning with `$$`.
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
Suite.prototype.serialize = function serialize() {
|
||||
return {
|
||||
_bail: this._bail,
|
||||
$$fullTitle: this.fullTitle(),
|
||||
$$isPending: Boolean(this.isPending()),
|
||||
root: this.root,
|
||||
title: this.title,
|
||||
[MOCHA_ID_PROP_NAME]: this.id,
|
||||
parent: this.parent ? {[MOCHA_ID_PROP_NAME]: this.parent.id} : null
|
||||
};
|
||||
};
|
||||
|
||||
var constants = defineConstants(
|
||||
/**
|
||||
* {@link Suite}-related constants.
|
||||
* @public
|
||||
* @memberof Suite
|
||||
* @alias constants
|
||||
* @readonly
|
||||
* @static
|
||||
* @enum {string}
|
||||
*/
|
||||
{
|
||||
/**
|
||||
* Event emitted after a test file has been loaded. Not emitted in browser.
|
||||
*/
|
||||
EVENT_FILE_POST_REQUIRE: 'post-require',
|
||||
/**
|
||||
* Event emitted before a test file has been loaded. In browser, this is emitted once an interface has been selected.
|
||||
*/
|
||||
EVENT_FILE_PRE_REQUIRE: 'pre-require',
|
||||
/**
|
||||
* Event emitted immediately after a test file has been loaded. Not emitted in browser.
|
||||
*/
|
||||
EVENT_FILE_REQUIRE: 'require',
|
||||
/**
|
||||
* Event emitted when `global.run()` is called (use with `delay` option).
|
||||
*/
|
||||
EVENT_ROOT_SUITE_RUN: 'run',
|
||||
|
||||
/**
|
||||
* Namespace for collection of a `Suite`'s "after all" hooks.
|
||||
*/
|
||||
HOOK_TYPE_AFTER_ALL: 'afterAll',
|
||||
/**
|
||||
* Namespace for collection of a `Suite`'s "after each" hooks.
|
||||
*/
|
||||
HOOK_TYPE_AFTER_EACH: 'afterEach',
|
||||
/**
|
||||
* Namespace for collection of a `Suite`'s "before all" hooks.
|
||||
*/
|
||||
HOOK_TYPE_BEFORE_ALL: 'beforeAll',
|
||||
/**
|
||||
* Namespace for collection of a `Suite`'s "before each" hooks.
|
||||
*/
|
||||
HOOK_TYPE_BEFORE_EACH: 'beforeEach',
|
||||
|
||||
/**
|
||||
* Emitted after a child `Suite` has been added to a `Suite`.
|
||||
*/
|
||||
EVENT_SUITE_ADD_SUITE: 'suite',
|
||||
/**
|
||||
* Emitted after an "after all" `Hook` has been added to a `Suite`.
|
||||
*/
|
||||
EVENT_SUITE_ADD_HOOK_AFTER_ALL: 'afterAll',
|
||||
/**
|
||||
* Emitted after an "after each" `Hook` has been added to a `Suite`.
|
||||
*/
|
||||
EVENT_SUITE_ADD_HOOK_AFTER_EACH: 'afterEach',
|
||||
/**
|
||||
* Emitted after an "before all" `Hook` has been added to a `Suite`.
|
||||
*/
|
||||
EVENT_SUITE_ADD_HOOK_BEFORE_ALL: 'beforeAll',
|
||||
/**
|
||||
* Emitted after an "before each" `Hook` has been added to a `Suite`.
|
||||
*/
|
||||
EVENT_SUITE_ADD_HOOK_BEFORE_EACH: 'beforeEach',
|
||||
/**
|
||||
* Emitted after a `Test` has been added to a `Suite`.
|
||||
*/
|
||||
EVENT_SUITE_ADD_TEST: 'test'
|
||||
}
|
||||
);
|
||||
|
||||
Suite.constants = constants;
|
||||
113
node_modules/mocha/lib/test.js
generated
vendored
Normal file
113
node_modules/mocha/lib/test.js
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
'use strict';
|
||||
var Runnable = require('./runnable');
|
||||
var utils = require('./utils');
|
||||
var errors = require('./errors');
|
||||
var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError;
|
||||
var isString = utils.isString;
|
||||
|
||||
const {MOCHA_ID_PROP_NAME} = utils.constants;
|
||||
|
||||
module.exports = Test;
|
||||
|
||||
/**
|
||||
* Initialize a new `Test` with the given `title` and callback `fn`.
|
||||
*
|
||||
* @public
|
||||
* @class
|
||||
* @extends Runnable
|
||||
* @param {String} title - Test title (required)
|
||||
* @param {Function} [fn] - Test callback. If omitted, the Test is considered "pending"
|
||||
*/
|
||||
function Test(title, fn) {
|
||||
if (!isString(title)) {
|
||||
throw createInvalidArgumentTypeError(
|
||||
'Test argument "title" should be a string. Received type "' +
|
||||
typeof title +
|
||||
'"',
|
||||
'title',
|
||||
'string'
|
||||
);
|
||||
}
|
||||
this.type = 'test';
|
||||
Runnable.call(this, title, fn);
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Runnable.prototype`.
|
||||
*/
|
||||
utils.inherits(Test, Runnable);
|
||||
|
||||
/**
|
||||
* Resets the state initially or for a next run.
|
||||
*/
|
||||
Test.prototype.reset = function () {
|
||||
Runnable.prototype.reset.call(this);
|
||||
this.pending = !this.fn;
|
||||
delete this.state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get retried test
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Test.prototype.retriedTest = function (n) {
|
||||
if (!arguments.length) {
|
||||
return this._retriedTest;
|
||||
}
|
||||
this._retriedTest = n;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add test to the list of tests marked `only`.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Test.prototype.markOnly = function () {
|
||||
this.parent.appendOnlyTest(this);
|
||||
};
|
||||
|
||||
Test.prototype.clone = function () {
|
||||
var test = new Test(this.title, this.fn);
|
||||
test.timeout(this.timeout());
|
||||
test.slow(this.slow());
|
||||
test.retries(this.retries());
|
||||
test.currentRetry(this.currentRetry());
|
||||
test.retriedTest(this.retriedTest() || this);
|
||||
test.globals(this.globals());
|
||||
test.parent = this.parent;
|
||||
test.file = this.file;
|
||||
test.ctx = this.ctx;
|
||||
return test;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an minimal object suitable for transmission over IPC.
|
||||
* Functions are represented by keys beginning with `$$`.
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
Test.prototype.serialize = function serialize() {
|
||||
return {
|
||||
$$currentRetry: this._currentRetry,
|
||||
$$fullTitle: this.fullTitle(),
|
||||
$$isPending: Boolean(this.pending),
|
||||
$$retriedTest: this._retriedTest || null,
|
||||
$$slow: this._slow,
|
||||
$$titlePath: this.titlePath(),
|
||||
body: this.body,
|
||||
duration: this.duration,
|
||||
err: this.err,
|
||||
parent: {
|
||||
$$fullTitle: this.parent.fullTitle(),
|
||||
[MOCHA_ID_PROP_NAME]: this.parent.id
|
||||
},
|
||||
speed: this.speed,
|
||||
state: this.state,
|
||||
title: this.title,
|
||||
type: this.type,
|
||||
file: this.file,
|
||||
[MOCHA_ID_PROP_NAME]: this.id
|
||||
};
|
||||
};
|
||||
640
node_modules/mocha/lib/utils.js
generated
vendored
Normal file
640
node_modules/mocha/lib/utils.js
generated
vendored
Normal file
@@ -0,0 +1,640 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Various utility functions used throughout Mocha's codebase.
|
||||
* @module utils
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
const {nanoid} = require('nanoid/non-secure');
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var he = require('he');
|
||||
|
||||
const MOCHA_ID_PROP_NAME = '__mocha_id__';
|
||||
|
||||
/**
|
||||
* Inherit the prototype methods from one constructor into another.
|
||||
*
|
||||
* @param {function} ctor - Constructor function which needs to inherit the
|
||||
* prototype.
|
||||
* @param {function} superCtor - Constructor function to inherit prototype from.
|
||||
* @throws {TypeError} if either constructor is null, or if super constructor
|
||||
* lacks a prototype.
|
||||
*/
|
||||
exports.inherits = util.inherits;
|
||||
|
||||
/**
|
||||
* Escape special characters in the given string of html.
|
||||
*
|
||||
* @private
|
||||
* @param {string} html
|
||||
* @return {string}
|
||||
*/
|
||||
exports.escape = function (html) {
|
||||
return he.encode(String(html), {useNamedReferences: false});
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if the given obj is type of string.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} obj
|
||||
* @return {boolean}
|
||||
*/
|
||||
exports.isString = function (obj) {
|
||||
return typeof obj === 'string';
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute a slug from the given `str`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
exports.slug = function (str) {
|
||||
return str
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/[^-\w]/g, '')
|
||||
.replace(/-{2,}/g, '-');
|
||||
};
|
||||
|
||||
/**
|
||||
* Strip the function definition from `str`, and re-indent for pre whitespace.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
exports.clean = function (str) {
|
||||
str = str
|
||||
.replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
|
||||
.replace(/^\uFEFF/, '')
|
||||
// (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content
|
||||
.replace(
|
||||
/^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/,
|
||||
'$1$2$3'
|
||||
);
|
||||
|
||||
var spaces = str.match(/^\n?( *)/)[1].length;
|
||||
var tabs = str.match(/^\n?(\t*)/)[1].length;
|
||||
var re = new RegExp(
|
||||
'^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}',
|
||||
'gm'
|
||||
);
|
||||
|
||||
str = str.replace(re, '');
|
||||
|
||||
return str.trim();
|
||||
};
|
||||
|
||||
/**
|
||||
* If a value could have properties, and has none, this function is called,
|
||||
* which returns a string representation of the empty value.
|
||||
*
|
||||
* Functions w/ no properties return `'[Function]'`
|
||||
* Arrays w/ length === 0 return `'[]'`
|
||||
* Objects w/ no properties return `'{}'`
|
||||
* All else: return result of `value.toString()`
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to inspect.
|
||||
* @param {string} typeHint The type of the value
|
||||
* @returns {string}
|
||||
*/
|
||||
function emptyRepresentation(value, typeHint) {
|
||||
switch (typeHint) {
|
||||
case 'function':
|
||||
return '[Function]';
|
||||
case 'object':
|
||||
return '{}';
|
||||
case 'array':
|
||||
return '[]';
|
||||
default:
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes some variable and asks `Object.prototype.toString()` what it thinks it
|
||||
* is.
|
||||
*
|
||||
* @private
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
|
||||
* @param {*} value The value to test.
|
||||
* @returns {string} Computed type
|
||||
* @example
|
||||
* canonicalType({}) // 'object'
|
||||
* canonicalType([]) // 'array'
|
||||
* canonicalType(1) // 'number'
|
||||
* canonicalType(false) // 'boolean'
|
||||
* canonicalType(Infinity) // 'number'
|
||||
* canonicalType(null) // 'null'
|
||||
* canonicalType(new Date()) // 'date'
|
||||
* canonicalType(/foo/) // 'regexp'
|
||||
* canonicalType('type') // 'string'
|
||||
* canonicalType(global) // 'global'
|
||||
* canonicalType(new String('foo') // 'object'
|
||||
* canonicalType(async function() {}) // 'asyncfunction'
|
||||
* canonicalType(await import(name)) // 'module'
|
||||
*/
|
||||
var canonicalType = (exports.canonicalType = function canonicalType(value) {
|
||||
if (value === undefined) {
|
||||
return 'undefined';
|
||||
} else if (value === null) {
|
||||
return 'null';
|
||||
} else if (Buffer.isBuffer(value)) {
|
||||
return 'buffer';
|
||||
}
|
||||
return Object.prototype.toString
|
||||
.call(value)
|
||||
.replace(/^\[.+\s(.+?)]$/, '$1')
|
||||
.toLowerCase();
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns a general type or data structure of a variable
|
||||
* @private
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
|
||||
* @param {*} value The value to test.
|
||||
* @returns {string} One of undefined, boolean, number, string, bigint, symbol, object
|
||||
* @example
|
||||
* type({}) // 'object'
|
||||
* type([]) // 'array'
|
||||
* type(1) // 'number'
|
||||
* type(false) // 'boolean'
|
||||
* type(Infinity) // 'number'
|
||||
* type(null) // 'null'
|
||||
* type(new Date()) // 'object'
|
||||
* type(/foo/) // 'object'
|
||||
* type('type') // 'string'
|
||||
* type(global) // 'object'
|
||||
* type(new String('foo') // 'string'
|
||||
*/
|
||||
exports.type = function type(value) {
|
||||
// Null is special
|
||||
if (value === null) return 'null';
|
||||
const primitives = new Set([
|
||||
'undefined',
|
||||
'boolean',
|
||||
'number',
|
||||
'string',
|
||||
'bigint',
|
||||
'symbol'
|
||||
]);
|
||||
const _type = typeof value;
|
||||
if (_type === 'function') return _type;
|
||||
if (primitives.has(_type)) return _type;
|
||||
if (value instanceof String) return 'string';
|
||||
if (value instanceof Error) return 'error';
|
||||
if (Array.isArray(value)) return 'array';
|
||||
|
||||
return _type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringify `value`. Different behavior depending on type of value:
|
||||
*
|
||||
* - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
|
||||
* - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
|
||||
* - If `value` is an *empty* object, function, or array, return result of function
|
||||
* {@link emptyRepresentation}.
|
||||
* - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
|
||||
* JSON.stringify().
|
||||
*
|
||||
* @private
|
||||
* @see exports.type
|
||||
* @param {*} value
|
||||
* @return {string}
|
||||
*/
|
||||
exports.stringify = function (value) {
|
||||
var typeHint = canonicalType(value);
|
||||
|
||||
if (!~['object', 'array', 'function'].indexOf(typeHint)) {
|
||||
if (typeHint === 'buffer') {
|
||||
var json = Buffer.prototype.toJSON.call(value);
|
||||
// Based on the toJSON result
|
||||
return jsonStringify(
|
||||
json.data && json.type ? json.data : json,
|
||||
2
|
||||
).replace(/,(\n|$)/g, '$1');
|
||||
}
|
||||
|
||||
// IE7/IE8 has a bizarre String constructor; needs to be coerced
|
||||
// into an array and back to obj.
|
||||
if (typeHint === 'string' && typeof value === 'object') {
|
||||
value = value.split('').reduce(function (acc, char, idx) {
|
||||
acc[idx] = char;
|
||||
return acc;
|
||||
}, {});
|
||||
typeHint = 'object';
|
||||
} else {
|
||||
return jsonStringify(value);
|
||||
}
|
||||
}
|
||||
|
||||
for (var prop in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, prop)) {
|
||||
return jsonStringify(
|
||||
exports.canonicalize(value, null, typeHint),
|
||||
2
|
||||
).replace(/,(\n|$)/g, '$1');
|
||||
}
|
||||
}
|
||||
|
||||
return emptyRepresentation(value, typeHint);
|
||||
};
|
||||
|
||||
/**
|
||||
* like JSON.stringify but more sense.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object
|
||||
* @param {number=} spaces
|
||||
* @param {number=} depth
|
||||
* @returns {*}
|
||||
*/
|
||||
function jsonStringify(object, spaces, depth) {
|
||||
if (typeof spaces === 'undefined') {
|
||||
// primitive types
|
||||
return _stringify(object);
|
||||
}
|
||||
|
||||
depth = depth || 1;
|
||||
var space = spaces * depth;
|
||||
var str = Array.isArray(object) ? '[' : '{';
|
||||
var end = Array.isArray(object) ? ']' : '}';
|
||||
var length =
|
||||
typeof object.length === 'number'
|
||||
? object.length
|
||||
: Object.keys(object).length;
|
||||
// `.repeat()` polyfill
|
||||
function repeat(s, n) {
|
||||
return new Array(n).join(s);
|
||||
}
|
||||
|
||||
function _stringify(val) {
|
||||
switch (canonicalType(val)) {
|
||||
case 'null':
|
||||
case 'undefined':
|
||||
val = '[' + val + ']';
|
||||
break;
|
||||
case 'array':
|
||||
case 'object':
|
||||
val = jsonStringify(val, spaces, depth + 1);
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'regexp':
|
||||
case 'symbol':
|
||||
case 'number':
|
||||
val =
|
||||
val === 0 && 1 / val === -Infinity // `-0`
|
||||
? '-0'
|
||||
: val.toString();
|
||||
break;
|
||||
case 'bigint':
|
||||
val = val.toString() + 'n';
|
||||
break;
|
||||
case 'date':
|
||||
var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString();
|
||||
val = '[Date: ' + sDate + ']';
|
||||
break;
|
||||
case 'buffer':
|
||||
var json = val.toJSON();
|
||||
// Based on the toJSON result
|
||||
json = json.data && json.type ? json.data : json;
|
||||
val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
|
||||
break;
|
||||
default:
|
||||
val =
|
||||
val === '[Function]' || val === '[Circular]'
|
||||
? val
|
||||
: JSON.stringify(val); // string
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
for (var i in object) {
|
||||
if (!Object.prototype.hasOwnProperty.call(object, i)) {
|
||||
continue; // not my business
|
||||
}
|
||||
--length;
|
||||
str +=
|
||||
'\n ' +
|
||||
repeat(' ', space) +
|
||||
(Array.isArray(object) ? '' : '"' + i + '": ') + // key
|
||||
_stringify(object[i]) + // value
|
||||
(length ? ',' : ''); // comma
|
||||
}
|
||||
|
||||
return (
|
||||
str +
|
||||
// [], {}
|
||||
(str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new Thing that has the keys in sorted order. Recursive.
|
||||
*
|
||||
* If the Thing...
|
||||
* - has already been seen, return string `'[Circular]'`
|
||||
* - is `undefined`, return string `'[undefined]'`
|
||||
* - is `null`, return value `null`
|
||||
* - is some other primitive, return the value
|
||||
* - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
|
||||
* - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
|
||||
* - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
|
||||
*
|
||||
* @private
|
||||
* @see {@link exports.stringify}
|
||||
* @param {*} value Thing to inspect. May or may not have properties.
|
||||
* @param {Array} [stack=[]] Stack of seen values
|
||||
* @param {string} [typeHint] Type hint
|
||||
* @return {(Object|Array|Function|string|undefined)}
|
||||
*/
|
||||
exports.canonicalize = function canonicalize(value, stack, typeHint) {
|
||||
var canonicalizedObj;
|
||||
/* eslint-disable no-unused-vars */
|
||||
var prop;
|
||||
/* eslint-enable no-unused-vars */
|
||||
typeHint = typeHint || canonicalType(value);
|
||||
function withStack(value, fn) {
|
||||
stack.push(value);
|
||||
fn();
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
stack = stack || [];
|
||||
|
||||
if (stack.indexOf(value) !== -1) {
|
||||
return '[Circular]';
|
||||
}
|
||||
|
||||
switch (typeHint) {
|
||||
case 'undefined':
|
||||
case 'buffer':
|
||||
case 'null':
|
||||
canonicalizedObj = value;
|
||||
break;
|
||||
case 'array':
|
||||
withStack(value, function () {
|
||||
canonicalizedObj = value.map(function (item) {
|
||||
return exports.canonicalize(item, stack);
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'function':
|
||||
/* eslint-disable-next-line no-unused-vars, no-unreachable-loop */
|
||||
for (prop in value) {
|
||||
canonicalizedObj = {};
|
||||
break;
|
||||
}
|
||||
/* eslint-enable guard-for-in */
|
||||
if (!canonicalizedObj) {
|
||||
canonicalizedObj = emptyRepresentation(value, typeHint);
|
||||
break;
|
||||
}
|
||||
/* falls through */
|
||||
case 'object':
|
||||
canonicalizedObj = canonicalizedObj || {};
|
||||
withStack(value, function () {
|
||||
Object.keys(value)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
canonicalizedObj[key] = exports.canonicalize(value[key], stack);
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'date':
|
||||
case 'number':
|
||||
case 'regexp':
|
||||
case 'boolean':
|
||||
case 'symbol':
|
||||
canonicalizedObj = value;
|
||||
break;
|
||||
default:
|
||||
canonicalizedObj = value + '';
|
||||
}
|
||||
|
||||
return canonicalizedObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary
|
||||
* This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
|
||||
* @description
|
||||
* When invoking this function you get a filter function that get the Error.stack as an input,
|
||||
* and return a prettify output.
|
||||
* (i.e: strip Mocha and internal node functions from stack trace).
|
||||
* @returns {Function}
|
||||
*/
|
||||
exports.stackTraceFilter = function () {
|
||||
// TODO: Replace with `process.browser`
|
||||
var is = typeof document === 'undefined' ? {node: true} : {browser: true};
|
||||
var slash = path.sep;
|
||||
var cwd;
|
||||
if (is.node) {
|
||||
cwd = exports.cwd() + slash;
|
||||
} else {
|
||||
cwd = (
|
||||
typeof location === 'undefined' ? window.location : location
|
||||
).href.replace(/\/[^/]*$/, '/');
|
||||
slash = '/';
|
||||
}
|
||||
|
||||
function isMochaInternal(line) {
|
||||
return (
|
||||
~line.indexOf('node_modules' + slash + 'mocha' + slash) ||
|
||||
~line.indexOf(slash + 'mocha.js') ||
|
||||
~line.indexOf(slash + 'mocha.min.js')
|
||||
);
|
||||
}
|
||||
|
||||
function isNodeInternal(line) {
|
||||
return (
|
||||
~line.indexOf('(timers.js:') ||
|
||||
~line.indexOf('(events.js:') ||
|
||||
~line.indexOf('(node.js:') ||
|
||||
~line.indexOf('(module.js:') ||
|
||||
~line.indexOf('GeneratorFunctionPrototype.next (native)') ||
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return function (stack) {
|
||||
stack = stack.split('\n');
|
||||
|
||||
stack = stack.reduce(function (list, line) {
|
||||
if (isMochaInternal(line)) {
|
||||
return list;
|
||||
}
|
||||
|
||||
if (is.node && isNodeInternal(line)) {
|
||||
return list;
|
||||
}
|
||||
|
||||
// Clean up cwd(absolute)
|
||||
if (/:\d+:\d+\)?$/.test(line)) {
|
||||
line = line.replace('(' + cwd, '(');
|
||||
}
|
||||
|
||||
list.push(line);
|
||||
return list;
|
||||
}, []);
|
||||
|
||||
return stack.join('\n');
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Crude, but effective.
|
||||
* @public
|
||||
* @param {*} value
|
||||
* @returns {boolean} Whether or not `value` is a Promise
|
||||
*/
|
||||
exports.isPromise = function isPromise(value) {
|
||||
return (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
typeof value.then === 'function'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clamps a numeric value to an inclusive range.
|
||||
*
|
||||
* @param {number} value - Value to be clamped.
|
||||
* @param {number[]} range - Two element array specifying [min, max] range.
|
||||
* @returns {number} clamped value
|
||||
*/
|
||||
exports.clamp = function clamp(value, range) {
|
||||
return Math.min(Math.max(value, range[0]), range[1]);
|
||||
};
|
||||
|
||||
/**
|
||||
* It's a noop.
|
||||
* @public
|
||||
*/
|
||||
exports.noop = function () {};
|
||||
|
||||
/**
|
||||
* Creates a map-like object.
|
||||
*
|
||||
* @description
|
||||
* A "map" is an object with no prototype, for our purposes. In some cases
|
||||
* this would be more appropriate than a `Map`, especially if your environment
|
||||
* doesn't support it. Recommended for use in Mocha's public APIs.
|
||||
*
|
||||
* @public
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Custom_and_Null_objects|MDN:Map}
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects|MDN:Object.create - Custom objects}
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Custom_and_Null_objects|MDN:Object.assign}
|
||||
* @param {...*} [obj] - Arguments to `Object.assign()`.
|
||||
* @returns {Object} An object with no prototype, having `...obj` properties
|
||||
*/
|
||||
exports.createMap = function (obj) {
|
||||
return Object.assign.apply(
|
||||
null,
|
||||
[Object.create(null)].concat(Array.prototype.slice.call(arguments))
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a read-only map-like object.
|
||||
*
|
||||
* @description
|
||||
* This differs from {@link module:utils.createMap createMap} only in that
|
||||
* the argument must be non-empty, because the result is frozen.
|
||||
*
|
||||
* @see {@link module:utils.createMap createMap}
|
||||
* @param {...*} [obj] - Arguments to `Object.assign()`.
|
||||
* @returns {Object} A frozen object with no prototype, having `...obj` properties
|
||||
* @throws {TypeError} if argument is not a non-empty object.
|
||||
*/
|
||||
exports.defineConstants = function (obj) {
|
||||
if (canonicalType(obj) !== 'object' || !Object.keys(obj).length) {
|
||||
throw new TypeError('Invalid argument; expected a non-empty object');
|
||||
}
|
||||
return Object.freeze(exports.createMap(obj));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns current working directory
|
||||
*
|
||||
* Wrapper around `process.cwd()` for isolation
|
||||
* @private
|
||||
*/
|
||||
exports.cwd = function cwd() {
|
||||
return process.cwd();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns `true` if Mocha is running in a browser.
|
||||
* Checks for `process.browser`.
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
exports.isBrowser = function isBrowser() {
|
||||
return Boolean(process.browser);
|
||||
};
|
||||
|
||||
/*
|
||||
* Casts `value` to an array; useful for optionally accepting array parameters
|
||||
*
|
||||
* It follows these rules, depending on `value`. If `value` is...
|
||||
* 1. `undefined`: return an empty Array
|
||||
* 2. `null`: return an array with a single `null` element
|
||||
* 3. Any other object: return the value of `Array.from()` _if_ the object is iterable
|
||||
* 4. otherwise: return an array with a single element, `value`
|
||||
* @param {*} value - Something to cast to an Array
|
||||
* @returns {Array<*>}
|
||||
*/
|
||||
exports.castArray = function castArray(value) {
|
||||
if (value === undefined) {
|
||||
return [];
|
||||
}
|
||||
if (value === null) {
|
||||
return [null];
|
||||
}
|
||||
if (
|
||||
typeof value === 'object' &&
|
||||
(typeof value[Symbol.iterator] === 'function' || value.length !== undefined)
|
||||
) {
|
||||
return Array.from(value);
|
||||
}
|
||||
return [value];
|
||||
};
|
||||
|
||||
exports.constants = exports.defineConstants({
|
||||
MOCHA_ID_PROP_NAME
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a new unique identifier
|
||||
* @returns {string} Unique identifier
|
||||
*/
|
||||
exports.uniqueID = () => nanoid();
|
||||
|
||||
exports.assignNewMochaID = obj => {
|
||||
const id = exports.uniqueID();
|
||||
Object.defineProperty(obj, MOCHA_ID_PROP_NAME, {
|
||||
get() {
|
||||
return id;
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves a Mocha ID from an object, if present.
|
||||
* @param {*} [obj] - Object
|
||||
* @returns {string|void}
|
||||
*/
|
||||
exports.getMochaID = obj =>
|
||||
obj && typeof obj === 'object' ? obj[MOCHA_ID_PROP_NAME] : undefined;
|
||||
325
node_modules/mocha/mocha.css
generated
vendored
Normal file
325
node_modules/mocha/mocha.css
generated
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
@charset "utf-8";
|
||||
|
||||
body {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#mocha {
|
||||
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
margin: 60px 50px;
|
||||
}
|
||||
|
||||
#mocha ul,
|
||||
#mocha li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#mocha ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#mocha h1,
|
||||
#mocha h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#mocha h1 {
|
||||
margin-top: 15px;
|
||||
font-size: 1em;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
#mocha h1 a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#mocha h1 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#mocha .suite .suite h1 {
|
||||
margin-top: 0;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
#mocha .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha h2 {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mocha .suite {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
#mocha .test {
|
||||
margin-left: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#mocha .test.pending:hover h2::after {
|
||||
content: '(pending)';
|
||||
font-family: arial, sans-serif;
|
||||
}
|
||||
|
||||
#mocha .test.pass.medium .duration {
|
||||
background: #c09853;
|
||||
}
|
||||
|
||||
#mocha .test.pass.slow .duration {
|
||||
background: #b94a48;
|
||||
}
|
||||
|
||||
#mocha .test.pass::before {
|
||||
content: '✓';
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
color: #00d6b2;
|
||||
}
|
||||
|
||||
#mocha .test.pass .duration {
|
||||
font-size: 9px;
|
||||
margin-left: 5px;
|
||||
padding: 2px 5px;
|
||||
color: #fff;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-ms-border-radius: 5px;
|
||||
-o-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#mocha .test.pass.fast .duration {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha .test.pending {
|
||||
color: #0b97c4;
|
||||
}
|
||||
|
||||
#mocha .test.pending::before {
|
||||
content: '◦';
|
||||
color: #0b97c4;
|
||||
}
|
||||
|
||||
#mocha .test.fail {
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
#mocha .test.fail pre {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#mocha .test.fail::before {
|
||||
content: '✖';
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
#mocha .test pre.error {
|
||||
color: #c00;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#mocha .test .html-error {
|
||||
overflow: auto;
|
||||
color: black;
|
||||
display: block;
|
||||
float: left;
|
||||
clear: left;
|
||||
font: 12px/1.5 monaco, monospace;
|
||||
margin: 5px;
|
||||
padding: 15px;
|
||||
border: 1px solid #eee;
|
||||
max-width: 85%; /*(1)*/
|
||||
max-width: -webkit-calc(100% - 42px);
|
||||
max-width: -moz-calc(100% - 42px);
|
||||
max-width: calc(100% - 42px); /*(2)*/
|
||||
max-height: 300px;
|
||||
word-wrap: break-word;
|
||||
border-bottom-color: #ddd;
|
||||
-webkit-box-shadow: 0 1px 3px #eee;
|
||||
-moz-box-shadow: 0 1px 3px #eee;
|
||||
box-shadow: 0 1px 3px #eee;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#mocha .test .html-error pre.error {
|
||||
border: none;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: 0;
|
||||
-moz-box-shadow: 0;
|
||||
box-shadow: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-top: 18px;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* (1): approximate for browsers not supporting calc
|
||||
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
|
||||
* ^^ seriously
|
||||
*/
|
||||
#mocha .test pre {
|
||||
display: block;
|
||||
float: left;
|
||||
clear: left;
|
||||
font: 12px/1.5 monaco, monospace;
|
||||
margin: 5px;
|
||||
padding: 15px;
|
||||
border: 1px solid #eee;
|
||||
max-width: 85%; /*(1)*/
|
||||
max-width: -webkit-calc(100% - 42px);
|
||||
max-width: -moz-calc(100% - 42px);
|
||||
max-width: calc(100% - 42px); /*(2)*/
|
||||
word-wrap: break-word;
|
||||
border-bottom-color: #ddd;
|
||||
-webkit-box-shadow: 0 1px 3px #eee;
|
||||
-moz-box-shadow: 0 1px 3px #eee;
|
||||
box-shadow: 0 1px 3px #eee;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#mocha .test h2 {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#mocha .test a.replay {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 0;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
display: block;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
text-align: center;
|
||||
background: #eee;
|
||||
font-size: 15px;
|
||||
-webkit-border-radius: 15px;
|
||||
-moz-border-radius: 15px;
|
||||
border-radius: 15px;
|
||||
-webkit-transition:opacity 200ms;
|
||||
-moz-transition:opacity 200ms;
|
||||
-o-transition:opacity 200ms;
|
||||
transition: opacity 200ms;
|
||||
opacity: 0.3;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
#mocha .test:hover a.replay {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#mocha-report.pass .test.fail {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha-report.fail .test.pass {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha-report.pending .test.pass,
|
||||
#mocha-report.pending .test.fail {
|
||||
display: none;
|
||||
}
|
||||
#mocha-report.pending .test.pass.pending {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#mocha-error {
|
||||
color: #c00;
|
||||
font-size: 1.5em;
|
||||
font-weight: 100;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
#mocha-stats {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
right: 10px;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
color: #888;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#mocha-stats .progress {
|
||||
float: right;
|
||||
padding-top: 0;
|
||||
|
||||
/**
|
||||
* Set safe initial values, so mochas .progress does not inherit these
|
||||
* properties from Bootstrap .progress (which causes .progress height to
|
||||
* equal line height set in Bootstrap).
|
||||
*/
|
||||
height: auto;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
background-color: initial;
|
||||
}
|
||||
|
||||
#mocha-stats em {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#mocha-stats a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#mocha-stats a:hover {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#mocha-stats li {
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
list-style: none;
|
||||
padding-top: 11px;
|
||||
}
|
||||
|
||||
#mocha-stats canvas {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
#mocha code .comment { color: #ddd; }
|
||||
#mocha code .init { color: #2f6fad; }
|
||||
#mocha code .string { color: #5890ad; }
|
||||
#mocha code .keyword { color: #8a6343; }
|
||||
#mocha code .number { color: #2f6fad; }
|
||||
|
||||
@media screen and (max-device-width: 480px) {
|
||||
#mocha {
|
||||
margin: 60px 0px;
|
||||
}
|
||||
|
||||
#mocha #stats {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
20617
node_modules/mocha/mocha.js
generated
vendored
Normal file
20617
node_modules/mocha/mocha.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/mocha/mocha.js.map
generated
vendored
Normal file
1
node_modules/mocha/mocha.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
190
node_modules/mocha/package.json
generated
vendored
Normal file
190
node_modules/mocha/package.json
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
{
|
||||
"name": "mocha",
|
||||
"version": "10.0.0",
|
||||
"type": "commonjs",
|
||||
"description": "simple, flexible, fun test framework",
|
||||
"keywords": [
|
||||
"mocha",
|
||||
"test",
|
||||
"bdd",
|
||||
"tdd",
|
||||
"tap",
|
||||
"testing",
|
||||
"chai",
|
||||
"assertion",
|
||||
"ava",
|
||||
"jest",
|
||||
"tape",
|
||||
"jasmine",
|
||||
"karma"
|
||||
],
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mochajs/mocha.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/mochajs/mocha/issues/"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mochajs"
|
||||
},
|
||||
"gitter": "https://gitter.im/mochajs/mocha",
|
||||
"homepage": "https://mochajs.org/",
|
||||
"logo": "https://cldup.com/S9uQ-cOLYz.svg",
|
||||
"notifyLogo": "https://ibin.co/4QuRuGjXvl36.png",
|
||||
"bin": {
|
||||
"mocha": "./bin/mocha.js",
|
||||
"_mocha": "./bin/_mocha"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "./lib",
|
||||
"test": "./test"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "nps test clean build",
|
||||
"start": "nps",
|
||||
"test": "nps test",
|
||||
"version": "nps version",
|
||||
"test:smoke": "node ./bin/mocha --no-config test/smoke/smoke.spec.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ungap/promise-all-settled": "1.1.2",
|
||||
"ansi-colors": "4.1.1",
|
||||
"browser-stdout": "1.3.1",
|
||||
"chokidar": "3.5.3",
|
||||
"debug": "4.3.4",
|
||||
"diff": "5.0.0",
|
||||
"escape-string-regexp": "4.0.0",
|
||||
"find-up": "5.0.0",
|
||||
"glob": "7.2.0",
|
||||
"he": "1.2.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"log-symbols": "4.1.0",
|
||||
"minimatch": "5.0.1",
|
||||
"ms": "2.1.3",
|
||||
"nanoid": "3.3.3",
|
||||
"serialize-javascript": "6.0.0",
|
||||
"strip-json-comments": "3.1.1",
|
||||
"supports-color": "8.1.1",
|
||||
"workerpool": "6.2.1",
|
||||
"yargs": "16.2.0",
|
||||
"yargs-parser": "20.2.4",
|
||||
"yargs-unparser": "2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^1.0.0",
|
||||
"@11ty/eleventy-plugin-inclusive-language": "^1.0.3",
|
||||
"@babel/eslint-parser": "^7.16.5",
|
||||
"@mocha/docdash": "^4.0.1",
|
||||
"@rollup/plugin-commonjs": "^21.0.2",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-multi-entry": "^4.0.1",
|
||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||
"assetgraph-builder": "^9.0.0",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"canvas": "^2.9.0",
|
||||
"chai": "^4.3.4",
|
||||
"coffeescript": "^2.6.1",
|
||||
"configstore": "^5.0.1",
|
||||
"coveralls": "^3.1.1",
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-semistandard": "^16.0.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"fail-on-errors-webpack-plugin": "^3.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"husky": "^4.2.5",
|
||||
"hyperlink": "^5.0.4",
|
||||
"jsdoc": "^3.6.7",
|
||||
"jsdoc-ts-utils": "^2.0.1",
|
||||
"karma": "^6.3.11",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
"karma-mocha": "^2.0.1",
|
||||
"karma-mocha-reporter": "^2.2.5",
|
||||
"karma-sauce-launcher": "^4.3.6",
|
||||
"lint-staged": "^10.2.11",
|
||||
"markdown-it": "^12.3.2",
|
||||
"markdown-it-anchor": "^8.4.1",
|
||||
"markdown-it-attrs": "^4.1.3",
|
||||
"markdown-it-emoji": "^2.0.0",
|
||||
"markdown-it-prism": "^2.2.2",
|
||||
"markdown-toc": "^1.2.0",
|
||||
"markdownlint-cli": "^0.30.0",
|
||||
"needle": "^2.5.0",
|
||||
"nps": "^5.10.0",
|
||||
"nyc": "^15.1.0",
|
||||
"pidtree": "^0.5.0",
|
||||
"prettier": "^2.4.1",
|
||||
"remark": "^14.0.2",
|
||||
"remark-github": "^11.2.2",
|
||||
"remark-inline-links": "^6.0.1",
|
||||
"rewiremock": "^3.14.3",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.70.1",
|
||||
"rollup-plugin-node-globals": "^1.4.0",
|
||||
"rollup-plugin-polyfill-node": "^0.8.0",
|
||||
"rollup-plugin-visualizer": "^5.6.0",
|
||||
"sinon": "^9.0.3",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"svgo": "^1.3.2",
|
||||
"through2": "^4.0.2",
|
||||
"touch": "^3.1.0",
|
||||
"unexpected": "^11.14.0",
|
||||
"unexpected-eventemitter": "^2.2.0",
|
||||
"unexpected-map": "^2.0.0",
|
||||
"unexpected-set": "^3.0.0",
|
||||
"unexpected-sinon": "^10.11.2",
|
||||
"update-notifier": "^4.1.0",
|
||||
"uslug": "^1.0.4",
|
||||
"uuid": "^8.3.0",
|
||||
"watchify": "^4.0.0",
|
||||
"webpack": "^5.67.0",
|
||||
"webpack-cli": "^4.9.1"
|
||||
},
|
||||
"files": [
|
||||
"bin/*mocha*",
|
||||
"lib/**/*.{js,html,json}",
|
||||
"index.js",
|
||||
"mocha.css",
|
||||
"mocha.js",
|
||||
"mocha.js.map",
|
||||
"browser-entry.js"
|
||||
],
|
||||
"browser": {
|
||||
"./index.js": "./browser-entry.js",
|
||||
"fs": false,
|
||||
"path": false,
|
||||
"supports-color": false,
|
||||
"./lib/nodejs/buffered-worker-pool.js": false,
|
||||
"./lib/nodejs/esm-utils.js": false,
|
||||
"./lib/nodejs/file-unloader.js": false,
|
||||
"./lib/nodejs/parallel-buffered-runner.js": false,
|
||||
"./lib/nodejs/serializer.js": false,
|
||||
"./lib/nodejs/worker.js": false,
|
||||
"./lib/nodejs/reporters/parallel-buffered.js": false,
|
||||
"./lib/cli/index.js": false
|
||||
},
|
||||
"prettier": {
|
||||
"arrowParens": "avoid",
|
||||
"bracketSpacing": false,
|
||||
"endOfLine": "auto",
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user