diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js
index 2ebc6d0e..47035410 100644
--- a/lib/jasmine-core/jasmine-html.js
+++ b/lib/jasmine-core/jasmine-html.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
diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js
index 8d4de616..3e77af64 100644
--- a/lib/jasmine-core/jasmine.js
+++ b/lib/jasmine-core/jasmine.js
@@ -742,6 +742,7 @@ getJasmineRequireObj().Spec = function(j$) {
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
this.filename = attrs.filename;
+ this.parentSuiteId = attrs.parentSuiteId;
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns =
@@ -890,6 +891,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @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|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
* @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.
@@ -905,6 +907,7 @@ getJasmineRequireObj().Spec = function(j$) {
id: this.id,
description: this.description,
fullName: this.getFullName(),
+ parentSuiteId: this.parentSuiteId,
filename: this.filename,
failedExpectations: [],
passedExpectations: [],
@@ -9533,6 +9536,7 @@ getJasmineRequireObj().Suite = function(j$) {
this.id = attrs.id;
this.parentSuite = attrs.parentSuite;
this.description = attrs.description;
+ this.reportedParentSuiteId = attrs.reportedParentSuiteId;
this.filename = attrs.filename;
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
@@ -9639,6 +9643,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|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
* @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.
@@ -9651,6 +9656,7 @@ getJasmineRequireObj().Suite = function(j$) {
id: this.id,
description: this.description,
fullName: this.getFullName(),
+ parentSuiteId: this.reportedParentSuiteId,
filename: this.filename,
failedExpectations: [],
deprecationWarnings: [],
@@ -10018,11 +10024,15 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
suiteFactory_(description, filename) {
const config = this.env_.configuration();
+ const parentSuite = this.currentDeclarationSuite_;
+ const reportedParentSuiteId =
+ parentSuite === this.topSuite ? null : parentSuite.id;
return new j$.Suite({
id: 'suite' + this.nextSuiteId_++,
description,
filename,
- parentSuite: this.currentDeclarationSuite_,
+ parentSuite,
+ reportedParentSuiteId,
timer: new j$.Timer(),
expectationFactory: this.expectationFactory_,
asyncExpectationFactory: this.suiteAsyncExpectationFactory_,
@@ -10058,9 +10068,11 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
this.totalSpecsDefined++;
const config = this.env_.configuration();
const suite = this.currentDeclarationSuite_;
+ const parentSuiteId = suite === this.topSuite ? null : suite.id;
const spec = new j$.Spec({
id: 'spec' + this.nextSpecId_++,
filename,
+ parentSuiteId,
beforeAndAfterFns: beforeAndAfterFns(suite),
expectationFactory: this.expectationFactory_,
asyncExpectationFactory: this.specAsyncExpectationFactory_,
diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js
index 40e84424..599760ed 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',
+ parentSuiteId: 'suite1',
filename: 'someSpecFile.js',
getSpecName: function() {
return 'a suite with a spec';
@@ -220,6 +221,7 @@ describe('Spec', function() {
status: 'pending',
description: 'with a spec',
fullName: 'a suite with a spec',
+ parentSuiteId: 'suite1',
filename: 'someSpecFile.js',
failedExpectations: [],
passedExpectations: [],
diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js
index 4923a9bd..dbcaff2d 100644
--- a/spec/core/integration/EnvSpec.js
+++ b/spec/core/integration/EnvSpec.js
@@ -1933,11 +1933,17 @@ describe('Env integration', function() {
'specStarted',
'specDone'
]);
+ const suiteFullNameToId = {};
+ reporter.suiteStarted.and.callFake(function(e) {
+ suiteFullNameToId[e.fullName] = e.id;
+ });
env.addReporter(reporter);
+ env.it('a top level spec', function() {});
+
env.describe('A Suite', function() {
- env.it('with a top level spec', function() {
+ env.it('with a spec', function() {
env.expect(true).toBe(true);
});
env.describe('with a nested suite', function() {
@@ -1960,37 +1966,109 @@ describe('Env integration', function() {
await env.execute();
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
- totalSpecsDefined: 5,
+ totalSpecsDefined: 6,
order: jasmine.any(jasmineUnderTest.Order)
});
- expect(reporter.specDone.calls.count()).toBe(5);
+ expect(reporter.specStarted.calls.count()).toBe(6);
+ expect(reporter.specDone.calls.count()).toBe(6);
- expect(reporter.specDone).toHaveBeenCalledWith(
+ expect(reporter.specStarted).toHaveBeenCalledWith(
jasmine.objectContaining({
- description: 'with a top level spec',
- status: 'passed'
+ description: 'a top level spec',
+ parentSuiteId: null
})
);
-
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
- description: "with an x'ed spec",
- status: 'pending'
+ description: 'a top level spec',
+ status: 'passed',
+ parentSuiteId: null
+ })
+ );
+ expect(reporter.specStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'with a spec',
+ parentSuiteId: suiteFullNameToId['A Suite']
})
);
-
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
description: 'with a spec',
- status: 'failed'
+ status: 'passed',
+ parentSuiteId: suiteFullNameToId['A Suite']
})
);
+ expect(reporter.specStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: "with an x'ed spec",
+ parentSuiteId: suiteFullNameToId['A Suite with a nested suite']
+ })
+ );
+ expect(reporter.specDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: "with an x'ed spec",
+ status: 'pending',
+ parentSuiteId: suiteFullNameToId['A Suite with a nested suite']
+ })
+ );
+
+ expect(reporter.specStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'with a spec',
+ parentSuiteId: suiteFullNameToId['A Suite with a nested suite']
+ })
+ );
+ expect(reporter.specDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'with a spec',
+ status: 'failed',
+ parentSuiteId: suiteFullNameToId['A Suite with a nested suite']
+ })
+ );
+
+ expect(reporter.specStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'is pending',
+ parentSuiteId:
+ suiteFullNameToId['A Suite with only non-executable specs']
+ })
+ );
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
description: 'is pending',
- status: 'pending'
+ status: 'pending',
+ parentSuiteId:
+ suiteFullNameToId['A Suite with only non-executable specs']
+ })
+ );
+
+ expect(reporter.suiteStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'A Suite',
+ parentSuiteId: null
+ })
+ );
+ expect(reporter.suiteDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'A Suite',
+ status: 'passed',
+ parentSuiteId: null
+ })
+ );
+
+ expect(reporter.suiteStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'with a nested suite',
+ parentSuiteId: suiteFullNameToId['A Suite']
+ })
+ );
+ expect(reporter.suiteDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'with a nested suite',
+ status: 'passed',
+ parentSuiteId: suiteFullNameToId['A Suite']
})
);
@@ -2001,6 +2079,89 @@ describe('Env integration', function() {
expect(suiteResult.description).toEqual('A Suite');
});
+ it('reports focused specs and suites as expected', async function() {
+ const reporter = jasmine.createSpyObj('fakeReporter', [
+ 'suiteStarted',
+ 'suiteDone',
+ 'specStarted',
+ 'specDone'
+ ]);
+ const suiteFullNameToId = {};
+ reporter.suiteStarted.and.callFake(function(e) {
+ suiteFullNameToId[e.fullName] = e.id;
+ });
+
+ env.fit('a focused top level spec', function() {});
+
+ env.describe('a suite', function() {
+ env.fdescribe('a focused suite', function() {
+ env.fit('a focused spec', function() {});
+ });
+ });
+
+ env.addReporter(reporter);
+ await env.execute();
+
+ expect(reporter.specStarted).toHaveBeenCalledTimes(2);
+ expect(reporter.specDone).toHaveBeenCalledTimes(2);
+
+ expect(reporter.specStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a focused top level spec',
+ parentSuiteId: null
+ })
+ );
+ expect(reporter.specDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a focused top level spec',
+ status: 'passed',
+ parentSuiteId: null
+ })
+ );
+
+ expect(reporter.specStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a focused spec',
+ parentSuiteId: suiteFullNameToId['a suite a focused suite']
+ })
+ );
+ expect(reporter.specDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a focused spec',
+ status: 'passed',
+ parentSuiteId: suiteFullNameToId['a suite a focused suite']
+ })
+ );
+
+ expect(reporter.suiteStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a suite',
+ parentSuiteId: null
+ })
+ );
+ expect(reporter.suiteDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a suite',
+ status: 'passed',
+ parentSuiteId: null
+ })
+ );
+
+ expect(reporter.suiteStarted).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a focused suite',
+ parentSuiteId: suiteFullNameToId['a suite']
+ })
+ );
+ expect(reporter.suiteDone).toHaveBeenCalledWith(
+ jasmine.objectContaining({
+ description: 'a focused suite',
+ status: 'passed',
+ parentSuiteId: suiteFullNameToId['a suite']
+ })
+ );
+ });
+
it('should report the random seed at the beginning and end of execution', async function() {
const reporter = jasmine.createSpyObj('fakeReporter', [
'jasmineStarted',
diff --git a/src/core/Spec.js b/src/core/Spec.js
index 81544c46..52a24a5d 100644
--- a/src/core/Spec.js
+++ b/src/core/Spec.js
@@ -5,6 +5,7 @@ getJasmineRequireObj().Spec = function(j$) {
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
this.filename = attrs.filename;
+ this.parentSuiteId = attrs.parentSuiteId;
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns =
@@ -153,6 +154,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @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|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
* @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.
@@ -168,6 +170,7 @@ getJasmineRequireObj().Spec = function(j$) {
id: this.id,
description: this.description,
fullName: this.getFullName(),
+ parentSuiteId: this.parentSuiteId,
filename: this.filename,
failedExpectations: [],
passedExpectations: [],
diff --git a/src/core/Suite.js b/src/core/Suite.js
index 5a1a38a7..55a5227f 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.reportedParentSuiteId = attrs.reportedParentSuiteId;
this.filename = attrs.filename;
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
@@ -110,6 +111,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|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
* @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.
@@ -122,6 +124,7 @@ getJasmineRequireObj().Suite = function(j$) {
id: this.id,
description: this.description,
fullName: this.getFullName(),
+ parentSuiteId: this.reportedParentSuiteId,
filename: this.filename,
failedExpectations: [],
deprecationWarnings: [],
diff --git a/src/core/SuiteBuilder.js b/src/core/SuiteBuilder.js
index 50aabeb3..e02955b4 100644
--- a/src/core/SuiteBuilder.js
+++ b/src/core/SuiteBuilder.js
@@ -161,11 +161,15 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
suiteFactory_(description, filename) {
const config = this.env_.configuration();
+ const parentSuite = this.currentDeclarationSuite_;
+ const reportedParentSuiteId =
+ parentSuite === this.topSuite ? null : parentSuite.id;
return new j$.Suite({
id: 'suite' + this.nextSuiteId_++,
description,
filename,
- parentSuite: this.currentDeclarationSuite_,
+ parentSuite,
+ reportedParentSuiteId,
timer: new j$.Timer(),
expectationFactory: this.expectationFactory_,
asyncExpectationFactory: this.suiteAsyncExpectationFactory_,
@@ -201,9 +205,11 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
this.totalSpecsDefined++;
const config = this.env_.configuration();
const suite = this.currentDeclarationSuite_;
+ const parentSuiteId = suite === this.topSuite ? null : suite.id;
const spec = new j$.Spec({
id: 'spec' + this.nextSpecId_++,
filename,
+ parentSuiteId,
beforeAndAfterFns: beforeAndAfterFns(suite),
expectationFactory: this.expectationFactory_,
asyncExpectationFactory: this.specAsyncExpectationFactory_,