From 179e54b9fb53f5ee508fbbb19f5aaa3d3ea16a9c Mon Sep 17 00:00:00 2001 From: "Davis W. Frank and Sheel Choksi" Date: Wed, 3 Jul 2013 09:29:52 -0700 Subject: [PATCH] Refactor suite timing out of Env and into each Reporter [finishes #45659879] --- lib/jasmine-core/boot.js | 8 +++--- lib/jasmine-core/boot/boot.js | 8 +++--- lib/jasmine-core/jasmine-html.js | 12 +++++++-- lib/jasmine-core/jasmine.js | 38 ++++++++++++++++++++++----- spec/console/ConsoleReporterSpec.js | 36 ++++++++++++++++++++------ spec/core/JsApiReporterSpec.js | 40 ++++++++++++++++++++--------- spec/core/TimerSpec.js | 13 ++++++++++ spec/html/HtmlReporterSpec.js | 22 ++++++++++++++-- spec/node_suite.js | 7 +++-- spec/support/dev_boot.js | 7 +++-- src/console/ConsoleReporter.js | 12 +++++++-- src/console/console.js | 12 +++++++-- src/core/JsApiReporter.js | 19 +++++++++----- src/core/Timer.js | 18 +++++++++++++ src/core/requireCore.js | 1 + src/html/HtmlReporter.js | 12 +++++++-- 16 files changed, 213 insertions(+), 52 deletions(-) create mode 100644 spec/core/TimerSpec.js create mode 100644 src/core/Timer.js diff --git a/lib/jasmine-core/boot.js b/lib/jasmine-core/boot.js index 1c1345ac..5e0aaff5 100644 --- a/lib/jasmine-core/boot.js +++ b/lib/jasmine-core/boot.js @@ -73,8 +73,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. clearTimeout: env.clock.clearTimeout, setInterval: env.clock.setInterval, clearInterval: env.clock.clearInterval, - - jsApiReporter: new jasmine.JsApiReporter(jasmine) + jsApiReporter: new jasmine.JsApiReporter({ + timer: new jasmine.Timer() + }) }; if (typeof window == "undefined" && typeof exports == "object") { @@ -97,7 +98,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); }, getContainer: function() { return document.body; }, createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); } + createTextNode: function() { return document.createTextNode.apply(document, arguments); }, + timer: new jasmine.Timer() }); env.addReporter(jasmineInterface.jsApiReporter); diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index 908aea4c..38586bf8 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -51,8 +51,9 @@ clearTimeout: env.clock.clearTimeout, setInterval: env.clock.setInterval, clearInterval: env.clock.clearInterval, - - jsApiReporter: new jasmine.JsApiReporter(jasmine) + jsApiReporter: new jasmine.JsApiReporter({ + timer: new jasmine.Timer() + }) }; if (typeof window == "undefined" && typeof exports == "object") { @@ -75,7 +76,8 @@ onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); }, getContainer: function() { return document.body; }, createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); } + createTextNode: function() { return document.createTextNode.apply(document, arguments); }, + timer: new jasmine.Timer() }); env.addReporter(jasmineInterface.jsApiReporter); diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 08df7bcb..3abb44ba 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -27,12 +27,19 @@ jasmineRequire.html = function(j$) { j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); }; jasmineRequire.HtmlReporter = function() { + + var noopTimer = { + start: function(){}, + elapsed: function(){ return 0; } + }; + function HtmlReporter(options) { var env = options.env || {}, getContainer = options.getContainer, createElement = options.createElement, createTextNode = options.createTextNode, onRaiseExceptionsClick = options.onRaiseExceptionsClick, + timer = options.timer || noopTimer, results = [], specsExecuted = 0, failureCount = 0, @@ -60,6 +67,7 @@ jasmineRequire.HtmlReporter = function() { var totalSpecsDefined; this.jasmineStarted = function(options) { totalSpecsDefined = options.totalSpecsDefined || 0; + timer.start(); }; var summary = createDom("div", {className: "summary"}); @@ -120,9 +128,9 @@ jasmineRequire.HtmlReporter = function() { } }; - this.jasmineDone = function(options) { + this.jasmineDone = function() { var banner = find(".banner"); - banner.appendChild(createDom("span", {className: "duration"}, "finished in " + options.executionTime / 1000 + "s")); + banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s")); var alert = find(".alert"); diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 9f40ee4a..8a6ee24c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -50,6 +50,7 @@ getJasmineRequireObj().core = function(jRequire) { j$.Spec = jRequire.Spec(); j$.Spy = jRequire.Spy(j$); j$.Suite = jRequire.Suite(); + j$.Timer = jRequire.Timer(); j$.version = jRequire.version(); j$.matchers = jRequire.requireMatchers(jRequire, j$); @@ -648,23 +649,30 @@ getJasmineRequireObj().Env = function(j$) { }; getJasmineRequireObj().JsApiReporter = function() { - function JsApiReporter(jasmine) { // TODO: this doesn't appear to be used - this.jasmine = jasmine || {}; + + var noopTimer = { + start: function(){}, + elapsed: function(){ return 0; } + }; + + function JsApiReporter(options) { + var timer = options.timer || noopTimer, + status = "loaded"; + this.started = false; this.finished = false; - var status = 'loaded'; - this.jasmineStarted = function() { this.started = true; status = 'started'; + timer.start(); }; var executionTime; - this.jasmineDone = function(options) { + this.jasmineDone = function() { this.finished = true; - executionTime = options.executionTime; + executionTime = timer.elapsed(); status = 'done'; }; @@ -1567,6 +1575,24 @@ if (typeof window == void 0 && typeof exports == "object") { exports.Suite = jasmineRequire.Suite; } +getJasmineRequireObj().Timer = function() { + function Timer(options) { + options = options || {}; + + var now = options.now || function() { return new Date().getTime(); }, + startTime; + + this.start = function() { + startTime = now(); + }; + + this.elapsed = function() { + return now() - startTime; + }; + } + + return Timer; +}; getJasmineRequireObj().matchersUtil = function(j$) { // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter? diff --git a/spec/console/ConsoleReporterSpec.js b/spec/console/ConsoleReporterSpec.js index 252c847b..c8687d6b 100644 --- a/spec/console/ConsoleReporterSpec.js +++ b/spec/console/ConsoleReporterSpec.js @@ -28,6 +28,18 @@ describe("ConsoleReporter", function() { expect(out.getOutput()).toEqual("Started\n"); }); + it("starts the provided timer when jasmine starts", function() { + var timerSpy = jasmine.createSpyObj('timer', ['start']), + reporter = new j$.ConsoleReporter({ + print: out.print, + timer: timerSpy + }); + + reporter.jasmineStarted(); + + expect(timerSpy.start).toHaveBeenCalled(); + }); + it("reports a passing spec as a dot", function() { var reporter = new j$.ConsoleReporter({ print: out.print @@ -69,15 +81,19 @@ describe("ConsoleReporter", function() { }); it("reports a summary when done (singluar spec and time)", function() { - var reporter = new j$.ConsoleReporter({ - print: out.print, - }); + var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), + reporter = new j$.ConsoleReporter({ + print: out.print, + timer: timerSpy + }); reporter.jasmineStarted(); reporter.specDone({status: "passed"}); + timerSpy.elapsed.andReturn(1000); + out.clear(); - reporter.jasmineDone({executionTime: 1000}); + reporter.jasmineDone(); expect(out.getOutput()).toMatch(/1 spec, 0 failures/); expect(out.getOutput()).not.toMatch(/0 pending specs/); @@ -85,9 +101,11 @@ describe("ConsoleReporter", function() { }); it("reports a summary when done (pluralized specs and seconds)", function() { - var reporter = new j$.ConsoleReporter({ - print: out.print, - }); + var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), + reporter = new j$.ConsoleReporter({ + print: out.print, + timer: timerSpy + }); reporter.jasmineStarted(); reporter.specDone({status: "passed"}); @@ -109,7 +127,9 @@ describe("ConsoleReporter", function() { out.clear(); - reporter.jasmineDone({executionTime: 100}); + timerSpy.elapsed.andReturn(100); + + reporter.jasmineDone(); expect(out.getOutput()).toMatch(/3 specs, 1 failure, 1 pending spec/); expect(out.getOutput()).toMatch("Finished in 0.1 seconds\n"); diff --git a/spec/core/JsApiReporterSpec.js b/spec/core/JsApiReporterSpec.js index 7acf948f..63ecf23f 100644 --- a/spec/core/JsApiReporterSpec.js +++ b/spec/core/JsApiReporterSpec.js @@ -26,7 +26,7 @@ xdescribe('JsApiReporter (integration specs)', function() { }); - reporter = new j$.JsApiReporter(jasmine); + reporter = new j$.JsApiReporter({}); env.addReporter(reporter); env.execute(); @@ -83,7 +83,7 @@ xdescribe('JsApiReporter (integration specs)', function() { describe("JsApiReporter", function() { it("knows when a full environment is started", function() { - var reporter = new j$.JsApiReporter(); + var reporter = new j$.JsApiReporter({}); expect(reporter.started).toBe(false); expect(reporter.finished).toBe(false); @@ -95,7 +95,7 @@ describe("JsApiReporter", function() { }); it("knows when a full environment is done", function() { - var reporter = new j$.JsApiReporter(); + var reporter = new j$.JsApiReporter({}); expect(reporter.started).toBe(false); expect(reporter.finished).toBe(false); @@ -107,13 +107,13 @@ describe("JsApiReporter", function() { }); it("defaults to 'loaded' status", function() { - var reporter = new j$.JsApiReporter(); + var reporter = new j$.JsApiReporter({}); expect(reporter.status()).toEqual('loaded'); }); it("reports 'started' when Jasmine has started", function() { - var reporter = new j$.JsApiReporter(); + var reporter = new j$.JsApiReporter({}); reporter.jasmineStarted(); @@ -121,7 +121,7 @@ describe("JsApiReporter", function() { }); it("reports 'done' when Jasmine is done", function() { - var reporter = new j$.JsApiReporter(); + var reporter = new j$.JsApiReporter({}); reporter.jasmineDone({}); @@ -129,7 +129,7 @@ describe("JsApiReporter", function() { }); it("tracks a suite", function() { - var reporter = new j$.JsApiReporter(); + var reporter = new j$.JsApiReporter({}); reporter.suiteStarted({ id: 123, @@ -152,7 +152,7 @@ describe("JsApiReporter", function() { describe("#specResults", function() { var reporter, specResult1, specResult2; beforeEach(function() { - reporter = new j$.JsApiReporter(); + reporter = new j$.JsApiReporter({}); specResult1 = { id: 1, description: "A spec" @@ -180,18 +180,34 @@ describe("JsApiReporter", function() { }); describe("#executionTime", function() { - var reporter; - beforeEach(function() { - reporter = new j$.JsApiReporter(); + it("should start the timer when jasmine starts", function() { + var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), + reporter = new j$.JsApiReporter({ + timer: timerSpy + }); + + reporter.jasmineStarted(); + expect(timerSpy.start).toHaveBeenCalled(); }); it("should return the time it took the specs to run, in ms", function() { - reporter.jasmineDone({executionTime: 1000}); + var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), + reporter = new j$.JsApiReporter({ + timer: timerSpy + }); + + timerSpy.elapsed.andReturn(1000); + reporter.jasmineDone(); expect(reporter.executionTime()).toEqual(1000); }); describe("when the specs haven't finished being run", function() { it("should return undefined", function() { + var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), + reporter = new j$.JsApiReporter({ + timer: timerSpy + }); + expect(reporter.executionTime()).toBeUndefined(); }); }); diff --git a/spec/core/TimerSpec.js b/spec/core/TimerSpec.js new file mode 100644 index 00000000..d9317b20 --- /dev/null +++ b/spec/core/TimerSpec.js @@ -0,0 +1,13 @@ +describe("Timer", function() { + it("reports the time elapsed", function() { + var fakeNow = jasmine.createSpy('fake Date.now'), + timer = new j$.Timer({now: fakeNow}); + + fakeNow.andReturn(100); + timer.start(); + + fakeNow.andReturn(200); + + expect(timer.elapsed()).toEqual(100); + }); +}); diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index 5f15cecb..f44f8465 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -30,6 +30,20 @@ describe("New HtmlReporter", function() { expect(version.innerHTML).toEqual(jasmine.version); }); + it("starts the timer when jasmine begins", function() { + var env = new jasmine.Env(), + startTimerSpy = jasmine.createSpy("start-timer-spy"), + reporter = new jasmine.HtmlReporter({ + env: env, + createElement: function() { return document.createElement.apply(document, arguments); }, + timer: { start: startTimerSpy } + }); + + reporter.jasmineStarted({}); + + expect(startTimerSpy).toHaveBeenCalled(); + }); + describe("when a spec is done", function() { it("reports the status symbol of a disabled spec", function() { var env = new jasmine.Env(), @@ -119,18 +133,22 @@ describe("New HtmlReporter", function() { it("reports the run time", function() { var env = new jasmine.Env(), container = document.createElement("div"), + timer = jasmine.createSpyObj('timer', ['start', 'elapsed']), getContainer = function() { return container; }, reporter = new jasmine.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); } + createTextNode: function() { return document.createTextNode.apply(document, arguments); }, + timer: timer }); reporter.initialize(); reporter.jasmineStarted({}); - reporter.jasmineDone({executionTime: 100}); + + timer.elapsed.andReturn(100); + reporter.jasmineDone(); var duration = container.querySelector(".banner .duration"); expect(duration.innerHTML).toMatch(/finished in 0.1s/); diff --git a/spec/node_suite.js b/spec/node_suite.js index b47c00dd..c67bddc0 100644 --- a/spec/node_suite.js +++ b/spec/node_suite.js @@ -55,7 +55,9 @@ var jasmineInterface = { setInterval: env.clock.setInterval, clearInterval: env.clock.clearInterval, - jsApiReporter: new jasmine.JsApiReporter(jasmine) + jsApiReporter: new jasmine.JsApiReporter({ + timer: new jasmine.Timer() + }) }; extend(global, jasmineInterface); @@ -78,7 +80,8 @@ function executeSpecs(specs, done, isVerbose, showColors) { var consoleReporter = new jasmine.ConsoleReporter({ print: util.print, onComplete: done, - showColors: showColors + showColors: showColors, + timer: new jasmine.Timer() }); env.addReporter(consoleReporter); diff --git a/spec/support/dev_boot.js b/spec/support/dev_boot.js index d1528c22..3a6572d8 100644 --- a/spec/support/dev_boot.js +++ b/spec/support/dev_boot.js @@ -53,7 +53,9 @@ setInterval: env.clock.setInterval, clearInterval: env.clock.clearInterval, - jsApiReporter: new jasmine.JsApiReporter(jasmine) + jsApiReporter: new jasmine.JsApiReporter({ + timer: new jasmine.Timer() + }) }; if (typeof window == "undefined" && typeof exports == "object") { @@ -76,7 +78,8 @@ onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); }, getContainer: function() { return document.body; }, createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); } + createTextNode: function() { return document.createTextNode.apply(document, arguments); }, + timer: new jasmine.Timer() }); env.addReporter(jasmineInterface.jsApiReporter); diff --git a/src/console/ConsoleReporter.js b/src/console/ConsoleReporter.js index 2299c229..bd04d7d9 100644 --- a/src/console/ConsoleReporter.js +++ b/src/console/ConsoleReporter.js @@ -1,8 +1,15 @@ getJasmineRequireObj().ConsoleReporter = function() { + + var noopTimer = { + start: function(){}, + elapsed: function(){ return 0; } + }; + function ConsoleReporter(options) { var print = options.print, showColors = options.showColors || false, onComplete = options.onComplete || function() {}, + timer = options.timer || noopTimer, specCount, failureCount, failedSpecs = [], @@ -20,9 +27,10 @@ getJasmineRequireObj().ConsoleReporter = function() { pendingCount = 0; print("Started"); printNewline(); + timer.start(); }; - this.jasmineDone = function(options) { + this.jasmineDone = function() { printNewline(); for (var i = 0; i < failedSpecs.length; i++) { specFailureDetails(failedSpecs[i]); @@ -39,7 +47,7 @@ getJasmineRequireObj().ConsoleReporter = function() { print(specCounts); printNewline(); - var seconds = options.executionTime / 1000; + var seconds = timer.elapsed() / 1000; print("Finished in " + seconds + " " + plural("second", seconds)); printNewline(); diff --git a/src/console/console.js b/src/console/console.js index 85f6166c..67121233 100644 --- a/src/console/console.js +++ b/src/console/console.js @@ -34,10 +34,17 @@ getJasmineRequireObj().console = function(jRequire, j$) { }; getJasmineRequireObj().ConsoleReporter = function() { + + var noopTimer = { + start: function(){}, + elapsed: function(){ return 0; } + }; + function ConsoleReporter(options) { var print = options.print, showColors = options.showColors || false, onComplete = options.onComplete || function() {}, + timer = options.timer || noopTimer, specCount, failureCount, failedSpecs = [], @@ -55,9 +62,10 @@ getJasmineRequireObj().ConsoleReporter = function() { pendingCount = 0; print("Started"); printNewline(); + timer.start(); }; - this.jasmineDone = function(options) { + this.jasmineDone = function() { printNewline(); for (var i = 0; i < failedSpecs.length; i++) { specFailureDetails(failedSpecs[i]); @@ -74,7 +82,7 @@ getJasmineRequireObj().ConsoleReporter = function() { print(specCounts); printNewline(); - var seconds = options.executionTime / 1000; + var seconds = timer.elapsed() / 1000; print("Finished in " + seconds + " " + plural("second", seconds)); printNewline(); diff --git a/src/core/JsApiReporter.js b/src/core/JsApiReporter.js index 13ec6488..bcae8943 100644 --- a/src/core/JsApiReporter.js +++ b/src/core/JsApiReporter.js @@ -1,21 +1,28 @@ getJasmineRequireObj().JsApiReporter = function() { - function JsApiReporter(jasmine) { // TODO: this doesn't appear to be used - this.jasmine = jasmine || {}; + + var noopTimer = { + start: function(){}, + elapsed: function(){ return 0; } + }; + + function JsApiReporter(options) { + var timer = options.timer || noopTimer, + status = "loaded"; + this.started = false; this.finished = false; - var status = 'loaded'; - this.jasmineStarted = function() { this.started = true; status = 'started'; + timer.start(); }; var executionTime; - this.jasmineDone = function(options) { + this.jasmineDone = function() { this.finished = true; - executionTime = options.executionTime; + executionTime = timer.elapsed(); status = 'done'; }; diff --git a/src/core/Timer.js b/src/core/Timer.js new file mode 100644 index 00000000..74f5a7f4 --- /dev/null +++ b/src/core/Timer.js @@ -0,0 +1,18 @@ +getJasmineRequireObj().Timer = function() { + function Timer(options) { + options = options || {}; + + var now = options.now || function() { return new Date().getTime(); }, + startTime; + + this.start = function() { + startTime = now(); + }; + + this.elapsed = function() { + return now() - startTime; + }; + } + + return Timer; +}; \ No newline at end of file diff --git a/src/core/requireCore.js b/src/core/requireCore.js index 29e47717..edc3ae1c 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -28,6 +28,7 @@ getJasmineRequireObj().core = function(jRequire) { j$.Spec = jRequire.Spec(); j$.Spy = jRequire.Spy(j$); j$.Suite = jRequire.Suite(); + j$.Timer = jRequire.Timer(); j$.version = jRequire.version(); j$.matchers = jRequire.requireMatchers(jRequire, j$); diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 4fc32614..c59a4fa1 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -1,10 +1,17 @@ jasmineRequire.HtmlReporter = function() { + + var noopTimer = { + start: function(){}, + elapsed: function(){ return 0; } + }; + function HtmlReporter(options) { var env = options.env || {}, getContainer = options.getContainer, createElement = options.createElement, createTextNode = options.createTextNode, onRaiseExceptionsClick = options.onRaiseExceptionsClick, + timer = options.timer || noopTimer, results = [], specsExecuted = 0, failureCount = 0, @@ -32,6 +39,7 @@ jasmineRequire.HtmlReporter = function() { var totalSpecsDefined; this.jasmineStarted = function(options) { totalSpecsDefined = options.totalSpecsDefined || 0; + timer.start(); }; var summary = createDom("div", {className: "summary"}); @@ -92,9 +100,9 @@ jasmineRequire.HtmlReporter = function() { } }; - this.jasmineDone = function(options) { + this.jasmineDone = function() { var banner = find(".banner"); - banner.appendChild(createDom("span", {className: "duration"}, "finished in " + options.executionTime / 1000 + "s")); + banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s")); var alert = find(".alert");