Skip to content

Commit

Permalink
move deprecate() and warn() from utils into errors module
Browse files Browse the repository at this point in the history
This avoids a circular dependency which arises when Mocha is bundled.

These are private APIs.
  • Loading branch information
boneskull committed Sep 2, 2020
1 parent eeb7dae commit 91eaaf0
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 151 deletions.
60 changes: 53 additions & 7 deletions lib/errors.js
@@ -1,13 +1,57 @@
'use strict';

var format = require('util').format;
const {deprecate} = require('./utils');
const {format} = require('util');

/**
* Factory functions to create throwable error objects
* @module Errors
* 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 {
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 throw exceptions (or otherwise errors), it attempts to assign a
* `code` property to the `Error` object, for easier handling. These are the
Expand Down Expand Up @@ -383,15 +427,17 @@ module.exports = {
createInvalidArgumentValueError,
createInvalidExceptionError,
createInvalidInterfaceError,
createInvalidLegacyPluginError,
createInvalidPluginDefinitionError,
createInvalidPluginImplementationError,
createInvalidPluginError,
createInvalidLegacyPluginError,
createInvalidPluginImplementationError,
createInvalidReporterError,
createMissingArgumentError,
createMochaInstanceAlreadyDisposedError,
createMochaInstanceAlreadyRunningError,
createMultipleDoneError,
createNoFilesMatchPatternError,
createUnsupportedError
createUnsupportedError,
deprecate,
warn
};
7 changes: 4 additions & 3 deletions lib/mocha.js
Expand Up @@ -18,6 +18,7 @@ var esmUtils = utils.supportsEsModules(true)
: undefined;
var createStatsCollector = require('./stats-collector');
const {
warn,
createInvalidReporterError,
createInvalidInterfaceError,
createMochaInstanceAlreadyDisposedError,
Expand Down Expand Up @@ -290,15 +291,15 @@ Mocha.prototype.reporter = function(reporterName, reporterOptions) {
reporter = require(path.resolve(utils.cwd(), reporterName));
} catch (_err) {
_err.code === 'MODULE_NOT_FOUND'
? utils.warn(sQuote(reporterName) + ' reporter not found')
: utils.warn(
? warn(sQuote(reporterName) + ' reporter not found')
: warn(
sQuote(reporterName) +
' reporter blew up with error:\n' +
err.stack
);
}
} else {
utils.warn(
warn(
sQuote(reporterName) + ' reporter blew up with error:\n' + err.stack
);
}
Expand Down
7 changes: 3 additions & 4 deletions lib/suite.js
Expand Up @@ -10,8 +10,7 @@ var utils = require('./utils');
var inherits = utils.inherits;
var debug = require('debug')('mocha:suite');
var milliseconds = require('ms');
var errors = require('./errors');
var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError;
const errors = require('./errors');

/**
* Expose `Suite`.
Expand Down Expand Up @@ -48,7 +47,7 @@ Suite.create = function(parent, title) {
*/
function Suite(title, parentContext, isRoot) {
if (!utils.isString(title)) {
throw createInvalidArgumentTypeError(
throw errors.createInvalidArgumentTypeError(
'Suite argument "title" must be a string. Received type "' +
typeof title +
'"',
Expand Down Expand Up @@ -78,7 +77,7 @@ function Suite(title, parentContext, isRoot) {

this.on('newListener', function(event) {
if (deprecatedEvents[event]) {
utils.deprecate(
errors.deprecate(
'Event "' +
event +
'" is deprecated. Please let the Mocha team know about your use case: https://git.io/v6Lwm'
Expand Down
49 changes: 3 additions & 46 deletions lib/utils.js
Expand Up @@ -12,6 +12,7 @@
var path = require('path');
var util = require('util');
var he = require('he');
const errors = require('./errors');

/**
* Inherit the prototype methods from one constructor into another.
Expand Down Expand Up @@ -376,50 +377,6 @@ exports.canonicalize = function canonicalize(value, stack, typeHint) {
return canonicalizedObj;
};

/**
* process.emitWarning or a polyfill
* @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options
* @ignore
*/
function emitWarning(msg, type) {
if (process.emitWarning) {
process.emitWarning(msg, type);
} else {
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
*/
exports.deprecate = function deprecate(msg) {
msg = String(msg);
if (msg && !deprecate.cache[msg]) {
deprecate.cache[msg] = true;
emitWarning(msg, 'DeprecationWarning');
}
};
exports.deprecate.cache = {};

/**
* Show a generic warning.
* Ignores empty messages.
*
* @param {string} [msg] - Warning to print
* @private
*/
exports.warn = function warn(msg) {
if (msg) {
emitWarning(msg);
}
};

/**
* @summary
* This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
Expand Down Expand Up @@ -663,11 +620,11 @@ exports.isBrowser = function isBrowser() {
*/
exports.lookupFiles = (...args) => {
if (exports.isBrowser()) {
throw require('./errors').createUnsupportedError(
throw errors.createUnsupportedError(
'lookupFiles() is only supported in Node.js!'
);
}
exports.deprecate(
errors.deprecate(
'`lookupFiles()` in module `mocha/lib/utils` has moved to module `mocha/lib/cli` and will be removed in the next major revision of Mocha'
);
return require('./cli').lookupFiles(...args);
Expand Down
8 changes: 4 additions & 4 deletions test/integration/fixtures/deprecate.fixture.js
@@ -1,9 +1,9 @@
'use strict';

var utils = require("../../../lib/utils");
var errors = require("../../../lib/errors");

it('consolidates identical calls to deprecate', function() {
utils.deprecate("suite foo did a deprecated thing");
utils.deprecate("suite foo did a deprecated thing");
utils.deprecate("suite bar did a deprecated thing");
errors.deprecate("suite foo did a deprecated thing");
errors.deprecate("suite foo did a deprecated thing");
errors.deprecate("suite bar did a deprecated thing");
});
22 changes: 17 additions & 5 deletions test/node-unit/mocha.spec.js
Expand Up @@ -19,9 +19,20 @@ describe('Mocha', function() {
opts = {reporter: sinon.stub()};

stubs = {};
stubs.errors = {
warn: sinon.stub(),
createMochaInstanceAlreadyDisposedError: sinon
.stub()
.throws({code: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED'}),
createInvalidReporterError: sinon
.stub()
.throws({code: 'ERR_MOCHA_INVALID_REPORTER'}),
createUnsupportedError: sinon
.stub()
.throws({code: 'ERR_MOCHA_UNSUPPORTED'})
};
stubs.utils = {
supportsEsModules: sinon.stub().returns(false),
warn: sinon.stub(),
isString: sinon.stub(),
noop: sinon.stub(),
cwd: sinon.stub().returns(process.cwd()),
Expand Down Expand Up @@ -55,7 +66,8 @@ describe('Mocha', function() {
'../../lib/suite.js': stubs.Suite,
'../../lib/nodejs/parallel-buffered-runner.js':
stubs.ParallelBufferedRunner,
'../../lib/runner.js': stubs.Runner
'../../lib/runner.js': stubs.Runner,
'../../lib/errors.js': stubs.errors
})
);
delete require.cache[DUMB_FIXTURE_PATH];
Expand Down Expand Up @@ -260,7 +272,7 @@ describe('Mocha', function() {
);
} catch (ignored) {
} finally {
expect(stubs.utils.warn, 'to have a call satisfying', [
expect(stubs.errors.warn, 'to have a call satisfying', [
expect.it('to match', /reporter blew up/)
]);
}
Expand Down Expand Up @@ -297,7 +309,7 @@ describe('Mocha', function() {
);
} catch (ignored) {
} finally {
expect(stubs.utils.warn, 'to have a call satisfying', [
expect(stubs.errors.warn, 'to have a call satisfying', [
expect.it('to match', /reporter blew up/)
]);
}
Expand All @@ -321,7 +333,7 @@ describe('Mocha', function() {
mocha.unloadFiles();
},
'to throw',
'Mocha instance is already disposed, it cannot be used again.'
{code: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED'}
);
});
});
Expand Down
81 changes: 81 additions & 0 deletions test/unit/errors.spec.js
@@ -1,8 +1,13 @@
'use strict';

var errors = require('../../lib/errors');
const sinon = require('sinon');

describe('Errors', function() {
afterEach(function() {
sinon.restore();
});

var message = 'some message';

describe('createInvalidReporterError()', function() {
Expand Down Expand Up @@ -62,4 +67,80 @@ describe('Errors', function() {
});
});
});

describe('deprecate()', function() {
var emitWarning;

beforeEach(function() {
if (process.emitWarning) {
emitWarning = process.emitWarning;
sinon.stub(process, 'emitWarning');
} else {
process.emitWarning = sinon.spy();
}
errors.deprecate.cache = {};
});

afterEach(function() {
// if this is not set, then we created it, so we should remove it.
if (!emitWarning) {
delete process.emitWarning;
}
});

it('should coerce its parameter to a string', function() {
errors.deprecate(1);
expect(process.emitWarning, 'to have a call satisfying', [
'1',
'DeprecationWarning'
]);
});

it('should cache the message', function() {
errors.deprecate('foo');
errors.deprecate('foo');
expect(process.emitWarning, 'was called times', 1);
});

it('should ignore falsy messages', function() {
errors.deprecate('');
expect(process.emitWarning, 'was not called');
});
});

describe('warn()', function() {
var emitWarning;

beforeEach(function() {
if (process.emitWarning) {
emitWarning = process.emitWarning;
sinon.stub(process, 'emitWarning');
} else {
process.emitWarning = sinon.spy();
}
});

afterEach(function() {
// if this is not set, then we created it, so we should remove it.
if (!emitWarning) {
delete process.emitWarning;
}
});

it('should call process.emitWarning', function() {
errors.warn('foo');
expect(process.emitWarning, 'was called times', 1);
});

it('should not cache messages', function() {
errors.warn('foo');
errors.warn('foo');
expect(process.emitWarning, 'was called times', 2);
});

it('should ignore falsy messages', function() {
errors.warn('');
expect(process.emitWarning, 'was not called');
});
});
});
3 changes: 2 additions & 1 deletion test/unit/mocha.spec.js
Expand Up @@ -4,6 +4,7 @@ var sinon = require('sinon');
var EventEmitter = require('events').EventEmitter;
var Mocha = require('../../lib/mocha');
var utils = require('../../lib/utils');
const errors = require('../../lib/errors');

describe('Mocha', function() {
/**
Expand Down Expand Up @@ -76,7 +77,7 @@ describe('Mocha', function() {
Suite.constants = {};

sinon.stub(utils, 'supportsEsModules').returns(false);
sinon.stub(utils, 'warn');
sinon.stub(errors, 'warn');
sinon.stub(utils, 'isString');
sinon.stub(utils, 'noop');
});
Expand Down

0 comments on commit 91eaaf0

Please sign in to comment.