Remove access to non-public properties of suites and specs returned by describe, it, etc.

[#179064612]
This commit is contained in:
Steve Gravrock
2021-07-30 17:36:50 -07:00
parent 6d002d22af
commit 13dfcacbb0
5 changed files with 272 additions and 169 deletions

View File

@@ -663,12 +663,6 @@ getJasmineRequireObj().Spec = function(j$) {
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
/**
* The unique ID of this spec.
* @name Spec#id
* @readonly
* @type {string}
*/
this.id = attrs.id;
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
@@ -898,34 +892,43 @@ 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,
Object.defineProperty(Spec.prototype, 'metadata', {
get: function() {
if (!this.metadata_) {
this.metadata_ = {
/**
* The unique ID of this spec.
* @name Spec#id
* @readonly
* @type {string}
*/
id: this.id,
/**
* The full description including all ancestors of this spec.
* @name Spec#getFullName
* @function
* @returns {string}
*/
getFullName: this.getFullName.bind(this)
};
};
/**
* 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 this.metadata_;
}
});
return Spec;
};
if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Spec = jasmineRequire.Spec;
}
/*jshint bitwise: false*/
getJasmineRequireObj().Order = function() {
@@ -1523,7 +1526,7 @@ getJasmineRequireObj().Env = function(j$) {
* @return {Suite} the root suite
*/
this.topSuite = function() {
return topSuite.buildMetadata(null);
return topSuite.metadata;
};
/**
@@ -1906,7 +1909,7 @@ getJasmineRequireObj().Env = function(j$) {
if (suite.parentSuite && !suite.children.length) {
throw new Error('describe with no children (describe() or it())');
}
return suite;
return suite.metadata;
};
this.xdescribe = function(description, specDefinitions) {
@@ -1915,7 +1918,7 @@ getJasmineRequireObj().Env = function(j$) {
var suite = suiteFactory(description);
suite.pend();
addSpecsToSuite(suite, specDefinitions);
return suite;
return suite.metadata;
};
var focusedRunnables = [];
@@ -1930,7 +1933,7 @@ getJasmineRequireObj().Env = function(j$) {
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
return suite.metadata;
};
function addSpecsToSuite(suite, specDefinitions) {
@@ -2020,7 +2023,7 @@ getJasmineRequireObj().Env = function(j$) {
}
};
this.it = function(description, fn, timeout) {
this.it_ = function(description, fn, timeout) {
ensureIsNotNested('it');
// it() sometimes doesn't have a fn argument, so only check the type if
// it's given.
@@ -2036,6 +2039,11 @@ getJasmineRequireObj().Env = function(j$) {
return spec;
};
this.it = function(description, fn, timeout) {
const spec = this.it_(description, fn, timeout);
return spec.metadata;
};
this.xit = function(description, fn, timeout) {
ensureIsNotNested('xit');
// xit(), like it(), doesn't always have a fn argument, so only check the
@@ -2043,9 +2051,9 @@ getJasmineRequireObj().Env = function(j$) {
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunctionOrAsync(fn, 'xit');
}
var spec = this.it.apply(this, arguments);
var spec = this.it_.apply(this, arguments);
spec.pend('Temporarily disabled with xit');
return spec;
return spec.metadata;
};
this.fit = function(description, fn, timeout) {
@@ -2055,7 +2063,7 @@ getJasmineRequireObj().Env = function(j$) {
currentDeclarationSuite.addChild(spec);
focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
return spec.metadata;
};
/**
@@ -9045,12 +9053,6 @@ getJasmineRequireObj().StackTrace = function(j$) {
getJasmineRequireObj().Suite = function(j$) {
function Suite(attrs) {
this.env = attrs.env;
/**
* The unique ID of this suite.
* @name Suite#id
* @readonly
* @type {string}
*/
this.id = attrs.id;
this.parentSuite = attrs.parentSuite;
this.description = attrs.description;
@@ -9235,49 +9237,68 @@ getJasmineRequireObj().Suite = function(j$) {
);
};
Suite.prototype.buildMetadata = function(parentMetadata) {
Object.defineProperty(Suite.prototype, 'metadata', {
get: function() {
if (!this.metadata_) {
this.metadata_ = new SuiteMetadata(this);
}
return this.metadata_;
}
});
/**
* @interface Suite
* @see Env#topSuite
*/
function SuiteMetadata(suite) {
this.suite_ = suite;
/**
* @interface Suite
* @see Env#topSuite
* The unique ID of this suite.
* @name Suite#id
* @readonly
* @type {string}
*/
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)
};
this.id = suite.id;
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
* The parent of this suite, or null if this is the top suite.
* @name Suite#parentSuite
* @readonly
* @type {Suite}
*/
result.children = this.children.map(function(child) {
return child.buildMetadata(result);
});
this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null;
return result;
/**
* The description passed to the {@link describe} that created this suite.
* @name Suite#description
* @readonly
* @type {string}
*/
this.description = suite.description;
}
/**
* The full description including all ancestors of this suite.
* @name Suite#getFullName
* @function
* @returns {string}
*/
SuiteMetadata.prototype.getFullName = function() {
return this.suite_.getFullName();
};
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
*/
Object.defineProperty(SuiteMetadata.prototype, 'children', {
get: function() {
return this.suite_.children.map(child => child.metadata);
}
});
function isFailure(args) {
return !args[0];
}
@@ -9285,11 +9306,6 @@ getJasmineRequireObj().Suite = function(j$) {
return Suite;
};
if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Suite = jasmineRequire.Suite;
}
getJasmineRequireObj().Timer = function() {
var defaultNow = (function(Date) {
return function() {

View File

@@ -90,7 +90,7 @@ describe('Env', function() {
it('can configure specs to throw errors on expectation failures', function() {
env.configure({ oneFailurePerSpec: true });
spyOn(jasmineUnderTest, 'Spec');
spyOn(jasmineUnderTest, 'Spec').and.callThrough();
env.it('foo', function() {});
expect(jasmineUnderTest.Spec).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -162,7 +162,7 @@ describe('Env', function() {
});
it('defaults to multiple failures for specs', function() {
spyOn(jasmineUnderTest, 'Spec');
spyOn(jasmineUnderTest, 'Spec').and.callThrough();
env.it('bar', function() {});
expect(jasmineUnderTest.Spec).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -181,7 +181,40 @@ describe('Env', function() {
);
});
function behavesLikeDescribe(methodName) {
it('returns a suite metadata object', function() {
let innerSuite;
let spec;
const suite = env.describe('outer suite', function() {
innerSuite = env.describe('inner suite', function() {
spec = env.it('a spec');
});
});
expect(suite.parentSuite).toEqual(
jasmine.objectContaining({
description: 'Jasmine__TopLevel__Suite'
})
);
expect(suite.parentSuite.pend).toBeUndefined();
expect(suite.pend).toBeUndefined();
expect(suite.description).toEqual('outer suite');
expect(suite.getFullName()).toEqual('outer suite');
expect(suite.id).toBeInstanceOf(String);
expect(suite.id).not.toEqual('');
expect(suite.children.length).toEqual(1);
expect(suite.children[0]).toBe(innerSuite);
expect(innerSuite.children.length).toEqual(1);
expect(innerSuite.children[0]).toBe(spec);
expect(innerSuite.getFullName()).toEqual('outer suite inner suite');
expect(innerSuite.parentSuite).toBe(suite);
expect(spec.getFullName()).toEqual('outer suite inner suite a spec');
});
}
describe('#describe', function() {
behavesLikeDescribe('describe');
it('throws an error when given arguments', function() {
expect(function() {
env.describe('done method', function(done) {});
@@ -232,7 +265,41 @@ describe('Env', function() {
});
});
describe('#fdescribe', function() {
behavesLikeDescribe('fdescribe');
});
describe('xdescribe', function() {
behavesLikeDescribe('xdescribe');
});
function behavesLikeIt(methodName) {
it('returns a spec metadata object', function() {
let spec;
env.describe('a suite', function() {
spec = env[methodName]('a spec', function() {});
});
expect(spec.description)
.withContext('description')
.toEqual('a spec');
expect(spec.getFullName())
.withContext('getFullName')
.toEqual('a suite a spec');
expect(spec.id)
.withContext('id')
.toBeInstanceOf(String);
expect(spec.id)
.withContext('id')
.not.toEqual('');
expect(spec.pend).toBeFalsy();
});
}
describe('#it', function() {
behavesLikeIt('it');
it('throws an error when it receives a non-fn argument', function() {
expect(function() {
env.it('undefined arg', null);
@@ -255,9 +322,11 @@ describe('Env', function() {
});
describe('#xit', function() {
behavesLikeIt('xit');
it('calls spec.pend with "Temporarily disabled with xit"', function() {
var pendSpy = jasmine.createSpy();
spyOn(env, 'it').and.returnValue({
spyOn(env, 'it_').and.returnValue({
pend: pendSpy
});
env.xit('foo', function() {});
@@ -286,6 +355,8 @@ describe('Env', function() {
});
describe('#fit', function() {
behavesLikeIt('fit');
it('throws an error when it receives a non-fn argument', function() {
expect(function() {
env.fit('undefined arg', undefined);

View File

@@ -549,7 +549,7 @@ getJasmineRequireObj().Env = function(j$) {
* @return {Suite} the root suite
*/
this.topSuite = function() {
return topSuite.buildMetadata(null);
return topSuite.metadata;
};
/**
@@ -932,7 +932,7 @@ getJasmineRequireObj().Env = function(j$) {
if (suite.parentSuite && !suite.children.length) {
throw new Error('describe with no children (describe() or it())');
}
return suite;
return suite.metadata;
};
this.xdescribe = function(description, specDefinitions) {
@@ -941,7 +941,7 @@ getJasmineRequireObj().Env = function(j$) {
var suite = suiteFactory(description);
suite.pend();
addSpecsToSuite(suite, specDefinitions);
return suite;
return suite.metadata;
};
var focusedRunnables = [];
@@ -956,7 +956,7 @@ getJasmineRequireObj().Env = function(j$) {
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
return suite.metadata;
};
function addSpecsToSuite(suite, specDefinitions) {
@@ -1046,7 +1046,7 @@ getJasmineRequireObj().Env = function(j$) {
}
};
this.it = function(description, fn, timeout) {
this.it_ = function(description, fn, timeout) {
ensureIsNotNested('it');
// it() sometimes doesn't have a fn argument, so only check the type if
// it's given.
@@ -1062,6 +1062,11 @@ getJasmineRequireObj().Env = function(j$) {
return spec;
};
this.it = function(description, fn, timeout) {
const spec = this.it_(description, fn, timeout);
return spec.metadata;
};
this.xit = function(description, fn, timeout) {
ensureIsNotNested('xit');
// xit(), like it(), doesn't always have a fn argument, so only check the
@@ -1069,9 +1074,9 @@ getJasmineRequireObj().Env = function(j$) {
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunctionOrAsync(fn, 'xit');
}
var spec = this.it.apply(this, arguments);
var spec = this.it_.apply(this, arguments);
spec.pend('Temporarily disabled with xit');
return spec;
return spec.metadata;
};
this.fit = function(description, fn, timeout) {
@@ -1081,7 +1086,7 @@ getJasmineRequireObj().Env = function(j$) {
currentDeclarationSuite.addChild(spec);
focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
return spec.metadata;
};
/**

View File

@@ -3,12 +3,6 @@ getJasmineRequireObj().Spec = function(j$) {
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
/**
* The unique ID of this spec.
* @name Spec#id
* @readonly
* @type {string}
*/
this.id = attrs.id;
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
@@ -238,30 +232,39 @@ 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,
Object.defineProperty(Spec.prototype, 'metadata', {
get: function() {
if (!this.metadata_) {
this.metadata_ = {
/**
* The unique ID of this spec.
* @name Spec#id
* @readonly
* @type {string}
*/
id: this.id,
/**
* The full description including all ancestors of this spec.
* @name Spec#getFullName
* @function
* @returns {string}
*/
getFullName: this.getFullName.bind(this)
};
};
/**
* 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 this.metadata_;
}
});
return Spec;
};
if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Spec = jasmineRequire.Spec;
}

View File

@@ -1,12 +1,6 @@
getJasmineRequireObj().Suite = function(j$) {
function Suite(attrs) {
this.env = attrs.env;
/**
* The unique ID of this suite.
* @name Suite#id
* @readonly
* @type {string}
*/
this.id = attrs.id;
this.parentSuite = attrs.parentSuite;
this.description = attrs.description;
@@ -191,57 +185,71 @@ getJasmineRequireObj().Suite = function(j$) {
);
};
Suite.prototype.buildMetadata = function(parentMetadata) {
Object.defineProperty(Suite.prototype, 'metadata', {
get: function() {
if (!this.metadata_) {
this.metadata_ = new SuiteMetadata(this);
}
return this.metadata_;
}
});
/**
* @interface Suite
* @see Env#topSuite
*/
function SuiteMetadata(suite) {
this.suite_ = suite;
/**
* @interface Suite
* @see Env#topSuite
* The unique ID of this suite.
* @name Suite#id
* @readonly
* @type {string}
*/
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)
};
this.id = suite.id;
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
* The parent of this suite, or null if this is the top suite.
* @name Suite#parentSuite
* @readonly
* @type {Suite}
*/
result.children = this.children.map(function(child) {
return child.buildMetadata(result);
});
this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null;
return result;
/**
* The description passed to the {@link describe} that created this suite.
* @name Suite#description
* @readonly
* @type {string}
*/
this.description = suite.description;
}
/**
* The full description including all ancestors of this suite.
* @name Suite#getFullName
* @function
* @returns {string}
*/
SuiteMetadata.prototype.getFullName = function() {
return this.suite_.getFullName();
};
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
*/
Object.defineProperty(SuiteMetadata.prototype, 'children', {
get: function() {
return this.suite_.children.map(child => child.metadata);
}
});
function isFailure(args) {
return !args[0];
}
return Suite;
};
if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Suite = jasmineRequire.Suite;
}