diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index ad86289c..303e567e 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -557,6 +557,7 @@ getJasmineRequireObj().Spec = function(j$) { this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + this.timer = attrs.timer || j$.noopTimer; if (!this.queueableFn.fn) { this.pend(); @@ -572,6 +573,7 @@ getJasmineRequireObj().Spec = function(j$) { * @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. */ this.result = { id: this.id, @@ -580,7 +582,8 @@ getJasmineRequireObj().Spec = function(j$) { failedExpectations: [], passedExpectations: [], deprecationWarnings: [], - pendingReason: '' + pendingReason: '', + duration: null, }; } @@ -610,6 +613,7 @@ getJasmineRequireObj().Spec = function(j$) { var onStart = { fn: function(done) { + self.timer.start(); self.onStart(self, done); } }; @@ -633,6 +637,7 @@ getJasmineRequireObj().Spec = function(j$) { self.onException.apply(self, arguments); }, onComplete: function() { + self.result.duration = self.timer.elapsed(); onComplete(self.result.status === 'failed' && new j$.StopExecutionError('spec failed')); }, userContext: this.userContext() @@ -1290,6 +1295,7 @@ getJasmineRequireObj().Env = function(j$) { currentlyExecutingSuites.push(suite); defaultResourcesForRunnable(suite.id, suite.parentSuite.id); reporter.suiteStarted(suite.result, next); + suite.startTimer(); }, nodeComplete: function(suite, result, next) { if (suite !== currentSuite()) { @@ -1302,7 +1308,7 @@ getJasmineRequireObj().Env = function(j$) { if (result.status === 'failed') { hasFailures = true; } - + suite.endTimer(); reporter.suiteDone(result, next); }, orderChildren: function(node) { @@ -1582,9 +1588,9 @@ getJasmineRequireObj().Env = function(j$) { fn: fn, timeout: timeout || 0 }, - throwOnExpectationFailure: config.oneFailurePerSpec + throwOnExpectationFailure: config.oneFailurePerSpec, + timer: new j$.Timer(), }); - return spec; function specResultCallback(result, next) { @@ -6582,6 +6588,8 @@ getJasmineRequireObj().Suite = function(j$) { this.beforeAllFns = []; this.afterAllFns = []; + this.timer = attrs.timer || j$.noopTimer; + this.children = []; /** @@ -6592,13 +6600,15 @@ getJasmineRequireObj().Suite = function(j$) { * @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. + * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], - deprecationWarnings: [] + deprecationWarnings: [], + duration: null, }; } @@ -6640,6 +6650,14 @@ getJasmineRequireObj().Suite = function(j$) { this.afterAllFns.unshift(fn); }; + Suite.prototype.startTimer = function() { + this.timer.start(); + }; + + Suite.prototype.endTimer = function() { + this.result.duration = this.timer.elapsed(); + }; + function removeFns(queueableFns) { for(var i = 0; i < queueableFns.length; i++) { queueableFns[i].fn = null; diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index df75d122..1191f7c3 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -207,7 +207,8 @@ describe("Spec", function() { failedExpectations: [], passedExpectations: [], deprecationWarnings: [], - pendingReason: '' + pendingReason: '', + duration: null, }, 'things'); }); @@ -242,6 +243,22 @@ describe("Spec", function() { expect(done).toHaveBeenCalledWith(jasmine.any(jasmineUnderTest.StopExecutionError)); }); + it("should report the duration of the test", function() { + var done = jasmine.createSpy('done callback'), + timer = jasmine.createSpyObj('timer', {'start': null, elapsed: 77000}), + spec = new jasmineUnderTest.Spec({ + queueableFn: { fn: jasmine.createSpy("spec body")}, + catchExceptions: function() { return false; }, + resultCallback: function() {}, + queueRunnerFactory: function(attrs) { + attrs.onComplete(); + }, + timer: timer, + }); + spec.execute(done); + expect(spec.result.duration).toBe(77000); + }); + it("#status returns passing by default", function() { var spec = new jasmineUnderTest.Spec({queueableFn: { fn: jasmine.createSpy("spec body")} }); expect(spec.status()).toBe('passed'); diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index fd9144d9..1739259e 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -111,6 +111,19 @@ describe("Suite", function() { expect(suite.getResult().failedExpectations).toEqual([]); }); + it("calls timer to compute duration", function(){ + var env = new jasmineUnderTest.Env(), + suite = new jasmineUnderTest.Suite({ + env: env, + id: 456, + description: "I am a suite", + timer: jasmine.createSpyObj('timer', {'start': null, elapsed: 77000}), + }); + suite.startTimer(); + suite.endTimer(); + expect(suite.getResult().duration).toEqual(77000); + }); + describe('#sharedUserContext', function() { beforeEach(function() { this.suite = new jasmineUnderTest.Suite({}); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 6314123d..3a10e30b 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -1436,6 +1436,9 @@ describe("Env integration", function() { status: 'pending' })); + var suiteDone = reporter.suiteDone.calls.argsFor(0)[0]; + expect(typeof suiteDone.duration).toBe('number'); + var suiteResult = reporter.suiteStarted.calls.argsFor(0)[0]; expect(suiteResult.description).toEqual("A Suite"); diff --git a/src/core/Env.js b/src/core/Env.js index f407745d..680d0d49 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -512,6 +512,7 @@ getJasmineRequireObj().Env = function(j$) { currentlyExecutingSuites.push(suite); defaultResourcesForRunnable(suite.id, suite.parentSuite.id); reporter.suiteStarted(suite.result, next); + suite.startTimer(); }, nodeComplete: function(suite, result, next) { if (suite !== currentSuite()) { @@ -524,7 +525,7 @@ getJasmineRequireObj().Env = function(j$) { if (result.status === 'failed') { hasFailures = true; } - + suite.endTimer(); reporter.suiteDone(result, next); }, orderChildren: function(node) { @@ -804,9 +805,9 @@ getJasmineRequireObj().Env = function(j$) { fn: fn, timeout: timeout || 0 }, - throwOnExpectationFailure: config.oneFailurePerSpec + throwOnExpectationFailure: config.oneFailurePerSpec, + timer: new j$.Timer(), }); - return spec; function specResultCallback(result, next) { diff --git a/src/core/Spec.js b/src/core/Spec.js index 524dece6..8adbacd7 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -14,6 +14,7 @@ getJasmineRequireObj().Spec = function(j$) { this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + this.timer = attrs.timer || j$.noopTimer; if (!this.queueableFn.fn) { this.pend(); @@ -29,6 +30,7 @@ getJasmineRequireObj().Spec = function(j$) { * @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. */ this.result = { id: this.id, @@ -37,7 +39,8 @@ getJasmineRequireObj().Spec = function(j$) { failedExpectations: [], passedExpectations: [], deprecationWarnings: [], - pendingReason: '' + pendingReason: '', + duration: null, }; } @@ -67,6 +70,7 @@ getJasmineRequireObj().Spec = function(j$) { var onStart = { fn: function(done) { + self.timer.start(); self.onStart(self, done); } }; @@ -90,6 +94,7 @@ getJasmineRequireObj().Spec = function(j$) { self.onException.apply(self, arguments); }, onComplete: function() { + self.result.duration = self.timer.elapsed(); onComplete(self.result.status === 'failed' && new j$.StopExecutionError('spec failed')); }, userContext: this.userContext() diff --git a/src/core/Suite.js b/src/core/Suite.js index c85f10c7..e076e73f 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -14,6 +14,8 @@ getJasmineRequireObj().Suite = function(j$) { this.beforeAllFns = []; this.afterAllFns = []; + this.timer = attrs.timer || j$.noopTimer; + this.children = []; /** @@ -24,13 +26,15 @@ getJasmineRequireObj().Suite = function(j$) { * @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. + * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], - deprecationWarnings: [] + deprecationWarnings: [], + duration: null, }; } @@ -72,6 +76,14 @@ getJasmineRequireObj().Suite = function(j$) { this.afterAllFns.unshift(fn); }; + Suite.prototype.startTimer = function() { + this.timer.start(); + }; + + Suite.prototype.endTimer = function() { + this.result.duration = this.timer.elapsed(); + }; + function removeFns(queueableFns) { for(var i = 0; i < queueableFns.length; i++) { queueableFns[i].fn = null;