diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2bb7824d..8d4de616 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2022 Pivotal Labs +Copyright (c) 2008-2023 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -741,6 +741,7 @@ getJasmineRequireObj().Spec = function(j$) { this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; this.id = attrs.id; + this.filename = attrs.filename; this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = @@ -774,35 +775,7 @@ getJasmineRequireObj().Spec = function(j$) { this.exclude(); } - /** - * @typedef SpecResult - * @property {String} id - The unique id of this spec. - * @property {String} description - The description passed to the {@link it} that created this spec. - * @property {String} fullName - The full description including all ancestors of this spec. - * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. - * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. - * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. - * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. - * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. - * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. - * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} - * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. - * @since 2.0.0 - */ - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - failedExpectations: [], - passedExpectations: [], - deprecationWarnings: [], - pendingReason: '', - duration: null, - properties: null, - debugLogs: null - }; - - this.reportedDone = false; + this.reset(); } Spec.prototype.addExpectationResult = function(passed, data, isError) { @@ -912,14 +885,31 @@ getJasmineRequireObj().Spec = function(j$) { }; Spec.prototype.reset = function() { + /** + * @typedef SpecResult + * @property {String} id - The unique id of this spec. + * @property {String} description - The description passed to the {@link it} that created this spec. + * @property {String} fullName - The full description including all ancestors of this spec. + * @property {String} filename - The name of the file the spec was defined in. + * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. + * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. + * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. + * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. + * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. + * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} + * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. + * @since 2.0.0 + */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), + filename: this.filename, failedExpectations: [], passedExpectations: [], deprecationWarnings: [], - pendingReason: this.excludeMessage, + pendingReason: this.excludeMessage || '', duration: null, properties: null, debugLogs: null @@ -1816,17 +1806,23 @@ getJasmineRequireObj().Env = function(j$) { this.describe = function(description, definitionFn) { ensureIsNotNested('describe'); - return suiteBuilder.describe(description, definitionFn).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.describe(description, definitionFn, filename) + .metadata; }; this.xdescribe = function(description, definitionFn) { ensureIsNotNested('xdescribe'); - return suiteBuilder.xdescribe(description, definitionFn).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.xdescribe(description, definitionFn, filename) + .metadata; }; this.fdescribe = function(description, definitionFn) { ensureIsNotNested('fdescribe'); - return suiteBuilder.fdescribe(description, definitionFn).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.fdescribe(description, definitionFn, filename) + .metadata; }; function specResultCallback(spec, result, next) { @@ -1853,17 +1849,20 @@ getJasmineRequireObj().Env = function(j$) { this.it = function(description, fn, timeout) { ensureIsNotNested('it'); - return suiteBuilder.it(description, fn, timeout).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.it(description, fn, timeout, filename).metadata; }; this.xit = function(description, fn, timeout) { ensureIsNotNested('xit'); - return suiteBuilder.xit(description, fn, timeout).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.xit(description, fn, timeout, filename).metadata; }; this.fit = function(description, fn, timeout) { ensureIsNotNested('fit'); - return suiteBuilder.fit(description, fn, timeout).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.fit(description, fn, timeout, filename).metadata; }; /** @@ -2003,6 +2002,10 @@ getJasmineRequireObj().Env = function(j$) { }; } + function callerCallerFilename() { + return new j$.StackTrace(new Error()).frames[3].file; + } + return Env; }; @@ -9530,6 +9533,7 @@ getJasmineRequireObj().Suite = function(j$) { this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; + this.filename = attrs.filename; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; @@ -9635,6 +9639,7 @@ getJasmineRequireObj().Suite = function(j$) { * @property {String} id - The unique id of this suite. * @property {String} description - The description text passed to the {@link describe} that made this suite. * @property {String} fullName - The full description including all ancestors of this suite. + * @property {String} filename - The name of the file the suite was defined in. * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. @@ -9646,6 +9651,7 @@ getJasmineRequireObj().Suite = function(j$) { id: this.id, description: this.description, fullName: this.getFullName(), + filename: this.filename, failedExpectations: [], deprecationWarnings: [], duration: null, @@ -9873,9 +9879,9 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { this.focusedRunables = []; } - describe(description, definitionFn) { + describe(description, definitionFn, filename) { ensureIsFunction(definitionFn, 'describe'); - const suite = this.suiteFactory_(description); + const suite = this.suiteFactory_(description, filename); if (definitionFn.length > 0) { throw new Error('describe does not expect any arguments'); } @@ -9886,9 +9892,9 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return suite; } - fdescribe(description, definitionFn) { + fdescribe(description, definitionFn, filename) { ensureIsFunction(definitionFn, 'fdescribe'); - const suite = this.suiteFactory_(description); + const suite = this.suiteFactory_(description, filename); suite.isFocused = true; this.focusedRunables.push(suite.id); @@ -9898,37 +9904,37 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return suite; } - xdescribe(description, definitionFn) { + xdescribe(description, definitionFn, filename) { ensureIsFunction(definitionFn, 'xdescribe'); - const suite = this.suiteFactory_(description); + const suite = this.suiteFactory_(description, filename); suite.exclude(); this.addSpecsToSuite_(suite, definitionFn); return suite; } - it(description, fn, timeout) { + it(description, fn, timeout, filename) { // it() sometimes doesn't have a fn argument, so only check the type if // it's given. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'it'); } - return this.it_(description, fn, timeout); + return this.it_(description, fn, timeout, filename); } - xit(description, fn, timeout) { + xit(description, fn, timeout, filename) { // xit(), like it(), doesn't always have a fn argument, so only check the // type when needed. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'xit'); } - const spec = this.it_(description, fn, timeout); + const spec = this.it_(description, fn, timeout, filename); spec.exclude('Temporarily disabled with xit'); return spec; } - fit(description, fn, timeout) { + fit(description, fn, timeout, filename) { // Unlike it and xit, the function is required because it doesn't make // sense to focus on nothing. ensureIsFunctionOrAsync(fn, 'fit'); @@ -9936,7 +9942,7 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { if (timeout) { j$.util.validateTimeout(timeout); } - const spec = this.specFactory_(description, fn, timeout); + const spec = this.specFactory_(description, fn, timeout, filename); this.currentDeclarationSuite_.addChild(spec); this.focusedRunables.push(spec.id); this.unfocusAncestor_(); @@ -9996,12 +10002,12 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { }); } - it_(description, fn, timeout) { + it_(description, fn, timeout, filename) { if (timeout) { j$.util.validateTimeout(timeout); } - const spec = this.specFactory_(description, fn, timeout); + const spec = this.specFactory_(description, fn, timeout, filename); if (this.currentDeclarationSuite_.markedExcluding) { spec.exclude(); } @@ -10010,11 +10016,12 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return spec; } - suiteFactory_(description) { + suiteFactory_(description, filename) { const config = this.env_.configuration(); return new j$.Suite({ id: 'suite' + this.nextSuiteId_++, description, + filename, parentSuite: this.currentDeclarationSuite_, timer: new j$.Timer(), expectationFactory: this.expectationFactory_, @@ -10047,12 +10054,13 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { this.currentDeclarationSuite_ = parentSuite; } - specFactory_(description, fn, timeout) { + specFactory_(description, fn, timeout, filename) { this.totalSpecsDefined++; const config = this.env_.configuration(); const suite = this.currentDeclarationSuite_; const spec = new j$.Spec({ id: 'spec' + this.nextSpecId_++, + filename, beforeAndAfterFns: beforeAndAfterFns(suite), expectationFactory: this.expectationFactory_, asyncExpectationFactory: this.specAsyncExpectationFactory_, diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 33bea8b3..40e84424 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -195,6 +195,7 @@ describe('Spec', function() { onStart: startCallback, resultCallback: resultCallback, description: 'with a spec', + filename: 'someSpecFile.js', getSpecName: function() { return 'a suite with a spec'; }, @@ -219,6 +220,7 @@ describe('Spec', function() { status: 'pending', description: 'with a spec', fullName: 'a suite with a spec', + filename: 'someSpecFile.js', failedExpectations: [], passedExpectations: [], deprecationWarnings: [], diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 8f2990ad..4923a9bd 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -4004,6 +4004,99 @@ describe('Env integration', function() { ); }); + it('reports suite and spec filenames', async function() { + const methods = ['suiteStarted', 'suiteDone', 'specStarted', 'specDone']; + const reporter = jasmine.createSpyObj('reporter', methods); + env.addReporter(reporter); + + // Simulate calling through global it and describe, + // which add another stack frame vs calling env methods directly + function describeShim(name, fn) { + env.describe(name, fn); + } + function itShim(name, fn) { + env.it(name, fn); + } + + describeShim('a suite', function() { + itShim('a spec', function() {}); + }); + + await env.execute(); + + for (const method of methods) { + expect(reporter[method]) + .withContext(method) + .toHaveBeenCalledWith( + jasmine.objectContaining({ + filename: jasmine.stringMatching(/EnvSpec\.js$/) + }) + ); + } + }); + + it('reports skipped suite and spec filenames', async function() { + const methods = ['suiteStarted', 'suiteDone', 'specStarted', 'specDone']; + const reporter = jasmine.createSpyObj('reporter', methods); + env.addReporter(reporter); + + // Simulate calling through global it and describe, + // which add another stack frame vs calling env methods directly + function xdescribeShim(name, fn) { + env.xdescribe(name, fn); + } + function xitShim(name, fn) { + env.xit(name, fn); + } + + xdescribeShim('a suite', function() { + xitShim('a spec', function() {}); + }); + + await env.execute(); + + for (const method of methods) { + expect(reporter[method]) + .withContext(method) + .toHaveBeenCalledWith( + jasmine.objectContaining({ + filename: jasmine.stringMatching(/EnvSpec\.js$/) + }) + ); + } + }); + + it('reports focused suite and spec filenames', async function() { + const methods = ['suiteStarted', 'suiteDone', 'specStarted', 'specDone']; + const reporter = jasmine.createSpyObj('reporter', methods); + env.addReporter(reporter); + + // Simulate calling through global it and describe, + // which add another stack frame vs calling env methods directly + function fdescribeShim(name, fn) { + env.fdescribe(name, fn); + } + function fitShim(name, fn) { + env.fit(name, fn); + } + + fdescribeShim('a suite', function() { + fitShim('a spec', function() {}); + }); + + await env.execute(); + + for (const method of methods) { + expect(reporter[method]) + .withContext(method) + .toHaveBeenCalledWith( + jasmine.objectContaining({ + filename: jasmine.stringMatching(/EnvSpec\.js$/) + }) + ); + } + }); + function browserEventMethods() { return { addEventListener() {}, diff --git a/src/core/Env.js b/src/core/Env.js index b6fabb6d..115dcd5f 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -674,17 +674,23 @@ getJasmineRequireObj().Env = function(j$) { this.describe = function(description, definitionFn) { ensureIsNotNested('describe'); - return suiteBuilder.describe(description, definitionFn).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.describe(description, definitionFn, filename) + .metadata; }; this.xdescribe = function(description, definitionFn) { ensureIsNotNested('xdescribe'); - return suiteBuilder.xdescribe(description, definitionFn).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.xdescribe(description, definitionFn, filename) + .metadata; }; this.fdescribe = function(description, definitionFn) { ensureIsNotNested('fdescribe'); - return suiteBuilder.fdescribe(description, definitionFn).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.fdescribe(description, definitionFn, filename) + .metadata; }; function specResultCallback(spec, result, next) { @@ -711,17 +717,20 @@ getJasmineRequireObj().Env = function(j$) { this.it = function(description, fn, timeout) { ensureIsNotNested('it'); - return suiteBuilder.it(description, fn, timeout).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.it(description, fn, timeout, filename).metadata; }; this.xit = function(description, fn, timeout) { ensureIsNotNested('xit'); - return suiteBuilder.xit(description, fn, timeout).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.xit(description, fn, timeout, filename).metadata; }; this.fit = function(description, fn, timeout) { ensureIsNotNested('fit'); - return suiteBuilder.fit(description, fn, timeout).metadata; + const filename = callerCallerFilename(); + return suiteBuilder.fit(description, fn, timeout, filename).metadata; }; /** @@ -861,5 +870,9 @@ getJasmineRequireObj().Env = function(j$) { }; } + function callerCallerFilename() { + return new j$.StackTrace(new Error()).frames[3].file; + } + return Env; }; diff --git a/src/core/Spec.js b/src/core/Spec.js index f4149622..81544c46 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -4,6 +4,7 @@ getJasmineRequireObj().Spec = function(j$) { this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; this.id = attrs.id; + this.filename = attrs.filename; this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = @@ -37,35 +38,7 @@ getJasmineRequireObj().Spec = function(j$) { this.exclude(); } - /** - * @typedef SpecResult - * @property {String} id - The unique id of this spec. - * @property {String} description - The description passed to the {@link it} that created this spec. - * @property {String} fullName - The full description including all ancestors of this spec. - * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. - * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. - * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. - * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. - * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. - * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. - * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} - * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. - * @since 2.0.0 - */ - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - failedExpectations: [], - passedExpectations: [], - deprecationWarnings: [], - pendingReason: '', - duration: null, - properties: null, - debugLogs: null - }; - - this.reportedDone = false; + this.reset(); } Spec.prototype.addExpectationResult = function(passed, data, isError) { @@ -175,14 +148,31 @@ getJasmineRequireObj().Spec = function(j$) { }; Spec.prototype.reset = function() { + /** + * @typedef SpecResult + * @property {String} id - The unique id of this spec. + * @property {String} description - The description passed to the {@link it} that created this spec. + * @property {String} fullName - The full description including all ancestors of this spec. + * @property {String} filename - The name of the file the spec was defined in. + * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. + * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. + * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. + * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. + * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. + * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} + * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. + * @since 2.0.0 + */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), + filename: this.filename, failedExpectations: [], passedExpectations: [], deprecationWarnings: [], - pendingReason: this.excludeMessage, + pendingReason: this.excludeMessage || '', duration: null, properties: null, debugLogs: null diff --git a/src/core/Suite.js b/src/core/Suite.js index 449ff861..5a1a38a7 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -4,6 +4,7 @@ getJasmineRequireObj().Suite = function(j$) { this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; + this.filename = attrs.filename; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; @@ -109,6 +110,7 @@ getJasmineRequireObj().Suite = function(j$) { * @property {String} id - The unique id of this suite. * @property {String} description - The description text passed to the {@link describe} that made this suite. * @property {String} fullName - The full description including all ancestors of this suite. + * @property {String} filename - The name of the file the suite was defined in. * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. @@ -120,6 +122,7 @@ getJasmineRequireObj().Suite = function(j$) { id: this.id, description: this.description, fullName: this.getFullName(), + filename: this.filename, failedExpectations: [], deprecationWarnings: [], duration: null, diff --git a/src/core/SuiteBuilder.js b/src/core/SuiteBuilder.js index c29b2f40..50aabeb3 100644 --- a/src/core/SuiteBuilder.js +++ b/src/core/SuiteBuilder.js @@ -22,9 +22,9 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { this.focusedRunables = []; } - describe(description, definitionFn) { + describe(description, definitionFn, filename) { ensureIsFunction(definitionFn, 'describe'); - const suite = this.suiteFactory_(description); + const suite = this.suiteFactory_(description, filename); if (definitionFn.length > 0) { throw new Error('describe does not expect any arguments'); } @@ -35,9 +35,9 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return suite; } - fdescribe(description, definitionFn) { + fdescribe(description, definitionFn, filename) { ensureIsFunction(definitionFn, 'fdescribe'); - const suite = this.suiteFactory_(description); + const suite = this.suiteFactory_(description, filename); suite.isFocused = true; this.focusedRunables.push(suite.id); @@ -47,37 +47,37 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return suite; } - xdescribe(description, definitionFn) { + xdescribe(description, definitionFn, filename) { ensureIsFunction(definitionFn, 'xdescribe'); - const suite = this.suiteFactory_(description); + const suite = this.suiteFactory_(description, filename); suite.exclude(); this.addSpecsToSuite_(suite, definitionFn); return suite; } - it(description, fn, timeout) { + it(description, fn, timeout, filename) { // it() sometimes doesn't have a fn argument, so only check the type if // it's given. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'it'); } - return this.it_(description, fn, timeout); + return this.it_(description, fn, timeout, filename); } - xit(description, fn, timeout) { + xit(description, fn, timeout, filename) { // xit(), like it(), doesn't always have a fn argument, so only check the // type when needed. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'xit'); } - const spec = this.it_(description, fn, timeout); + const spec = this.it_(description, fn, timeout, filename); spec.exclude('Temporarily disabled with xit'); return spec; } - fit(description, fn, timeout) { + fit(description, fn, timeout, filename) { // Unlike it and xit, the function is required because it doesn't make // sense to focus on nothing. ensureIsFunctionOrAsync(fn, 'fit'); @@ -85,7 +85,7 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { if (timeout) { j$.util.validateTimeout(timeout); } - const spec = this.specFactory_(description, fn, timeout); + const spec = this.specFactory_(description, fn, timeout, filename); this.currentDeclarationSuite_.addChild(spec); this.focusedRunables.push(spec.id); this.unfocusAncestor_(); @@ -145,12 +145,12 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { }); } - it_(description, fn, timeout) { + it_(description, fn, timeout, filename) { if (timeout) { j$.util.validateTimeout(timeout); } - const spec = this.specFactory_(description, fn, timeout); + const spec = this.specFactory_(description, fn, timeout, filename); if (this.currentDeclarationSuite_.markedExcluding) { spec.exclude(); } @@ -159,11 +159,12 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { return spec; } - suiteFactory_(description) { + suiteFactory_(description, filename) { const config = this.env_.configuration(); return new j$.Suite({ id: 'suite' + this.nextSuiteId_++, description, + filename, parentSuite: this.currentDeclarationSuite_, timer: new j$.Timer(), expectationFactory: this.expectationFactory_, @@ -196,12 +197,13 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { this.currentDeclarationSuite_ = parentSuite; } - specFactory_(description, fn, timeout) { + specFactory_(description, fn, timeout, filename) { this.totalSpecsDefined++; const config = this.env_.configuration(); const suite = this.currentDeclarationSuite_; const spec = new j$.Spec({ id: 'spec' + this.nextSpecId_++, + filename, beforeAndAfterFns: beforeAndAfterFns(suite), expectationFactory: this.expectationFactory_, asyncExpectationFactory: this.specAsyncExpectationFactory_,