diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index c6665c2f..76dbb7bb 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -792,11 +792,11 @@ getJasmineRequireObj().Spec = function(j$) { this.onStart = attrs.onStart || function() {}; this.autoCleanClosures = attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; - this.getSpecName = - attrs.getSpecName || - function() { - return ''; - }; + + this.getPath = function() { + return attrs.getPath ? attrs.getPath(this) : []; + }; + this.onLateError = attrs.onLateError || function() {}; this.catchingExceptions = attrs.catchingExceptions || @@ -1022,7 +1022,7 @@ getJasmineRequireObj().Spec = function(j$) { }; Spec.prototype.getFullName = function() { - return this.getSpecName(this); + return this.getPath().join(' '); }; Spec.prototype.addDeprecationWarning = function(deprecation) { @@ -1076,6 +1076,10 @@ getJasmineRequireObj().Spec = function(j$) { * @since 2.0.0 */ Object.defineProperty(Spec.prototype, 'metadata', { + // NOTE: Although most of jasmine-core only exposes these metadata objects, + // actual Spec instances are still passed to Configuration#specFilter. Until + // that is fixed, it's important to make sure that all metadata properties + // also exist in compatible form on the underlying Spec. get: function() { if (!this.metadata_) { this.metadata_ = { @@ -1104,7 +1108,16 @@ getJasmineRequireObj().Spec = function(j$) { * @returns {string} * @since 2.0.0 */ - getFullName: this.getFullName.bind(this) + getFullName: this.getFullName.bind(this), + + /** + * The full path of the spec, as an array of names. + * @name Spec#getPath + * @function + * @returns {Array.} + * @since 5.7.0 + */ + getPath: this.getPath.bind(this) }; } @@ -10947,9 +10960,7 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { resultCallback: (result, next) => { this.specResultCallback_(spec, result, next); }, - getSpecName: function(spec) { - return getSpecName(spec, suite); - }, + getPath: spec => this.getSpecPath_(spec, suite), onStart: (spec, next) => this.specStarted_(spec, suite, next), description: description, userContext: function() { @@ -10966,6 +10977,17 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return spec; } + getSpecPath_(spec, suite) { + const path = [spec.description]; + + while (suite && suite !== this.topSuite) { + path.unshift(suite.description); + suite = suite.parentSuite; + } + + return path; + } + unfocusAncestor_() { const focusedAncestor = findFocusedAncestor( this.currentDeclarationSuite_ @@ -11029,16 +11051,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { }; } - function getSpecName(spec, suite) { - const fullName = [spec.description], - suiteFullName = suite.getFullName(); - - if (suiteFullName !== '') { - fullName.unshift(suiteFullName); - } - return fullName.join(' '); - } - return SuiteBuilder; }; diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 599760ed..bcde9478 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -197,8 +197,8 @@ describe('Spec', function() { description: 'with a spec', parentSuiteId: 'suite1', filename: 'someSpecFile.js', - getSpecName: function() { - return 'a suite with a spec'; + getPath: function() { + return ['a suite', 'with a spec']; }, queueableFn: { fn: null } }); @@ -485,17 +485,33 @@ describe('Spec', function() { }); it('can return its full name', function() { - const specNameSpy = jasmine - .createSpy('specNameSpy') - .and.returnValue('expected val'); + const getPath = jasmine + .createSpy('getPath') + .and.returnValue(['expected', 'val']); const spec = new jasmineUnderTest.Spec({ - getSpecName: specNameSpy, + getPath, queueableFn: { fn: null } }); expect(spec.getFullName()).toBe('expected val'); - expect(specNameSpy.calls.mostRecent().args[0].id).toEqual(spec.id); + expect(getPath.calls.mostRecent().args[0]).toBe(spec); + }); + + it('can return its full path', function() { + const getPath = jasmine + .createSpy('getPath') + .and.returnValue(['expected val']); + + const spec = new jasmineUnderTest.Spec({ + getPath, + queueableFn: { fn: null } + }); + + expect(spec.getPath()).toEqual(['expected val']); + expect(getPath.calls.mostRecent().args[0]).toBe(spec); + + expect(spec.metadata.getPath()).toEqual(['expected val']); }); describe('when a spec is marked pending during execution', function() { @@ -586,8 +602,8 @@ describe('Spec', function() { spec = new jasmineUnderTest.Spec({ onLateError: onLateError, queueableFn: { fn: function() {} }, - getSpecName: function() { - return 'a spec'; + getPath: function() { + return ['a spec']; } }); diff --git a/spec/core/SuiteBuilderSpec.js b/spec/core/SuiteBuilderSpec.js index 0bde3a43..0f03579c 100644 --- a/spec/core/SuiteBuilderSpec.js +++ b/spec/core/SuiteBuilderSpec.js @@ -163,6 +163,20 @@ describe('SuiteBuilder', function() { expect(spec2.id).toMatch(/^spec[0-9]+$/); expect(spec1.id).not.toEqual(spec2.id); }); + + it('gives each spec a full path', function() { + const env = { configuration: () => ({}) }; + const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env }); + let spec; + + suiteBuilder.describe('a suite', function() { + suiteBuilder.describe('a nested suite', function() { + spec = suiteBuilder[fnName]('a spec', function() {}); + }); + }); + + expect(spec.getPath()).toEqual(['a suite', 'a nested suite', 'a spec']); + }); } function sameInstanceAs(expected) { diff --git a/src/core/Spec.js b/src/core/Spec.js index d3781159..6ba9870a 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -21,11 +21,11 @@ getJasmineRequireObj().Spec = function(j$) { this.onStart = attrs.onStart || function() {}; this.autoCleanClosures = attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; - this.getSpecName = - attrs.getSpecName || - function() { - return ''; - }; + + this.getPath = function() { + return attrs.getPath ? attrs.getPath(this) : []; + }; + this.onLateError = attrs.onLateError || function() {}; this.catchingExceptions = attrs.catchingExceptions || @@ -251,7 +251,7 @@ getJasmineRequireObj().Spec = function(j$) { }; Spec.prototype.getFullName = function() { - return this.getSpecName(this); + return this.getPath().join(' '); }; Spec.prototype.addDeprecationWarning = function(deprecation) { @@ -305,6 +305,10 @@ getJasmineRequireObj().Spec = function(j$) { * @since 2.0.0 */ Object.defineProperty(Spec.prototype, 'metadata', { + // NOTE: Although most of jasmine-core only exposes these metadata objects, + // actual Spec instances are still passed to Configuration#specFilter. Until + // that is fixed, it's important to make sure that all metadata properties + // also exist in compatible form on the underlying Spec. get: function() { if (!this.metadata_) { this.metadata_ = { @@ -333,7 +337,16 @@ getJasmineRequireObj().Spec = function(j$) { * @returns {string} * @since 2.0.0 */ - getFullName: this.getFullName.bind(this) + getFullName: this.getFullName.bind(this), + + /** + * The full path of the spec, as an array of names. + * @name Spec#getPath + * @function + * @returns {Array.} + * @since 5.7.0 + */ + getPath: this.getPath.bind(this) }; } diff --git a/src/core/SuiteBuilder.js b/src/core/SuiteBuilder.js index ef6010c9..b1052d46 100644 --- a/src/core/SuiteBuilder.js +++ b/src/core/SuiteBuilder.js @@ -250,9 +250,7 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { resultCallback: (result, next) => { this.specResultCallback_(spec, result, next); }, - getSpecName: function(spec) { - return getSpecName(spec, suite); - }, + getPath: spec => this.getSpecPath_(spec, suite), onStart: (spec, next) => this.specStarted_(spec, suite, next), description: description, userContext: function() { @@ -269,6 +267,17 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return spec; } + getSpecPath_(spec, suite) { + const path = [spec.description]; + + while (suite && suite !== this.topSuite) { + path.unshift(suite.description); + suite = suite.parentSuite; + } + + return path; + } + unfocusAncestor_() { const focusedAncestor = findFocusedAncestor( this.currentDeclarationSuite_ @@ -332,15 +341,5 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { }; } - function getSpecName(spec, suite) { - const fullName = [spec.description], - suiteFullName = suite.getFullName(); - - if (suiteFullName !== '') { - fullName.unshift(suiteFullName); - } - return fullName.join(' '); - } - return SuiteBuilder; };