Remove access to non-public Suite and Spec members via Env#topSuite

This commit is contained in:
Steve Gravrock
2021-05-22 17:33:46 -07:00
parent 3f3fb38cf1
commit a0f6b77c3e
11 changed files with 142 additions and 540 deletions

View File

@@ -66,8 +66,6 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
j$.Deprecator = jRequire.Deprecator(j$);
j$.Env = jRequire.Env(j$);
j$.deprecatingSuiteProxy = jRequire.deprecatingSuiteProxy(j$);
j$.deprecatingSpecProxy = jRequire.deprecatingSpecProxy(j$);
j$.StackTrace = jRequire.StackTrace(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
@@ -672,21 +670,11 @@ getJasmineRequireObj().util = function(j$) {
};
getJasmineRequireObj().Spec = function(j$) {
/**
* @interface Spec
* @see Configuration#specFilter
*/
function Spec(attrs) {
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
/**
* The description passed to the {@link it} that created this spec.
* @name Spec#description
* @readonly
* @type {string}
*/
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns =
@@ -878,12 +866,6 @@ getJasmineRequireObj().Spec = function(j$) {
return 'passed';
};
/**
* The full description including all ancestors of this spec.
* @name Spec#getFullName
* @function
* @returns {string}
*/
Spec.prototype.getFullName = function() {
return this.getSpecName(this);
};
@@ -916,6 +898,30 @@ getJasmineRequireObj().Spec = function(j$) {
);
};
/**
* @interface Spec
* @see Configuration#specFilter
*/
Spec.prototype.buildMetadata = function() {
return {
/**
* The description passed to the {@link it} that created this spec.
* @name Spec#description
* @readonly
* @type {string}
*/
description: this.description,
/**
* The full description including all ancestors of this spec.
* @name Spec#getFullName
* @function
* @returns {string}
*/
getFullName: this.getFullName.bind(this)
};
};
return Spec;
};
@@ -1526,7 +1532,7 @@ getJasmineRequireObj().Env = function(j$) {
* @return {Suite} the root suite
*/
this.topSuite = function() {
return j$.deprecatingSuiteProxy(topSuite, null, this);
return topSuite.buildMetadata(null);
};
/**
@@ -3354,176 +3360,6 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
return DelayedFunctionScheduler;
};
/* eslint-disable compat/compat */
// TODO: Remove this in the next major release.
getJasmineRequireObj().deprecatingSpecProxy = function(j$) {
function isMember(target, prop) {
return (
Object.keys(target).indexOf(prop) !== -1 ||
Object.keys(j$.Spec.prototype).indexOf(prop) !== -1
);
}
function isAllowedMember(prop) {
return prop === 'description' || prop === 'getFullName';
}
function msg(member) {
var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
return (
'Access to private Spec members (in this case `' +
memberName +
'`) via Env#topSuite is not supported and will break in ' +
'a future release. See <https://jasmine.github.io/api/edge/Spec.html> ' +
'for correct usage.'
);
}
try {
new Proxy({}, {});
} catch (e) {
// Environment does not support Poxy.
return function(spec) {
return spec;
};
}
function DeprecatingSpecProxyHandler(env) {
this._env = env;
}
DeprecatingSpecProxyHandler.prototype.get = function(target, prop, receiver) {
this._maybeDeprecate(target, prop);
if (prop === 'getFullName') {
// getFullName calls a private method. Re-bind 'this' to avoid a bogus
// deprecation warning.
return target.getFullName.bind(target);
} else {
return target[prop];
}
};
DeprecatingSpecProxyHandler.prototype.set = function(target, prop, value) {
this._maybeDeprecate(target, prop);
return (target[prop] = value);
};
DeprecatingSpecProxyHandler.prototype._maybeDeprecate = function(
target,
prop
) {
if (isMember(target, prop) && !isAllowedMember(prop)) {
this._env.deprecated(msg(prop));
}
};
function deprecatingSpecProxy(spec, env) {
return new Proxy(spec, new DeprecatingSpecProxyHandler(env));
}
return deprecatingSpecProxy;
};
/* eslint-disable compat/compat */
// TODO: Remove this in the next major release.
getJasmineRequireObj().deprecatingSuiteProxy = function(j$) {
var allowedMembers = [
'children',
'description',
'parentSuite',
'getFullName'
];
function isMember(target, prop) {
return (
Object.keys(target).indexOf(prop) !== -1 ||
Object.keys(j$.Suite.prototype).indexOf(prop) !== -1
);
}
function isAllowedMember(prop) {
return allowedMembers.indexOf(prop) !== -1;
}
function msg(member) {
var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
return (
'Access to private Suite members (in this case `' +
memberName +
'`) via Env#topSuite is not supported and will break in ' +
'a future release. See <https://jasmine.github.io/api/edge/Suite.html> ' +
'for correct usage.'
);
}
try {
new Proxy({}, {});
} catch (e) {
// Environment does not support Poxy.
return function(suite) {
return suite;
};
}
function DeprecatingSuiteProxyHandler(parentSuite, env) {
this._parentSuite = parentSuite;
this._env = env;
}
DeprecatingSuiteProxyHandler.prototype.get = function(
target,
prop,
receiver
) {
if (prop === 'children') {
if (!this._children) {
this._children = target.children.map(
this._proxyForChild.bind(this, receiver)
);
}
return this._children;
} else if (prop === 'parentSuite') {
return this._parentSuite;
} else {
this._maybeDeprecate(target, prop);
return target[prop];
}
};
DeprecatingSuiteProxyHandler.prototype.set = function(target, prop, value) {
debugger;
this._maybeDeprecate(target, prop);
return (target[prop] = value);
};
DeprecatingSuiteProxyHandler.prototype._maybeDeprecate = function(
target,
prop
) {
if (isMember(target, prop) && !isAllowedMember(prop)) {
this._env.deprecated(msg(prop));
}
};
DeprecatingSuiteProxyHandler.prototype._proxyForChild = function(
ownProxy,
child
) {
if (child.children) {
return deprecatingSuiteProxy(child, ownProxy, this._env);
} else {
return j$.deprecatingSpecProxy(child, this._env);
}
};
function deprecatingSuiteProxy(suite, parentSuite, env) {
return new Proxy(suite, new DeprecatingSuiteProxyHandler(parentSuite, env));
}
return deprecatingSuiteProxy;
};
getJasmineRequireObj().Deprecator = function(j$) {
function Deprecator(topSuite) {
this.topSuite_ = topSuite;
@@ -9088,26 +8924,10 @@ getJasmineRequireObj().StackTrace = function(j$) {
};
getJasmineRequireObj().Suite = function(j$) {
/**
* @interface Suite
* @see Env#topSuite
*/
function Suite(attrs) {
this.env = attrs.env;
this.id = attrs.id;
/**
* The parent of this suite, or null if this is the top suite.
* @name Suite#parentSuite
* @readonly
* @type {Suite}
*/
this.parentSuite = attrs.parentSuite;
/**
* The description passed to the {@link describe} that created this suite.
* @name Suite#description
* @readonly
* @type {string}
*/
this.description = attrs.description;
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
@@ -9118,14 +8938,7 @@ getJasmineRequireObj().Suite = function(j$) {
this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
this.timer = attrs.timer || new j$.Timer();
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
*/
this.children = [];
/**
@@ -9163,12 +8976,6 @@ getJasmineRequireObj().Suite = function(j$) {
return this.asyncExpectationFactory(actual, this);
};
/**
* The full description including all ancestors of this suite.
* @name Suite#getFullName
* @function
* @returns {string}
*/
Suite.prototype.getFullName = function() {
var fullName = [];
for (
@@ -9303,6 +9110,49 @@ getJasmineRequireObj().Suite = function(j$) {
);
};
Suite.prototype.buildMetadata = function(parentMetadata) {
/**
* @interface Suite
* @see Env#topSuite
*/
var result = {
/**
* The parent of this suite, or null if this is the top suite.
* @name Suite#parentSuite
* @readonly
* @type {Suite}
*/
parentSuite: parentMetadata,
/**
* The description passed to the {@link describe} that created this suite.
* @name Suite#description
* @readonly
* @type {string}
*/
description: this.description,
/**
* The full description including all ancestors of this suite.
* @name Suite#getFullName
* @function
* @returns {string}
*/
getFullName: this.getFullName.bind(this)
};
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
*/
result.children = this.children.map(function(child) {
return child.buildMetadata(result);
});
return result;
};
function isFailure(args) {
return !args[0];
}

View File

@@ -39,19 +39,25 @@ describe('Env', function() {
});
suite = env.topSuite();
expect(suite).not.toBeInstanceOf(jasmineUnderTest.Suite);
expect(suite.description).toEqual('Jasmine__TopLevel__Suite');
expect(suite.getFullName()).toEqual('');
expect(suite.children.length).toEqual(2);
expect(suite.children[0]).not.toBeInstanceOf(jasmineUnderTest.Spec);
expect(suite.children[0].description).toEqual('a top level spec');
expect(suite.children[0].getFullName()).toEqual('a top level spec');
expect(suite.children[0].children).toBeFalsy();
expect(suite.children[1]).not.toBeInstanceOf(jasmineUnderTest.Suite);
expect(suite.children[1].description).toEqual('a suite');
expect(suite.children[1].getFullName()).toEqual('a suite');
expect(suite.children[1].parentSuite).toBe(suite);
expect(suite.children[1].children.length).toEqual(2);
expect(suite.children[1].children[0]).not.toBeInstanceOf(
jasmineUnderTest.Spec
);
expect(suite.children[1].children[0].description).toEqual('a spec');
expect(suite.children[1].children[0].getFullName()).toEqual(
'a suite a spec'
@@ -75,93 +81,6 @@ describe('Env', function() {
);
expect(suite.children[1].children[1].children[0].children).toBeFalsy();
});
it('does not deprecate access to public Suite and Spec members', function() {
jasmine.getEnv().requireProxy();
var suite;
spyOn(env, 'deprecated');
env.it('a top level spec');
env.describe('a suite', function() {
env.it('a spec');
});
suite = env.topSuite();
suite.description;
suite.getFullName();
suite.children;
suite.parentSuite;
suite.children[0].description;
suite.children[0].getFullName();
suite.children[0].children;
suite.children[1].description;
suite.children[1].getFullName();
suite.children[1].parentSuite;
suite.children[1].children;
expect(env.deprecated).not.toHaveBeenCalled();
});
it('deprecates access to internal Suite and Spec members', function() {
jasmine.getEnv().requireProxy();
var topSuite, expectationFactory, spec;
env.it('a top level spec');
spyOn(env, 'deprecated');
topSuite = env.topSuite();
topSuite.expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `expectationFactory`) via Env#topSuite is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
env.deprecated.calls.reset();
topSuite.expectationFactory = expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `expectationFactory`) via Env#topSuite is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
topSuite.status();
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `status`) via Env#topSuite is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
spec = topSuite.children[0];
spec.pend();
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Spec ' +
'members (in this case `pend`) via Env#topSuite ' +
'is not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
expectationFactory = spec.expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Spec ' +
'members (in this case `expectationFactory`) via Env#topSuite ' +
'is not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
env.deprecated.calls.reset();
spec.expectationFactory = expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Spec ' +
'members (in this case `expectationFactory`) via Env#topSuite ' +
'is not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
});
});
it('accepts its own current configureation', function() {

View File

@@ -1,17 +0,0 @@
/* eslint-disable compat/compat */
(function(env) {
function hasProxyConstructor() {
try {
new Proxy({}, {});
return true;
} catch (e) {
return false;
}
}
env.requireProxy = function() {
if (!hasProxyConstructor()) {
env.pending('Environment does not support Proxy');
}
};
})(jasmine.getEnv());

View File

@@ -21,7 +21,6 @@ module.exports = {
'helpers/generator.js',
'helpers/BrowserFlags.js',
'helpers/checkForMap.js',
'helpers/checkForProxy.js',
'helpers/checkForSet.js',
'helpers/checkForSymbol.js',
'helpers/checkForUrl.js',

View File

@@ -8,7 +8,6 @@
"helpers/asyncAwait.js",
"helpers/generator.js",
"helpers/checkForMap.js",
"helpers/checkForProxy.js",
"helpers/checkForSet.js",
"helpers/checkForSymbol.js",
"helpers/checkForUrl.js",

View File

@@ -554,7 +554,7 @@ getJasmineRequireObj().Env = function(j$) {
* @return {Suite} the root suite
*/
this.topSuite = function() {
return j$.deprecatingSuiteProxy(topSuite, null, this);
return topSuite.buildMetadata(null);
};
/**

View File

@@ -1,19 +1,9 @@
getJasmineRequireObj().Spec = function(j$) {
/**
* @interface Spec
* @see Configuration#specFilter
*/
function Spec(attrs) {
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
/**
* The description passed to the {@link it} that created this spec.
* @name Spec#description
* @readonly
* @type {string}
*/
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns =
@@ -205,12 +195,6 @@ getJasmineRequireObj().Spec = function(j$) {
return 'passed';
};
/**
* The full description including all ancestors of this spec.
* @name Spec#getFullName
* @function
* @returns {string}
*/
Spec.prototype.getFullName = function() {
return this.getSpecName(this);
};
@@ -243,6 +227,30 @@ getJasmineRequireObj().Spec = function(j$) {
);
};
/**
* @interface Spec
* @see Configuration#specFilter
*/
Spec.prototype.buildMetadata = function() {
return {
/**
* The description passed to the {@link it} that created this spec.
* @name Spec#description
* @readonly
* @type {string}
*/
description: this.description,
/**
* The full description including all ancestors of this spec.
* @name Spec#getFullName
* @function
* @returns {string}
*/
getFullName: this.getFullName.bind(this)
};
};
return Spec;
};

View File

@@ -1,24 +1,8 @@
getJasmineRequireObj().Suite = function(j$) {
/**
* @interface Suite
* @see Env#topSuite
*/
function Suite(attrs) {
this.env = attrs.env;
this.id = attrs.id;
/**
* The parent of this suite, or null if this is the top suite.
* @name Suite#parentSuite
* @readonly
* @type {Suite}
*/
this.parentSuite = attrs.parentSuite;
/**
* The description passed to the {@link describe} that created this suite.
* @name Suite#description
* @readonly
* @type {string}
*/
this.description = attrs.description;
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
@@ -29,14 +13,7 @@ getJasmineRequireObj().Suite = function(j$) {
this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
this.timer = attrs.timer || new j$.Timer();
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
*/
this.children = [];
/**
@@ -74,12 +51,6 @@ getJasmineRequireObj().Suite = function(j$) {
return this.asyncExpectationFactory(actual, this);
};
/**
* The full description including all ancestors of this suite.
* @name Suite#getFullName
* @function
* @returns {string}
*/
Suite.prototype.getFullName = function() {
var fullName = [];
for (
@@ -214,6 +185,49 @@ getJasmineRequireObj().Suite = function(j$) {
);
};
Suite.prototype.buildMetadata = function(parentMetadata) {
/**
* @interface Suite
* @see Env#topSuite
*/
var result = {
/**
* The parent of this suite, or null if this is the top suite.
* @name Suite#parentSuite
* @readonly
* @type {Suite}
*/
parentSuite: parentMetadata,
/**
* The description passed to the {@link describe} that created this suite.
* @name Suite#description
* @readonly
* @type {string}
*/
description: this.description,
/**
* The full description including all ancestors of this suite.
* @name Suite#getFullName
* @function
* @returns {string}
*/
getFullName: this.getFullName.bind(this)
};
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
*/
result.children = this.children.map(function(child) {
return child.buildMetadata(result);
});
return result;
};
function isFailure(args) {
return !args[0];
}

View File

@@ -1,70 +0,0 @@
/* eslint-disable compat/compat */
// TODO: Remove this in the next major release.
getJasmineRequireObj().deprecatingSpecProxy = function(j$) {
function isMember(target, prop) {
return (
Object.keys(target).indexOf(prop) !== -1 ||
Object.keys(j$.Spec.prototype).indexOf(prop) !== -1
);
}
function isAllowedMember(prop) {
return prop === 'description' || prop === 'getFullName';
}
function msg(member) {
var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
return (
'Access to private Spec members (in this case `' +
memberName +
'`) via Env#topSuite is not supported and will break in ' +
'a future release. See <https://jasmine.github.io/api/edge/Spec.html> ' +
'for correct usage.'
);
}
try {
new Proxy({}, {});
} catch (e) {
// Environment does not support Poxy.
return function(spec) {
return spec;
};
}
function DeprecatingSpecProxyHandler(env) {
this._env = env;
}
DeprecatingSpecProxyHandler.prototype.get = function(target, prop, receiver) {
this._maybeDeprecate(target, prop);
if (prop === 'getFullName') {
// getFullName calls a private method. Re-bind 'this' to avoid a bogus
// deprecation warning.
return target.getFullName.bind(target);
} else {
return target[prop];
}
};
DeprecatingSpecProxyHandler.prototype.set = function(target, prop, value) {
this._maybeDeprecate(target, prop);
return (target[prop] = value);
};
DeprecatingSpecProxyHandler.prototype._maybeDeprecate = function(
target,
prop
) {
if (isMember(target, prop) && !isAllowedMember(prop)) {
this._env.deprecated(msg(prop));
}
};
function deprecatingSpecProxy(spec, env) {
return new Proxy(spec, new DeprecatingSpecProxyHandler(env));
}
return deprecatingSpecProxy;
};

View File

@@ -1,98 +0,0 @@
/* eslint-disable compat/compat */
// TODO: Remove this in the next major release.
getJasmineRequireObj().deprecatingSuiteProxy = function(j$) {
var allowedMembers = [
'children',
'description',
'parentSuite',
'getFullName'
];
function isMember(target, prop) {
return (
Object.keys(target).indexOf(prop) !== -1 ||
Object.keys(j$.Suite.prototype).indexOf(prop) !== -1
);
}
function isAllowedMember(prop) {
return allowedMembers.indexOf(prop) !== -1;
}
function msg(member) {
var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
return (
'Access to private Suite members (in this case `' +
memberName +
'`) via Env#topSuite is not supported and will break in ' +
'a future release. See <https://jasmine.github.io/api/edge/Suite.html> ' +
'for correct usage.'
);
}
try {
new Proxy({}, {});
} catch (e) {
// Environment does not support Poxy.
return function(suite) {
return suite;
};
}
function DeprecatingSuiteProxyHandler(parentSuite, env) {
this._parentSuite = parentSuite;
this._env = env;
}
DeprecatingSuiteProxyHandler.prototype.get = function(
target,
prop,
receiver
) {
if (prop === 'children') {
if (!this._children) {
this._children = target.children.map(
this._proxyForChild.bind(this, receiver)
);
}
return this._children;
} else if (prop === 'parentSuite') {
return this._parentSuite;
} else {
this._maybeDeprecate(target, prop);
return target[prop];
}
};
DeprecatingSuiteProxyHandler.prototype.set = function(target, prop, value) {
debugger;
this._maybeDeprecate(target, prop);
return (target[prop] = value);
};
DeprecatingSuiteProxyHandler.prototype._maybeDeprecate = function(
target,
prop
) {
if (isMember(target, prop) && !isAllowedMember(prop)) {
this._env.deprecated(msg(prop));
}
};
DeprecatingSuiteProxyHandler.prototype._proxyForChild = function(
ownProxy,
child
) {
if (child.children) {
return deprecatingSuiteProxy(child, ownProxy, this._env);
} else {
return j$.deprecatingSpecProxy(child, this._env);
}
};
function deprecatingSuiteProxy(suite, parentSuite, env) {
return new Proxy(suite, new DeprecatingSuiteProxyHandler(parentSuite, env));
}
return deprecatingSuiteProxy;
};

View File

@@ -44,8 +44,6 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
j$.Deprecator = jRequire.Deprecator(j$);
j$.Env = jRequire.Env(j$);
j$.deprecatingSuiteProxy = jRequire.deprecatingSuiteProxy(j$);
j$.deprecatingSpecProxy = jRequire.deprecatingSpecProxy(j$);
j$.StackTrace = jRequire.StackTrace(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();