Improved & unified deprecation handling
* De-duplication now happens in core, not in reporters. This ensures that the console doesn't get flooded. * Stack traces are opt-out, not opt-in. * The current runnable is not reported or logged for certain deprecations where it's irrelevant. * HtmlReporter shows stack traces in expandable widgets. * Env#deprecated and Env#deprecatedOnceWithStack are merged.
This commit is contained in:
90
src/core/Deprecator.js
Normal file
90
src/core/Deprecator.js
Normal file
@@ -0,0 +1,90 @@
|
||||
getJasmineRequireObj().Deprecator = function(j$) {
|
||||
function Deprecator(topSuite) {
|
||||
this.topSuite_ = topSuite;
|
||||
this.verbose_ = false;
|
||||
this.toSuppress_ = [];
|
||||
}
|
||||
|
||||
var verboseNote =
|
||||
'Note: This message will be shown only once. ' +
|
||||
'Set config.verboseDeprecations to true to see every occurrence.';
|
||||
|
||||
Deprecator.prototype.verboseDeprecations = function(enabled) {
|
||||
this.verbose_ = enabled;
|
||||
};
|
||||
|
||||
// runnable is a spec or a suite.
|
||||
// deprecation is a string or an Error.
|
||||
// See Env#deprecated for a description of the options argument.
|
||||
Deprecator.prototype.addDeprecationWarning = function(
|
||||
runnable,
|
||||
deprecation,
|
||||
options
|
||||
) {
|
||||
options = options || {};
|
||||
|
||||
if (!this.verbose_ && !j$.isError_(deprecation)) {
|
||||
if (this.toSuppress_.indexOf(deprecation) !== -1) {
|
||||
return;
|
||||
}
|
||||
this.toSuppress_.push(deprecation);
|
||||
}
|
||||
|
||||
this.log_(runnable, deprecation, options);
|
||||
this.report_(runnable, deprecation, options);
|
||||
};
|
||||
|
||||
Deprecator.prototype.log_ = function(runnable, deprecation, options) {
|
||||
var context;
|
||||
|
||||
if (j$.isError_(deprecation)) {
|
||||
console.error(deprecation);
|
||||
return;
|
||||
}
|
||||
|
||||
if (runnable === this.topSuite_ || options.ignoreRunnable) {
|
||||
context = '';
|
||||
} else if (runnable.children) {
|
||||
context = ' (in suite: ' + runnable.getFullName() + ')';
|
||||
} else {
|
||||
context = ' (in spec: ' + runnable.getFullName() + ')';
|
||||
}
|
||||
|
||||
if (!options.omitStackTrace) {
|
||||
context += '\n' + this.stackTrace_();
|
||||
}
|
||||
|
||||
if (!this.verbose_) {
|
||||
context += '\n' + verboseNote;
|
||||
}
|
||||
|
||||
console.error('DEPRECATION: ' + deprecation + context);
|
||||
};
|
||||
|
||||
Deprecator.prototype.stackTrace_ = function() {
|
||||
var formatter = new j$.ExceptionFormatter();
|
||||
return formatter.stack(j$.util.errorWithStack()).replace(/^Error\n/m, '');
|
||||
};
|
||||
|
||||
Deprecator.prototype.report_ = function(runnable, deprecation, options) {
|
||||
if (options.ignoreRunnable) {
|
||||
runnable = this.topSuite_;
|
||||
}
|
||||
|
||||
if (j$.isError_(deprecation)) {
|
||||
runnable.addDeprecationWarning(deprecation);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.verbose_) {
|
||||
deprecation += '\n' + verboseNote;
|
||||
}
|
||||
|
||||
runnable.addDeprecationWarning({
|
||||
message: deprecation,
|
||||
omitStackTrace: options.omitStackTrace || false
|
||||
});
|
||||
};
|
||||
|
||||
return Deprecator;
|
||||
};
|
||||
128
src/core/Env.js
128
src/core/Env.js
@@ -32,7 +32,6 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
var currentlyExecutingSuites = [];
|
||||
var currentDeclarationSuite = null;
|
||||
var hasFailures = false;
|
||||
var deprecationsToSuppress = [];
|
||||
|
||||
/**
|
||||
* This represents the available options to configure Jasmine.
|
||||
@@ -228,6 +227,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
|
||||
if (configuration.hasOwnProperty('verboseDeprecations')) {
|
||||
config.verboseDeprecations = configuration.verboseDeprecations;
|
||||
deprecator.verboseDeprecations(config.verboseDeprecations);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -249,13 +249,19 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
Object.defineProperty(this, 'specFilter', {
|
||||
get: function() {
|
||||
self.deprecated(
|
||||
'Getting specFilter directly from Env is deprecated and will be removed in a future version of Jasmine, please check the specFilter option from `configuration`'
|
||||
'Getting specFilter directly from Env is deprecated and will be ' +
|
||||
'removed in a future version of Jasmine. Please check the ' +
|
||||
'specFilter option from `configuration` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
return config.specFilter;
|
||||
},
|
||||
set: function(val) {
|
||||
self.deprecated(
|
||||
'Setting specFilter directly on Env is deprecated and will be removed in a future version of Jasmine, please use the specFilter option in `configure`'
|
||||
'Setting specFilter directly on Env is deprecated and will be ' +
|
||||
'removed in a future version of Jasmine. Please use the ' +
|
||||
'specFilter option in `configure` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
config.specFilter = val;
|
||||
}
|
||||
@@ -303,7 +309,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
|
||||
for (var matcherName in matchersToAdd) {
|
||||
if (matchersToAdd[matcherName].length > 1) {
|
||||
self.deprecatedOnceWithStack(
|
||||
self.deprecated(
|
||||
'The matcher factory for "' +
|
||||
matcherName +
|
||||
'" ' +
|
||||
@@ -328,7 +334,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
|
||||
for (var matcherName in matchersToAdd) {
|
||||
if (matchersToAdd[matcherName].length > 1) {
|
||||
self.deprecatedOnceWithStack(
|
||||
self.deprecated(
|
||||
'The matcher factory for "' +
|
||||
matcherName +
|
||||
'" ' +
|
||||
@@ -535,14 +541,21 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
*/
|
||||
this.throwOnExpectationFailure = function(value) {
|
||||
this.deprecated(
|
||||
'Setting throwOnExpectationFailure directly on Env is deprecated and will be removed in a future version of Jasmine, please use the oneFailurePerSpec option in `configure`'
|
||||
'Setting throwOnExpectationFailure directly on Env is deprecated ' +
|
||||
'and will be removed in a future version of Jasmine. Please use the ' +
|
||||
'oneFailurePerSpec option in `configure` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
this.configure({ oneFailurePerSpec: !!value });
|
||||
};
|
||||
|
||||
this.throwingExpectationFailures = function() {
|
||||
this.deprecated(
|
||||
'Getting throwingExpectationFailures directly from Env is deprecated and will be removed in a future version of Jasmine, please check the oneFailurePerSpec option from `configuration`'
|
||||
'Getting throwingExpectationFailures directly from Env is ' +
|
||||
'deprecated and will be removed in a future version of Jasmine. ' +
|
||||
'Please check the oneFailurePerSpec option from `configuration` ' +
|
||||
'instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
return config.oneFailurePerSpec;
|
||||
};
|
||||
@@ -557,14 +570,20 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
*/
|
||||
this.stopOnSpecFailure = function(value) {
|
||||
this.deprecated(
|
||||
'Setting stopOnSpecFailure directly is deprecated and will be removed in a future version of Jasmine, please use the failFast option in `configure`'
|
||||
'Setting stopOnSpecFailure directly is deprecated and will be ' +
|
||||
'removed in a future version of Jasmine. Please use the failFast ' +
|
||||
'option in `configure` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
this.configure({ failFast: !!value });
|
||||
};
|
||||
|
||||
this.stoppingOnSpecFailure = function() {
|
||||
this.deprecated(
|
||||
'Getting stoppingOnSpecFailure directly from Env is deprecated and will be removed in a future version of Jasmine, please check the failFast option from `configuration`'
|
||||
'Getting stoppingOnSpecFailure directly from Env is deprecated ' +
|
||||
'and will be removed in a future version of Jasmine. Please check ' +
|
||||
'the failFast option from `configuration` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
return config.failFast;
|
||||
};
|
||||
@@ -579,14 +598,20 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
*/
|
||||
this.randomizeTests = function(value) {
|
||||
this.deprecated(
|
||||
'Setting randomizeTests directly is deprecated and will be removed in a future version of Jasmine, please use the random option in `configure`'
|
||||
'Setting randomizeTests directly is deprecated and will be removed ' +
|
||||
'in a future version of Jasmine. Please use the random option in ' +
|
||||
'`configure` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
config.random = !!value;
|
||||
};
|
||||
|
||||
this.randomTests = function() {
|
||||
this.deprecated(
|
||||
'Getting randomTests directly from Env is deprecated and will be removed in a future version of Jasmine, please check the random option from `configuration`'
|
||||
'Getting randomTests directly from Env is deprecated and will be ' +
|
||||
'removed in a future version of Jasmine. Please check the random ' +
|
||||
'option from `configuration` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
return config.random;
|
||||
};
|
||||
@@ -601,7 +626,10 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
*/
|
||||
this.seed = function(value) {
|
||||
this.deprecated(
|
||||
'Setting seed directly is deprecated and will be removed in a future version of Jasmine, please use the seed option in `configure`'
|
||||
'Setting seed directly is deprecated and will be removed in a ' +
|
||||
'future version of Jasmine. Please use the seed option in ' +
|
||||
'`configure` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
if (value) {
|
||||
config.seed = value;
|
||||
@@ -611,7 +639,10 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
|
||||
this.hidingDisabled = function(value) {
|
||||
this.deprecated(
|
||||
'Getting hidingDisabled directly from Env is deprecated and will be removed in a future version of Jasmine, please check the hideDisabled option from `configuration`'
|
||||
'Getting hidingDisabled directly from Env is deprecated and will ' +
|
||||
'be removed in a future version of Jasmine. Please check the ' +
|
||||
'hideDisabled option from `configuration` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
return config.hideDisabled;
|
||||
};
|
||||
@@ -623,53 +654,39 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
*/
|
||||
this.hideDisabled = function(value) {
|
||||
this.deprecated(
|
||||
'Setting hideDisabled directly is deprecated and will be removed in a future version of Jasmine, please use the hideDisabled option in `configure`'
|
||||
'Setting hideDisabled directly is deprecated and will be removed ' +
|
||||
'in a future version of Jasmine. Please use the hideDisabled option ' +
|
||||
'in `configure` instead.',
|
||||
{ ignoreRunnable: true }
|
||||
);
|
||||
config.hideDisabled = !!value;
|
||||
};
|
||||
|
||||
this.deprecated = function(deprecation) {
|
||||
/**
|
||||
* Causes a deprecation warning to be logged to the console and reported to
|
||||
* reporters.
|
||||
*
|
||||
* The optional second parameter is an object that can have either of the
|
||||
* following properties:
|
||||
*
|
||||
* omitStackTrace: Whether to omit the stack trace. Optional. Defaults to
|
||||
* false. This option is ignored if the deprecation is an Error. Set this
|
||||
* when the stack trace will not contain anything that helps the user find
|
||||
* the source of the deprecation.
|
||||
*
|
||||
* ignoreRunnable: Whether to log the deprecation on the root suite, ignoring
|
||||
* the spec or suite that's running when it happens. Optional. Defaults to
|
||||
* false.
|
||||
*
|
||||
* @name Env#deprecated
|
||||
* @since 2.99
|
||||
* @function
|
||||
* @param {String|Error} deprecation The deprecation message
|
||||
* @param {Object} [options] Optional extra options, as described above
|
||||
*/
|
||||
this.deprecated = function(deprecation, options) {
|
||||
var runnable = currentRunnable() || topSuite;
|
||||
var context;
|
||||
|
||||
if (runnable === topSuite) {
|
||||
context = '';
|
||||
} else if (runnable === currentSuite()) {
|
||||
context = ' (in suite: ' + runnable.getFullName() + ')';
|
||||
} else {
|
||||
context = ' (in spec: ' + runnable.getFullName() + ')';
|
||||
}
|
||||
|
||||
runnable.addDeprecationWarning(deprecation);
|
||||
if (
|
||||
typeof console !== 'undefined' &&
|
||||
typeof console.error === 'function'
|
||||
) {
|
||||
console.error('DEPRECATION: ' + deprecation + context);
|
||||
}
|
||||
};
|
||||
|
||||
this.deprecatedOnceWithStack = function(deprecation) {
|
||||
var formatter = new j$.ExceptionFormatter(),
|
||||
stackTrace = formatter
|
||||
.stack(j$.util.errorWithStack())
|
||||
.replace(/^Error\n/m, '');
|
||||
|
||||
if (config.verboseDeprecations) {
|
||||
this.deprecated(deprecation + '\n' + stackTrace);
|
||||
} else {
|
||||
if (deprecationsToSuppress.indexOf(deprecation) === -1) {
|
||||
this.deprecated(
|
||||
deprecation +
|
||||
'\n' +
|
||||
'Note: This message will be shown only once. ' +
|
||||
'Set config.verboseDeprecations to true to see every occurrence.\n' +
|
||||
stackTrace
|
||||
);
|
||||
}
|
||||
|
||||
deprecationsToSuppress.push(deprecation);
|
||||
}
|
||||
deprecator.addDeprecationWarning(runnable, deprecation, options);
|
||||
};
|
||||
|
||||
var queueRunnerFactory = function(options, args) {
|
||||
@@ -705,6 +722,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
asyncExpectationFactory: suiteAsyncExpectationFactory,
|
||||
expectationResultFactory: expectationResultFactory
|
||||
});
|
||||
var deprecator = new j$.Deprecator(topSuite);
|
||||
defaultResourcesForRunnable(topSuite.id);
|
||||
currentDeclarationSuite = topSuite;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
|
||||
var result = {
|
||||
matcherName: options.matcherName,
|
||||
message: message(),
|
||||
stack: stack(),
|
||||
stack: options.omitStackTrace ? '' : stack(),
|
||||
passed: options.passed
|
||||
};
|
||||
|
||||
|
||||
@@ -215,25 +215,29 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
};
|
||||
|
||||
QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) {
|
||||
var msg;
|
||||
|
||||
if (retval && j$.isFunction_(retval.then)) {
|
||||
// Issue a warning that matches the user's code
|
||||
// Issue a warning that matches the user's code.
|
||||
// Omit the stack trace because there's almost certainly no user code
|
||||
// on the stack at this point.
|
||||
if (j$.isAsyncFunction_(fn)) {
|
||||
this.deprecated(
|
||||
msg =
|
||||
'An asynchronous before/it/after ' +
|
||||
'function was defined with the async keyword but also took a ' +
|
||||
'done callback. This is not supported and will stop working in' +
|
||||
' the future. Either remove the done callback (recommended) or ' +
|
||||
'remove the async keyword.'
|
||||
);
|
||||
'function was defined with the async keyword but also took a ' +
|
||||
'done callback. This is not supported and will stop working in' +
|
||||
' the future. Either remove the done callback (recommended) or ' +
|
||||
'remove the async keyword.';
|
||||
} else {
|
||||
this.deprecated(
|
||||
msg =
|
||||
'An asynchronous before/it/after ' +
|
||||
'function took a done callback but also returned a promise. ' +
|
||||
'This is not supported and will stop working in the future. ' +
|
||||
'Either remove the done callback (recommended) or change the ' +
|
||||
'function to not return a promise.'
|
||||
);
|
||||
'function took a done callback but also returned a promise. ' +
|
||||
'This is not supported and will stop working in the future. ' +
|
||||
'Either remove the done callback (recommended) or change the ' +
|
||||
'function to not return a promise.';
|
||||
}
|
||||
|
||||
this.deprecated(msg, { omitStackTrace: true });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
|
||||
*/
|
||||
MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
|
||||
if (customTesters) {
|
||||
j$.getEnv().deprecatedOnceWithStack(
|
||||
j$.getEnv().deprecated(
|
||||
'Passing custom equality testers ' +
|
||||
'to MatchersUtil#contains is deprecated. ' +
|
||||
'See <https://jasmine.github.io/tutorials/upgrading_to_4.0> for details.'
|
||||
@@ -172,7 +172,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
|
||||
diffBuilder = customTestersOrDiffBuilder;
|
||||
} else {
|
||||
if (customTestersOrDiffBuilder) {
|
||||
j$.getEnv().deprecatedOnceWithStack(
|
||||
j$.getEnv().deprecated(
|
||||
'Passing custom equality testers ' +
|
||||
'to MatchersUtil#equals is deprecated. ' +
|
||||
'See <https://jasmine.github.io/tutorials/upgrading_to_4.0> for details.'
|
||||
@@ -180,7 +180,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
|
||||
}
|
||||
|
||||
if (diffBuilderOrNothing) {
|
||||
j$.getEnv().deprecatedOnceWithStack(
|
||||
j$.getEnv().deprecated(
|
||||
'Diff builder should be passed ' +
|
||||
'as the third argument to MatchersUtil#equals, not the fourth. ' +
|
||||
'See <https://jasmine.github.io/tutorials/upgrading_to_4.0> for details.'
|
||||
|
||||
@@ -42,6 +42,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
||||
j$.getClearStack = jRequire.clearStack(j$);
|
||||
j$.Clock = jRequire.Clock();
|
||||
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
|
||||
j$.Deprecator = jRequire.Deprecator(j$);
|
||||
j$.Env = jRequire.Env(j$);
|
||||
j$.deprecatingThisProxy = jRequire.deprecatingThisProxy(j$);
|
||||
j$.StackTrace = jRequire.StackTrace(j$);
|
||||
@@ -58,7 +59,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
||||
j$.basicPrettyPrinter_ = j$.makePrettyPrinter();
|
||||
Object.defineProperty(j$, 'pp', {
|
||||
get: function() {
|
||||
j$.getEnv().deprecatedOnceWithStack(
|
||||
j$.getEnv().deprecated(
|
||||
'jasmine.pp is deprecated and will be removed in a future release. ' +
|
||||
'Use the pp method of the matchersUtil passed to the matcher factory ' +
|
||||
"or the asymmetric equality tester's `asymmetricMatch` method " +
|
||||
@@ -75,7 +76,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
||||
});
|
||||
Object.defineProperty(j$, 'matchersUtil', {
|
||||
get: function() {
|
||||
j$.getEnv().deprecatedOnceWithStack(
|
||||
j$.getEnv().deprecated(
|
||||
'jasmine.matchersUtil is deprecated and will be removed ' +
|
||||
'in a future release. Use the instance passed to the matcher factory or ' +
|
||||
"the asymmetric equality tester's `asymmetricMatch` method instead. " +
|
||||
|
||||
Reference in New Issue
Block a user