From 6ac4b686a39115a07101fb3203fc4276ecd0df92 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank" Date: Sat, 11 Aug 2012 16:53:08 -0700 Subject: [PATCH 01/55] Move to an earlier RedCarpet to fix an incompatibility with Rocco. Regen of gh-pages. --- jasmine-core.gemspec | 1 + pages | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/jasmine-core.gemspec b/jasmine-core.gemspec index 47e7aa22..7f4711e3 100644 --- a/jasmine-core.gemspec +++ b/jasmine-core.gemspec @@ -26,6 +26,7 @@ Gem::Specification.new do |s| s.add_development_dependency "awesome_print" s.add_development_dependency "thor" s.add_development_dependency "nokogiri" + s.add_development_dependency "redcarpet", "1.7" s.add_development_dependency "rocco" s.add_development_dependency "rdiscount" end diff --git a/pages b/pages index c852d330..39dcf87b 160000 --- a/pages +++ b/pages @@ -1 +1 @@ -Subproject commit c852d33084c114bfc09174eb1fde011dd20ff299 +Subproject commit 39dcf87b563e7cb0435208af562cc8ea033a47ff From 5e594946bb957bdad4f922f697126415f54efbaf Mon Sep 17 00:00:00 2001 From: Dave Burt Date: Tue, 31 Jul 2012 15:03:55 +1000 Subject: [PATCH 02/55] Change toBeCloseTo matcher to be more consistent. It now calculates and compares a difference, rather than rounding two separate quantities and testing for their equality. --- lib/jasmine-core/jasmine.js | 7 ++----- spec/core/MatchersSpec.js | 5 +++++ src/core/Matchers.js | 5 +---- src/version.js | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 6bac2236..dd350611 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1445,10 +1445,7 @@ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { if (!(precision === 0)) { precision = precision || 2; } - var multiplier = Math.pow(10, precision); - var actual = Math.round(this.actual * multiplier); - expected = Math.round(expected * multiplier); - return expected == actual; + return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2); }; /** @@ -2537,5 +2534,5 @@ jasmine.version_= { "major": 1, "minor": 2, "build": 0, - "revision": 1337006083 + "revision": 1343710612 }; diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index 7be2b814..963a557f 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -510,6 +510,11 @@ describe("jasmine.Matchers", function() { expect(-1.23).not.toBeCloseTo(-1.24); }); + it("expects close numbers to 'be close' and further numbers not to", function() { + expect(1.225).not.toBeCloseTo(1.234); // difference is 0.009 + expect(1.225).toBeCloseTo(1.224); // difference is 0.001 + }); + it("accepts an optional precision argument", function() { expect(1).toBeCloseTo(1.1, 0); expect(1.2).toBeCloseTo(1.23, 1); diff --git a/src/core/Matchers.js b/src/core/Matchers.js index 7303facb..ad025638 100644 --- a/src/core/Matchers.js +++ b/src/core/Matchers.js @@ -302,10 +302,7 @@ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { if (!(precision === 0)) { precision = precision || 2; } - var multiplier = Math.pow(10, precision); - var actual = Math.round(this.actual * multiplier); - expected = Math.round(expected * multiplier); - return expected == actual; + return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2); }; /** diff --git a/src/version.js b/src/version.js index e728798a..0ed57491 100644 --- a/src/version.js +++ b/src/version.js @@ -3,5 +3,5 @@ jasmine.version_= { "major": 1, "minor": 2, "build": 0, - "revision": 1337006083 + "revision": 1343710612 }; From 4d106c2b33fd904594374705a2e916851236e074 Mon Sep 17 00:00:00 2001 From: Oliver Caldwell Date: Wed, 15 Aug 2012 21:44:28 +0200 Subject: [PATCH 03/55] Wrapped the reserved word, "for", in quotes. This stops it throwing errors in IE and other browsers. I think the newer Firefox and Chrome versions are the only browsers to not die when running it. --- lib/jasmine-core/jasmine-html.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 157f7e85..543d5696 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -154,7 +154,7 @@ jasmine.HtmlReporter = function(_doc) { dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), dom.alert = self.createDom('div', {className: 'alert'}, self.createDom('span', { className: 'exceptions' }, - self.createDom('label', { className: 'label', for: 'no_try_catch' }, 'No try/catch'), + self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), dom.results = self.createDom('div', {className: 'results'}, dom.summary = self.createDom('div', { className: 'summary' }), From b5b50182b29d711c68d27c0d53eef6f54023bba9 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 28 Sep 2010 20:43:50 -0700 Subject: [PATCH 04/55] Consolidate all waitsFor specs in the same describe block. --- spec/core/SpecRunningSpec.js | 168 +++++++++++++++++------------------ 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/spec/core/SpecRunningSpec.js b/spec/core/SpecRunningSpec.js index f5ce2988..fb717373 100644 --- a/spec/core/SpecRunningSpec.js +++ b/spec/core/SpecRunningSpec.js @@ -398,6 +398,90 @@ describe("jasmine spec running", function () { expect(timeoutSpec.results().getItems()[0].message).toEqual('timeout: timed out after 500 msec waiting for something to happen'); expect(subsequentSpecRan).toEqual(true); }); + + describe('with consecutive calls', function () { + var foo; + beforeEach(function () { + foo = 0; + }); + + it('exits immediately (does not stack) if the latchFunction times out', function () { + var reachedFirstWaitsFor = false; + var reachedSecondWaitsFor = false; + env.describe('suite that waits', function () { + env.it('should stack timeouts', function() { + this.waitsFor(500, function () { + reachedFirstWaitsFor = true; + return false; + }); + this.waitsFor(500, function () { + reachedSecondWaitsFor = true; + }); + this.runs(function () { + foo++; + }); + }); + }); + + expect(reachedFirstWaitsFor).toEqual(false); + env.execute(); + + expect(reachedFirstWaitsFor).toEqual(true); + expect(foo).toEqual(0); + expect(reachedSecondWaitsFor).toEqual(false); + fakeTimer.tick(500); + expect(reachedSecondWaitsFor).toEqual(false); + expect(foo).toEqual(0); + fakeTimer.tick(500); + expect(reachedSecondWaitsFor).toEqual(false); + expect(foo).toEqual(0); + }); + + it('stacks latchFunctions', function () { + var firstWaitsResult = false; + var secondWaitsResult = false; + var waitsSuite = env.describe('suite that waits', function () { + env.it('spec with waitsFors', function() { + this.waitsFor(600, function () { + fakeTimer.setTimeout(function () { + firstWaitsResult = true; + }, 300); + return firstWaitsResult; + }); + this.waitsFor(600, function () { + fakeTimer.setTimeout(function () { + secondWaitsResult = true; + }, 300); + return secondWaitsResult; + }); + this.runs(function () { + foo++; + }); + }); + }); + + expect(firstWaitsResult).toEqual(false); + expect(secondWaitsResult).toEqual(false); + waitsSuite.execute(); + + expect(firstWaitsResult).toEqual(false); + expect(secondWaitsResult).toEqual(false); + expect(foo).toEqual(0); + + fakeTimer.tick(300); + + expect(firstWaitsResult).toEqual(true); + expect(secondWaitsResult).toEqual(false); + expect(foo).toEqual(0); + + fakeTimer.tick(300); + + expect(firstWaitsResult).toEqual(true); + expect(secondWaitsResult).toEqual(true); + expect(foo).toEqual(1); + + }); + }); }); it("testSpecAfter", function() { @@ -579,90 +663,6 @@ describe("jasmine spec running", function () { expect(quux).toEqual(1); }); - describe('#waitsFor should allow consecutive calls', function () { - var foo; - beforeEach(function () { - foo = 0; - }); - - it('exits immediately (does not stack) if the latchFunction times out', function () { - var reachedFirstWaitsFor = false; - var reachedSecondWaitsFor = false; - env.describe('suite that waits', function () { - env.it('should stack timeouts', function() { - this.waitsFor(500, function () { - reachedFirstWaitsFor = true; - return false; - }); - this.waitsFor(500, function () { - reachedSecondWaitsFor = true; - }); - this.runs(function () { - foo++; - }); - }); - }); - - expect(reachedFirstWaitsFor).toEqual(false); - env.execute(); - - expect(reachedFirstWaitsFor).toEqual(true); - expect(foo).toEqual(0); - expect(reachedSecondWaitsFor).toEqual(false); - fakeTimer.tick(500); - expect(reachedSecondWaitsFor).toEqual(false); - expect(foo).toEqual(0); - fakeTimer.tick(500); - expect(reachedSecondWaitsFor).toEqual(false); - expect(foo).toEqual(0); - }); - - it('stacks latchFunctions', function () { - var firstWaitsResult = false; - var secondWaitsResult = false; - var waitsSuite = env.describe('suite that waits', function () { - env.it('spec with waitsFors', function() { - this.waitsFor(600, function () { - fakeTimer.setTimeout(function () { - firstWaitsResult = true; - }, 300); - return firstWaitsResult; - }); - this.waitsFor(600, function () { - fakeTimer.setTimeout(function () { - secondWaitsResult = true; - }, 300); - return secondWaitsResult; - }); - this.runs(function () { - foo++; - }); - }); - }); - - expect(firstWaitsResult).toEqual(false); - expect(secondWaitsResult).toEqual(false); - waitsSuite.execute(); - - expect(firstWaitsResult).toEqual(false); - expect(secondWaitsResult).toEqual(false); - expect(foo).toEqual(0); - - fakeTimer.tick(300); - - expect(firstWaitsResult).toEqual(true); - expect(secondWaitsResult).toEqual(false); - expect(foo).toEqual(0); - - fakeTimer.tick(300); - - expect(firstWaitsResult).toEqual(true); - expect(secondWaitsResult).toEqual(true); - expect(foo).toEqual(1); - - }); - }); - it("#beforeEach should be able to eval runs and waits blocks", function () { var foo = 0; var bar = 0; From 9990eb7b6e373498e247a32a63e238f7711ac8c7 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 29 Sep 2010 08:19:43 -0700 Subject: [PATCH 05/55] Test that afterEach is called after a failing spec. --- spec/core/RunnerSpec.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/core/RunnerSpec.js b/spec/core/RunnerSpec.js index 3f66aaa5..090a15ea 100644 --- a/spec/core/RunnerSpec.js +++ b/spec/core/RunnerSpec.js @@ -105,6 +105,19 @@ describe('RunnerTest', function() { expect(runnerResults.totalCount).toEqual(3); expect(runnerResults.passedCount).toEqual(3); }); + + it('should run after a failing spec', function () { + var afterEach = jasmine.createSpy(); + env.afterEach(afterEach); + + env.describe('suite', function () { + env.it('fails', function () { + this.explodes(); + }); + }).execute(); + + expect(afterEach).toHaveBeenCalled(); + }); }); From c5c57247f87ff258c2ed154f7ebb1dd83396f782 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 29 Sep 2010 08:25:06 -0700 Subject: [PATCH 06/55] Test that show that afterEach and after are not being called when a waitsFor times out. --- spec/core/SpecRunningSpec.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/spec/core/SpecRunningSpec.js b/spec/core/SpecRunningSpec.js index fb717373..a0268224 100644 --- a/spec/core/SpecRunningSpec.js +++ b/spec/core/SpecRunningSpec.js @@ -399,6 +399,39 @@ describe("jasmine spec running", function () { expect(subsequentSpecRan).toEqual(true); }); + it("runs afterEach after timing out", function() { + var afterEach = jasmine.createSpy('afterEach'); + + env.describe('foo', function () { + env.afterEach(afterEach); + + env.it('waitsFor', function () { + this.waitsFor(100, function() { + return false; + }); + }); + }).execute(); + + fakeTimer.tick(500); + expect(afterEach).toHaveBeenCalled(); + }); + + it("runs single-spec after functions after timing out", function() { + var after = jasmine.createSpy('after'); + + env.describe('foo', function () { + env.it('waitsFor', function () { + this.after(after); + this.waitsFor(100, function() { + return false; + }); + }); + }).execute(); + + fakeTimer.tick(500); + expect(after).toHaveBeenCalled(); + }); + describe('with consecutive calls', function () { var foo; beforeEach(function () { From bbc4c70c911e1cbf7885c050c221419ca8e98fca Mon Sep 17 00:00:00 2001 From: rgould Date: Tue, 24 Jul 2012 18:01:21 -0400 Subject: [PATCH 07/55] Add 'ensured' blocks to the queue. This blocks will be run even when a preceeding block sets the abort flag. This is so that we can support afterEach calls running when the spec fails due to a timeout. --- src/core/Queue.js | 27 +++++++++++++++++++++++---- src/core/Spec.js | 8 ++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/core/Queue.js b/src/core/Queue.js index 065408c2..d4cd5ba7 100644 --- a/src/core/Queue.js +++ b/src/core/Queue.js @@ -1,5 +1,9 @@ jasmine.Queue = function(env) { this.env = env; + + // parallel to blocks. each true value in this array means the block will + // get executed even if we abort + this.ensured = []; this.blocks = []; this.running = false; this.index = 0; @@ -7,15 +11,30 @@ jasmine.Queue = function(env) { this.abort = false; }; -jasmine.Queue.prototype.addBefore = function(block) { +jasmine.Queue.prototype.addBefore = function(block, ensure) { + if (ensure === jasmine.undefined) { + ensure = false; + } + this.blocks.unshift(block); + this.ensured.unshift(ensure); }; -jasmine.Queue.prototype.add = function(block) { +jasmine.Queue.prototype.add = function(block, ensure) { + if (ensure === jasmine.undefined) { + ensure = false; + } + this.blocks.push(block); + this.ensured.push(ensure); }; -jasmine.Queue.prototype.insertNext = function(block) { +jasmine.Queue.prototype.insertNext = function(block, ensure) { + if (ensure === jasmine.undefined) { + ensure = false; + } + + this.ensured.splice((this.index + this.offset + 1), 0, ensure); this.blocks.splice((this.index + this.offset + 1), 0, block); this.offset++; }; @@ -39,7 +58,7 @@ jasmine.Queue.prototype.next_ = function() { while (goAgain) { goAgain = false; - if (self.index < self.blocks.length && !this.abort) { + if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { var calledSynchronously = true; var completedSynchronously = false; diff --git a/src/core/Spec.js b/src/core/Spec.js index 972ccfde..469345b4 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -154,7 +154,7 @@ jasmine.Spec.prototype.finish = function(onComplete) { jasmine.Spec.prototype.after = function(doAfter) { if (this.queue.isRunning()) { - this.queue.add(new jasmine.Block(this.env, doAfter, this)); + this.queue.add(new jasmine.Block(this.env, doAfter, this), true); } else { this.afterCallbacks.unshift(doAfter); } @@ -192,15 +192,15 @@ jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); } for (i = 0; i < this.afterCallbacks.length; i++) { - this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); + this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true); } for (suite = this.suite; suite; suite = suite.parentSuite) { for (i = 0; i < suite.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); + this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true); } } for (i = 0; i < runner.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); + this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true); } }; From c5ba032d289dd84d6364d8e85610041ae1275882 Mon Sep 17 00:00:00 2001 From: rgould Date: Tue, 24 Jul 2012 18:37:00 -0400 Subject: [PATCH 08/55] Regenerate jasmine.js after adding ensured support. --- lib/jasmine-core/jasmine.js | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index dd350611..84548dd6 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1961,6 +1961,10 @@ jasmine.StringPrettyPrinter.prototype.append = function(value) { }; jasmine.Queue = function(env) { this.env = env; + + // parallel to blocks. each true value in this array means the block will + // get executed even if we abort + this.ensured = []; this.blocks = []; this.running = false; this.index = 0; @@ -1968,15 +1972,30 @@ jasmine.Queue = function(env) { this.abort = false; }; -jasmine.Queue.prototype.addBefore = function(block) { +jasmine.Queue.prototype.addBefore = function(block, ensure) { + if (ensure === jasmine.undefined) { + ensure = false; + } + this.blocks.unshift(block); + this.ensured.unshift(ensure); }; -jasmine.Queue.prototype.add = function(block) { +jasmine.Queue.prototype.add = function(block, ensure) { + if (ensure === jasmine.undefined) { + ensure = false; + } + this.blocks.push(block); + this.ensured.push(ensure); }; -jasmine.Queue.prototype.insertNext = function(block) { +jasmine.Queue.prototype.insertNext = function(block, ensure) { + if (ensure === jasmine.undefined) { + ensure = false; + } + + this.ensured.splice((this.index + this.offset + 1), 0, ensure); this.blocks.splice((this.index + this.offset + 1), 0, block); this.offset++; }; @@ -2000,7 +2019,7 @@ jasmine.Queue.prototype.next_ = function() { while (goAgain) { goAgain = false; - if (self.index < self.blocks.length && !this.abort) { + if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { var calledSynchronously = true; var completedSynchronously = false; @@ -2291,7 +2310,7 @@ jasmine.Spec.prototype.finish = function(onComplete) { jasmine.Spec.prototype.after = function(doAfter) { if (this.queue.isRunning()) { - this.queue.add(new jasmine.Block(this.env, doAfter, this)); + this.queue.add(new jasmine.Block(this.env, doAfter, this), true); } else { this.afterCallbacks.unshift(doAfter); } @@ -2329,15 +2348,15 @@ jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); } for (i = 0; i < this.afterCallbacks.length; i++) { - this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); + this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true); } for (suite = this.suite; suite; suite = suite.parentSuite) { for (i = 0; i < suite.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); + this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true); } } for (i = 0; i < runner.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); + this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true); } }; From 26f0f6f2134a128dae18f17494c5ba989c8750c3 Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Thu, 19 Jul 2012 14:10:39 -0600 Subject: [PATCH 09/55] Don't assume exports is defined when window is undefined The current code makes the assumption that if window is undefined it is being run in an environment which supports the CommonJS Modules spec. This is not the case when Jasmine is being run in rhino or SpiderMonkey (smjs) without EnvJS. The fix is simply to check that exports is an object. Signed-off-by: Kevin Locke --- lib/jasmine-core/jasmine.js | 2 +- src/core/base.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 84548dd6..63e9a9a9 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1,4 +1,4 @@ -var isCommonJS = typeof window == "undefined"; +var isCommonJS = typeof window == "undefined" && typeof exports == "object"; /** * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. diff --git a/src/core/base.js b/src/core/base.js index a4afea98..40d38aed 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -1,4 +1,4 @@ -var isCommonJS = typeof window == "undefined"; +var isCommonJS = typeof window == "undefined" && typeof exports == "object"; /** * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. From ae9ddd74a23724b5883df4d076f6e936b8ea86b7 Mon Sep 17 00:00:00 2001 From: Alexey Androsov Date: Tue, 10 Jul 2012 15:12:32 +0400 Subject: [PATCH 10/55] update jsdoc for jasmine.Matchers.prototype.toThrow expected argument is optional --- src/core/Matchers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Matchers.js b/src/core/Matchers.js index ad025638..75b9a5a8 100644 --- a/src/core/Matchers.js +++ b/src/core/Matchers.js @@ -308,7 +308,7 @@ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { /** * Matcher that checks that the expected exception was thrown by the actual. * - * @param {String} expected + * @param {String} [expected] */ jasmine.Matchers.prototype.toThrow = function(expected) { var result = false; From cfa95fcf2cb59711c71170dbc093c74188d49189 Mon Sep 17 00:00:00 2001 From: Kevin Connor Date: Wed, 15 Aug 2012 12:41:09 -0700 Subject: [PATCH 11/55] create downloads dir if needed during build_standalone_distribution --- tasks/jasmine_dev/build_standalone_distribution.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tasks/jasmine_dev/build_standalone_distribution.rb b/tasks/jasmine_dev/build_standalone_distribution.rb index cf50693d..a3613e56 100644 --- a/tasks/jasmine_dev/build_standalone_distribution.rb +++ b/tasks/jasmine_dev/build_standalone_distribution.rb @@ -28,7 +28,8 @@ class JasmineDev < Thor run_with_output "zip -rq ../jasmine-standalone-#{version_string}.zip ." say "Copying Zip file to downloads directory", :yellow - run "cp ../jasmine-standalone-#{version_string}.zip #{download_dir}" + run "mkdir -p #{download_dir}" + run "cp ../jasmine-standalone-#{version_string}.zip #{download_dir}/" end end @@ -46,4 +47,4 @@ class JasmineDev < Thor File.join('lib', "jasmine-#{version_string}") end end -end \ No newline at end of file +end From b527ccd2fae61e80b1be9ef415b4b8328fcc225b Mon Sep 17 00:00:00 2001 From: Christopher Mitchell Date: Sat, 16 Jun 2012 16:12:49 -0700 Subject: [PATCH 12/55] Fix swapped template values in build_standalone_runner.rb. `example_source_tags` and `example_spec_tags` each returned what the other should have returned. I noticed this bug because it made the comments in SpecRunner.html about where to include spec and source files incongruous with the example tags that followed. --- tasks/jasmine_dev/build_standalone_runner.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasks/jasmine_dev/build_standalone_runner.rb b/tasks/jasmine_dev/build_standalone_runner.rb index 0f440657..c324740a 100644 --- a/tasks/jasmine_dev/build_standalone_runner.rb +++ b/tasks/jasmine_dev/build_standalone_runner.rb @@ -49,11 +49,11 @@ class JasmineDev < Thor end def example_source_tags - script_tags_for ['spec/SpecHelper.js', 'spec/PlayerSpec.js'] + script_tags_for ['src/Player.js', 'src/Song.js'] end def example_spec_tags - script_tags_for ['src/Player.js', 'src/Song.js'] + script_tags_for ['spec/SpecHelper.js', 'spec/PlayerSpec.js'] end end -end \ No newline at end of file +end From acdc497361ef38c4aa700f34242b1a0a466fe72a Mon Sep 17 00:00:00 2001 From: PLOE09 Date: Fri, 14 Sep 2012 16:36:32 +0200 Subject: [PATCH 13/55] Add JSDoc @return-tag to 'spyOn' and 'expect' functions support code completion in Spket IDE --- src/core/base.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/base.js b/src/core/base.js index 40d38aed..51761ba2 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -470,7 +470,7 @@ jasmine.log = function() { * @see jasmine.createSpy * @param obj * @param methodName - * @returns a Jasmine spy that can be chained with all spy methods + * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods */ var spyOn = function(obj, methodName) { return jasmine.getEnv().currentSpec.spyOn(obj, methodName); @@ -515,6 +515,7 @@ if (isCommonJS) exports.xit = xit; * jasmine.Matchers functions. * * @param {Object} actual Actual value to test against and expected value + * @return {jasmine.Matchers} */ var expect = function(actual) { return jasmine.getEnv().currentSpec.expect(actual); From ac55e26870c8a2407ec2e22f9cd1e9b10a6c6332 Mon Sep 17 00:00:00 2001 From: James Cracknell Date: Thu, 12 Jul 2012 19:14:13 -0600 Subject: [PATCH 14/55] Added toBeNaN matcher --- lib/jasmine-core/jasmine.js | 11 +++++++++++ spec/core/MatchersSpec.js | 23 +++++++++++++++++++++++ src/core/Matchers.js | 11 +++++++++++ 3 files changed, 45 insertions(+) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 63e9a9a9..c65f7e13 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1293,6 +1293,17 @@ jasmine.Matchers.prototype.toBeNull = function() { return (this.actual === null); }; +/** + * Matcher that compares the actual to NaN. + */ +jasmine.Matchers.prototype.toBeNaN = function() { + this.message = function() { + return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ]; + }; + + return (this.actual !== this.actual); +}; + /** * Matcher that boolean not-nots the actual. */ diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index 963a557f..ac34fdfe 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -281,6 +281,29 @@ describe("jasmine.Matchers", function() { expect(result.actual).toEqual(actual); }); + it("toBeNaN", function() { + expect(match(Number.NaN).toBeNaN()).toPass(); + expect(match(0).toBeNaN()).toFail(); + expect(match(1).toBeNaN()).toFail(); + expect(match(null).toBeNaN()).toFail(); + expect(match(Number.POSITIVE_INFINITY).toBeNaN()).toFail(); + expect(match(Number.NEGATIVE_INFINITY).toBeNaN()).toFail(); + expect(match('NaN').toBeNaN()).toFail(); + }); + + it("toBeNaN to build an ExpectationResult", function() { + var actual = 'a'; + var matcher = match(actual); + matcher.toBeNaN(); + + var result = lastResult(); + + expect(result.matcherName).toEqual("toBeNaN"); + expect(result.passed()).toFail(); + expect(result.message).toMatch("Expected 'a' to be NaN."); + expect(result.actual).toMatch(actual); + }); + it("toBeFalsy", function() { expect(match(false).toBeFalsy()).toPass(); expect(match(true).toBeFalsy()).toFail(); diff --git a/src/core/Matchers.js b/src/core/Matchers.js index 75b9a5a8..cf4c00f5 100644 --- a/src/core/Matchers.js +++ b/src/core/Matchers.js @@ -150,6 +150,17 @@ jasmine.Matchers.prototype.toBeNull = function() { return (this.actual === null); }; +/** + * Matcher that compares the actual to NaN. + */ +jasmine.Matchers.prototype.toBeNaN = function() { + this.message = function() { + return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ]; + }; + + return (this.actual !== this.actual); +}; + /** * Matcher that boolean not-nots the actual. */ From a34077a8afa7ddf56158a60c01ee8d7da0bcb7f4 Mon Sep 17 00:00:00 2001 From: Gunnar Ahlberg Date: Wed, 2 May 2012 14:11:22 +0200 Subject: [PATCH 15/55] cover spy on on undefined method --- spec/core/SpySpec.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/core/SpySpec.js b/spec/core/SpySpec.js index 05239172..90439c4e 100644 --- a/spec/core/SpySpec.js +++ b/spec/core/SpySpec.js @@ -165,6 +165,21 @@ describe('Spies', function () { expect(exception).toBeDefined(); }); + + it('to spy on an undefined method throws exception', function() { + var TestClass = { + someFunction : function() { + } + }; + function efunc() { + this.spyOn(TestClass, 'someOtherFunction'); + }; + expect(function() { + efunc(); + }).toThrow('someOtherFunction() method does not exist'); + + }); + it('should be able to reset a spy', function() { var TestClass = { someFunction: function() {} }; this.spyOn(TestClass, 'someFunction'); From 3685d3199c847fd9b0e9ca1388f4d7d50d9d0067 Mon Sep 17 00:00:00 2001 From: gvanhove Date: Fri, 2 Mar 2012 19:28:15 -0800 Subject: [PATCH 16/55] less confusing messages for toHaveBeenCalledWith --- spec/core/MatchersSpec.js | 10 ++++++++-- src/core/Matchers.js | 14 +++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index ac34fdfe..addd96ee 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -799,7 +799,13 @@ describe("jasmine.Matchers", function() { TestClass.spyFunction('d', 'e', 'f'); var expected = match(TestClass.spyFunction); expect(expected.toHaveBeenCalledWith('a', 'b')).toFail(); - expect(lastResult().message).toEqual("Expected spy My spy to have been called with [ 'a', 'b' ] but was called with [ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] ]"); + expect(lastResult().message).toEqual("Expected spy My spy to have been called with [ 'a', 'b' ] but actual calls were [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ]"); + }); + + it("should return a decent message when it hasn't been called", function() { + var expected = match(TestClass.spyFunction); + expect(expected.toHaveBeenCalledWith('a', 'b')).toFail(); + expect(lastResult().message).toEqual("Expected spy My spy to have been called with [ 'a', 'b' ] but it was never called."); }); it("should return a decent message when inverted", function() { @@ -807,7 +813,7 @@ describe("jasmine.Matchers", function() { TestClass.spyFunction('d', 'e', 'f'); var expected = match(TestClass.spyFunction); expect(expected.not.toHaveBeenCalledWith('a', 'b', 'c')).toFail(); - expect(lastResult().message).toEqual("Expected spy My spy not to have been called with [ 'a', 'b', 'c' ] but was called with [ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] ]"); + expect(lastResult().message).toEqual("Expected spy My spy not to have been called with [ 'a', 'b', 'c' ] but it was."); }); it('should throw an exception when invoked on a non-spy', shouldThrowAnExceptionWhenInvokedOnANonSpy('toHaveBeenCalledWith')); diff --git a/src/core/Matchers.js b/src/core/Matchers.js index cf4c00f5..85802d39 100644 --- a/src/core/Matchers.js +++ b/src/core/Matchers.js @@ -238,18 +238,14 @@ jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { + var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."; + var positiveMessage = ""; if (this.actual.callCount === 0) { - // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw] - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.", - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was." - ]; + positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called."; } else { - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall), - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall) - ]; + positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '') } + return [positiveMessage, invertedMessage]; }; return this.env.contains_(this.actual.argsForCall, expectedArgs); From b95c43ab7cd7eab54c1740de2e81a6beadbc09e9 Mon Sep 17 00:00:00 2001 From: Joost Elfering Date: Mon, 4 Jun 2012 00:12:58 +0200 Subject: [PATCH 17/55] resolving issue that was identified via pivotal/jasmine#199 where RegExp objects were not properly compared resulting in non-matching RegExp objects to always return true. a patch to jasmine.Env.equals_ adds an extra step for RexExp objects to be compared. --- lib/jasmine-core/jasmine.js | 20 ++++++++++++++++++++ spec/core/MatchersSpec.js | 3 +++ src/core/Env.js | 20 ++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index c65f7e13..d1c365c4 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -874,6 +874,22 @@ jasmine.Env.prototype.xit = function(desc, func) { }; }; +jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.source != b.source) + mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); + + if (a.ignoreCase != b.ignoreCase) + mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.global != b.global) + mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.multiline != b.multiline) + mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); + + return (mismatchValues.length === 0); +}; + jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { return true; @@ -960,6 +976,10 @@ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { return (a == b); } + if (a instanceof RegExp && b instanceof RegExp) { + return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); + } + if (typeof a === "object" && typeof b === "object") { return this.compareObjects_(a, b, mismatchKeys, mismatchValues); } diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index addd96ee..64f72fc5 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -75,6 +75,9 @@ describe("jasmine.Matchers", function() { expect((match(parseInt('5', 10)).toEqual(5))).toPass(); expect((match(5).toNotEqual(5))).toFail(); expect((match(parseInt('5', 10)).toNotEqual(5))).toFail(); + + expect((match(/1/i).toEqual(/1/i))).toPass(); + expect((match(/1/i).toNotEqual(/1/i))).toFail(); }); it("toEqual to build an Expectation Result", function() { diff --git a/src/core/Env.js b/src/core/Env.js index 4ebc0963..a3ae8ab2 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -168,6 +168,22 @@ jasmine.Env.prototype.xit = function(desc, func) { }; }; +jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.source != b.source) + mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); + + if (a.ignoreCase != b.ignoreCase) + mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.global != b.global) + mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.multiline != b.multiline) + mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); + + return (mismatchValues.length === 0); +}; + jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { return true; @@ -254,6 +270,10 @@ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { return (a == b); } + if (a instanceof RegExp && b instanceof RegExp) { + return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); + } + if (typeof a === "object" && typeof b === "object") { return this.compareObjects_(a, b, mismatchKeys, mismatchValues); } From 63ad879c12e7462a25e2f0680a9e6756c205be28 Mon Sep 17 00:00:00 2001 From: Joost Elfering Date: Tue, 5 Jun 2012 20:58:42 +0200 Subject: [PATCH 18/55] added some specs to strengthen the coverage pivotal/jasmine#234 --- spec/core/MatchersSpec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index 64f72fc5..c095cc24 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -78,6 +78,8 @@ describe("jasmine.Matchers", function() { expect((match(/1/i).toEqual(/1/i))).toPass(); expect((match(/1/i).toNotEqual(/1/i))).toFail(); + expect((match(/[abc]/gm).toEqual(/1/i))).toFail(); + expect((match(/[abc]/gm).toNotEqual(/1/i))).toPass(); }); it("toEqual to build an Expectation Result", function() { From d9467317a88d4698dbfaefb8b8f12317b40aaca4 Mon Sep 17 00:00:00 2001 From: Joost Elfering Date: Thu, 19 Jul 2012 01:52:27 +0200 Subject: [PATCH 19/55] adding a check for the sticky regExp option supported by Firefox and accepted by the ES6. Note that the tests for this case are checking for the support of the sticky parameter. the logic is still tested by the other expect statements in browsers that do not support sticky but will never enter that block as creating a regExp with that flag is not allowed. Coverage is still good. See pivotal/jasmine#234 --- lib/jasmine-core/jasmine.js | 3 +++ spec/core/MatchersSpec.js | 7 +++++++ src/core/Env.js | 3 +++ 3 files changed, 13 insertions(+) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index d1c365c4..d71facfb 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -887,6 +887,9 @@ jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchVal if (a.multiline != b.multiline) mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); + if (a.sticky != b.sticky) + mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); + return (mismatchValues.length === 0); }; diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index c095cc24..73cfe1f7 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -80,6 +80,13 @@ describe("jasmine.Matchers", function() { expect((match(/1/i).toNotEqual(/1/i))).toFail(); expect((match(/[abc]/gm).toEqual(/1/i))).toFail(); expect((match(/[abc]/gm).toNotEqual(/1/i))).toPass(); + + // only test if the browser supports the sticky option on a regExp see pull #234 + if (RegExp.prototype.sticky !== undefined) { + var sticky_regexp = new RegExp("[abc]", "y"); + expect((match(sticky_regexp).toEqual(/1/i))).toFail(); + expect((match(sticky_regexp).toNotEqual(/1/i))).toPass(); + } }); it("toEqual to build an Expectation Result", function() { diff --git a/src/core/Env.js b/src/core/Env.js index a3ae8ab2..aa461ab4 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -181,6 +181,9 @@ jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchVal if (a.multiline != b.multiline) mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); + if (a.sticky != b.sticky) + mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); + return (mismatchValues.length === 0); }; From ead9aa6d5a8ff92409ee13e111d5eb9700055bcf Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sun, 4 Mar 2012 16:18:43 -0800 Subject: [PATCH 20/55] When pretty-printing objects, don't include inherited properties. When making assertions about complex objects, Jasmine's failure message are sometimes gigantic and difficult to read because the string representation of an object contains all of the methods and properties in its prototype chain. This commit causes the pretty printer to only display on object's own properties. --- spec/core/PrettyPrintSpec.js | 8 ++++++++ src/core/PrettyPrinter.js | 1 + 2 files changed, 9 insertions(+) diff --git a/spec/core/PrettyPrintSpec.js b/spec/core/PrettyPrintSpec.js index becf8a61..6d1cfc08 100644 --- a/spec/core/PrettyPrintSpec.js +++ b/spec/core/PrettyPrintSpec.js @@ -32,6 +32,14 @@ describe("jasmine.pp", function () { }, bar: [1, 2, 3]})).toEqual("{ foo : Function, bar : [ 1, 2, 3 ] }"); }); + it("should not include inherited properties when stringifying an object", function() { + var SomeClass = function() {}; + SomeClass.prototype.foo = "inherited foo"; + var instance = new SomeClass(); + instance.bar = "my own bar"; + expect(jasmine.pp(instance)).toEqual("{ bar : 'my own bar' }"); + }); + it("should stringify RegExp objects properly", function() { expect(jasmine.pp(/x|y|z/)).toEqual("/x|y|z/"); }); diff --git a/src/core/PrettyPrinter.js b/src/core/PrettyPrinter.js index a7d283b6..74fa4e7a 100644 --- a/src/core/PrettyPrinter.js +++ b/src/core/PrettyPrinter.js @@ -57,6 +57,7 @@ jasmine.PrettyPrinter.prototype.format = function(value) { jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { for (var property in obj) { + if (!obj.hasOwnProperty(property)) continue; if (property == '__Jasmine_been_here_before__') continue; fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && obj.__lookupGetter__(property) !== null) : false); From e3a013ae99decb7a5efad5bce35aa492ae32d6d1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sun, 4 Mar 2012 16:27:16 -0800 Subject: [PATCH 21/55] Allow users to set the pretty-printer's recursion depth Currently, jasmine's pretty printer traverses objects to 40 levels of nesting. If an object is more deeply nested than that, an exception is thrown. I find that after a few levels of nesting, the output becomes difficult to read. The process of serializing such deep objects also sometimes crashes the browser or causes a 'slow script' warning. This commit exposes a 'MAX_PRETTY_PRINT_DEPTH' option. It also causes the pretty printer to skip over parts of an object that are nested to deeply by simply printing out 'Object' or 'Array', rather than throwing an exception. --- spec/core/PrettyPrintSpec.js | 22 ++++++++++++++++++++++ src/core/PrettyPrinter.js | 14 ++++++++++---- src/core/base.js | 5 +++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/spec/core/PrettyPrintSpec.js b/spec/core/PrettyPrintSpec.js index 6d1cfc08..14d0d3e0 100644 --- a/spec/core/PrettyPrintSpec.js +++ b/spec/core/PrettyPrintSpec.js @@ -40,6 +40,28 @@ describe("jasmine.pp", function () { expect(jasmine.pp(instance)).toEqual("{ bar : 'my own bar' }"); }); + it("should not recurse objects and arrays more deeply than jasmine.MAX_PRETTY_PRINT_DEPTH", function() { + var originalMaxDepth = jasmine.MAX_PRETTY_PRINT_DEPTH; + var nestedObject = { level1: { level2: { level3: { level4: "leaf" } } } }; + var nestedArray = [1, [2, [3, [4, "leaf"]]]]; + + try { + jasmine.MAX_PRETTY_PRINT_DEPTH = 2; + expect(jasmine.pp(nestedObject)).toEqual("{ level1 : { level2 : Object } }"); + expect(jasmine.pp(nestedArray)).toEqual("[ 1, [ 2, Array ] ]"); + + jasmine.MAX_PRETTY_PRINT_DEPTH = 3; + expect(jasmine.pp(nestedObject)).toEqual("{ level1 : { level2 : { level3 : Object } } }"); + expect(jasmine.pp(nestedArray)).toEqual("[ 1, [ 2, [ 3, Array ] ] ]"); + + jasmine.MAX_PRETTY_PRINT_DEPTH = 4; + expect(jasmine.pp(nestedObject)).toEqual("{ level1 : { level2 : { level3 : { level4 : 'leaf' } } } }"); + expect(jasmine.pp(nestedArray)).toEqual("[ 1, [ 2, [ 3, [ 4, 'leaf' ] ] ] ]"); + } finally { + jasmine.MAX_PRETTY_PRINT_DEPTH = originalMaxDepth; + } + }); + it("should stringify RegExp objects properly", function() { expect(jasmine.pp(/x|y|z/)).toEqual("/x|y|z/"); }); diff --git a/src/core/PrettyPrinter.js b/src/core/PrettyPrinter.js index 74fa4e7a..f276cea3 100644 --- a/src/core/PrettyPrinter.js +++ b/src/core/PrettyPrinter.js @@ -11,10 +11,6 @@ jasmine.PrettyPrinter = function() { * @param value */ jasmine.PrettyPrinter.prototype.format = function(value) { - if (this.ppNestLevel_ > 40) { - throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); - } - this.ppNestLevel_++; try { if (value === jasmine.undefined) { @@ -85,6 +81,11 @@ jasmine.StringPrettyPrinter.prototype.emitString = function(value) { }; jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { + if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { + this.append("Array"); + return; + } + this.append('[ '); for (var i = 0; i < array.length; i++) { if (i > 0) { @@ -96,6 +97,11 @@ jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { }; jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { + if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { + this.append("Object"); + return; + } + var self = this; this.append('{ '); var first = true; diff --git a/src/core/base.js b/src/core/base.js index 51761ba2..af8d3ea0 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -34,6 +34,11 @@ jasmine.VERBOSE = false; */ jasmine.DEFAULT_UPDATE_INTERVAL = 250; +/** + * Maximum levels of nesting that will be included when an object is pretty-printed + */ +jasmine.MAX_PRETTY_PRINT_DEPTH = 40; + /** * Default timeout interval in milliseconds for waitsFor() blocks. */ From 9a7c76ea2355d7ea953e623ed3cb54b2ea29d153 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Tue, 27 Nov 2012 13:47:02 -0800 Subject: [PATCH 22/55] Releasing 1.3 - Allow users to set the pretty-printer's recursion depth - When pretty-printing objects, don't include inherited properties. - Change toBeCloseTo matcher to be more consistent - Added toBeNaN matcher - Add checkbox to test runner which toggles catching of exceptions duri - Add config option which stops jasmine from capturing exceptions in a --- lib/jasmine-core/jasmine-html.js | 2 +- lib/jasmine-core/jasmine.js | 45 +++++++++++++++++++------------- lib/jasmine-core/version.rb | 2 +- pages | 2 +- src/core/Matchers.js | 2 +- src/version.js | 4 +-- src/version.json | 2 +- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 543d5696..157f7e85 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -154,7 +154,7 @@ jasmine.HtmlReporter = function(_doc) { dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), dom.alert = self.createDom('div', {className: 'alert'}, self.createDom('span', { className: 'exceptions' }, - self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), + self.createDom('label', { className: 'label', for: 'no_try_catch' }, 'No try/catch'), self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), dom.results = self.createDom('div', {className: 'results'}, dom.summary = self.createDom('div', { className: 'summary' }), diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index d71facfb..59641128 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -34,6 +34,11 @@ jasmine.VERBOSE = false; */ jasmine.DEFAULT_UPDATE_INTERVAL = 250; +/** + * Maximum levels of nesting that will be included when an object is pretty-printed + */ +jasmine.MAX_PRETTY_PRINT_DEPTH = 40; + /** * Default timeout interval in milliseconds for waitsFor() blocks. */ @@ -470,7 +475,7 @@ jasmine.log = function() { * @see jasmine.createSpy * @param obj * @param methodName - * @returns a Jasmine spy that can be chained with all spy methods + * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods */ var spyOn = function(obj, methodName) { return jasmine.getEnv().currentSpec.spyOn(obj, methodName); @@ -515,6 +520,7 @@ if (isCommonJS) exports.xit = xit; * jasmine.Matchers functions. * * @param {Object} actual Actual value to test against and expected value + * @return {jasmine.Matchers} */ var expect = function(actual) { return jasmine.getEnv().currentSpec.expect(actual); @@ -1404,18 +1410,14 @@ jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { + var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."; + var positiveMessage = ""; if (this.actual.callCount === 0) { - // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw] - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.", - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was." - ]; + positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called."; } else { - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall), - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall) - ]; + positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '') } + return [positiveMessage, invertedMessage]; }; return this.env.contains_(this.actual.argsForCall, expectedArgs); @@ -1473,7 +1475,7 @@ jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { * up to a given level of decimal precision (default 2). * * @param {Number} expected - * @param {Number} precision + * @param {Number} precision, as number of decimal places */ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { if (!(precision === 0)) { @@ -1485,7 +1487,7 @@ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { /** * Matcher that checks that the expected exception was thrown by the actual. * - * @param {String} expected + * @param {String} [expected] */ jasmine.Matchers.prototype.toThrow = function(expected) { var result = false; @@ -1883,10 +1885,6 @@ jasmine.PrettyPrinter = function() { * @param value */ jasmine.PrettyPrinter.prototype.format = function(value) { - if (this.ppNestLevel_ > 40) { - throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); - } - this.ppNestLevel_++; try { if (value === jasmine.undefined) { @@ -1929,6 +1927,7 @@ jasmine.PrettyPrinter.prototype.format = function(value) { jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { for (var property in obj) { + if (!obj.hasOwnProperty(property)) continue; if (property == '__Jasmine_been_here_before__') continue; fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && obj.__lookupGetter__(property) !== null) : false); @@ -1956,6 +1955,11 @@ jasmine.StringPrettyPrinter.prototype.emitString = function(value) { }; jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { + if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { + this.append("Array"); + return; + } + this.append('[ '); for (var i = 0; i < array.length; i++) { if (i > 0) { @@ -1967,6 +1971,11 @@ jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { }; jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { + if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { + this.append("Object"); + return; + } + var self = this; this.append('{ '); var first = true; @@ -2585,7 +2594,7 @@ jasmine.WaitsForBlock.prototype.execute = function(onComplete) { jasmine.version_= { "major": 1, - "minor": 2, + "minor": 3, "build": 0, - "revision": 1343710612 + "revision": 1354052693 }; diff --git a/lib/jasmine-core/version.rb b/lib/jasmine-core/version.rb index 026512ad..c3b58c72 100644 --- a/lib/jasmine-core/version.rb +++ b/lib/jasmine-core/version.rb @@ -1,6 +1,6 @@ module Jasmine module Core - VERSION = "1.2.0" + VERSION = "1.3.0" end end diff --git a/pages b/pages index 39dcf87b..00ba05c2 160000 --- a/pages +++ b/pages @@ -1 +1 @@ -Subproject commit 39dcf87b563e7cb0435208af562cc8ea033a47ff +Subproject commit 00ba05c213c22325e2dfc21307a8d07a379fd9a4 diff --git a/src/core/Matchers.js b/src/core/Matchers.js index 85802d39..09f449d8 100644 --- a/src/core/Matchers.js +++ b/src/core/Matchers.js @@ -303,7 +303,7 @@ jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { * up to a given level of decimal precision (default 2). * * @param {Number} expected - * @param {Number} precision + * @param {Number} precision, as number of decimal places */ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { if (!(precision === 0)) { diff --git a/src/version.js b/src/version.js index 0ed57491..17802ee9 100644 --- a/src/version.js +++ b/src/version.js @@ -1,7 +1,7 @@ jasmine.version_= { "major": 1, - "minor": 2, + "minor": 3, "build": 0, - "revision": 1343710612 + "revision": 1354052693 }; diff --git a/src/version.json b/src/version.json index f9c57fa6..0ec3a6d2 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { "major": 1, - "minor": 2, + "minor": 3, "build": 0 } From 86994b25db4cff39a45add0597af86446f3c94fa Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Wed, 28 Nov 2012 14:25:39 -0800 Subject: [PATCH 23/55] Use jasmine-gem for jasmine-core tests --- Gemfile | 8 +++++++ Rakefile | 38 +++++++++++++++++++++++++++++++++- lib/jasmine-core/jasmine.js | 2 +- spec/jasmine.yml | 21 +++++++++++++++++++ spec/jasmine_self_test_spec.rb | 23 ++++++++++++++++++++ src/version.js | 2 +- 6 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 spec/jasmine.yml create mode 100644 spec/jasmine_self_test_spec.rb diff --git a/Gemfile b/Gemfile index 7ec0cc26..5d929af7 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,11 @@ source :rubygems gem "rake" +gem "jasmine", git: 'https://github.com/pivotal/jasmine-gem.git' + +unless ENV["TRAVIS"] + group :debug do + gem 'debugger' + end +end + gemspec diff --git a/Rakefile b/Rakefile index 1acbd943..18530c8a 100644 --- a/Rakefile +++ b/Rakefile @@ -41,4 +41,40 @@ desc "View full development tasks" task :list_dev_tasks do puts "Jasmine uses Thor for command line tasks for development. Here is the command set:" system "thor list" -end \ No newline at end of file +end + +require "jasmine" +require 'rspec' +require 'rspec/core/rake_task' + +desc "Run all examples" +RSpec::Core::RakeTask.new(:jasmine_core_spec) do |t| + t.pattern = 'spec/jasmine_self_test_spec.rb' +end + +namespace :jasmine do + task :server do + port = ENV['JASMINE_PORT'] || 8888 + Jasmine.load_configuration_from_yaml(File.join(Dir.pwd, 'spec', 'jasmine.yml')) + config = Jasmine.config + server = Jasmine::Server.new(8888, Jasmine::Application.app(config)) + server.start + + puts "your tests are here:" + puts " http://localhost:#{port}/" + end + + desc "Copy examples from Jasmine JS to the gem" + task :copy_examples_to_gem do + require "fileutils" + + # copy jasmine's example tree into our generator templates dir + FileUtils.rm_r('generators/jasmine/templates/jasmine-example', :force => true) + FileUtils.cp_r(File.join(Jasmine::Core.path, 'example'), 'generators/jasmine/templates/jasmine-example', :preserve => true) + end +end + +desc "Run specs via server" +task :jasmine => ['jasmine:server'] + + diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 59641128..5d387683 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -2596,5 +2596,5 @@ jasmine.version_= { "major": 1, "minor": 3, "build": 0, - "revision": 1354052693 + "revision": 1354127958 }; diff --git a/spec/jasmine.yml b/spec/jasmine.yml new file mode 100644 index 00000000..a3f08713 --- /dev/null +++ b/spec/jasmine.yml @@ -0,0 +1,21 @@ +jasmine_dir: + - 'src' +jasmine_files: + - 'core/base.js' + - 'core/util.js' + - 'core/Reporter.js' + - 'html/HtmlReporterHelpers.js' + - '**/*.js' +jasmine_css_files: + - 'html/jasmine.css' +src_files: +stylesheets: +helpers: + - 'helpers/**/*.js' +spec_files: + - '**/*[sS]pec.js' +src_dir: +spec_dir: + - 'spec' + + diff --git a/spec/jasmine_self_test_spec.rb b/spec/jasmine_self_test_spec.rb new file mode 100644 index 00000000..1d36c211 --- /dev/null +++ b/spec/jasmine_self_test_spec.rb @@ -0,0 +1,23 @@ +require 'jasmine' + +Jasmine.load_configuration_from_yaml(File.join(Dir.pwd, 'spec', 'jasmine.yml')) +config = Jasmine.config +server = Jasmine::Server.new(config.port, Jasmine::Application.app(config)) +driver = Jasmine::SeleniumDriver.new(config.browser, "#{config.host}:#{config.port}/") + +t = Thread.new do + begin + server.start + rescue ChildProcess::TimeoutError + end + # # ignore bad exits +end +t.abort_on_exception = true +Jasmine::wait_for_listener(config.port, "jasmine server") +puts "jasmine server started." + +results_processor = Jasmine::ResultsProcessor.new(config) +results = Jasmine::Runners::HTTP.new(driver, results_processor, config.result_batch_size).run +formatter = Jasmine::RspecFormatter.new +formatter.format_results(results) + diff --git a/src/version.js b/src/version.js index 17802ee9..890cba47 100644 --- a/src/version.js +++ b/src/version.js @@ -3,5 +3,5 @@ jasmine.version_= { "major": 1, "minor": 3, "build": 0, - "revision": 1354052693 + "revision": 1354127999 }; From f7c9aaa996ac703636205da9c536ae51591e0e64 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Wed, 28 Nov 2012 14:27:07 -0800 Subject: [PATCH 24/55] Setup Travis build --- .gitmodules | 3 --- .rspec | 1 - .travis.yml | 9 +++++++++ README.markdown | 3 ++- pages | 1 - spec/jasmine.yml | 20 +++++++++++++++++++- 6 files changed, 30 insertions(+), 7 deletions(-) delete mode 100644 .gitmodules create mode 100644 .travis.yml delete mode 160000 pages diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 91b24fcd..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "pages"] - path = pages - url = git@github.com:pivotal/jasmine.git diff --git a/.rspec b/.rspec index 35f4d744..4e1e0d2f 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1 @@ --color ---format Fuubar diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..9e926baf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +# before_script: + # - "sh -e /etc/init.d/xvfb start" +before_install: + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start"# +script: "DISPLAY=:99.0 bundle exec rake jasmine_core_spec" + +rvm: + - "1.9.3" diff --git a/README.markdown b/README.markdown index 6382295d..a7eefb17 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,5 @@ -[Jasmine](http://pivotal.github.com/jasmine/) +[Jasmine](http://pivotal.github.com/jasmine/) + ======= **A JavaScript Testing Framework** diff --git a/pages b/pages deleted file mode 160000 index 00ba05c2..00000000 --- a/pages +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 00ba05c213c22325e2dfc21307a8d07a379fd9a4 diff --git a/spec/jasmine.yml b/spec/jasmine.yml index a3f08713..bd25c368 100644 --- a/spec/jasmine.yml +++ b/spec/jasmine.yml @@ -1,10 +1,28 @@ jasmine_dir: - 'src' +#This 'magic' inclusion order allows the travis build to pass. +#TODO: search for the correct files to include to prevent jasmine_files: - 'core/base.js' - 'core/util.js' - 'core/Reporter.js' + #end of known dependencies + - 'core/Env.js' + - 'core/Block.js' + - 'core/JsApiReporter.js' + - 'core/Matchers.js' + - 'core/mock-timeout.js' + - 'core/MultiReporter.js' + - 'core/NestedResults.js' + - 'core/PrettyPrinter.js' + - 'core/Queue.js' + - 'core/Runner.js' + - 'core/Spec.js' + - 'core/Suite.js' + - 'core/WaitsBlock.js' + - 'core/WaitsForBlock.js' - 'html/HtmlReporterHelpers.js' + - 'html/HtmlReporter.js' - '**/*.js' jasmine_css_files: - 'html/jasmine.css' @@ -13,7 +31,7 @@ stylesheets: helpers: - 'helpers/**/*.js' spec_files: - - '**/*[sS]pec.js' + - '**/*[Ss]pec.js' src_dir: spec_dir: - 'spec' From e74f09df9ce0a29707f72dafeab231a0d3a524b1 Mon Sep 17 00:00:00 2001 From: dev Date: Mon, 3 Dec 2012 15:07:46 +0000 Subject: [PATCH 25/55] Fixing test runner failures in IE 6/7/8 whereby HtmlReporter.js bails out as we're using for (reserved keyword) as object property name. Fix is just to quote the name which allows IE6/7/8 to run the tests. I think this might also fix Issue #303 on main repo (https://github.com/pivotal/jasmine/issues/303) --- src/html/HtmlReporter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index b5d062b8..2fde6f42 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -94,7 +94,7 @@ jasmine.HtmlReporter = function(_doc) { dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), dom.alert = self.createDom('div', {className: 'alert'}, self.createDom('span', { className: 'exceptions' }, - self.createDom('label', { className: 'label', for: 'no_try_catch' }, 'No try/catch'), + self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), dom.results = self.createDom('div', {className: 'results'}, dom.summary = self.createDom('div', { className: 'summary' }), From 6785d1a05c9cb319ca1e6fd4d8f6f3f233021397 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Mon, 3 Dec 2012 09:47:02 -0800 Subject: [PATCH 26/55] Re-add pages submodule for release build script - Use public github url --- .gitmodules | 3 +++ pages | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 pages diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..d88c3948 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "pages"] + path = pages + url = https://github.com/pivotal/jasmine.git diff --git a/pages b/pages new file mode 160000 index 00000000..00ba05c2 --- /dev/null +++ b/pages @@ -0,0 +1 @@ +Subproject commit 00ba05c213c22325e2dfc21307a8d07a379fd9a4 From b6c3999c3a6cae0930c46bdb21da95dca5f4b8f4 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Mon, 3 Dec 2012 09:51:08 -0800 Subject: [PATCH 27/55] Version 1.3.1 --- lib/jasmine-core/jasmine-html.js | 2 +- lib/jasmine-core/jasmine.js | 4 ++-- lib/jasmine-core/version.rb | 2 +- pages | 2 +- src/version.js | 4 ++-- src/version.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 157f7e85..543d5696 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -154,7 +154,7 @@ jasmine.HtmlReporter = function(_doc) { dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), dom.alert = self.createDom('div', {className: 'alert'}, self.createDom('span', { className: 'exceptions' }, - self.createDom('label', { className: 'label', for: 'no_try_catch' }, 'No try/catch'), + self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), dom.results = self.createDom('div', {className: 'results'}, dom.summary = self.createDom('div', { className: 'summary' }), diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 5d387683..6b3459b9 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -2595,6 +2595,6 @@ jasmine.WaitsForBlock.prototype.execute = function(onComplete) { jasmine.version_= { "major": 1, "minor": 3, - "build": 0, - "revision": 1354127958 + "build": 1, + "revision": 1354556913 }; diff --git a/lib/jasmine-core/version.rb b/lib/jasmine-core/version.rb index c3b58c72..2dafd0eb 100644 --- a/lib/jasmine-core/version.rb +++ b/lib/jasmine-core/version.rb @@ -1,6 +1,6 @@ module Jasmine module Core - VERSION = "1.3.0" + VERSION = "1.3.1" end end diff --git a/pages b/pages index 00ba05c2..dae7b20e 160000 --- a/pages +++ b/pages @@ -1 +1 @@ -Subproject commit 00ba05c213c22325e2dfc21307a8d07a379fd9a4 +Subproject commit dae7b20e1c018830aead62fec77da88d1affe91f diff --git a/src/version.js b/src/version.js index 890cba47..c7dc8057 100644 --- a/src/version.js +++ b/src/version.js @@ -2,6 +2,6 @@ jasmine.version_= { "major": 1, "minor": 3, - "build": 0, - "revision": 1354127999 + "build": 1, + "revision": 1354556913 }; diff --git a/src/version.json b/src/version.json index 0ec3a6d2..552c2e5c 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { "major": 1, "minor": 3, - "build": 0 + "build": 1 } From e2af08e0a68b1090bd05c55fb9b0969198eb330a Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Mon, 3 Dec 2012 14:54:05 -0800 Subject: [PATCH 28/55] Move most jasmine global usage into boot. - thor build scripts broken for now. --- Gemfile | 5 +- lib/jasmine-core.rb | 8 + lib/jasmine-core/boot/boot.js | 75 +++++ lib/jasmine-core/jasmine.js | 158 +-------- spec/core/BaseSpec.js | 8 - spec/core/CustomMatchersSpec.js | 4 +- spec/core/EnvSpec.js | 2 +- spec/core/MatchersSpec.js | 6 +- spec/core/MockClockSpec.js | 6 +- spec/core/MultiReporterSpec.js | 12 +- spec/core/QueueSpec.js | 3 +- spec/core/RunnerSpec.js | 8 +- spec/core/SpecRunningSpec.js | 8 +- spec/core/SpecSpec.js | 8 +- spec/core/SpySpec.js | 8 +- spec/core/SuiteSpec.js | 4 +- spec/core/WaitsForBlockSpec.js | 6 +- spec/html/TrivialReporterSpec.js | 2 +- spec/jasmine.yml | 14 +- spec/support/boot.js | 1 + spec/support/dev_boot.js | 5 + src/core/Env.js | 555 ++++++++++++++++--------------- src/core/base.js | 158 +-------- 23 files changed, 423 insertions(+), 641 deletions(-) create mode 100644 lib/jasmine-core/boot/boot.js create mode 120000 spec/support/boot.js create mode 100644 spec/support/dev_boot.js diff --git a/Gemfile b/Gemfile index 5d929af7..f2cb57c0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,11 +1,12 @@ source :rubygems gem "rake" -gem "jasmine", git: 'https://github.com/pivotal/jasmine-gem.git' +#gem "jasmine", git: 'https://github.com/pivotal/jasmine-gem.git' +gem "jasmine", path: '~/workspace/jasmine-gem' unless ENV["TRAVIS"] group :debug do gem 'debugger' end end - + gemspec diff --git a/lib/jasmine-core.rb b/lib/jasmine-core.rb index ecf968a6..3bf880c3 100644 --- a/lib/jasmine-core.rb +++ b/lib/jasmine-core.rb @@ -23,6 +23,14 @@ module Jasmine spec_files("node") end + def boot_files + ["boot.js"] + end + + def boot_dir + File.join(path, 'boot') + end + def spec_files(type) raise ArgumentError.new("Unrecognized spec type") unless SPEC_TYPES.include?(type) (Dir.glob(File.join(path, "spec", type, "*.js"))).map { |f| File.join("spec", type, File.basename(f)) }.uniq diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js new file mode 100644 index 00000000..73e2db53 --- /dev/null +++ b/lib/jasmine-core/boot/boot.js @@ -0,0 +1,75 @@ +(function() { + var env = jasmine.getEnv(); + + var jasmineInterface = { + describe: function(description, specDefinitions) { + return env.describe(description, specDefinitions); + }, + + xdescribe: function(description, specDefinitions) { + return env.xdescribe(description, specDefinitions); + }, + + it: function(desc, func) { + return env.it(desc, func); + }, + + xit: function(desc, func) { + return env.xit(desc, func); + }, + + beforeEach: function(beforeEachFunction) { + return env.beforeEach(beforeEachFunction); + }, + + afterEach: function(afterEachFunction) { + return env.afterEach(afterEachFunction); + }, + + expect: function(actual) { + return env.currentSpec.expect(actual); + }, + + runs: function(func) { + return env.currentSpec.runs(func); + }, + + waits: function(timeout) { + return env.currentSpec.waits(timeout); + }, + + waitsFor: function(latchFunction, optional_timeoutMessage, optional_timeout) { + return env.currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); + }, + + spyOn: function(obj, methodName) { + return env.currentSpec.spyOn(obj, methodName); + }, + jsApiReporter: new jasmine.JsApiReporter() + }; + + if (typeof window == "undefined" && typeof exports == "object") { + jasmine.util.extend(exports, jasmineInterface); + } else { + jasmine.util.extend(window, jasmineInterface); + } + + var htmlReporter = new jasmine.HtmlReporter(); + + env.addReporter(jasmineInterface.jsApiReporter); + env.addReporter(htmlReporter); + + env.specFilter = function(spec) { + return htmlReporter.specFilter(spec); + }; + + var currentWindowOnload = window.onload; + + window.onload = function() { + if (currentWindowOnload) { + currentWindowOnload(); + } + env.execute(); + }; + +}()); diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 6b3459b9..115a94cd 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1,4 +1,3 @@ -var isCommonJS = typeof window == "undefined" && typeof exports == "object"; /** * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. @@ -6,7 +5,7 @@ var isCommonJS = typeof window == "undefined" && typeof exports == "object"; * @namespace */ var jasmine = {}; -if (isCommonJS) exports.jasmine = jasmine; + /** * @private */ @@ -128,6 +127,7 @@ jasmine.ExpectationResult.prototype.passed = function () { */ jasmine.getEnv = function() { var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); + //jasmine. singletons in here (setTimeout blah blah). return env; }; @@ -462,160 +462,6 @@ jasmine.log = function() { spec.log.apply(spec, arguments); }; -/** - * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. - * - * @example - * // spy example - * var foo = { - * not: function(bool) { return !bool; } - * } - * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops - * - * @see jasmine.createSpy - * @param obj - * @param methodName - * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods - */ -var spyOn = function(obj, methodName) { - return jasmine.getEnv().currentSpec.spyOn(obj, methodName); -}; -if (isCommonJS) exports.spyOn = spyOn; - -/** - * Creates a Jasmine spec that will be added to the current suite. - * - * // TODO: pending tests - * - * @example - * it('should be true', function() { - * expect(true).toEqual(true); - * }); - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var it = function(desc, func) { - return jasmine.getEnv().it(desc, func); -}; -if (isCommonJS) exports.it = it; - -/** - * Creates a disabled Jasmine spec. - * - * A convenience method that allows existing specs to be disabled temporarily during development. - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var xit = function(desc, func) { - return jasmine.getEnv().xit(desc, func); -}; -if (isCommonJS) exports.xit = xit; - -/** - * Starts a chain for a Jasmine expectation. - * - * It is passed an Object that is the actual value and should chain to one of the many - * jasmine.Matchers functions. - * - * @param {Object} actual Actual value to test against and expected value - * @return {jasmine.Matchers} - */ -var expect = function(actual) { - return jasmine.getEnv().currentSpec.expect(actual); -}; -if (isCommonJS) exports.expect = expect; - -/** - * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. - * - * @param {Function} func Function that defines part of a jasmine spec. - */ -var runs = function(func) { - jasmine.getEnv().currentSpec.runs(func); -}; -if (isCommonJS) exports.runs = runs; - -/** - * Waits a fixed time period before moving to the next block. - * - * @deprecated Use waitsFor() instead - * @param {Number} timeout milliseconds to wait - */ -var waits = function(timeout) { - jasmine.getEnv().currentSpec.waits(timeout); -}; -if (isCommonJS) exports.waits = waits; - -/** - * Waits for the latchFunction to return true before proceeding to the next block. - * - * @param {Function} latchFunction - * @param {String} optional_timeoutMessage - * @param {Number} optional_timeout - */ -var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { - jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); -}; -if (isCommonJS) exports.waitsFor = waitsFor; - -/** - * A function that is called before each spec in a suite. - * - * Used for spec setup, including validating assumptions. - * - * @param {Function} beforeEachFunction - */ -var beforeEach = function(beforeEachFunction) { - jasmine.getEnv().beforeEach(beforeEachFunction); -}; -if (isCommonJS) exports.beforeEach = beforeEach; - -/** - * A function that is called after each spec in a suite. - * - * Used for restoring any state that is hijacked during spec execution. - * - * @param {Function} afterEachFunction - */ -var afterEach = function(afterEachFunction) { - jasmine.getEnv().afterEach(afterEachFunction); -}; -if (isCommonJS) exports.afterEach = afterEach; - -/** - * Defines a suite of specifications. - * - * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared - * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization - * of setup in some tests. - * - * @example - * // TODO: a simple suite - * - * // TODO: a simple suite with a nested describe block - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var describe = function(description, specDefinitions) { - return jasmine.getEnv().describe(description, specDefinitions); -}; -if (isCommonJS) exports.describe = describe; - -/** - * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var xdescribe = function(description, specDefinitions) { - return jasmine.getEnv().xdescribe(description, specDefinitions); -}; -if (isCommonJS) exports.xdescribe = xdescribe; - - // Provide the XMLHttpRequest class for IE 5.x-6.x: jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { function tryIt(f) { diff --git a/spec/core/BaseSpec.js b/spec/core/BaseSpec.js index 121a8815..f0477e8b 100644 --- a/spec/core/BaseSpec.js +++ b/spec/core/BaseSpec.js @@ -7,14 +7,6 @@ describe("base.js", function() { }); }); - describe("jasmine.log", function() { - it("should accept n arguments", function() { - spyOn(jasmine.getEnv().currentSpec, 'log'); - jasmine.log(1, 2, 3); - expect(jasmine.getEnv().currentSpec.log).toHaveBeenCalledWith(1, 2, 3); - }); - }); - describe("jasmine.getGlobal", function() { it("should return the global object", function() { var globalObject = (function() { diff --git a/spec/core/CustomMatchersSpec.js b/spec/core/CustomMatchersSpec.js index 7a724b57..86f98547 100644 --- a/spec/core/CustomMatchersSpec.js +++ b/spec/core/CustomMatchersSpec.js @@ -65,7 +65,7 @@ describe("Custom Matchers", function() { actual: true, expected: jasmine.undefined, message: "Passed." }); var failResult = new jasmine.ExpectationResult({passed: false, matcherName: 'toBeTrue', actual: false, expected: jasmine.undefined, message: "Expected false to be true." }); - failResult.trace = jasmine.any(Object); + failResult.trace = originalJasmine.any(Object); expect(spec.results().getItems()).toEqual([passResult, failResult]); }); @@ -94,4 +94,4 @@ describe("Custom Matchers", function() { expect(matcherCallArgs).toEqual([[], ['arg'], ['arg1', 'arg2']]); }); -}); \ No newline at end of file +}); diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 3bd67031..7211618a 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -17,7 +17,7 @@ describe("jasmine.Env", function() { var fakeReporter; beforeEach(function() { - fakeReporter = jasmine.createSpyObj("fakeReporter", ["log"]); + fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log"]); }); describe('version', function () { diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index 73cfe1f7..8cce5cd2 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -391,7 +391,7 @@ describe("jasmine.Matchers", function() { var matcher; beforeEach(function () { matcher = { - jasmineMatches: jasmine.createSpy("jasmineMatches") + jasmineMatches: originalJasmine.createSpy("jasmineMatches") }; }); @@ -694,7 +694,7 @@ describe("jasmine.Matchers", function() { TestClass = { normalFunction: function() { }, - spyFunction: jasmine.createSpy("My spy") + spyFunction: originalJasmine.createSpy("My spy") }; }); @@ -974,7 +974,7 @@ describe("jasmine.Matchers", function() { describe("in real life", function () { var method; beforeEach(function () { - method = jasmine.createSpy("method"); + method = originalJasmine.createSpy("method"); method({a:"b", c:"d"}); }); it("works correctly for positive matches", function () { diff --git a/spec/core/MockClockSpec.js b/spec/core/MockClockSpec.js index be683440..24053a5f 100644 --- a/spec/core/MockClockSpec.js +++ b/spec/core/MockClockSpec.js @@ -1,7 +1,9 @@ -describe("MockClock", function () { +// TODO: Disabling b/c this spec isn't testing what it thinks it is. +// Make a proper unit and intergration tests for this object +xdescribe("MockClock", function () { beforeEach(function() { - jasmine.Clock.useMock(); + jasmine.Clock.useMock(); }); describe("setTimeout", function () { diff --git a/spec/core/MultiReporterSpec.js b/spec/core/MultiReporterSpec.js index f269d682..bbad22ff 100644 --- a/spec/core/MultiReporterSpec.js +++ b/spec/core/MultiReporterSpec.js @@ -3,8 +3,8 @@ describe("jasmine.MultiReporter", function() { beforeEach(function() { multiReporter = new jasmine.MultiReporter(); - fakeReporter1 = jasmine.createSpyObj("fakeReporter1", ["reportSpecResults"]); - fakeReporter2 = jasmine.createSpyObj("fakeReporter2", ["reportSpecResults", "reportRunnerStarting"]); + fakeReporter1 = originalJasmine.createSpyObj("fakeReporter1", ["reportSpecResults"]); + fakeReporter2 = originalJasmine.createSpyObj("fakeReporter2", ["reportSpecResults", "reportRunnerStarting"]); multiReporter.addReporter(fakeReporter1); multiReporter.addReporter(fakeReporter2); }); @@ -15,11 +15,11 @@ describe("jasmine.MultiReporter", function() { this.addMatchers({ toDelegateMethod: function(methodName) { - delegate[methodName] = jasmine.createSpy(methodName); + delegate[methodName] = originalJasmine.createSpy(methodName); this.actual[methodName]("whatever argument"); - return delegate[methodName].wasCalled && - delegate[methodName].mostRecentCall.args.length == 1 && + return delegate[methodName].wasCalled && + delegate[methodName].mostRecentCall.args.length == 1 && delegate[methodName].mostRecentCall.args[0] == "whatever argument"; } }); @@ -42,4 +42,4 @@ describe("jasmine.MultiReporter", function() { multiReporter.reportRunnerStarting('blah', 'foo'); expect(fakeReporter2.reportRunnerStarting).toHaveBeenCalledWith('blah', 'foo'); }); -}); \ No newline at end of file +}); diff --git a/spec/core/QueueSpec.js b/spec/core/QueueSpec.js index 59a70f39..a21e675b 100644 --- a/spec/core/QueueSpec.js +++ b/spec/core/QueueSpec.js @@ -12,7 +12,6 @@ describe("jasmine.Queue", function() { queue.next_ = function() { nestCount++; if (nestCount > maxNestCount) maxNestCount = nestCount; - jasmine.Queue.prototype.next_.apply(queue, arguments); nestCount--; }; @@ -20,4 +19,4 @@ describe("jasmine.Queue", function() { queue.start(); expect(maxNestCount).toEqual(1); }); -}); \ No newline at end of file +}); diff --git a/spec/core/RunnerSpec.js b/spec/core/RunnerSpec.js index 090a15ea..5d00bbd6 100644 --- a/spec/core/RunnerSpec.js +++ b/spec/core/RunnerSpec.js @@ -107,7 +107,7 @@ describe('RunnerTest', function() { }); it('should run after a failing spec', function () { - var afterEach = jasmine.createSpy(); + var afterEach = originalJasmine.createSpy(); env.afterEach(afterEach); env.describe('suite', function () { @@ -200,7 +200,7 @@ describe('RunnerTest', function() { describe('reporting', function () { var fakeReporter; beforeEach(function () { - fakeReporter = jasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting", "reportRunnerResults"]); + fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting", "reportRunnerResults"]); env.addReporter(fakeReporter); }); @@ -233,7 +233,7 @@ describe('RunnerTest', function() { }); it("should report when the tests start running", function() { - var fakeReporter = jasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting"]); + var fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting"]); env.addReporter(fakeReporter); @@ -277,4 +277,4 @@ describe('RunnerTest', function() { expect(suiteNames(suites)).toEqual([suite1.getFullName(), suite3.getFullName()]); }); }); -}); \ No newline at end of file +}); diff --git a/spec/core/SpecRunningSpec.js b/spec/core/SpecRunningSpec.js index a0268224..377e5812 100644 --- a/spec/core/SpecRunningSpec.js +++ b/spec/core/SpecRunningSpec.js @@ -6,7 +6,7 @@ describe("jasmine spec running", function () { env = new jasmine.Env(); env.updateInterval = 0; - fakeTimer = new jasmine.FakeTimer(); + fakeTimer = new originalJasmine.FakeTimer(); env.setTimeout = fakeTimer.setTimeout; env.clearTimeout = fakeTimer.clearTimeout; env.setInterval = fakeTimer.setInterval; @@ -400,7 +400,7 @@ describe("jasmine spec running", function () { }); it("runs afterEach after timing out", function() { - var afterEach = jasmine.createSpy('afterEach'); + var afterEach = originalJasmine.createSpy('afterEach'); env.describe('foo', function () { env.afterEach(afterEach); @@ -417,7 +417,7 @@ describe("jasmine spec running", function () { }); it("runs single-spec after functions after timing out", function() { - var after = jasmine.createSpy('after'); + var after = originalJasmine.createSpy('after'); env.describe('foo', function () { env.it('waitsFor', function () { @@ -1200,7 +1200,7 @@ describe("jasmine spec running", function () { }); it('shouldn\'t execute specs in disabled suites', function() { - var spy = jasmine.createSpy(); + var spy = originalJasmine.createSpy(); var disabledSuite = env.xdescribe('a disabled suite', function() { env.it('enabled spec, but should not be run', function() { spy(); diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 1e4a22d4..0c96be84 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -113,12 +113,12 @@ describe('Spec', function () { spec.execute(); var items = results.getItems(); expect(items).toEqual([ - jasmine.any(jasmine.ExpectationResult), - jasmine.any(jasmine.ExpectationResult), - jasmine.any(jasmine.MessageResult) + originalJasmine.any(jasmine.ExpectationResult), + originalJasmine.any(jasmine.ExpectationResult), + originalJasmine.any(jasmine.MessageResult) ]); var logResult = items[2]; expect(logResult.values).toEqual(["here's some log message", {key: 'value'}, 123]); }); }); -}); \ No newline at end of file +}); diff --git a/spec/core/SpySpec.js b/spec/core/SpySpec.js index 90439c4e..d48608f7 100644 --- a/spec/core/SpySpec.js +++ b/spec/core/SpySpec.js @@ -165,7 +165,7 @@ describe('Spies', function () { expect(exception).toBeDefined(); }); - + it('to spy on an undefined method throws exception', function() { var TestClass = { someFunction : function() { @@ -177,8 +177,8 @@ describe('Spies', function () { expect(function() { efunc(); }).toThrow('someOtherFunction() method does not exist'); - - }); + + }); it('should be able to reset a spy', function() { var TestClass = { someFunction: function() {} }; @@ -195,7 +195,7 @@ describe('Spies', function () { describe("createSpyObj", function() { it("should create an object with a bunch of spy methods when you call jasmine.createSpyObj()", function() { var spyObj = jasmine.createSpyObj('BaseName', ['method1', 'method2']); - expect(spyObj).toEqual({ method1: jasmine.any(Function), method2: jasmine.any(Function)}); + expect(spyObj).toEqual({ method1: originalJasmine.any(Function), method2: originalJasmine.any(Function)}); expect(spyObj.method1.identity).toEqual('BaseName.method1'); expect(spyObj.method2.identity).toEqual('BaseName.method2'); }); diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index d48ef39c..84141dec 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -6,7 +6,7 @@ describe('Suite', function() { env = new jasmine.Env(); env.updateInterval = 0; - fakeTimer = new jasmine.FakeTimer(); + fakeTimer = new originalJasmine.FakeTimer(); env.setTimeout = fakeTimer.setTimeout; env.clearTimeout = fakeTimer.clearTimeout; env.setInterval = fakeTimer.setInterval; @@ -117,4 +117,4 @@ describe('Suite', function() { expect(suite.specs().length).toEqual(3); }); }); -}); \ No newline at end of file +}); diff --git a/spec/core/WaitsForBlockSpec.js b/spec/core/WaitsForBlockSpec.js index e1807212..741a98ef 100644 --- a/spec/core/WaitsForBlockSpec.js +++ b/spec/core/WaitsForBlockSpec.js @@ -7,7 +7,7 @@ describe('WaitsForBlock', function () { timeout = 1000; spec = new jasmine.Spec(env, suite); message = "some error message"; - onComplete = jasmine.createSpy("onComplete"); + onComplete = originalJasmine.createSpy("onComplete"); }); describe("jasmine.VERBOSE", function() { @@ -63,7 +63,7 @@ describe('WaitsForBlock', function () { }); it('should fail spec and call onComplete if there is an error in the latchFunction', function() { - var latchFunction = jasmine.createSpy('latchFunction').andThrow('some error'); + var latchFunction = originalJasmine.createSpy('latchFunction').andThrow('some error'); spyOn(spec, 'fail'); var block = new jasmine.WaitsForBlock(env, timeout, latchFunction, message, spec); block.execute(onComplete); @@ -74,7 +74,7 @@ describe('WaitsForBlock', function () { describe("if latchFunction returns false", function() { var latchFunction, fakeTimer; beforeEach(function() { - latchFunction = jasmine.createSpy('latchFunction').andReturn(false); + latchFunction = originalJasmine.createSpy('latchFunction').andReturn(false); fakeTimer = new jasmine.FakeTimer(); env.setTimeout = fakeTimer.setTimeout; env.clearTimeout = fakeTimer.clearTimeout; diff --git a/spec/html/TrivialReporterSpec.js b/spec/html/TrivialReporterSpec.js index 4e0830da..8462f0c6 100644 --- a/spec/html/TrivialReporterSpec.js +++ b/spec/html/TrivialReporterSpec.js @@ -69,7 +69,7 @@ describe("TrivialReporter", function() { var runner, spec, fakeTimer; beforeEach(function () { - fakeTimer = new jasmine.FakeTimer(); + fakeTimer = new originalJasmine.FakeTimer(); env.setTimeout = fakeTimer.setTimeout; env.clearTimeout = fakeTimer.clearTimeout; env.setInterval = fakeTimer.setInterval; diff --git a/spec/jasmine.yml b/spec/jasmine.yml index bd25c368..ff98886f 100644 --- a/spec/jasmine.yml +++ b/spec/jasmine.yml @@ -1,8 +1,8 @@ -jasmine_dir: - - 'src' #This 'magic' inclusion order allows the travis build to pass. #TODO: search for the correct files to include to prevent -jasmine_files: +src_dir: + - 'src' +src_files: - 'core/base.js' - 'core/util.js' - 'core/Reporter.js' @@ -24,15 +24,15 @@ jasmine_files: - 'html/HtmlReporterHelpers.js' - 'html/HtmlReporter.js' - '**/*.js' -jasmine_css_files: - - 'html/jasmine.css' -src_files: stylesheets: +boot_dir: 'spec/support' +boot_files: + - 'boot.js' + - 'dev_boot.js' helpers: - 'helpers/**/*.js' spec_files: - '**/*[Ss]pec.js' -src_dir: spec_dir: - 'spec' diff --git a/spec/support/boot.js b/spec/support/boot.js new file mode 120000 index 00000000..fc5f90d3 --- /dev/null +++ b/spec/support/boot.js @@ -0,0 +1 @@ +../../lib/jasmine-core/boot/boot.js \ No newline at end of file diff --git a/spec/support/dev_boot.js b/spec/support/dev_boot.js new file mode 100644 index 00000000..471ca317 --- /dev/null +++ b/spec/support/dev_boot.js @@ -0,0 +1,5 @@ +var originalJasmine = jasmine; +//copy clock methods back into window, +//so second jasmine load doesn't use jasmine clock methods. +jasmine.util.extend(window, jasmine.Clock.real); +jasmine = null; diff --git a/src/core/Env.js b/src/core/Env.js index aa461ab4..80767e99 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -3,298 +3,305 @@ * * @constructor */ -jasmine.Env = function() { - this.currentSpec = null; - this.currentSuite = null; - this.currentRunner_ = new jasmine.Runner(this); +(function() { - this.reporter = new jasmine.MultiReporter(); + function createSpec(env, suite, description) { + return new jasmine.Spec(env, suite, description); + } - this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; - this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; - this.lastUpdate = 0; - this.specFilter = function() { - return true; + jasmine.Env = function() { + this.currentSpec = null; + this.currentSuite = null; + this.currentRunner_ = new jasmine.Runner(this); + + this.reporter = new jasmine.MultiReporter(); + + this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; + this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; + this.lastUpdate = 0; + this.specFilter = function() { + return true; + }; + + this.nextSpecId_ = 0; + this.nextSuiteId_ = 0; + this.equalityTesters_ = []; + + // wrap matchers + this.matchersClass = function() { + jasmine.Matchers.apply(this, arguments); + }; + jasmine.util.inherit(this.matchersClass, jasmine.Matchers); + + jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); }; - this.nextSpecId_ = 0; - this.nextSuiteId_ = 0; - this.equalityTesters_ = []; - // wrap matchers - this.matchersClass = function() { - jasmine.Matchers.apply(this, arguments); - }; - jasmine.util.inherit(this.matchersClass, jasmine.Matchers); + jasmine.Env.prototype.setTimeout = jasmine.setTimeout; + jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; + jasmine.Env.prototype.setInterval = jasmine.setInterval; + jasmine.Env.prototype.clearInterval = jasmine.clearInterval; - jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); -}; - - -jasmine.Env.prototype.setTimeout = jasmine.setTimeout; -jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; -jasmine.Env.prototype.setInterval = jasmine.setInterval; -jasmine.Env.prototype.clearInterval = jasmine.clearInterval; - -/** - * @returns an object containing jasmine version build info, if set. - */ -jasmine.Env.prototype.version = function () { - if (jasmine.version_) { - return jasmine.version_; - } else { - throw new Error('Version not set'); - } -}; - -/** - * @returns string containing jasmine version build info, if set. - */ -jasmine.Env.prototype.versionString = function() { - if (!jasmine.version_) { - return "version unknown"; - } - - var version = this.version(); - var versionString = version.major + "." + version.minor + "." + version.build; - if (version.release_candidate) { - versionString += ".rc" + version.release_candidate; - } - versionString += " revision " + version.revision; - return versionString; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSpecId = function () { - return this.nextSpecId_++; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSuiteId = function () { - return this.nextSuiteId_++; -}; - -/** - * Register a reporter to receive status updates from Jasmine. - * @param {jasmine.Reporter} reporter An object which will receive status updates. - */ -jasmine.Env.prototype.addReporter = function(reporter) { - this.reporter.addReporter(reporter); -}; - -jasmine.Env.prototype.execute = function() { - this.currentRunner_.execute(); -}; - -jasmine.Env.prototype.describe = function(description, specDefinitions) { - var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); - - var parentSuite = this.currentSuite; - if (parentSuite) { - parentSuite.add(suite); - } else { - this.currentRunner_.add(suite); - } - - this.currentSuite = suite; - - var declarationError = null; - try { - specDefinitions.call(suite); - } catch(e) { - declarationError = e; - } - - if (declarationError) { - this.it("encountered a declaration exception", function() { - throw declarationError; - }); - } - - this.currentSuite = parentSuite; - - return suite; -}; - -jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { - if (this.currentSuite) { - this.currentSuite.beforeEach(beforeEachFunction); - } else { - this.currentRunner_.beforeEach(beforeEachFunction); - } -}; - -jasmine.Env.prototype.currentRunner = function () { - return this.currentRunner_; -}; - -jasmine.Env.prototype.afterEach = function(afterEachFunction) { - if (this.currentSuite) { - this.currentSuite.afterEach(afterEachFunction); - } else { - this.currentRunner_.afterEach(afterEachFunction); - } - -}; - -jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { - return { - execute: function() { + /** + * @returns an object containing jasmine version build info, if set. + */ + jasmine.Env.prototype.version = function () { + if (jasmine.version_) { + return jasmine.version_; + } else { + throw new Error('Version not set'); } }; -}; -jasmine.Env.prototype.it = function(description, func) { - var spec = new jasmine.Spec(this, this.currentSuite, description); - this.currentSuite.add(spec); - this.currentSpec = spec; - - if (func) { - spec.runs(func); - } - - return spec; -}; - -jasmine.Env.prototype.xit = function(desc, func) { - return { - id: this.nextSpecId(), - runs: function() { + /** + * @returns string containing jasmine version build info, if set. + */ + jasmine.Env.prototype.versionString = function() { + if (!jasmine.version_) { + return "version unknown"; } - }; -}; -jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { - if (a.source != b.source) - mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); - - if (a.ignoreCase != b.ignoreCase) - mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); - - if (a.global != b.global) - mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); - - if (a.multiline != b.multiline) - mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); - - if (a.sticky != b.sticky) - mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); - - return (mismatchValues.length === 0); -}; - -jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { - if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { - return true; - } - - a.__Jasmine_been_here_before__ = b; - b.__Jasmine_been_here_before__ = a; - - var hasKey = function(obj, keyName) { - return obj !== null && obj[keyName] !== jasmine.undefined; + var version = this.version(); + var versionString = version.major + "." + version.minor + "." + version.build; + if (version.release_candidate) { + versionString += ".rc" + version.release_candidate; + } + versionString += " revision " + version.revision; + return versionString; }; - for (var property in b) { - if (!hasKey(a, property) && hasKey(b, property)) { - mismatchKeys.push("expected has key '" + property + "', but missing from actual."); + /** + * @returns a sequential integer starting at 0 + */ + jasmine.Env.prototype.nextSpecId = function () { + return this.nextSpecId_++; + }; + + /** + * @returns a sequential integer starting at 0 + */ + jasmine.Env.prototype.nextSuiteId = function () { + return this.nextSuiteId_++; + }; + + /** + * Register a reporter to receive status updates from Jasmine. + * @param {jasmine.Reporter} reporter An object which will receive status updates. + */ + jasmine.Env.prototype.addReporter = function(reporter) { + this.reporter.addReporter(reporter); + }; + + jasmine.Env.prototype.execute = function() { + this.currentRunner_.execute(); + }; + + jasmine.Env.prototype.describe = function(description, specDefinitions) { + var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); + + var parentSuite = this.currentSuite; + if (parentSuite) { + parentSuite.add(suite); + } else { + this.currentRunner_.add(suite); } - } - for (property in a) { - if (!hasKey(b, property) && hasKey(a, property)) { - mismatchKeys.push("expected missing key '" + property + "', but present in actual."); + + this.currentSuite = suite; + + var declarationError = null; + try { + specDefinitions.call(suite); + } catch(e) { + declarationError = e; } - } - for (property in b) { - if (property == '__Jasmine_been_here_before__') continue; - if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { - mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); + + if (declarationError) { + this.it("encountered a declaration exception", function() { + throw declarationError; + }); } - } - if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { - mismatchValues.push("arrays were not the same length"); - } + this.currentSuite = parentSuite; - delete a.__Jasmine_been_here_before__; - delete b.__Jasmine_been_here_before__; - return (mismatchKeys.length === 0 && mismatchValues.length === 0); -}; + return suite; + }; -jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { - mismatchKeys = mismatchKeys || []; - mismatchValues = mismatchValues || []; - - for (var i = 0; i < this.equalityTesters_.length; i++) { - var equalityTester = this.equalityTesters_[i]; - var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); - if (result !== jasmine.undefined) return result; - } - - if (a === b) return true; - - if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { - return (a == jasmine.undefined && b == jasmine.undefined); - } - - if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { - return a === b; - } - - if (a instanceof Date && b instanceof Date) { - return a.getTime() == b.getTime(); - } - - if (a.jasmineMatches) { - return a.jasmineMatches(b); - } - - if (b.jasmineMatches) { - return b.jasmineMatches(a); - } - - if (a instanceof jasmine.Matchers.ObjectContaining) { - return a.matches(b); - } - - if (b instanceof jasmine.Matchers.ObjectContaining) { - return b.matches(a); - } - - if (jasmine.isString_(a) && jasmine.isString_(b)) { - return (a == b); - } - - if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { - return (a == b); - } - - if (a instanceof RegExp && b instanceof RegExp) { - return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); - } - - if (typeof a === "object" && typeof b === "object") { - return this.compareObjects_(a, b, mismatchKeys, mismatchValues); - } - - //Straight check - return (a === b); -}; - -jasmine.Env.prototype.contains_ = function(haystack, needle) { - if (jasmine.isArray_(haystack)) { - for (var i = 0; i < haystack.length; i++) { - if (this.equals_(haystack[i], needle)) return true; + jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { + if (this.currentSuite) { + this.currentSuite.beforeEach(beforeEachFunction); + } else { + this.currentRunner_.beforeEach(beforeEachFunction); } - return false; - } - return haystack.indexOf(needle) >= 0; -}; + }; -jasmine.Env.prototype.addEqualityTester = function(equalityTester) { - this.equalityTesters_.push(equalityTester); -}; + jasmine.Env.prototype.currentRunner = function () { + return this.currentRunner_; + }; + + jasmine.Env.prototype.afterEach = function(afterEachFunction) { + if (this.currentSuite) { + this.currentSuite.afterEach(afterEachFunction); + } else { + this.currentRunner_.afterEach(afterEachFunction); + } + + }; + + jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { + return { + execute: function() { + } + }; + }; + + jasmine.Env.prototype.it = function(description, func) { + var spec = createSpec(this, this.currentSuite, description); + this.currentSuite.add(spec); + this.currentSpec = spec; + + if (func) { + spec.runs(func); + } + + return spec; + }; + + jasmine.Env.prototype.xit = function(desc, func) { + return { + id: this.nextSpecId(), + runs: function() { + } + }; + }; + + jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.source != b.source) + mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); + + if (a.ignoreCase != b.ignoreCase) + mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.global != b.global) + mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.multiline != b.multiline) + mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.sticky != b.sticky) + mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); + + return (mismatchValues.length === 0); + }; + + jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { + return true; + } + + a.__Jasmine_been_here_before__ = b; + b.__Jasmine_been_here_before__ = a; + + var hasKey = function(obj, keyName) { + return obj !== null && obj[keyName] !== jasmine.undefined; + }; + + for (var property in b) { + if (!hasKey(a, property) && hasKey(b, property)) { + mismatchKeys.push("expected has key '" + property + "', but missing from actual."); + } + } + for (property in a) { + if (!hasKey(b, property) && hasKey(a, property)) { + mismatchKeys.push("expected missing key '" + property + "', but present in actual."); + } + } + for (property in b) { + if (property == '__Jasmine_been_here_before__') continue; + if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { + mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); + } + } + + if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { + mismatchValues.push("arrays were not the same length"); + } + + delete a.__Jasmine_been_here_before__; + delete b.__Jasmine_been_here_before__; + return (mismatchKeys.length === 0 && mismatchValues.length === 0); + }; + + jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { + mismatchKeys = mismatchKeys || []; + mismatchValues = mismatchValues || []; + + for (var i = 0; i < this.equalityTesters_.length; i++) { + var equalityTester = this.equalityTesters_[i]; + var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); + if (result !== jasmine.undefined) return result; + } + + if (a === b) return true; + + if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { + return (a == jasmine.undefined && b == jasmine.undefined); + } + + if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { + return a === b; + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() == b.getTime(); + } + + if (a.jasmineMatches) { + return a.jasmineMatches(b); + } + + if (b.jasmineMatches) { + return b.jasmineMatches(a); + } + + if (a instanceof jasmine.Matchers.ObjectContaining) { + return a.matches(b); + } + + if (b instanceof jasmine.Matchers.ObjectContaining) { + return b.matches(a); + } + + if (jasmine.isString_(a) && jasmine.isString_(b)) { + return (a == b); + } + + if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { + return (a == b); + } + + if (a instanceof RegExp && b instanceof RegExp) { + return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); + } + + if (typeof a === "object" && typeof b === "object") { + return this.compareObjects_(a, b, mismatchKeys, mismatchValues); + } + + //Straight check + return (a === b); + }; + + jasmine.Env.prototype.contains_ = function(haystack, needle) { + if (jasmine.isArray_(haystack)) { + for (var i = 0; i < haystack.length; i++) { + if (this.equals_(haystack[i], needle)) return true; + } + return false; + } + return haystack.indexOf(needle) >= 0; + }; + + jasmine.Env.prototype.addEqualityTester = function(equalityTester) { + this.equalityTesters_.push(equalityTester); + }; +}()); diff --git a/src/core/base.js b/src/core/base.js index af8d3ea0..7ed149d1 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -1,4 +1,3 @@ -var isCommonJS = typeof window == "undefined" && typeof exports == "object"; /** * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. @@ -6,7 +5,7 @@ var isCommonJS = typeof window == "undefined" && typeof exports == "object"; * @namespace */ var jasmine = {}; -if (isCommonJS) exports.jasmine = jasmine; + /** * @private */ @@ -128,6 +127,7 @@ jasmine.ExpectationResult.prototype.passed = function () { */ jasmine.getEnv = function() { var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); + //jasmine. singletons in here (setTimeout blah blah). return env; }; @@ -462,160 +462,6 @@ jasmine.log = function() { spec.log.apply(spec, arguments); }; -/** - * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. - * - * @example - * // spy example - * var foo = { - * not: function(bool) { return !bool; } - * } - * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops - * - * @see jasmine.createSpy - * @param obj - * @param methodName - * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods - */ -var spyOn = function(obj, methodName) { - return jasmine.getEnv().currentSpec.spyOn(obj, methodName); -}; -if (isCommonJS) exports.spyOn = spyOn; - -/** - * Creates a Jasmine spec that will be added to the current suite. - * - * // TODO: pending tests - * - * @example - * it('should be true', function() { - * expect(true).toEqual(true); - * }); - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var it = function(desc, func) { - return jasmine.getEnv().it(desc, func); -}; -if (isCommonJS) exports.it = it; - -/** - * Creates a disabled Jasmine spec. - * - * A convenience method that allows existing specs to be disabled temporarily during development. - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var xit = function(desc, func) { - return jasmine.getEnv().xit(desc, func); -}; -if (isCommonJS) exports.xit = xit; - -/** - * Starts a chain for a Jasmine expectation. - * - * It is passed an Object that is the actual value and should chain to one of the many - * jasmine.Matchers functions. - * - * @param {Object} actual Actual value to test against and expected value - * @return {jasmine.Matchers} - */ -var expect = function(actual) { - return jasmine.getEnv().currentSpec.expect(actual); -}; -if (isCommonJS) exports.expect = expect; - -/** - * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. - * - * @param {Function} func Function that defines part of a jasmine spec. - */ -var runs = function(func) { - jasmine.getEnv().currentSpec.runs(func); -}; -if (isCommonJS) exports.runs = runs; - -/** - * Waits a fixed time period before moving to the next block. - * - * @deprecated Use waitsFor() instead - * @param {Number} timeout milliseconds to wait - */ -var waits = function(timeout) { - jasmine.getEnv().currentSpec.waits(timeout); -}; -if (isCommonJS) exports.waits = waits; - -/** - * Waits for the latchFunction to return true before proceeding to the next block. - * - * @param {Function} latchFunction - * @param {String} optional_timeoutMessage - * @param {Number} optional_timeout - */ -var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { - jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); -}; -if (isCommonJS) exports.waitsFor = waitsFor; - -/** - * A function that is called before each spec in a suite. - * - * Used for spec setup, including validating assumptions. - * - * @param {Function} beforeEachFunction - */ -var beforeEach = function(beforeEachFunction) { - jasmine.getEnv().beforeEach(beforeEachFunction); -}; -if (isCommonJS) exports.beforeEach = beforeEach; - -/** - * A function that is called after each spec in a suite. - * - * Used for restoring any state that is hijacked during spec execution. - * - * @param {Function} afterEachFunction - */ -var afterEach = function(afterEachFunction) { - jasmine.getEnv().afterEach(afterEachFunction); -}; -if (isCommonJS) exports.afterEach = afterEach; - -/** - * Defines a suite of specifications. - * - * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared - * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization - * of setup in some tests. - * - * @example - * // TODO: a simple suite - * - * // TODO: a simple suite with a nested describe block - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var describe = function(description, specDefinitions) { - return jasmine.getEnv().describe(description, specDefinitions); -}; -if (isCommonJS) exports.describe = describe; - -/** - * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var xdescribe = function(description, specDefinitions) { - return jasmine.getEnv().xdescribe(description, specDefinitions); -}; -if (isCommonJS) exports.xdescribe = xdescribe; - - // Provide the XMLHttpRequest class for IE 5.x-6.x: jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { function tryIt(f) { From 3e5da57cf91f72172ac47ea4afba1197fc899491 Mon Sep 17 00:00:00 2001 From: Rajan Agaskar Date: Wed, 28 Nov 2012 15:16:52 -0800 Subject: [PATCH 29/55] Remove jasmine.XmlHttpRequest - Cruft left over from when jasmine offered an "include" function --- lib/jasmine-core/jasmine.js | 28 ---------------------------- src/core/base.js | 28 ---------------------------- 2 files changed, 56 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 115a94cd..8ce280bb 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -461,34 +461,6 @@ jasmine.log = function() { var spec = jasmine.getEnv().currentSpec; spec.log.apply(spec, arguments); }; - -// Provide the XMLHttpRequest class for IE 5.x-6.x: -jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { - function tryIt(f) { - try { - return f(); - } catch(e) { - } - return null; - } - - var xhr = tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.6.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.3.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP"); - }) || - tryIt(function() { - return new ActiveXObject("Microsoft.XMLHTTP"); - }); - - if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); - - return xhr; -} : XMLHttpRequest; /** * @namespace */ diff --git a/src/core/base.js b/src/core/base.js index 7ed149d1..0a567acd 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -461,31 +461,3 @@ jasmine.log = function() { var spec = jasmine.getEnv().currentSpec; spec.log.apply(spec, arguments); }; - -// Provide the XMLHttpRequest class for IE 5.x-6.x: -jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { - function tryIt(f) { - try { - return f(); - } catch(e) { - } - return null; - } - - var xhr = tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.6.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.3.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP"); - }) || - tryIt(function() { - return new ActiveXObject("Microsoft.XMLHTTP"); - }); - - if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); - - return xhr; -} : XMLHttpRequest; From 8d94d0bfc546aebbb69fbb3c5b06c75299467551 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 12:17:20 -0800 Subject: [PATCH 30/55] Move ExpectationResult into its own file --- lib/jasmine-core/jasmine.js | 39 +++++++++++++++++------------------ src/core/ExpectationResult.js | 19 +++++++++++++++++ src/core/base.js | 20 ------------------ tasks/jasmine_dev/sources.rb | 1 + 4 files changed, 39 insertions(+), 40 deletions(-) create mode 100644 src/core/ExpectationResult.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 8ce280bb..b7bbbee9 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -102,26 +102,6 @@ jasmine.MessageResult.prototype.toString = function() { return text; }; -jasmine.ExpectationResult = function(params) { - this.type = 'expect'; - this.matcherName = params.matcherName; - this.passed_ = params.passed; - this.expected = params.expected; - this.actual = params.actual; - this.message = this.passed_ ? 'Passed.' : params.message; - - var trace = (params.trace || new Error(this.message)); - this.trace = this.passed_ ? '' : trace; -}; - -jasmine.ExpectationResult.prototype.toString = function () { - return this.message; -}; - -jasmine.ExpectationResult.prototype.passed = function () { - return this.passed_; -}; - /** * Getter for the Jasmine environment. Ensures one gets created */ @@ -528,6 +508,25 @@ jasmine.util.extend = function(destination, source) { return destination; }; +jasmine.ExpectationResult = function(params) { + this.type = 'expect'; + this.matcherName = params.matcherName; + this.passed_ = params.passed; + this.expected = params.expected; + this.actual = params.actual; + this.message = this.passed_ ? 'Passed.' : params.message; + + var trace = (params.trace || new Error(this.message)); + this.trace = this.passed_ ? '' : trace; +}; + +jasmine.ExpectationResult.prototype.toString = function () { + return this.message; +}; + +jasmine.ExpectationResult.prototype.passed = function () { + return this.passed_; +}; /** * Environment for Jasmine * diff --git a/src/core/ExpectationResult.js b/src/core/ExpectationResult.js new file mode 100644 index 00000000..39ac68ef --- /dev/null +++ b/src/core/ExpectationResult.js @@ -0,0 +1,19 @@ +jasmine.ExpectationResult = function(params) { + this.type = 'expect'; + this.matcherName = params.matcherName; + this.passed_ = params.passed; + this.expected = params.expected; + this.actual = params.actual; + this.message = this.passed_ ? 'Passed.' : params.message; + + var trace = (params.trace || new Error(this.message)); + this.trace = this.passed_ ? '' : trace; +}; + +jasmine.ExpectationResult.prototype.toString = function () { + return this.message; +}; + +jasmine.ExpectationResult.prototype.passed = function () { + return this.passed_; +}; diff --git a/src/core/base.js b/src/core/base.js index 0a567acd..a5809697 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -102,26 +102,6 @@ jasmine.MessageResult.prototype.toString = function() { return text; }; -jasmine.ExpectationResult = function(params) { - this.type = 'expect'; - this.matcherName = params.matcherName; - this.passed_ = params.passed; - this.expected = params.expected; - this.actual = params.actual; - this.message = this.passed_ ? 'Passed.' : params.message; - - var trace = (params.trace || new Error(this.message)); - this.trace = this.passed_ ? '' : trace; -}; - -jasmine.ExpectationResult.prototype.toString = function () { - return this.message; -}; - -jasmine.ExpectationResult.prototype.passed = function () { - return this.passed_; -}; - /** * Getter for the Jasmine environment. Ensures one gets created */ diff --git a/tasks/jasmine_dev/sources.rb b/tasks/jasmine_dev/sources.rb index a9f5abaa..671d5307 100644 --- a/tasks/jasmine_dev/sources.rb +++ b/tasks/jasmine_dev/sources.rb @@ -3,6 +3,7 @@ class JasmineDev < Thor :core => [ "base.js", "util.js", + "ExpectationResult.js", "Env.js", "Reporter.js", "Block.js", From 08f5a8c98fca3cf31e8380510f34bf96fdf9acef Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 12:17:42 -0800 Subject: [PATCH 31/55] Track abstract goals for Jasmine 2.0 --- GOALS_2.0.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 GOALS_2.0.md diff --git a/GOALS_2.0.md b/GOALS_2.0.md new file mode 100644 index 00000000..09956b90 --- /dev/null +++ b/GOALS_2.0.md @@ -0,0 +1,9 @@ +# Jasmine 2.0 Goals + +1. No globals! + * jasmine library is entirely inside `jasmine` namespace + * globals required for backwards compatibility should be added in `boot.js` (EG, var describe = jasmine.getCurrentEnv().describe lives in boot.js) +1. Don't use properties as getters. Use methods. + * Properties aren't encapsulated -- can be mutated, unsafe. + * easier to refactor as needed + From dfed37531edbb7d5f38b5102ead16f4bdfc77a41 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 12:17:43 -0800 Subject: [PATCH 32/55] Add unit coverage for ExpectationResult --- lib/jasmine-core/jasmine.js | 1 + spec/core/ExpectationResultSpec.js | 53 ++++++++++++++++++++++++++++++ spec/runner.html | 1 + src/core/ExpectationResult.js | 1 + tasks/jasmine_dev/count_specs.rb | 2 +- 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 spec/core/ExpectationResultSpec.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b7bbbee9..4761f6f9 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -508,6 +508,7 @@ jasmine.util.extend = function(destination, source) { return destination; }; +//TODO: expectation result may make more sense as a presentation of an expectation. jasmine.ExpectationResult = function(params) { this.type = 'expect'; this.matcherName = params.matcherName; diff --git a/spec/core/ExpectationResultSpec.js b/spec/core/ExpectationResultSpec.js new file mode 100644 index 00000000..b84b1f97 --- /dev/null +++ b/spec/core/ExpectationResultSpec.js @@ -0,0 +1,53 @@ +describe("ExpectationResult", function() { + + it("defaults to passed", function() { + var result = new jasmine.ExpectationResult({passed: 'some-value'}); + expect(result.passed()).toBe('some-value'); + }); + + it("#toString returns message", function() { + var result = new jasmine.ExpectationResult({message: 'some-value'}); + expect(result.toString()).toBe('some-value'); + }); + + it("has a type of expect", function() { + var result = new jasmine.ExpectationResult({}); + expect(result.type).toBe('expect'); + }); + + it("message defaults to Passed for passing specs", function() { + var result = new jasmine.ExpectationResult({passed: true, message: 'some-value'}); + expect(result.message).toBe('Passed.'); + }); + + it("message returns the message for failing specs", function() { + var result = new jasmine.ExpectationResult({passed: false, message: 'some-value'}); + expect(result.message).toBe('some-value'); + }); + + it("trace passes trace if exists", function() { + var result = new jasmine.ExpectationResult({trace: 'some-value'}); + expect(result.trace).toBe('some-value'); + }); + + it("trace returns a new error if trace is falsy", function() { + var result = new jasmine.ExpectationResult({trace: false}); + expect(result.trace).toEqual(jasmine.any(Error)); + }); + + it("matcherName returns passed matcherName", function() { + var result = new jasmine.ExpectationResult({matcherName: 'some-value'}); + expect(result.matcherName).toBe('some-value'); + }); + + it("expected returns passed expected", function() { + var result = new jasmine.ExpectationResult({expected: 'some-value'}); + expect(result.expected).toBe('some-value'); + }); + + it("actual returns passed actual", function() { + var result = new jasmine.ExpectationResult({actual: 'some-value'}); + expect(result.actual).toBe('some-value'); + }); + +}); diff --git a/spec/runner.html b/spec/runner.html index 0cde61fb..f9862c60 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -29,6 +29,7 @@ + diff --git a/src/core/ExpectationResult.js b/src/core/ExpectationResult.js index 39ac68ef..9c49cbc5 100644 --- a/src/core/ExpectationResult.js +++ b/src/core/ExpectationResult.js @@ -1,3 +1,4 @@ +//TODO: expectation result may make more sense as a presentation of an expectation. jasmine.ExpectationResult = function(params) { this.type = 'expect'; this.matcherName = params.matcherName; diff --git a/tasks/jasmine_dev/count_specs.rb b/tasks/jasmine_dev/count_specs.rb index b6839393..3b4de60e 100644 --- a/tasks/jasmine_dev/count_specs.rb +++ b/tasks/jasmine_dev/count_specs.rb @@ -26,4 +26,4 @@ class JasmineDev < Thor end end end -end \ No newline at end of file +end From 34bd1969e7cc704fe70239095b76511ed635cd46 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 12:17:44 -0800 Subject: [PATCH 33/55] Add performance smoke suite --- Rakefile | 5 +++-- spec/jasmine-performance.yml | 21 +++++++++++++++++++++ spec/smoke/performance_test.js | 10 ++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 spec/jasmine-performance.yml create mode 100644 spec/smoke/performance_test.js diff --git a/Rakefile b/Rakefile index 18530c8a..c2f7160d 100644 --- a/Rakefile +++ b/Rakefile @@ -55,9 +55,10 @@ end namespace :jasmine do task :server do port = ENV['JASMINE_PORT'] || 8888 - Jasmine.load_configuration_from_yaml(File.join(Dir.pwd, 'spec', 'jasmine.yml')) + jasmine_yml = ENV['JASMINE_YML'] || 'jasmine.yml' + Jasmine.load_configuration_from_yaml(File.join(Dir.pwd, 'spec', jasmine_yml)) config = Jasmine.config - server = Jasmine::Server.new(8888, Jasmine::Application.app(config)) + server = Jasmine::Server.new(port, Jasmine::Application.app(config)) server.start puts "your tests are here:" diff --git a/spec/jasmine-performance.yml b/spec/jasmine-performance.yml new file mode 100644 index 00000000..27a329e4 --- /dev/null +++ b/spec/jasmine-performance.yml @@ -0,0 +1,21 @@ +jasmine_dir: + - 'src' +jasmine_files: + - 'core/base.js' + - 'core/util.js' + - 'core/Reporter.js' + - 'html/HtmlReporterHelpers.js' + - 'core/ExpectationResult.js' + - '**/*.js' +jasmine_css_files: + - 'html/jasmine.css' +src_files: +stylesheets: +helpers: +spec_files: + - 'smoke/performance_test.js' +src_dir: +spec_dir: + - 'spec' + + diff --git a/spec/smoke/performance_test.js b/spec/smoke/performance_test.js new file mode 100644 index 00000000..0c97d20c --- /dev/null +++ b/spec/smoke/performance_test.js @@ -0,0 +1,10 @@ +describe("performance", function() { + for (var i = 0; i < 10000; i++) { + it("should pass", function() { + expect(true).toBe(true); + }); + it("should fail", function() { + expect(true).toBe(false); + }); + } +}); From f840458b3447ff640174e9b1de66933284ad5cf7 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 12:17:45 -0800 Subject: [PATCH 34/55] Encapsulate ExpectationResult --- lib/jasmine-core/jasmine.js | 32 +++++++++++++++--------------- spec/core/CustomMatchersSpec.js | 10 ++++------ spec/core/ExpectationResultSpec.js | 9 +++++++-- spec/node_suite.js | 2 +- src/core/ExpectationResult.js | 32 +++++++++++++++--------------- 5 files changed, 44 insertions(+), 41 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 4761f6f9..e0516c74 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -510,23 +510,23 @@ jasmine.util.extend = function(destination, source) { //TODO: expectation result may make more sense as a presentation of an expectation. jasmine.ExpectationResult = function(params) { - this.type = 'expect'; - this.matcherName = params.matcherName; - this.passed_ = params.passed; - this.expected = params.expected; - this.actual = params.actual; - this.message = this.passed_ ? 'Passed.' : params.message; - + var self = this; var trace = (params.trace || new Error(this.message)); - this.trace = this.passed_ ? '' : trace; -}; - -jasmine.ExpectationResult.prototype.toString = function () { - return this.message; -}; - -jasmine.ExpectationResult.prototype.passed = function () { - return this.passed_; + var message = params.passed ? 'Passed.' : params.message; + return jasmine.util.extend(self, { + type: 'expect', + matcherName: params.matcherName, + expected: params.expected, + actual: params.actual, + message: message, + trace: params.passed ? '' : trace, + toString: function() { + return message; + }, + passed: function() { + return params.passed; + } + }); }; /** * Environment for Jasmine diff --git a/spec/core/CustomMatchersSpec.js b/spec/core/CustomMatchersSpec.js index 86f98547..55c52067 100644 --- a/spec/core/CustomMatchersSpec.js +++ b/spec/core/CustomMatchersSpec.js @@ -61,12 +61,10 @@ describe("Custom Matchers", function() { }); suite.execute(); - var passResult = new jasmine.ExpectationResult({passed: true, matcherName: 'toBeTrue', - actual: true, expected: jasmine.undefined, message: "Passed." }); - var failResult = new jasmine.ExpectationResult({passed: false, matcherName: 'toBeTrue', - actual: false, expected: jasmine.undefined, message: "Expected false to be true." }); - failResult.trace = originalJasmine.any(Object); - expect(spec.results().getItems()).toEqual([passResult, failResult]); + + var results = spec.results().getItems(); + expect(results[0].message).toEqual("Passed."); + expect(results[1].message).toEqual("Expected false to be true."); }); it("should pass args", function() { diff --git a/spec/core/ExpectationResultSpec.js b/spec/core/ExpectationResultSpec.js index b84b1f97..03f52036 100644 --- a/spec/core/ExpectationResultSpec.js +++ b/spec/core/ExpectationResultSpec.js @@ -5,11 +5,16 @@ describe("ExpectationResult", function() { expect(result.passed()).toBe('some-value'); }); - it("#toString returns message", function() { - var result = new jasmine.ExpectationResult({message: 'some-value'}); + it("#toString returns message when failing", function() { + var result = new jasmine.ExpectationResult({passed: false, message: 'some-value'}); expect(result.toString()).toBe('some-value'); }); + it("#toString returns Passed when passing", function() { + var result = new jasmine.ExpectationResult({passed: true, message: 'some-value'}); + expect(result.toString()).toBe('Passed.'); + }); + it("has a type of expect", function() { var result = new jasmine.ExpectationResult({}); expect(result.type).toBe('expect'); diff --git a/spec/node_suite.js b/spec/node_suite.js index bd2867b3..7bd9c480 100644 --- a/spec/node_suite.js +++ b/spec/node_suite.js @@ -110,7 +110,7 @@ process.argv.forEach(function(arg) { } }); -var specs = jasmine.getAllSpecFiles(__dirname, new RegExp(".js$")); +var specs = jasmine.getAllSpecFiles(__dirname, new RegExp("Spec.js$")); var domIndependentSpecs = []; for (var i = 0; i < specs.length; i++) { if (fs.readFileSync(specs[i], "utf8").indexOf("document.createElement") < 0) { diff --git a/src/core/ExpectationResult.js b/src/core/ExpectationResult.js index 9c49cbc5..b33dd01a 100644 --- a/src/core/ExpectationResult.js +++ b/src/core/ExpectationResult.js @@ -1,20 +1,20 @@ //TODO: expectation result may make more sense as a presentation of an expectation. jasmine.ExpectationResult = function(params) { - this.type = 'expect'; - this.matcherName = params.matcherName; - this.passed_ = params.passed; - this.expected = params.expected; - this.actual = params.actual; - this.message = this.passed_ ? 'Passed.' : params.message; - + var self = this; var trace = (params.trace || new Error(this.message)); - this.trace = this.passed_ ? '' : trace; -}; - -jasmine.ExpectationResult.prototype.toString = function () { - return this.message; -}; - -jasmine.ExpectationResult.prototype.passed = function () { - return this.passed_; + var message = params.passed ? 'Passed.' : params.message; + return jasmine.util.extend(self, { + type: 'expect', + matcherName: params.matcherName, + expected: params.expected, + actual: params.actual, + message: message, + trace: params.passed ? '' : trace, + toString: function() { + return message; + }, + passed: function() { + return params.passed; + } + }); }; From f9cbad15129cddd6ffdad3a1eaf9e75082452498 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 15:14:27 -0800 Subject: [PATCH 35/55] Fix mistaken toFail() expect usage - It looks like toEqual got globally replaced where it shouldn't have been --- spec/core/MatchersSpec.js | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index 8cce5cd2..97c9fd69 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -98,7 +98,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toEqual"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.expected).toEqual(expected); @@ -113,7 +113,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotEqual"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(str)); expect(result.message).toMatch('not'); expect(result.expected).toEqual(str); @@ -142,7 +142,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBe"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.expected).toEqual(expected); @@ -157,7 +157,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotBe"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(str); expect(result.expected).toEqual(str); expect(result.actual).toEqual(str); @@ -186,7 +186,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toMatch"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch(expected.toString()); expect(result.expected).toEqual(expected); @@ -202,7 +202,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toMatch"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toEqual("Expected 'a' to match 'b'."); expect(result.expected).toEqual(expected); expect(result.actual).toEqual(actual); @@ -217,7 +217,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotMatch"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toEqual("Expected 'a' to not match /a/."); expect(result.expected).toEqual(expected); expect(result.actual).toEqual(actual); @@ -231,7 +231,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotMatch"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toEqual("Expected 'a' to not match 'a'."); expect(result.expected).toEqual(str); expect(result.actual).toEqual(str); @@ -249,7 +249,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeDefined"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toEqual('Expected undefined to be defined.'); expect(result.actual).toEqual(jasmine.undefined); }); @@ -273,7 +273,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeNull"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('null'); expect(result.actual).toEqual(actual); @@ -287,7 +287,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeNull"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('null'); expect(result.actual).toEqual(actual); @@ -311,7 +311,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeNaN"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch("Expected 'a' to be NaN."); expect(result.actual).toMatch(actual); }); @@ -332,7 +332,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeFalsy"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('falsy'); expect(result.actual).toEqual(actual); @@ -356,7 +356,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeTruthy"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toEqual("Expected false to be truthy."); expect(result.actual).toFail(); }); @@ -459,7 +459,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toContain"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('contain'); expect(result.message).toMatch(jasmine.pp(expected)); @@ -476,7 +476,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotContain"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('not contain'); expect(result.message).toMatch(jasmine.pp(expected)); @@ -499,7 +499,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeLessThan"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual) + ' to be less than'); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.actual).toEqual(actual); @@ -521,7 +521,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeGreaterThan"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toMatch(jasmine.pp(actual) + ' to be greater than'); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.actual).toEqual(actual); @@ -780,7 +780,7 @@ describe("jasmine.Matchers", function() { var expected = match(TestClass.spyFunction); expect(expected.toHaveBeenCalledWith('c', 'b', 'a')).toFail(); var result = lastResult(); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.expected).toEqual(['c', 'b', 'a']); expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); expect(result.message).toContain(jasmine.pp(result.expected)); @@ -791,7 +791,7 @@ describe("jasmine.Matchers", function() { var expected = match(TestClass.spyFunction); expect(expected.toHaveBeenCalledWith('c', 'b', 'a')).toFail(); var result = lastResult(); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.expected).toEqual(['c', 'b', 'a']); expect(result.actual.argsForCall).toEqual([]); expect(result.message).toContain(jasmine.pp(result.expected)); @@ -849,7 +849,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toHaveBeenCalledWith"); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.message).toContain(jasmine.pp(['a', 'b'])); expect(result.message).toContain(jasmine.pp(['a', 'c'])); expect(result.actual).toEqual(TestClass.someFunction); @@ -879,7 +879,7 @@ describe("jasmine.Matchers", function() { var expected = match(TestClass.spyFunction); expect(expected.wasNotCalledWith('a', 'b', 'c')).toFail(); var result = lastResult(); - expect(result.passed()).toFail(); + expect(result.passed()).toBe(false); expect(result.expected).toEqual(['a', 'b', 'c']); expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); expect(result.message).toContain(jasmine.pp(result.expected)); From cd3a0c854b454241661cce609bbf1d54c96d1ba7 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 15:29:45 -0800 Subject: [PATCH 36/55] buildExpectationResult now returns a data object. - Meant for passing to reporters. --- GOALS_2.0.md | 3 +- lib/jasmine-core/jasmine-html.js | 9 +++--- lib/jasmine-core/jasmine.js | 28 ++++++++--------- spec/core/ExceptionsSpec.js | 6 ++-- spec/core/ExpectationResultSpec.js | 32 +++++++------------- spec/core/JsApiReporterSpec.js | 2 +- spec/core/MatchersSpec.js | 48 +++++++++++++++--------------- spec/core/NestedResultsSpec.js | 12 ++++---- spec/core/SpecRunningSpec.js | 42 +++++++++++++------------- spec/core/SpecSpec.js | 8 ++--- spec/html/MatchersHtmlSpec.js | 6 ++-- spec/html/TrivialReporterSpec.js | 4 +-- src/console/ConsoleReporter.js | 2 +- src/core/ExpectationResult.js | 20 ++++--------- src/core/JsApiReporter.js | 7 +++-- src/core/Matchers.js | 2 +- src/core/NestedResults.js | 3 +- src/core/Spec.js | 2 +- src/html/SpecView.js | 4 +-- src/html/TrivialReporter.js | 4 +-- 20 files changed, 112 insertions(+), 132 deletions(-) diff --git a/GOALS_2.0.md b/GOALS_2.0.md index 09956b90..98fa6193 100644 --- a/GOALS_2.0.md +++ b/GOALS_2.0.md @@ -1,9 +1,10 @@ -# Jasmine 2.0 Goals +# (Vague) Jasmine 2.0 Goals/(Guidelines) 1. No globals! * jasmine library is entirely inside `jasmine` namespace * globals required for backwards compatibility should be added in `boot.js` (EG, var describe = jasmine.getCurrentEnv().describe lives in boot.js) 1. Don't use properties as getters. Use methods. * Properties aren't encapsulated -- can be mutated, unsafe. +1. Reporters get data objects (no methods). * easier to refactor as needed diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 543d5696..d4364bee 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -450,7 +450,7 @@ jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { if (result.type == 'log') { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && result.passed && !result.passed()) { + } else if (result.type == 'expect' && !result.passed) { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); if (result.trace.stack) { @@ -465,7 +465,8 @@ jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { } }; -jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { +jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView); +jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { this.suite = suite; this.dom = dom; this.views = views; @@ -615,7 +616,7 @@ jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { var results = spec.results(); - var status = results.passed() ? 'passed' : 'failed'; + var status = results.passed ? 'passed' : 'failed'; if (results.skipped) { status = 'skipped'; } @@ -635,7 +636,7 @@ jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { if (result.type == 'log') { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && result.passed && !result.passed()) { + } else if (result.type == 'expect' && !result.passed) { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); if (result.trace.stack) { diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index e0516c74..0892ee37 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -509,24 +509,18 @@ jasmine.util.extend = function(destination, source) { }; //TODO: expectation result may make more sense as a presentation of an expectation. -jasmine.ExpectationResult = function(params) { - var self = this; +jasmine.buildExpectationResult = function(params) { var trace = (params.trace || new Error(this.message)); var message = params.passed ? 'Passed.' : params.message; - return jasmine.util.extend(self, { + return { type: 'expect', matcherName: params.matcherName, expected: params.expected, actual: params.actual, message: message, trace: params.passed ? '' : trace, - toString: function() { - return message; - }, - passed: function() { - return params.passed; - } - }); + passed: params.passed + }; }; /** * Environment for Jasmine @@ -918,7 +912,7 @@ jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { type: isSuite ? 'suite' : 'spec', children: [] }; - + if (isSuite) { var children = suiteOrSpec.children(); for (var i = 0; i < children.length; i++) { @@ -973,11 +967,12 @@ jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ var resultMessage = result.messages[messageIndex]; summaryMessages.push({ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, - passed: resultMessage.passed ? resultMessage.passed() : true, + //TODO: wat? in theory this is saying non-expect results should always be considered passed, but that's weird. + passed: resultMessage.passed || true, type: resultMessage.type, message: resultMessage.message, trace: { - stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined + stack: !resultMessage.passed ? resultMessage.trace.stack : jasmine.undefined } }); } @@ -1050,7 +1045,7 @@ jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { message += "."; } } - var expectationResult = new jasmine.ExpectationResult({ + var expectationResult = jasmine.buildExpectationResult({ matcherName: matcherName, passed: result, expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], @@ -1668,13 +1663,14 @@ jasmine.NestedResults.prototype.getItems = function() { * Adds a result, tracking counts (total, passed, & failed) * @param {jasmine.ExpectationResult|jasmine.NestedResults} result */ +//TODO: Results are meant for consumption by reporters, not internally. jasmine.NestedResults.prototype.addResult = function(result) { if (result.type != 'log') { if (result.items_) { this.rollupCounts(result); } else { this.totalCount++; - if (result.passed()) { + if (result.passed) { this.passedCount++; } else { this.failedCount++; @@ -2135,7 +2131,7 @@ jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessag }; jasmine.Spec.prototype.fail = function (e) { - var expectationResult = new jasmine.ExpectationResult({ + var expectationResult = jasmine.buildExpectationResult({ passed: false, message: e ? jasmine.util.formatException(e) : 'Exception', trace: { stack: e.stack } diff --git a/spec/core/ExceptionsSpec.js b/spec/core/ExceptionsSpec.js index 315aa1bf..a7aa8aeb 100644 --- a/spec/core/ExceptionsSpec.js +++ b/spec/core/ExceptionsSpec.js @@ -111,14 +111,14 @@ describe('Exceptions:', function() { expect(specResults.length).toEqual(5); expect(specResults[0].passed()).toMatch(false); var blockResults = specResults[0].getItems(); - expect(blockResults[0].passed()).toEqual(false); + expect(blockResults[0].passed).toEqual(false); expect(blockResults[0].message).toMatch(/fake error 1/); expect(specResults[1].passed()).toEqual(false); blockResults = specResults[1].getItems(); - expect(blockResults[0].passed()).toEqual(false); + expect(blockResults[0].passed).toEqual(false); expect(blockResults[0].message).toMatch(/fake error 2/); - expect(blockResults[1].passed()).toEqual(true); + expect(blockResults[1].passed).toEqual(true); expect(specResults[2].passed()).toEqual(true); diff --git a/spec/core/ExpectationResultSpec.js b/spec/core/ExpectationResultSpec.js index 03f52036..36c4e49c 100644 --- a/spec/core/ExpectationResultSpec.js +++ b/spec/core/ExpectationResultSpec.js @@ -1,57 +1,47 @@ -describe("ExpectationResult", function() { +describe("buildExpectationResult", function() { it("defaults to passed", function() { - var result = new jasmine.ExpectationResult({passed: 'some-value'}); - expect(result.passed()).toBe('some-value'); - }); - - it("#toString returns message when failing", function() { - var result = new jasmine.ExpectationResult({passed: false, message: 'some-value'}); - expect(result.toString()).toBe('some-value'); - }); - - it("#toString returns Passed when passing", function() { - var result = new jasmine.ExpectationResult({passed: true, message: 'some-value'}); - expect(result.toString()).toBe('Passed.'); + var result = jasmine.buildExpectationResult({passed: 'some-value'}); + expect(result.passed).toBe('some-value'); }); it("has a type of expect", function() { - var result = new jasmine.ExpectationResult({}); + var result = jasmine.buildExpectationResult({}); expect(result.type).toBe('expect'); }); it("message defaults to Passed for passing specs", function() { - var result = new jasmine.ExpectationResult({passed: true, message: 'some-value'}); + var result = jasmine.buildExpectationResult({passed: true, message: 'some-value'}); expect(result.message).toBe('Passed.'); }); it("message returns the message for failing specs", function() { - var result = new jasmine.ExpectationResult({passed: false, message: 'some-value'}); + var result = jasmine.buildExpectationResult({passed: false, message: 'some-value'}); expect(result.message).toBe('some-value'); }); it("trace passes trace if exists", function() { - var result = new jasmine.ExpectationResult({trace: 'some-value'}); + var result = jasmine.buildExpectationResult({trace: 'some-value'}); expect(result.trace).toBe('some-value'); }); it("trace returns a new error if trace is falsy", function() { - var result = new jasmine.ExpectationResult({trace: false}); + var result = jasmine.buildExpectationResult({trace: false}); expect(result.trace).toEqual(jasmine.any(Error)); }); it("matcherName returns passed matcherName", function() { - var result = new jasmine.ExpectationResult({matcherName: 'some-value'}); + var result = jasmine.buildExpectationResult({matcherName: 'some-value'}); expect(result.matcherName).toBe('some-value'); }); it("expected returns passed expected", function() { - var result = new jasmine.ExpectationResult({expected: 'some-value'}); + var result = jasmine.buildExpectationResult({expected: 'some-value'}); expect(result.expected).toBe('some-value'); }); it("actual returns passed actual", function() { - var result = new jasmine.ExpectationResult({actual: 'some-value'}); + var result = jasmine.buildExpectationResult({actual: 'some-value'}); expect(result.actual).toBe('some-value'); }); diff --git a/spec/core/JsApiReporterSpec.js b/spec/core/JsApiReporterSpec.js index cca70674..953d7307 100644 --- a/spec/core/JsApiReporterSpec.js +++ b/spec/core/JsApiReporterSpec.js @@ -100,4 +100,4 @@ describe('jasmine.jsApiReporter', function() { }); }); }); -}); \ No newline at end of file +}); diff --git a/spec/core/MatchersSpec.js b/spec/core/MatchersSpec.js index 97c9fd69..8b088e0c 100644 --- a/spec/core/MatchersSpec.js +++ b/spec/core/MatchersSpec.js @@ -13,10 +13,10 @@ describe("jasmine.Matchers", function() { this.addMatchers({ toPass: function() { - return lastResult().passed(); + return lastResult().passed; }, toFail: function() { - return !lastResult().passed(); + return !lastResult().passed; } }); }); @@ -98,7 +98,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toEqual"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.expected).toEqual(expected); @@ -113,7 +113,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotEqual"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(str)); expect(result.message).toMatch('not'); expect(result.expected).toEqual(str); @@ -142,7 +142,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBe"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.expected).toEqual(expected); @@ -157,7 +157,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotBe"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(str); expect(result.expected).toEqual(str); expect(result.actual).toEqual(str); @@ -186,7 +186,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toMatch"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch(expected.toString()); expect(result.expected).toEqual(expected); @@ -202,7 +202,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toMatch"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toEqual("Expected 'a' to match 'b'."); expect(result.expected).toEqual(expected); expect(result.actual).toEqual(actual); @@ -217,7 +217,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotMatch"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toEqual("Expected 'a' to not match /a/."); expect(result.expected).toEqual(expected); expect(result.actual).toEqual(actual); @@ -231,7 +231,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotMatch"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toEqual("Expected 'a' to not match 'a'."); expect(result.expected).toEqual(str); expect(result.actual).toEqual(str); @@ -249,7 +249,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeDefined"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toEqual('Expected undefined to be defined.'); expect(result.actual).toEqual(jasmine.undefined); }); @@ -273,7 +273,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeNull"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('null'); expect(result.actual).toEqual(actual); @@ -287,7 +287,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeNull"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('null'); expect(result.actual).toEqual(actual); @@ -311,7 +311,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeNaN"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch("Expected 'a' to be NaN."); expect(result.actual).toMatch(actual); }); @@ -332,7 +332,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeFalsy"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('falsy'); expect(result.actual).toEqual(actual); @@ -356,7 +356,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeTruthy"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toEqual("Expected false to be truthy."); expect(result.actual).toFail(); }); @@ -459,7 +459,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toContain"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('contain'); expect(result.message).toMatch(jasmine.pp(expected)); @@ -476,7 +476,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toNotContain"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual)); expect(result.message).toMatch('not contain'); expect(result.message).toMatch(jasmine.pp(expected)); @@ -499,7 +499,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeLessThan"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual) + ' to be less than'); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.actual).toEqual(actual); @@ -521,7 +521,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toBeGreaterThan"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toMatch(jasmine.pp(actual) + ' to be greater than'); expect(result.message).toMatch(jasmine.pp(expected)); expect(result.actual).toEqual(actual); @@ -780,7 +780,7 @@ describe("jasmine.Matchers", function() { var expected = match(TestClass.spyFunction); expect(expected.toHaveBeenCalledWith('c', 'b', 'a')).toFail(); var result = lastResult(); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.expected).toEqual(['c', 'b', 'a']); expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); expect(result.message).toContain(jasmine.pp(result.expected)); @@ -791,7 +791,7 @@ describe("jasmine.Matchers", function() { var expected = match(TestClass.spyFunction); expect(expected.toHaveBeenCalledWith('c', 'b', 'a')).toFail(); var result = lastResult(); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.expected).toEqual(['c', 'b', 'a']); expect(result.actual.argsForCall).toEqual([]); expect(result.message).toContain(jasmine.pp(result.expected)); @@ -849,7 +849,7 @@ describe("jasmine.Matchers", function() { var result = lastResult(); expect(result.matcherName).toEqual("toHaveBeenCalledWith"); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.message).toContain(jasmine.pp(['a', 'b'])); expect(result.message).toContain(jasmine.pp(['a', 'c'])); expect(result.actual).toEqual(TestClass.someFunction); @@ -879,7 +879,7 @@ describe("jasmine.Matchers", function() { var expected = match(TestClass.spyFunction); expect(expected.wasNotCalledWith('a', 'b', 'c')).toFail(); var result = lastResult(); - expect(result.passed()).toBe(false); + expect(result.passed).toBe(false); expect(result.expected).toEqual(['a', 'b', 'c']); expect(result.actual.mostRecentCall.args).toEqual(['a', 'b', 'c']); expect(result.message).toContain(jasmine.pp(result.expected)); diff --git a/spec/core/NestedResultsSpec.js b/spec/core/NestedResultsSpec.js index e4bc9190..fc1e5607 100644 --- a/spec/core/NestedResultsSpec.js +++ b/spec/core/NestedResultsSpec.js @@ -3,7 +3,7 @@ describe('jasmine.NestedResults', function() { // Leaf case var results = new jasmine.NestedResults(); - results.addResult(new jasmine.ExpectationResult({ + results.addResult(jasmine.buildExpectationResult({ matcherName: "foo", passed: true, message: 'Passed.', actual: 'bar', expected: 'bar'} )); @@ -12,7 +12,7 @@ describe('jasmine.NestedResults', function() { expect(results.passedCount).toEqual(1); expect(results.failedCount).toEqual(0); - results.addResult(new jasmine.ExpectationResult({ + results.addResult(jasmine.buildExpectationResult({ matcherName: "baz", passed: false, message: 'FAIL.', actual: "corge", expected: "quux" })); @@ -25,19 +25,19 @@ describe('jasmine.NestedResults', function() { it('should roll up counts for nested results', function() { // Branch case var leafResultsOne = new jasmine.NestedResults(); - leafResultsOne.addResult(new jasmine.ExpectationResult({ + leafResultsOne.addResult(jasmine.buildExpectationResult({ matcherName: "toSomething", passed: true, message: 'message', actual: '', expected:'' })); - leafResultsOne.addResult(new jasmine.ExpectationResult({ + leafResultsOne.addResult(jasmine.buildExpectationResult({ matcherName: "toSomethingElse", passed: false, message: 'message', actual: 'a', expected: 'b' })); var leafResultsTwo = new jasmine.NestedResults(); - leafResultsTwo.addResult(new jasmine.ExpectationResult({ + leafResultsTwo.addResult(jasmine.buildExpectationResult({ matcherName: "toSomething", passed: true, message: 'message', actual: '', expected: '' })); - leafResultsTwo.addResult(new jasmine.ExpectationResult({ + leafResultsTwo.addResult(jasmine.buildExpectationResult({ matcherName: "toSomethineElse", passed: false, message: 'message', actual: 'c', expected: 'd' })); diff --git a/spec/core/SpecRunningSpec.js b/spec/core/SpecRunningSpec.js index 377e5812..98e7146b 100644 --- a/spec/core/SpecRunningSpec.js +++ b/spec/core/SpecRunningSpec.js @@ -68,10 +68,10 @@ describe("jasmine spec running", function () { expect(specWithNoBody.description).toEqual('new spec'); expect(specWithExpectation.results().getItems().length).toEqual(1); // "Results aren't there after a spec was executed" - expect(specWithExpectation.results().getItems()[0].passed()).toEqual(true); // "Results has a result, but it's true" + expect(specWithExpectation.results().getItems()[0].passed).toEqual(true); // "Results has a result, but it's true" expect(specWithExpectation.results().description).toEqual('spec with an expectation'); // "Spec's results did not get the spec's description" - expect(specWithFailingExpectations.results().getItems()[0].passed()).toEqual(false); // "Expectation that failed, passed" + expect(specWithFailingExpectations.results().getItems()[0].passed).toEqual(false); // "Expectation that failed, passed" expect(specWithMultipleExpectations.results().getItems().length).toEqual(2); // "Spec doesn't support multiple expectations" }); @@ -90,8 +90,8 @@ describe("jasmine spec running", function () { another_spec.done = true; expect(another_spec.results().getItems().length).toEqual(2); - expect(another_spec.results().getItems()[0].passed()).toEqual(true); // "In a spec without a run block, expected first expectation result to be true but was false" - expect(another_spec.results().getItems()[1].passed()).toEqual(false); // "In a spec without a run block, expected second expectation result to be false but was true"; + expect(another_spec.results().getItems()[0].passed).toEqual(true); // "In a spec without a run block, expected first expectation result to be true but was false" + expect(another_spec.results().getItems()[1].passed).toEqual(false); // "In a spec without a run block, expected second expectation result to be false but was true"; expect(another_spec.results().description).toEqual('spec with an expectation'); // "In a spec without a run block, results did not include the spec's description"; }); @@ -142,7 +142,7 @@ describe("jasmine spec running", function () { a_spec.execute(); expect(a_spec.results().getItems().length).toEqual(1); // 'No call to waits(): Spec queue did not run all functions'; - expect(a_spec.results().getItems()[0].passed()).toEqual(true); // 'No call to waits(): Queued expectation failed'; + expect(a_spec.results().getItems()[0].passed).toEqual(true); // 'No call to waits(): Queued expectation failed'; foo = 0; env.describe('test async spec', function() { @@ -169,7 +169,7 @@ describe("jasmine spec running", function () { fakeTimer.tick(500); expect(a_spec.results().getItems().length).toEqual(1); // 'Calling waits(): Spec queue did not run all functions'; - expect(a_spec.results().getItems()[0].passed()).toEqual(true); // 'Calling waits(): Queued expectation failed'; + expect(a_spec.results().getItems()[0].passed).toEqual(true); // 'Calling waits(): Queued expectation failed'; var bar = 0; var another_spec; @@ -200,7 +200,7 @@ describe("jasmine spec running", function () { fakeTimer.tick(1000); expect(another_spec.results().getItems().length).toEqual(1); - expect(another_spec.results().getItems()[0].passed()).toEqual(true); + expect(another_spec.results().getItems()[0].passed).toEqual(true); var baz = 0; var yet_another_spec; @@ -226,7 +226,7 @@ describe("jasmine spec running", function () { expect(yet_another_spec.results().getItems().length).toEqual(1); - expect(yet_another_spec.results().getItems()[0].passed()).toEqual(false); + expect(yet_another_spec.results().getItems()[0].passed).toEqual(false); }); it("testAsyncSpecsWithMockSuite", function () { @@ -255,7 +255,7 @@ describe("jasmine spec running", function () { another_spec.execute(); fakeTimer.tick(2000); expect(another_spec.results().getItems().length).toEqual(1); - expect(another_spec.results().getItems()[0].passed()).toEqual(true); + expect(another_spec.results().getItems()[0].passed).toEqual(true); }); describe("waitsFor", function() { @@ -901,8 +901,8 @@ describe("jasmine spec running", function () { expect(report).toEqual("firstsecond"); var suiteResults = suite.results(); - expect(suiteResults.getItems()[0].getItems()[0].passed()).toEqual(false); - expect(suiteResults.getItems()[1].getItems()[0].passed()).toEqual(true); + expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(false); + expect(suiteResults.getItems()[1].getItems()[0].passed).toEqual(true); }); it("testAfterExecutesSafely", function() { @@ -942,14 +942,14 @@ describe("jasmine spec running", function () { var suiteResults = suite.results(); expect(suiteResults.getItems().length).toEqual(3, 'testAfterExecutesSafely should have results for three specs'); - expect(suiteResults.getItems()[0].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 1st spec should pass"); - expect(suiteResults.getItems()[1].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 2nd spec should pass"); - expect(suiteResults.getItems()[2].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 3rd spec should pass"); + expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 1st spec should pass"); + expect(suiteResults.getItems()[1].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 2nd spec should pass"); + expect(suiteResults.getItems()[2].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 3rd spec should pass"); - expect(suiteResults.getItems()[0].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 1st result for 1st suite spec should pass"); - expect(suiteResults.getItems()[0].getItems()[1].passed()).toEqual(false, "testAfterExecutesSafely 2nd result for 1st suite spec should fail because afterEach failed"); - expect(suiteResults.getItems()[1].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 2nd suite spec should pass"); - expect(suiteResults.getItems()[2].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 3rd suite spec should pass"); + expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 1st result for 1st suite spec should pass"); + expect(suiteResults.getItems()[0].getItems()[1].passed).toEqual(false, "testAfterExecutesSafely 2nd result for 1st suite spec should fail because afterEach failed"); + expect(suiteResults.getItems()[1].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 2nd suite spec should pass"); + expect(suiteResults.getItems()[2].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 3rd suite spec should pass"); }); it("should permit nested describes", function() { @@ -1178,8 +1178,8 @@ describe("jasmine spec running", function () { expect(spec.foo).toEqual(2); var suiteResults = suite.results(); expect(suiteResults.getItems()[0].getItems().length).toEqual(2); - expect(suiteResults.getItems()[0].getItems()[0].passed()).toEqual(false); - expect(suiteResults.getItems()[0].getItems()[1].passed()).toEqual(true); + expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(false); + expect(suiteResults.getItems()[0].getItems()[1].passed).toEqual(true); }); it("shouldn't run disabled tests", function() { @@ -1239,7 +1239,7 @@ describe("jasmine spec running", function () { var results = spec.results().getItems(); for (var i = 0; i < results.length; i++) { var result = results[i]; - specs.push("Result: " + result); + specs.push("Result: " + result.message); } }; diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 0c96be84..a1cf547b 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -112,11 +112,9 @@ describe('Spec', function () { }); spec.execute(); var items = results.getItems(); - expect(items).toEqual([ - originalJasmine.any(jasmine.ExpectationResult), - originalJasmine.any(jasmine.ExpectationResult), - originalJasmine.any(jasmine.MessageResult) - ]); + expect(items[0].type).toBe('expect'); + expect(items[1].type).toBe('expect'); + expect(items[2].type).toBe('log'); var logResult = items[2]; expect(logResult.values).toEqual(["here's some log message", {key: 'value'}, 123]); }); diff --git a/spec/html/MatchersHtmlSpec.js b/spec/html/MatchersHtmlSpec.js index b528753a..5bc83dac 100644 --- a/spec/html/MatchersHtmlSpec.js +++ b/spec/html/MatchersHtmlSpec.js @@ -13,10 +13,10 @@ describe("MatchersSpec - HTML Dependent", function () { this.addMatchers({ toPass: function() { - return lastResult().passed(); + return lastResult().passed; }, toFail: function() { - return !lastResult().passed(); + return !lastResult().passed; } }); }); @@ -35,4 +35,4 @@ describe("MatchersSpec - HTML Dependent", function () { expect((match(nodeA).toEqual(nodeA))).toPass(); expect((match(nodeA).toEqual(nodeB))).toFail(); }); -}); \ No newline at end of file +}); diff --git a/spec/html/TrivialReporterSpec.js b/spec/html/TrivialReporterSpec.js index 8462f0c6..5cfe5e21 100644 --- a/spec/html/TrivialReporterSpec.js +++ b/spec/html/TrivialReporterSpec.js @@ -130,7 +130,7 @@ describe("TrivialReporter", function() { }); it("should add the failure message to the DOM (non-toEquals matchers)", function() { - expectationResult = new jasmine.ExpectationResult({ + expectationResult = jasmine.buildExpectationResult({ matcherName: "toBeNull", passed: false, message: "Expected 'a' to be null, but it was not" }); @@ -144,7 +144,7 @@ describe("TrivialReporter", function() { }); it("should add the failure message to the DOM (non-toEquals matchers) html escaping", function() { - expectationResult = new jasmine.ExpectationResult({ + expectationResult = jasmine.buildExpectationResult({ matcherName: "toBeNull", passed: false, message: "Expected '1 < 2' to e null, & it was not" }); diff --git a/src/console/ConsoleReporter.js b/src/console/ConsoleReporter.js index e65be81b..b026af9f 100644 --- a/src/console/ConsoleReporter.js +++ b/src/console/ConsoleReporter.js @@ -174,4 +174,4 @@ jasmine.ConsoleReporter = function(print, doneCallback, showColors) { summaryFunction(runner.specs().length, results.failedCount); doneCallback(runner); }; -}; \ No newline at end of file +}; diff --git a/src/core/ExpectationResult.js b/src/core/ExpectationResult.js index b33dd01a..bc783ede 100644 --- a/src/core/ExpectationResult.js +++ b/src/core/ExpectationResult.js @@ -1,20 +1,12 @@ //TODO: expectation result may make more sense as a presentation of an expectation. -jasmine.ExpectationResult = function(params) { - var self = this; - var trace = (params.trace || new Error(this.message)); - var message = params.passed ? 'Passed.' : params.message; - return jasmine.util.extend(self, { +jasmine.buildExpectationResult = function(params) { + return { type: 'expect', matcherName: params.matcherName, expected: params.expected, actual: params.actual, - message: message, - trace: params.passed ? '' : trace, - toString: function() { - return message; - }, - passed: function() { - return params.passed; - } - }); + message: params.passed ? 'Passed.' : params.message, + trace: params.passed ? '' : (params.trace || new Error(this.message)), + passed: params.passed + }; }; diff --git a/src/core/JsApiReporter.js b/src/core/JsApiReporter.js index 44f1802a..5a9e6790 100644 --- a/src/core/JsApiReporter.js +++ b/src/core/JsApiReporter.js @@ -30,7 +30,7 @@ jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { type: isSuite ? 'suite' : 'spec', children: [] }; - + if (isSuite) { var children = suiteOrSpec.children(); for (var i = 0; i < children.length; i++) { @@ -85,11 +85,12 @@ jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ var resultMessage = result.messages[messageIndex]; summaryMessages.push({ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, - passed: resultMessage.passed ? resultMessage.passed() : true, + //TODO: wat? in theory this is saying non-expect results should always be considered passed, but that's weird. + passed: resultMessage.passed || true, type: resultMessage.type, message: resultMessage.message, trace: { - stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined + stack: !resultMessage.passed ? resultMessage.trace.stack : jasmine.undefined } }); } diff --git a/src/core/Matchers.js b/src/core/Matchers.js index 09f449d8..634564a7 100644 --- a/src/core/Matchers.js +++ b/src/core/Matchers.js @@ -60,7 +60,7 @@ jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { message += "."; } } - var expectationResult = new jasmine.ExpectationResult({ + var expectationResult = jasmine.buildExpectationResult({ matcherName: matcherName, passed: result, expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], diff --git a/src/core/NestedResults.js b/src/core/NestedResults.js index 374e5e46..61d34f58 100644 --- a/src/core/NestedResults.js +++ b/src/core/NestedResults.js @@ -56,13 +56,14 @@ jasmine.NestedResults.prototype.getItems = function() { * Adds a result, tracking counts (total, passed, & failed) * @param {jasmine.ExpectationResult|jasmine.NestedResults} result */ +//TODO: Results are meant for consumption by reporters, not internally. jasmine.NestedResults.prototype.addResult = function(result) { if (result.type != 'log') { if (result.items_) { this.rollupCounts(result); } else { this.totalCount++; - if (result.passed()) { + if (result.passed) { this.passedCount++; } else { this.failedCount++; diff --git a/src/core/Spec.js b/src/core/Spec.js index 469345b4..8733d5bd 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -118,7 +118,7 @@ jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessag }; jasmine.Spec.prototype.fail = function (e) { - var expectationResult = new jasmine.ExpectationResult({ + var expectationResult = jasmine.buildExpectationResult({ passed: false, message: e ? jasmine.util.formatException(e) : 'Exception', trace: { stack: e.stack } diff --git a/src/html/SpecView.js b/src/html/SpecView.js index b9bcf08a..8af30cb5 100644 --- a/src/html/SpecView.js +++ b/src/html/SpecView.js @@ -61,7 +61,7 @@ jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { if (result.type == 'log') { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && result.passed && !result.passed()) { + } else if (result.type == 'expect' && !result.passed) { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); if (result.trace.stack) { @@ -76,4 +76,4 @@ jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { } }; -jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView); \ No newline at end of file +jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView); diff --git a/src/html/TrivialReporter.js b/src/html/TrivialReporter.js index 167ac506..05e08bc7 100644 --- a/src/html/TrivialReporter.js +++ b/src/html/TrivialReporter.js @@ -126,7 +126,7 @@ jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { var results = spec.results(); - var status = results.passed() ? 'passed' : 'failed'; + var status = results.passed ? 'passed' : 'failed'; if (results.skipped) { status = 'skipped'; } @@ -146,7 +146,7 @@ jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { if (result.type == 'log') { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && result.passed && !result.passed()) { + } else if (result.type == 'expect' && !result.passed) { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); if (result.trace.stack) { From 1f5e790c41803032d3165837e76eae0e322120c4 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Thu, 29 Nov 2012 15:55:46 -0800 Subject: [PATCH 37/55] Remove Matchers report code cruft. - Code that used reportWasCalled was removed previously. --- src/core/Matchers.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/core/Matchers.js b/src/core/Matchers.js index 634564a7..50e088df 100644 --- a/src/core/Matchers.js +++ b/src/core/Matchers.js @@ -9,7 +9,6 @@ jasmine.Matchers = function(env, actual, spec, opt_isNot) { this.actual = actual; this.spec = spec; this.isNot = opt_isNot || false; - this.reportWasCalled_ = false; }; // todo: @deprecated as of Jasmine 0.11, remove soon [xw] @@ -17,14 +16,8 @@ jasmine.Matchers.pp = function(str) { throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); }; -// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] -jasmine.Matchers.prototype.report = function(result, failing_message, details) { - throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); -}; - jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { for (var methodName in prototype) { - if (methodName == 'report') continue; var orig = prototype[methodName]; matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); } @@ -39,8 +32,6 @@ jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { result = !result; } - if (this.reportWasCalled_) return result; - var message; if (!result) { if (this.message) { From 779dee1211ddfd6c91b66d57e387a2cc2fd26b59 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Fri, 30 Nov 2012 10:08:20 -0800 Subject: [PATCH 38/55] Remove results from Queue - consequently, Runner & Suite no longer have results. - Results come back to reporters from Spec, we should not have a need to walk them later via suite/runner (in fact, no reporter used results on suite/runner -- only bad tests) - Remove/clean up tests relying on #results - Remove integration tests that duplicate already tested behavior --- lib/jasmine-core/example/SpecRunner.html | 54 --- lib/jasmine-core/jasmine-html.js | 195 +------- lib/jasmine-core/jasmine.css | 30 -- lib/jasmine-core/jasmine.js | 594 +++++++++++------------ spec/core/ExceptionsSpec.js | 105 +--- spec/core/RunnerSpec.js | 157 ++---- spec/core/SpecRunningSpec.js | 240 +-------- spec/html/TrivialReporterSpec.js | 239 --------- spec/runner.html | 2 - src/core/Queue.js | 16 +- src/core/Runner.js | 4 - src/core/Suite.js | 4 - src/html/HtmlReporterHelpers.js | 3 + src/html/TrivialReporter.js | 192 -------- src/html/_TrivialReporter.scss | 169 ------- src/html/jasmine.css | 30 -- src/html/jasmine.scss | 1 - tasks/jasmine_dev/sources.rb | 1 - 18 files changed, 354 insertions(+), 1682 deletions(-) delete mode 100644 lib/jasmine-core/example/SpecRunner.html delete mode 100644 spec/html/TrivialReporterSpec.js delete mode 100644 src/html/TrivialReporter.js delete mode 100644 src/html/_TrivialReporter.scss diff --git a/lib/jasmine-core/example/SpecRunner.html b/lib/jasmine-core/example/SpecRunner.html deleted file mode 100644 index ea58503d..00000000 --- a/lib/jasmine-core/example/SpecRunner.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - Jasmine Spec Runner - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index d4364bee..1633aae5 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -27,6 +27,9 @@ jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { }; jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { + if (!child.results) { + return; + } var results = child.results(); var status = results.passed() ? 'passed' : 'failed'; if (results.skipped) { @@ -488,195 +491,3 @@ jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); -/* @deprecated Use jasmine.HtmlReporter instead - */ -jasmine.TrivialReporter = function(doc) { - this.document = doc || document; - this.suiteDivs = {}; - this.logRunningSpecs = false; -}; - -jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { - var el = document.createElement(type); - - for (var i = 2; i < arguments.length; i++) { - var child = arguments[i]; - - if (typeof child === 'string') { - el.appendChild(document.createTextNode(child)); - } else { - if (child) { el.appendChild(child); } - } - } - - for (var attr in attrs) { - if (attr == "className") { - el[attr] = attrs[attr]; - } else { - el.setAttribute(attr, attrs[attr]); - } - } - - return el; -}; - -jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { - var showPassed, showSkipped; - - this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' }, - this.createDom('div', { className: 'banner' }, - this.createDom('div', { className: 'logo' }, - this.createDom('span', { className: 'title' }, "Jasmine"), - this.createDom('span', { className: 'version' }, runner.env.versionString())), - this.createDom('div', { className: 'options' }, - "Show ", - showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), - this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), - showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), - this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") - ) - ), - - this.runnerDiv = this.createDom('div', { className: 'runner running' }, - this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), - this.runnerMessageSpan = this.createDom('span', {}, "Running..."), - this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) - ); - - this.document.body.appendChild(this.outerDiv); - - var suites = runner.suites(); - for (var i = 0; i < suites.length; i++) { - var suite = suites[i]; - var suiteDiv = this.createDom('div', { className: 'suite' }, - this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), - this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); - this.suiteDivs[suite.id] = suiteDiv; - var parentDiv = this.outerDiv; - if (suite.parentSuite) { - parentDiv = this.suiteDivs[suite.parentSuite.id]; - } - parentDiv.appendChild(suiteDiv); - } - - this.startedAt = new Date(); - - var self = this; - showPassed.onclick = function(evt) { - if (showPassed.checked) { - self.outerDiv.className += ' show-passed'; - } else { - self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); - } - }; - - showSkipped.onclick = function(evt) { - if (showSkipped.checked) { - self.outerDiv.className += ' show-skipped'; - } else { - self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); - } - }; -}; - -jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { - var results = runner.results(); - var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; - this.runnerDiv.setAttribute("class", className); - //do it twice for IE - this.runnerDiv.setAttribute("className", className); - var specs = runner.specs(); - var specCount = 0; - for (var i = 0; i < specs.length; i++) { - if (this.specFilter(specs[i])) { - specCount++; - } - } - var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); - message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; - this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); - - this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); -}; - -jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { - var results = suite.results(); - var status = results.passed() ? 'passed' : 'failed'; - if (results.totalCount === 0) { // todo: change this to check results.skipped - status = 'skipped'; - } - this.suiteDivs[suite.id].className += " " + status; -}; - -jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { - if (this.logRunningSpecs) { - this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); - } -}; - -jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { - var results = spec.results(); - var status = results.passed ? 'passed' : 'failed'; - if (results.skipped) { - status = 'skipped'; - } - var specDiv = this.createDom('div', { className: 'spec ' + status }, - this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), - this.createDom('a', { - className: 'description', - href: '?spec=' + encodeURIComponent(spec.getFullName()), - title: spec.getFullName() - }, spec.description)); - - - var resultItems = results.getItems(); - var messagesDiv = this.createDom('div', { className: 'messages' }); - for (var i = 0; i < resultItems.length; i++) { - var result = resultItems[i]; - - if (result.type == 'log') { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && !result.passed) { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); - - if (result.trace.stack) { - messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); - } - } - } - - if (messagesDiv.childNodes.length > 0) { - specDiv.appendChild(messagesDiv); - } - - this.suiteDivs[spec.suite.id].appendChild(specDiv); -}; - -jasmine.TrivialReporter.prototype.log = function() { - var console = jasmine.getGlobal().console; - if (console && console.log) { - if (console.log.apply) { - console.log.apply(console, arguments); - } else { - console.log(arguments); // ie fix: console.log.apply doesn't exist on ie - } - } -}; - -jasmine.TrivialReporter.prototype.getLocation = function() { - return this.document.location; -}; - -jasmine.TrivialReporter.prototype.specFilter = function(spec) { - var paramMap = {}; - var params = this.getLocation().search.substring(1).split('&'); - for (var i = 0; i < params.length; i++) { - var p = params[i].split('='); - paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); - } - - if (!paramMap.spec) { - return true; - } - return spec.getFullName().indexOf(paramMap.spec) === 0; -}; diff --git a/lib/jasmine-core/jasmine.css b/lib/jasmine-core/jasmine.css index 8c008dc7..69e6db8b 100644 --- a/lib/jasmine-core/jasmine.css +++ b/lib/jasmine-core/jasmine.css @@ -50,33 +50,3 @@ body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } #HTMLReporter .resultMessage span.result { display: block; } #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } - -#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ } -#TrivialReporter a:visited, #TrivialReporter a { color: #303; } -#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; } -#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; } -#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; } -#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; } -#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; } -#TrivialReporter .runner.running { background-color: yellow; } -#TrivialReporter .options { text-align: right; font-size: .8em; } -#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; } -#TrivialReporter .suite .suite { margin: 5px; } -#TrivialReporter .suite.passed { background-color: #dfd; } -#TrivialReporter .suite.failed { background-color: #fdd; } -#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; } -#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; } -#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; } -#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; } -#TrivialReporter .spec.skipped { background-color: #bbb; } -#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; } -#TrivialReporter .passed { background-color: #cfc; display: none; } -#TrivialReporter .failed { background-color: #fbb; } -#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; } -#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; } -#TrivialReporter .resultMessage .mismatch { color: black; } -#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; } -#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; } -#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; } -#TrivialReporter #jasmine_content { position: fixed; right: 100%; } -#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; } diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 0892ee37..268cd769 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -510,15 +510,13 @@ jasmine.util.extend = function(destination, source) { //TODO: expectation result may make more sense as a presentation of an expectation. jasmine.buildExpectationResult = function(params) { - var trace = (params.trace || new Error(this.message)); - var message = params.passed ? 'Passed.' : params.message; return { type: 'expect', matcherName: params.matcherName, expected: params.expected, actual: params.actual, - message: message, - trace: params.passed ? '' : trace, + message: params.passed ? 'Passed.' : params.message, + trace: params.passed ? '' : (params.trace || new Error(this.message)), passed: params.passed }; }; @@ -527,301 +525,308 @@ jasmine.buildExpectationResult = function(params) { * * @constructor */ -jasmine.Env = function() { - this.currentSpec = null; - this.currentSuite = null; - this.currentRunner_ = new jasmine.Runner(this); +(function() { - this.reporter = new jasmine.MultiReporter(); + function createSpec(env, suite, description) { + return new jasmine.Spec(env, suite, description); + } - this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; - this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; - this.lastUpdate = 0; - this.specFilter = function() { - return true; + jasmine.Env = function() { + this.currentSpec = null; + this.currentSuite = null; + this.currentRunner_ = new jasmine.Runner(this); + + this.reporter = new jasmine.MultiReporter(); + + this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; + this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; + this.lastUpdate = 0; + this.specFilter = function() { + return true; + }; + + this.nextSpecId_ = 0; + this.nextSuiteId_ = 0; + this.equalityTesters_ = []; + + // wrap matchers + this.matchersClass = function() { + jasmine.Matchers.apply(this, arguments); + }; + jasmine.util.inherit(this.matchersClass, jasmine.Matchers); + + jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); }; - this.nextSpecId_ = 0; - this.nextSuiteId_ = 0; - this.equalityTesters_ = []; - // wrap matchers - this.matchersClass = function() { - jasmine.Matchers.apply(this, arguments); - }; - jasmine.util.inherit(this.matchersClass, jasmine.Matchers); + jasmine.Env.prototype.setTimeout = jasmine.setTimeout; + jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; + jasmine.Env.prototype.setInterval = jasmine.setInterval; + jasmine.Env.prototype.clearInterval = jasmine.clearInterval; - jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); -}; - - -jasmine.Env.prototype.setTimeout = jasmine.setTimeout; -jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; -jasmine.Env.prototype.setInterval = jasmine.setInterval; -jasmine.Env.prototype.clearInterval = jasmine.clearInterval; - -/** - * @returns an object containing jasmine version build info, if set. - */ -jasmine.Env.prototype.version = function () { - if (jasmine.version_) { - return jasmine.version_; - } else { - throw new Error('Version not set'); - } -}; - -/** - * @returns string containing jasmine version build info, if set. - */ -jasmine.Env.prototype.versionString = function() { - if (!jasmine.version_) { - return "version unknown"; - } - - var version = this.version(); - var versionString = version.major + "." + version.minor + "." + version.build; - if (version.release_candidate) { - versionString += ".rc" + version.release_candidate; - } - versionString += " revision " + version.revision; - return versionString; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSpecId = function () { - return this.nextSpecId_++; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSuiteId = function () { - return this.nextSuiteId_++; -}; - -/** - * Register a reporter to receive status updates from Jasmine. - * @param {jasmine.Reporter} reporter An object which will receive status updates. - */ -jasmine.Env.prototype.addReporter = function(reporter) { - this.reporter.addReporter(reporter); -}; - -jasmine.Env.prototype.execute = function() { - this.currentRunner_.execute(); -}; - -jasmine.Env.prototype.describe = function(description, specDefinitions) { - var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); - - var parentSuite = this.currentSuite; - if (parentSuite) { - parentSuite.add(suite); - } else { - this.currentRunner_.add(suite); - } - - this.currentSuite = suite; - - var declarationError = null; - try { - specDefinitions.call(suite); - } catch(e) { - declarationError = e; - } - - if (declarationError) { - this.it("encountered a declaration exception", function() { - throw declarationError; - }); - } - - this.currentSuite = parentSuite; - - return suite; -}; - -jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { - if (this.currentSuite) { - this.currentSuite.beforeEach(beforeEachFunction); - } else { - this.currentRunner_.beforeEach(beforeEachFunction); - } -}; - -jasmine.Env.prototype.currentRunner = function () { - return this.currentRunner_; -}; - -jasmine.Env.prototype.afterEach = function(afterEachFunction) { - if (this.currentSuite) { - this.currentSuite.afterEach(afterEachFunction); - } else { - this.currentRunner_.afterEach(afterEachFunction); - } - -}; - -jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { - return { - execute: function() { + /** + * @returns an object containing jasmine version build info, if set. + */ + jasmine.Env.prototype.version = function () { + if (jasmine.version_) { + return jasmine.version_; + } else { + throw new Error('Version not set'); } }; -}; -jasmine.Env.prototype.it = function(description, func) { - var spec = new jasmine.Spec(this, this.currentSuite, description); - this.currentSuite.add(spec); - this.currentSpec = spec; - - if (func) { - spec.runs(func); - } - - return spec; -}; - -jasmine.Env.prototype.xit = function(desc, func) { - return { - id: this.nextSpecId(), - runs: function() { + /** + * @returns string containing jasmine version build info, if set. + */ + jasmine.Env.prototype.versionString = function() { + if (!jasmine.version_) { + return "version unknown"; } - }; -}; -jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { - if (a.source != b.source) - mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); - - if (a.ignoreCase != b.ignoreCase) - mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); - - if (a.global != b.global) - mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); - - if (a.multiline != b.multiline) - mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); - - if (a.sticky != b.sticky) - mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); - - return (mismatchValues.length === 0); -}; - -jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { - if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { - return true; - } - - a.__Jasmine_been_here_before__ = b; - b.__Jasmine_been_here_before__ = a; - - var hasKey = function(obj, keyName) { - return obj !== null && obj[keyName] !== jasmine.undefined; + var version = this.version(); + var versionString = version.major + "." + version.minor + "." + version.build; + if (version.release_candidate) { + versionString += ".rc" + version.release_candidate; + } + versionString += " revision " + version.revision; + return versionString; }; - for (var property in b) { - if (!hasKey(a, property) && hasKey(b, property)) { - mismatchKeys.push("expected has key '" + property + "', but missing from actual."); + /** + * @returns a sequential integer starting at 0 + */ + jasmine.Env.prototype.nextSpecId = function () { + return this.nextSpecId_++; + }; + + /** + * @returns a sequential integer starting at 0 + */ + jasmine.Env.prototype.nextSuiteId = function () { + return this.nextSuiteId_++; + }; + + /** + * Register a reporter to receive status updates from Jasmine. + * @param {jasmine.Reporter} reporter An object which will receive status updates. + */ + jasmine.Env.prototype.addReporter = function(reporter) { + this.reporter.addReporter(reporter); + }; + + jasmine.Env.prototype.execute = function() { + this.currentRunner_.execute(); + }; + + jasmine.Env.prototype.describe = function(description, specDefinitions) { + var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); + + var parentSuite = this.currentSuite; + if (parentSuite) { + parentSuite.add(suite); + } else { + this.currentRunner_.add(suite); } - } - for (property in a) { - if (!hasKey(b, property) && hasKey(a, property)) { - mismatchKeys.push("expected missing key '" + property + "', but present in actual."); + + this.currentSuite = suite; + + var declarationError = null; + try { + specDefinitions.call(suite); + } catch(e) { + declarationError = e; } - } - for (property in b) { - if (property == '__Jasmine_been_here_before__') continue; - if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { - mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); + + if (declarationError) { + this.it("encountered a declaration exception", function() { + throw declarationError; + }); } - } - if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { - mismatchValues.push("arrays were not the same length"); - } + this.currentSuite = parentSuite; - delete a.__Jasmine_been_here_before__; - delete b.__Jasmine_been_here_before__; - return (mismatchKeys.length === 0 && mismatchValues.length === 0); -}; + return suite; + }; -jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { - mismatchKeys = mismatchKeys || []; - mismatchValues = mismatchValues || []; - - for (var i = 0; i < this.equalityTesters_.length; i++) { - var equalityTester = this.equalityTesters_[i]; - var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); - if (result !== jasmine.undefined) return result; - } - - if (a === b) return true; - - if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { - return (a == jasmine.undefined && b == jasmine.undefined); - } - - if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { - return a === b; - } - - if (a instanceof Date && b instanceof Date) { - return a.getTime() == b.getTime(); - } - - if (a.jasmineMatches) { - return a.jasmineMatches(b); - } - - if (b.jasmineMatches) { - return b.jasmineMatches(a); - } - - if (a instanceof jasmine.Matchers.ObjectContaining) { - return a.matches(b); - } - - if (b instanceof jasmine.Matchers.ObjectContaining) { - return b.matches(a); - } - - if (jasmine.isString_(a) && jasmine.isString_(b)) { - return (a == b); - } - - if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { - return (a == b); - } - - if (a instanceof RegExp && b instanceof RegExp) { - return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); - } - - if (typeof a === "object" && typeof b === "object") { - return this.compareObjects_(a, b, mismatchKeys, mismatchValues); - } - - //Straight check - return (a === b); -}; - -jasmine.Env.prototype.contains_ = function(haystack, needle) { - if (jasmine.isArray_(haystack)) { - for (var i = 0; i < haystack.length; i++) { - if (this.equals_(haystack[i], needle)) return true; + jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { + if (this.currentSuite) { + this.currentSuite.beforeEach(beforeEachFunction); + } else { + this.currentRunner_.beforeEach(beforeEachFunction); } - return false; - } - return haystack.indexOf(needle) >= 0; -}; + }; -jasmine.Env.prototype.addEqualityTester = function(equalityTester) { - this.equalityTesters_.push(equalityTester); -}; + jasmine.Env.prototype.currentRunner = function () { + return this.currentRunner_; + }; + + jasmine.Env.prototype.afterEach = function(afterEachFunction) { + if (this.currentSuite) { + this.currentSuite.afterEach(afterEachFunction); + } else { + this.currentRunner_.afterEach(afterEachFunction); + } + + }; + + jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { + return { + execute: function() { + } + }; + }; + + jasmine.Env.prototype.it = function(description, func) { + var spec = createSpec(this, this.currentSuite, description); + this.currentSuite.add(spec); + this.currentSpec = spec; + + if (func) { + spec.runs(func); + } + + return spec; + }; + + jasmine.Env.prototype.xit = function(desc, func) { + return { + id: this.nextSpecId(), + runs: function() { + } + }; + }; + + jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.source != b.source) + mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); + + if (a.ignoreCase != b.ignoreCase) + mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.global != b.global) + mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.multiline != b.multiline) + mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); + + if (a.sticky != b.sticky) + mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); + + return (mismatchValues.length === 0); + }; + + jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { + return true; + } + + a.__Jasmine_been_here_before__ = b; + b.__Jasmine_been_here_before__ = a; + + var hasKey = function(obj, keyName) { + return obj !== null && obj[keyName] !== jasmine.undefined; + }; + + for (var property in b) { + if (!hasKey(a, property) && hasKey(b, property)) { + mismatchKeys.push("expected has key '" + property + "', but missing from actual."); + } + } + for (property in a) { + if (!hasKey(b, property) && hasKey(a, property)) { + mismatchKeys.push("expected missing key '" + property + "', but present in actual."); + } + } + for (property in b) { + if (property == '__Jasmine_been_here_before__') continue; + if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { + mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); + } + } + + if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { + mismatchValues.push("arrays were not the same length"); + } + + delete a.__Jasmine_been_here_before__; + delete b.__Jasmine_been_here_before__; + return (mismatchKeys.length === 0 && mismatchValues.length === 0); + }; + + jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { + mismatchKeys = mismatchKeys || []; + mismatchValues = mismatchValues || []; + + for (var i = 0; i < this.equalityTesters_.length; i++) { + var equalityTester = this.equalityTesters_[i]; + var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); + if (result !== jasmine.undefined) return result; + } + + if (a === b) return true; + + if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { + return (a == jasmine.undefined && b == jasmine.undefined); + } + + if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { + return a === b; + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() == b.getTime(); + } + + if (a.jasmineMatches) { + return a.jasmineMatches(b); + } + + if (b.jasmineMatches) { + return b.jasmineMatches(a); + } + + if (a instanceof jasmine.Matchers.ObjectContaining) { + return a.matches(b); + } + + if (b instanceof jasmine.Matchers.ObjectContaining) { + return b.matches(a); + } + + if (jasmine.isString_(a) && jasmine.isString_(b)) { + return (a == b); + } + + if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { + return (a == b); + } + + if (a instanceof RegExp && b instanceof RegExp) { + return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); + } + + if (typeof a === "object" && typeof b === "object") { + return this.compareObjects_(a, b, mismatchKeys, mismatchValues); + } + + //Straight check + return (a === b); + }; + + jasmine.Env.prototype.contains_ = function(haystack, needle) { + if (jasmine.isArray_(haystack)) { + for (var i = 0; i < haystack.length; i++) { + if (this.equals_(haystack[i], needle)) return true; + } + return false; + } + return haystack.indexOf(needle) >= 0; + }; + + jasmine.Env.prototype.addEqualityTester = function(equalityTester) { + this.equalityTesters_.push(equalityTester); + }; +}()); /** No-op base class for Jasmine reporters. * * @constructor @@ -994,7 +999,6 @@ jasmine.Matchers = function(env, actual, spec, opt_isNot) { this.actual = actual; this.spec = spec; this.isNot = opt_isNot || false; - this.reportWasCalled_ = false; }; // todo: @deprecated as of Jasmine 0.11, remove soon [xw] @@ -1002,14 +1006,8 @@ jasmine.Matchers.pp = function(str) { throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); }; -// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] -jasmine.Matchers.prototype.report = function(result, failing_message, details) { - throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); -}; - jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { for (var methodName in prototype) { - if (methodName == 'report') continue; var orig = prototype[methodName]; matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); } @@ -1024,8 +1022,6 @@ jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { result = !result; } - if (this.reportWasCalled_) return result; - var message; if (!result) { if (this.message) { @@ -1875,7 +1871,7 @@ jasmine.Queue.prototype.next_ = function() { while (goAgain) { goAgain = false; - + if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { var calledSynchronously = true; var completedSynchronously = false; @@ -1913,7 +1909,7 @@ jasmine.Queue.prototype.next_ = function() { if (completedSynchronously) { onComplete(); } - + } else { self.running = false; if (self.onComplete) { @@ -1922,18 +1918,6 @@ jasmine.Queue.prototype.next_ = function() { } } }; - -jasmine.Queue.prototype.results = function() { - var results = new jasmine.NestedResults(); - for (var i = 0; i < this.blocks.length; i++) { - if (this.blocks[i].results) { - results.addResult(this.blocks[i].results()); - } - } - return results; -}; - - /** * Runner * @@ -2007,10 +1991,6 @@ jasmine.Runner.prototype.topLevelSuites = function() { } return topLevelSuites; }; - -jasmine.Runner.prototype.results = function() { - return this.queue.results(); -}; /** * Internal representation of a Jasmine specification, or test. * @@ -2303,10 +2283,6 @@ jasmine.Suite.prototype.afterEach = function(afterEachFunction) { this.after_.unshift(afterEachFunction); }; -jasmine.Suite.prototype.results = function() { - return this.queue.results(); -}; - jasmine.Suite.prototype.add = function(suiteOrSpec) { this.children_.push(suiteOrSpec); if (suiteOrSpec instanceof jasmine.Suite) { diff --git a/spec/core/ExceptionsSpec.js b/spec/core/ExceptionsSpec.js index a7aa8aeb..06ed46c4 100644 --- a/spec/core/ExceptionsSpec.js +++ b/spec/core/ExceptionsSpec.js @@ -59,117 +59,36 @@ describe('Exceptions:', function() { describe("with catch on exception", function() { it('should handle exceptions thrown, but continue', function() { - var fakeTimer = new jasmine.FakeTimer(); - env.setTimeout = fakeTimer.setTimeout; - env.clearTimeout = fakeTimer.clearTimeout; - env.setInterval = fakeTimer.setInterval; - env.clearInterval = fakeTimer.clearInterval; - - //we run two exception tests to make sure we continue after throwing an exception - var suite = env.describe('Suite for handles exceptions', function () { + var ranSecondTest = false, + suite = env.describe('Suite for handles exceptions', function () { env.it('should be a test that fails because it throws an exception', function() { - throw new Error('fake error 1'); + throw new Error(); }); - - env.it('should be another test that fails because it throws an exception', function() { - this.runs(function () { - throw new Error('fake error 2'); - }); - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - - env.it('should be a passing test that runs after exceptions are thrown', function() { - this.expect(true).toEqual(true); - }); - - env.it('should be another test that fails because it throws an exception after a wait', function() { - this.runs(function () { - var foo = 'foo'; - }); - this.waits(250); - this.runs(function () { - throw new Error('fake error 3'); - }); - }); - env.it('should be a passing test that runs after exceptions are thrown from a async test', function() { - this.expect(true).toEqual(true); + ranSecondTest = true; }); }); - var runner = env.currentRunner(); suite.execute(); - fakeTimer.tick(2500); - - var suiteResults = suite.results(); - var specResults = suiteResults.getItems(); - - expect(suiteResults.passed()).toEqual(false); - // - expect(specResults.length).toEqual(5); - expect(specResults[0].passed()).toMatch(false); - var blockResults = specResults[0].getItems(); - expect(blockResults[0].passed).toEqual(false); - expect(blockResults[0].message).toMatch(/fake error 1/); - - expect(specResults[1].passed()).toEqual(false); - blockResults = specResults[1].getItems(); - expect(blockResults[0].passed).toEqual(false); - expect(blockResults[0].message).toMatch(/fake error 2/); - expect(blockResults[1].passed).toEqual(true); - - expect(specResults[2].passed()).toEqual(true); - - expect(specResults[3].passed()).toEqual(false); - blockResults = specResults[3].getItems(); - expect(blockResults[0].message).toMatch(/fake error 3/); - - expect(specResults[4].passed()).toEqual(true); + expect(ranSecondTest).toBe(true); }); it("should handle exceptions thrown directly in top-level describe blocks and continue", function () { - var suite = env.describe("a top level describe block that throws an exception", function () { + var ranSecondDescribe = false, suite, suite2, runner = env.currentRunner(); + suite = env.describe("a suite that throws an exception", function () { env.it("is a test that should pass", function () { this.expect(true).toEqual(true); }); throw new Error("top level error"); }); - - suite.execute(); - var suiteResults = suite.results(); - var specResults = suiteResults.getItems(); - - expect(suiteResults.passed()).toEqual(false); - expect(specResults.length).toEqual(2); - - expect(specResults[1].description).toMatch(/encountered a declaration exception/); - }); - - it("should handle exceptions thrown directly in nested describe blocks and continue", function () { - var suite = env.describe("a top level describe", function () { - env.describe("a mid-level describe that throws an exception", function () { - env.it("is a test that should pass", function () { - this.expect(true).toEqual(true); - }); - - throw new Error("a mid-level error"); - }); + suite2 = env.describe("a suite that doesn't throw an exception", function () { + ranSecondDescribe = true; }); - suite.execute(); - var suiteResults = suite.results(); - var specResults = suiteResults.getItems(); - - expect(suiteResults.passed()).toEqual(false); - expect(specResults.length).toEqual(1); - - var nestedSpecResults = specResults[0].getItems(); - - expect(nestedSpecResults.length).toEqual(2); - expect(nestedSpecResults[1].description).toMatch(/encountered a declaration exception/); + runner.execute(); + expect(ranSecondDescribe).toBe(true); }); }); + }); diff --git a/spec/core/RunnerSpec.js b/spec/core/RunnerSpec.js index 5d00bbd6..6bea56e3 100644 --- a/spec/core/RunnerSpec.js +++ b/spec/core/RunnerSpec.js @@ -14,105 +14,83 @@ describe('RunnerTest', function() { }); describe('beforeEach', function() { - it('should run before each spec for all suites', function () { + it('should run before each spec for all suites', function() { var foo; - env.beforeEach(function () { + env.beforeEach(function() { foo = 0; }); - env.describe('suite 1', function () { + env.describe('suite 1', function() { env.it('test 1-1', function() { foo++; - this.expect(foo).toEqual(1); + expect(foo).toEqual(1); }); env.it('test 1-2', function() { foo++; - this.expect(foo).toEqual(1); + expect(foo).toEqual(1); }); }); - env.describe('suite 2', function () { + env.describe('suite 2', function() { env.it('test 2-1', function() { foo++; - this.expect(foo).toEqual(1); + expect(foo).toEqual(1); }); }); env.currentRunner().execute(); - - var runnerResults = env.currentRunner().results(); - expect(runnerResults.totalCount).toEqual(3); - expect(runnerResults.passedCount).toEqual(3); }); + it('should provide all specs', function() { - it('should provide all specs', function () { - var foo; - env.beforeEach(function () { - foo = 0; - }); - - env.describe('suite 1', function () { + env.describe('suite 1', function() { env.it('test 1-1', function() { - foo++; - this.expect(foo).toEqual(1); }); env.it('test 1-2', function() { - foo++; - this.expect(foo).toEqual(1); }); }); - env.describe('suite 2', function () { + env.describe('suite 2', function() { env.it('test 2-1', function() { - foo++; - this.expect(foo).toEqual(1); }); }); - env.currentRunner().execute(); - - expect(env.currentRunner().specs().length).toEqual(3); }); }); describe('afterEach', function() { - it('should run after each spec for all suites', function () { + it('should run after each spec for all suites', function() { var foo = 3; - env.afterEach(function () { + env.afterEach(function() { foo = foo - 1; }); - env.describe('suite 1', function () { + env.describe('suite 1', function() { env.it('test 1-1', function() { - this.expect(foo).toEqual(3); + expect(foo).toEqual(3); }); env.it('test 1-2', function() { - this.expect(foo).toEqual(2); + expect(foo).toEqual(2); }); }); - env.describe('suite 2', function () { + env.describe('suite 2', function() { env.it('test 2-1', function() { - this.expect(foo).toEqual(1); + expect(foo).toEqual(1); }); }); env.currentRunner().execute(); - - var runnerResults = env.currentRunner().results(); - expect(runnerResults.totalCount).toEqual(3); - expect(runnerResults.passedCount).toEqual(3); }); it('should run after a failing spec', function () { var afterEach = originalJasmine.createSpy(); env.afterEach(afterEach); - env.describe('suite', function () { - env.it('fails', function () { - this.explodes(); + env.describe('suite',function() { + env.it('fails', function() { + this.fail(); }); }).execute(); @@ -120,103 +98,32 @@ describe('RunnerTest', function() { }); }); - - it('should run child suites and specs and generate results when execute is called', function() { - env.describe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - - env.describe('another suite description', function () { - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(false); - }); - }); - }); - - env.currentRunner().execute(); - - var runnerResults = env.currentRunner().results(); - expect(runnerResults.totalCount).toEqual(2); - expect(runnerResults.passedCount).toEqual(1); - expect(runnerResults.failedCount).toEqual(1); - }); - - it('should ignore suites that have been x\'d', function() { - env.xdescribe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - - env.describe('another suite description', function () { - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(false); - }); - }); - }); - + var disabledDescribe = jasmine.createSpy('xdescribe'); + env.xdescribe('one suite description', disabledDescribe); env.currentRunner().execute(); - - var runnerResults = env.currentRunner().results(); - expect(runnerResults.totalCount).toEqual(1); - expect(runnerResults.passedCount).toEqual(0); - expect(runnerResults.failedCount).toEqual(1); + expect(disabledDescribe).not.toHaveBeenCalled(); }); - it('should roll up results from all specs', function() { - env.describe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - - env.describe('another suite description', function () { - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(false); - }); - }); - }); - - env.currentRunner().execute(); - - var results = env.currentRunner().results(); - expect(results.totalCount).toEqual(2); - expect(results.passedCount).toEqual(1); - expect(results.failedCount).toEqual(1); - }); - - describe('reporting', function () { + describe('reporting', function() { var fakeReporter; - beforeEach(function () { fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting", "reportRunnerResults"]); env.addReporter(fakeReporter); }); it('should report runner results when the runner has completed running', function() { - env.describe('one suite description', function () { + env.describe('one suite description', function() { env.it('should be a test', function() { - this.runs(function () { + this.runs(function() { this.expect(true).toEqual(true); }); }); }); - env.describe('another suite description', function () { + env.describe('another suite description', function() { env.it('should be another test', function() { this.waits(200); - this.runs(function () { + this.runs(function() { this.expect(true).toEqual(false); }); }); @@ -225,10 +132,7 @@ describe('RunnerTest', function() { env.currentRunner().execute(); expect(fakeReporter.reportRunnerResults).not.toHaveBeenCalled(); fakeTimer.tick(200); - //This blows up the JSApiReporter. - //expect(fakeReporter.reportRunnerResults).toHaveBeenCalledWith(env.currentRunner); - expect(fakeReporter.reportRunnerResults).toHaveBeenCalled(); - expect(fakeReporter.reportRunnerResults.mostRecentCall.args[0].results()).toEqual(env.currentRunner().results()); + expect(fakeReporter.reportRunnerResults).toHaveBeenCalledWith(env.currentRunner()); }); }); @@ -264,7 +168,8 @@ describe('RunnerTest', function() { suite2 = env.describe("suite 2", function() { }); }); - suite3 = env.describe("suite 3", function() {}); + suite3 = env.describe("suite 3", function() { + }); }); it("#suites should return a flat array of all suites, including nested suites", function() { diff --git a/spec/core/SpecRunningSpec.js b/spec/core/SpecRunningSpec.js index 98e7146b..bf06f989 100644 --- a/spec/core/SpecRunningSpec.js +++ b/spec/core/SpecRunningSpec.js @@ -576,66 +576,6 @@ describe("jasmine spec running", function () { }); - it("testBeforeAndAfterCallbacks", function () { - var suiteWithBefore = env.describe('one suite with a before', function () { - - this.beforeEach(function () { - this.foo = 1; - }); - - env.it('should be a spec', function () { - this.runs(function() { - this.foo++; - this.expect(this.foo).toEqual(2); - }); - }); - - env.it('should be another spec', function () { - this.runs(function() { - this.foo++; - this.expect(this.foo).toEqual(2); - }); - }); - }); - - suiteWithBefore.execute(); - - var suite = suiteWithBefore; - - expect(suite.results().getItems()[0].passed()).toEqual(true); // "testBeforeAndAfterCallbacks: the first spec's foo should have been 2"); - expect(suite.results().getItems()[1].passed()).toEqual(true); // "testBeforeAndAfterCallbacks: the second spec's this.foo should have been 2"); - - - var foo = 1; - var suiteWithAfter = env.describe('one suite with an after_each', function () { - - env.it('should be a spec with an after_each', function () { - this.expect(foo).toEqual(1); - foo++; - this.expect(foo).toEqual(2); - }); - - env.it('should be another spec with an after_each', function () { - this.expect(foo).toEqual(0); - foo++; - this.expect(foo).toEqual(1); - }); - - this.afterEach(function () { - foo = 0; - }); - }); - - suiteWithAfter.execute(); - - suite = suiteWithAfter; - expect(suite.afterEach.length).toEqual(1); - expect(suite.results().getItems()[0].passed()).toEqual(true); - expect(suite.results().getItems()[1].passed()).toEqual(true); - expect(foo).toEqual(0); - - }); - it('#waits should allow consecutive waits calls', function () { var foo = 0; var waitsSuite = env.describe('suite that waits', function () { @@ -873,85 +813,6 @@ describe("jasmine spec running", function () { expect(secondSpecHasRun).toEqual(true); }); - it("testBeforeExecutesSafely", function() { - var report = ""; - var suite = env.describe('before fails on first test, passes on second', function() { - var counter = 0; - this.beforeEach(function() { - counter++; - if (counter == 1) { - throw "before failure"; - } - }); - env.it("first should not run because before fails", function() { - this.runs(function() { - report += "first"; - this.expect(true).toEqual(true); - }); - }); - env.it("second should run and pass because before passes", function() { - this.runs(function() { - report += "second"; - this.expect(true).toEqual(true); - }); - }); - }); - - suite.execute(); - - expect(report).toEqual("firstsecond"); - var suiteResults = suite.results(); - expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(false); - expect(suiteResults.getItems()[1].getItems()[0].passed).toEqual(true); - }); - - it("testAfterExecutesSafely", function() { - var report = ""; - var suite = env.describe('after fails on first test, then passes', function() { - var counter = 0; - this.afterEach(function() { - counter++; - if (counter == 1) { - throw "after failure"; - } - }); - env.it("first should run, expectation passes, but spec fails because after fails", function() { - this.runs(function() { - report += "first"; - this.expect(true).toEqual(true); - }); - }); - env.it("second should run and pass because after passes", function() { - this.runs(function() { - report += "second"; - this.expect(true).toEqual(true); - }); - }); - env.it("third should run and pass because after passes", function() { - this.runs(function() { - report += "third"; - this.expect(true).toEqual(true); - }); - }); - }); - - suite.execute(); - - expect(report).toEqual("firstsecondthird"); // "all tests should run"); - //After each errors should not go in spec results because it confuses the count. - var suiteResults = suite.results(); - expect(suiteResults.getItems().length).toEqual(3, 'testAfterExecutesSafely should have results for three specs'); - - expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 1st spec should pass"); - expect(suiteResults.getItems()[1].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 2nd spec should pass"); - expect(suiteResults.getItems()[2].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 3rd spec should pass"); - - expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 1st result for 1st suite spec should pass"); - expect(suiteResults.getItems()[0].getItems()[1].passed).toEqual(false, "testAfterExecutesSafely 2nd result for 1st suite spec should fail because afterEach failed"); - expect(suiteResults.getItems()[1].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 2nd suite spec should pass"); - expect(suiteResults.getItems()[2].getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 3rd suite spec should pass"); - }); - it("should permit nested describes", function() { var actions = []; @@ -1115,101 +976,36 @@ describe("jasmine spec running", function () { expect(nestedSpec.getFullName()).toEqual('Test Subject when under circumstance A and circumstance B behaves thusly.'); //, "Spec.fullName was incorrect: " + nestedSpec.getFullName()); }); - it("should skip empty suites", function () { - env.describe('NonEmptySuite1', function() { - env.it('should pass', function() { - this.expect(true).toEqual(true); - }); - env.describe('NestedEmptySuite', function() { - }); - env.it('should pass', function() { - this.expect(true).toEqual(true); - }); - }); - - env.describe('EmptySuite', function() { - }); - - env.describe('NonEmptySuite2', function() { - env.it('should pass', function() { - this.expect(true).toEqual(true); - }); - }); - - env.execute(); - - var runnerResults = env.currentRunner_.results(); - expect(runnerResults.totalCount).toEqual(3); - expect(runnerResults.passedCount).toEqual(3); - expect(runnerResults.failedCount).toEqual(0); - }); - it("should bind 'this' to the running spec within the spec body", function() { - var spec; - var suite = env.describe('one suite description', function () { - env.it('should be a test with queuedFunctions', function() { - spec = this.runs(function() { + var specExecuted = jasmine.createSpy(), spec; + + env.describe('Test Subject', function() { + spec = env.it('should be a test with queuedFunctions', function() { + this.runs(function() { this.foo = 0; + expect(this.foo).toBe(0); + specExecuted(); + }); + + this.runs(function() { this.foo++; - }); - - this.runs(function() { - var that = this; - fakeTimer.setTimeout(function() { - that.foo++; - }, 250); - }); - - this.runs(function() { - this.expect(this.foo).toEqual(2); - }); - - this.waits(300); - - this.runs(function() { - this.expect(this.foo).toEqual(2); + expect(this.foo).toBe(1); + specExecuted(); }); }); - }); - suite.execute(); - fakeTimer.tick(600); - expect(spec.foo).toEqual(2); - var suiteResults = suite.results(); - expect(suiteResults.getItems()[0].getItems().length).toEqual(2); - expect(suiteResults.getItems()[0].getItems()[0].passed).toEqual(false); - expect(suiteResults.getItems()[0].getItems()[1].passed).toEqual(true); + spec.execute(); + expect(specExecuted.callCount).toBe(2); }); it("shouldn't run disabled tests", function() { - var xitSpecWasRun = false; - var suite = env.describe('default current suite', function() { - env.xit('disabled spec').runs(function () { - xitSpecWasRun = true; - }); - - env.it('enabled spec').runs(function () { - var foo = 'bar'; - expect(foo).toEqual('bar'); - }); + var disabledSpec = originalJasmine.createSpy('disabledSpec'), + suite = env.describe('default current suite', function() { + env.xit('disabled spec').runs(disabledSpec); }); - suite.execute(); - expect(xitSpecWasRun).toEqual(false); - }); - - it('shouldn\'t execute specs in disabled suites', function() { - var spy = originalJasmine.createSpy(); - var disabledSuite = env.xdescribe('a disabled suite', function() { - env.it('enabled spec, but should not be run', function() { - spy(); - }); - }); - - disabledSuite.execute(); - - expect(spy).not.toHaveBeenCalled(); + expect(disabledSpec).not.toHaveBeenCalled(); }); it('#explodes should throw an exception when it is called inside a spec', function() { diff --git a/spec/html/TrivialReporterSpec.js b/spec/html/TrivialReporterSpec.js deleted file mode 100644 index 5cfe5e21..00000000 --- a/spec/html/TrivialReporterSpec.js +++ /dev/null @@ -1,239 +0,0 @@ -describe("TrivialReporter", function() { - var env; - var trivialReporter; - var body; - var fakeDocument; - - beforeEach(function() { - env = new jasmine.Env(); - env.updateInterval = 0; - - body = document.createElement("body"); - fakeDocument = { body: body, location: { search: "" } }; - trivialReporter = new jasmine.TrivialReporter(fakeDocument); - }); - - function fakeSpec(name) { - return { - getFullName: function() { - return name; - } - }; - } - - function findElements(divs, withClass) { - var els = []; - for (var i = 0; i < divs.length; i++) { - if (divs[i].className == withClass) els.push(divs[i]); - } - return els; - } - - function findElement(divs, withClass) { - var els = findElements(divs, withClass); - if (els.length > 0) { - return els[0]; - } - throw new Error("couldn't find div with class " + withClass); - } - - it("should run only specs beginning with spec parameter", function() { - fakeDocument.location.search = "?spec=run%20this"; - expect(trivialReporter.specFilter(fakeSpec("run this"))).toBeTruthy(); - expect(trivialReporter.specFilter(fakeSpec("not the right spec"))).toBeFalsy(); - expect(trivialReporter.specFilter(fakeSpec("not run this"))).toBeFalsy(); - }); - - it("should display empty divs for every suite when the runner is starting", function() { - trivialReporter.reportRunnerStarting({ - env: env, - suites: function() { - return [ new jasmine.Suite({}, "suite 1", null, null) ]; - } - }); - - var divs = findElements(body.getElementsByTagName("div"), "suite"); - expect(divs.length).toEqual(1); - expect(divs[0].innerHTML).toContain("suite 1"); - }); - - describe('Matcher reporting', function () { - var getResultMessageDiv = function (body) { - var divs = body.getElementsByTagName("div"); - for (var i = 0; i < divs.length; i++) { - if (divs[i].className.match(/resultMessage/)) { - return divs[i]; - } - } - }; - - var runner, spec, fakeTimer; - beforeEach(function () { - fakeTimer = new originalJasmine.FakeTimer(); - env.setTimeout = fakeTimer.setTimeout; - env.clearTimeout = fakeTimer.clearTimeout; - env.setInterval = fakeTimer.setInterval; - env.clearInterval = fakeTimer.clearInterval; - runner = env.currentRunner(); - var suite = new jasmine.Suite(env, 'some suite'); - runner.add(suite); - spec = new jasmine.Spec(env, suite, 'some spec'); - suite.add(spec); - fakeDocument.location.search = "?"; - env.addReporter(trivialReporter); - }); - - describe('toContain', function () { - it('should show actual and expected', function () { - spec.runs(function () { - this.expect('foo').toContain('bar'); - }); - runner.execute(); - fakeTimer.tick(0); - - var resultEl = getResultMessageDiv(body); - expect(resultEl.innerHTML).toMatch(/foo/); - expect(resultEl.innerHTML).toMatch(/bar/); - }); - }); - }); - - describe("failure messages (integration)", function () { - var spec, results, expectationResult; - - beforeEach(function() { - results = { - passed: function() { - return false; - }, - getItems: function() { - }}; - - var suite1 = new jasmine.Suite(env, "suite 1", null, null); - - spec = { - suite: suite1, - getFullName: function() { - return "foo"; - }, - results: function() { - return results; - } - }; - - trivialReporter.reportRunnerStarting({ - env: env, - suites: function() { - return [ suite1 ]; - } - }); - }); - - it("should add the failure message to the DOM (non-toEquals matchers)", function() { - expectationResult = jasmine.buildExpectationResult({ - matcherName: "toBeNull", passed: false, message: "Expected 'a' to be null, but it was not" - }); - - spyOn(results, 'getItems').andReturn([expectationResult]); - - trivialReporter.reportSpecResults(spec); - - var divs = body.getElementsByTagName("div"); - var errorDiv = findElement(divs, 'resultMessage fail'); - expect(errorDiv.innerHTML).toEqual("Expected 'a' to be null, but it was not"); - }); - - it("should add the failure message to the DOM (non-toEquals matchers) html escaping", function() { - expectationResult = jasmine.buildExpectationResult({ - matcherName: "toBeNull", passed: false, message: "Expected '1 < 2' to e null, & it was not" - }); - - spyOn(results, 'getItems').andReturn([expectationResult]); - - trivialReporter.reportSpecResults(spec); - - var divs = body.getElementsByTagName("div"); - var errorDiv = findElement(divs, 'resultMessage fail'); - expect(errorDiv.innerHTML).toEqual("Expected '1 < 2' to <b>e null, & it was not"); - }); - }); - - describe("log messages", function() { - it("should appear in the report", function() { - env.describe("suite", function() { - env.it("will have log messages", function() { - this.log("this is a", "multipart log message"); - }); - }); - - env.addReporter(trivialReporter); - env.execute(); - - var divs = body.getElementsByTagName("div"); - var errorDiv = findElement(divs, 'resultMessage log'); - expect(errorDiv.innerHTML).toEqual("this is a multipart log message"); - }); - - xit("should work on IE without console.log.apply", function() { - }); - }); - - describe("duplicate example names", function() { - it("should report failures correctly", function() { - var suite1 = env.describe("suite", function() { - env.it("will have log messages", function() { - this.log("this one fails!"); - this.expect(true).toBeFalsy(); - }); - }); - - var suite2 = env.describe("suite", function() { - env.it("will have log messages", function() { - this.log("this one passes!"); - this.expect(true).toBeTruthy(); - }); - }); - - env.addReporter(trivialReporter); - env.execute(); - - var divs = body.getElementsByTagName("div"); - var passedSpecDiv = findElement(divs, 'suite passed'); - expect(passedSpecDiv.className).toEqual('suite passed'); - expect(passedSpecDiv.innerHTML).toContain("this one passes!"); - expect(passedSpecDiv.innerHTML).not.toContain("this one fails!"); - - var failedSpecDiv = findElement(divs, 'suite failed'); - expect(failedSpecDiv.className).toEqual('suite failed'); - expect(failedSpecDiv.innerHTML).toContain("this one fails!"); - expect(failedSpecDiv.innerHTML).not.toContain("this one passes!"); - }); - }); - - describe('#reportSpecStarting', function() { - var spec1; - beforeEach(function () { - env.describe("suite 1", function() { - spec1 = env.it("spec 1", function() { - }); - }); - }); - - it('DOES NOT log running specs by default', function() { - spyOn(trivialReporter, 'log'); - - trivialReporter.reportSpecStarting(spec1); - - expect(trivialReporter.log).not.toHaveBeenCalled(); - }); - - it('logs running specs when log_running_specs is true', function() { - trivialReporter.logRunningSpecs = true; - spyOn(trivialReporter, 'log'); - - trivialReporter.reportSpecStarting(spec1); - - expect(trivialReporter.log).toHaveBeenCalledWith('>> Jasmine Running suite 1 spec 1...'); - }); - }); -}); diff --git a/spec/runner.html b/spec/runner.html index f9862c60..94273fb7 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -21,7 +21,6 @@ - @@ -48,7 +47,6 @@ - - + + + + - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + - - var htmlReporter = new jasmine.HtmlReporter(); - - jasmineEnv.addReporter(htmlReporter); - - jasmineEnv.specFilter = function(spec) { - return htmlReporter.specFilter(spec); - }; - - var currentWindowOnload = window.onload; - - window.onload = function() { - if (currentWindowOnload) { - currentWindowOnload(); - } - execJasmine(); - }; - - function execJasmine() { - jasmineEnv.execute(); - } - - })(); - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec/templates/runner.html.erb b/spec/templates/runner.html.erb index a4aceedd..01354438 100644 --- a/spec/templates/runner.html.erb +++ b/spec/templates/runner.html.erb @@ -14,6 +14,7 @@ <%= spec_file_tags %> - + + diff --git a/src/core/Clock.js b/src/core/Clock.js new file mode 100644 index 00000000..47608b89 --- /dev/null +++ b/src/core/Clock.js @@ -0,0 +1,93 @@ +jasmine.Clock = function(global, delayedFunctionScheduler) { + var self = this, + realTimingFunctions = { + setTimeout: global.setTimeout, + clearTimeout: global.clearTimeout, + setInterval: global.setInterval, + clearInterval: global.clearInterval + }, + fakeTimingFunctions = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setInterval: setInterval, + clearInterval: clearInterval + }, + timer = realTimingFunctions, + installed = false; + + self.install = function() { + installed = true; + timer = fakeTimingFunctions; + }; + + self.uninstall = function() { + delayedFunctionScheduler.reset(); + installed = false; + timer = realTimingFunctions; + }; + + self.setTimeout = function(fn, delay, params) { + if (legacyIE()) { + if (arguments.length > 2) { + throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill"); + } + return timer.setTimeout(fn, delay); + } + return timer.setTimeout.apply(null, arguments); + }; + + self.setInterval = function(fn, delay, params) { + if (legacyIE()) { + if (arguments.length > 2) { + throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill"); + } + return timer.setInterval(fn, delay); + } + return timer.setInterval.apply(null, arguments); + }; + + self.clearTimeout = function(id) { + return timer.clearTimeout(id); + }; + + self.clearInterval = function(id) { + return timer.clearInterval(id); + }; + + self.tick = function(millis) { + if (installed) { + delayedFunctionScheduler.tick(millis) + } else { + throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); + } + }; + + return self; + + function legacyIE() { + //if these methods are polyfilled, apply will be present + //TODO: it may be difficult to load the polyfill before jasmine loads + //(env should be new-ed inside of onload) + return !(global.setTimeout || global.setInterval).apply; + } + + function setTimeout(fn, delay) { + return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments,2)); + } + + function clearTimeout(id) { + return delayedFunctionScheduler.removeFunctionWithId(id); + } + + function setInterval(fn, interval) { + return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true); + } + + function clearInterval(id) { + return delayedFunctionScheduler.removeFunctionWithId(id); + } + + function argSlice(argsObj, n) { + return Array.prototype.slice.call(argsObj, 2); + } +}; diff --git a/src/core/DelayedFunctionScheduler.js b/src/core/DelayedFunctionScheduler.js new file mode 100644 index 00000000..15cb3f37 --- /dev/null +++ b/src/core/DelayedFunctionScheduler.js @@ -0,0 +1,102 @@ +jasmine.DelayedFunctionScheduler = function() { + var self = this; + var scheduledFunctions = {}; + var currentTime = 0; + var delayedFnCount = 0; + + self.tick = function(millis) { + runFunctionsWithinRange(currentTime, currentTime + millis); + currentTime = currentTime + millis; + }; + + self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) { + timeoutKey = timeoutKey || ++delayedFnCount; + runAtMillis = runAtMillis || (currentTime + millis); + scheduledFunctions[timeoutKey] = { + runAtMillis: runAtMillis, + funcToCall: funcToCall, + recurring: recurring, + params: params, + timeoutKey: timeoutKey, + millis: millis + }; + return timeoutKey; + }; + + self.removeFunctionWithId = function(timeoutKey) { + delete scheduledFunctions[timeoutKey]; + }; + + self.reset = function() { + currentTime = 0; + scheduledFunctions = {}; + delayedFnCount = 0; + }; + + return self; + + + //finds/dupes functions within range and removes them. + function functionsWithinRange(startMillis, endMillis) { + var fnsToRun = []; + for (var timeoutKey in scheduledFunctions) { + var scheduledFunc = scheduledFunctions[timeoutKey]; + if (scheduledFunc && + scheduledFunc.runAtMillis >= startMillis && + scheduledFunc.runAtMillis <= endMillis) { + //remove fn -- we'll reschedule later if it is recurring. + self.removeFunctionWithId(timeoutKey); + if (!scheduledFunc.recurring) { + fnsToRun.push(scheduledFunc); // schedules each function only once + } else { + fnsToRun.push(buildNthInstanceOf(scheduledFunc, 0)); + var additionalTimesFnRunsInRange = + Math.floor((endMillis - scheduledFunc.runAtMillis) / scheduledFunc.millis); + for (var i = 0; i < additionalTimesFnRunsInRange; i++) { + fnsToRun.push(buildNthInstanceOf(scheduledFunc, i + 1)); + } + reschedule(buildNthInstanceOf(scheduledFunc, additionalTimesFnRunsInRange)); + } + } + } + + return fnsToRun; + } + + function buildNthInstanceOf(scheduledFunc, n) { + return { + runAtMillis: scheduledFunc.runAtMillis + (scheduledFunc.millis * n), + funcToCall: scheduledFunc.funcToCall, + params: scheduledFunc.params, + millis: scheduledFunc.millis, + recurring: scheduledFunc.recurring, + timeoutKey: scheduledFunc.timeoutKey + }; + } + + function reschedule(scheduledFn) { + self.scheduleFunction(scheduledFn.funcToCall, + scheduledFn.millis, + scheduledFn.params, + true, + scheduledFn.timeoutKey, + scheduledFn.runAtMillis + scheduledFn.millis); + } + + + function runFunctionsWithinRange(startMillis, endMillis) { + var funcsToRun = functionsWithinRange(startMillis, endMillis); + if (funcsToRun.length === 0) { + return; + } + + funcsToRun.sort(function(a, b) { + return a.runAtMillis - b.runAtMillis; + }); + + for (var i = 0; i < funcsToRun.length; ++i) { + var funcToRun = funcsToRun[i]; + funcToRun.funcToCall.apply(null, funcToRun.params); + } + } +}; diff --git a/src/core/Env.js b/src/core/Env.js index 52cbf446..15eef30f 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -4,12 +4,17 @@ * @constructor */ (function() { - jasmine.Env = function() { + jasmine.Env = function(options) { + options = options || {}; var self = this; + var global = options.global || jasmine.getGlobal(); + + this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler()); + var suiteConstructor = jasmine.Suite; var isSuite = function(thing) { return thing instanceof suiteConstructor; - } + }; this.jasmine = jasmine; this.currentRunner_ = new jasmine.Runner(this, isSuite); this.spies_ = []; @@ -95,8 +100,7 @@ afterFns: afterFns(suite), expectationFactory: expectationFactory, exceptionFormatter: exceptionFormatter, - //TODO: move spec creation to more appropriate level and remove this shim - resultCallback: function(result) { self.currentSpec = null; suite.specComplete(result); }, + resultCallback: specResultCallback, fullNameFactory: function(spec) { return fullNameFactory(spec, suite) }, startCallback: startCallback, description: description, @@ -110,8 +114,13 @@ } return spec; - }; + function specResultCallback(result) { + self.clock.uninstall(); + self.currentSpec = null; + suite.specComplete(result); + } + }; var queueConstructor = jasmine.Queue; var queueFactory = function() { @@ -123,12 +132,6 @@ }; - - jasmine.Env.prototype.setTimeout = jasmine.setTimeout; - jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; - jasmine.Env.prototype.setInterval = jasmine.setInterval; - jasmine.Env.prototype.clearInterval = jasmine.clearInterval; - //TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc. jasmine.Env.prototype.addMatchers = function(matchersPrototype) { var parent = this.matchersClass; diff --git a/src/core/base.js b/src/core/base.js index 8e411879..255288f1 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -108,8 +108,8 @@ jasmine.MessageResult.prototype.toString = function() { /** * Getter for the Jasmine environment. Ensures one gets created */ -jasmine.getEnv = function() { - var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); +jasmine.getEnv = function(options) { + var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(options); //jasmine. singletons in here (setTimeout blah blah). return env; }; diff --git a/src/core/mock-timeout.js b/src/core/mock-timeout.js deleted file mode 100644 index bd1251aa..00000000 --- a/src/core/mock-timeout.js +++ /dev/null @@ -1,184 +0,0 @@ -// Mock setTimeout, clearTimeout -// Contributed by Pivotal Computer Systems, www.pivotalsf.com - -jasmine.FakeTimer = function() { - this.reset(); - - var self = this; - self.setTimeout = function(funcToCall, millis) { - self.timeoutsMade++; - self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); - return self.timeoutsMade; - }; - - self.setInterval = function(funcToCall, millis) { - self.timeoutsMade++; - self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); - return self.timeoutsMade; - }; - - self.clearTimeout = function(timeoutKey) { - self.scheduledFunctions[timeoutKey] = jasmine.undefined; - }; - - self.clearInterval = function(timeoutKey) { - self.scheduledFunctions[timeoutKey] = jasmine.undefined; - }; - -}; - -jasmine.FakeTimer.prototype.reset = function() { - this.timeoutsMade = 0; - this.scheduledFunctions = {}; - this.nowMillis = 0; -}; - -jasmine.FakeTimer.prototype.tick = function(millis) { - var oldMillis = this.nowMillis; - var newMillis = oldMillis + millis; - this.runFunctionsWithinRange(oldMillis, newMillis); - this.nowMillis = newMillis; -}; - -jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { - var scheduledFunc; - var funcsToRun = []; - for (var timeoutKey in this.scheduledFunctions) { - scheduledFunc = this.scheduledFunctions[timeoutKey]; - if (scheduledFunc != jasmine.undefined && - scheduledFunc.runAtMillis >= oldMillis && - scheduledFunc.runAtMillis <= nowMillis) { - funcsToRun.push(scheduledFunc); - this.scheduledFunctions[timeoutKey] = jasmine.undefined; - } - } - - if (funcsToRun.length > 0) { - funcsToRun.sort(function(a, b) { - return a.runAtMillis - b.runAtMillis; - }); - for (var i = 0; i < funcsToRun.length; ++i) { - try { - var funcToRun = funcsToRun[i]; - this.nowMillis = funcToRun.runAtMillis; - funcToRun.funcToCall(); - if (funcToRun.recurring) { - this.scheduleFunction(funcToRun.timeoutKey, - funcToRun.funcToCall, - funcToRun.millis, - true); - } - } catch(e) { - } - } - this.runFunctionsWithinRange(oldMillis, nowMillis); - } -}; - -jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { - this.scheduledFunctions[timeoutKey] = { - runAtMillis: this.nowMillis + millis, - funcToCall: funcToCall, - recurring: recurring, - timeoutKey: timeoutKey, - millis: millis - }; -}; - -/** - * @namespace - */ -jasmine.Clock = { - defaultFakeTimer: new jasmine.FakeTimer(), - - reset: function() { - jasmine.Clock.assertInstalled(); - jasmine.Clock.defaultFakeTimer.reset(); - }, - - tick: function(millis) { - jasmine.Clock.assertInstalled(); - jasmine.Clock.defaultFakeTimer.tick(millis); - }, - - runFunctionsWithinRange: function(oldMillis, nowMillis) { - jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); - }, - - scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { - jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); - }, - - useMock: function() { - if (!jasmine.Clock.isInstalled()) { - //TODO: this is using an interface that doesn't exist. - var spec = jasmine.getEnv().currentSpec; - spec.after(jasmine.Clock.uninstallMock); - - jasmine.Clock.installMock(); - } - }, - - installMock: function() { - jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; - }, - - uninstallMock: function() { - jasmine.Clock.assertInstalled(); - jasmine.Clock.installed = jasmine.Clock.real; - }, - - real: { - setTimeout: jasmine.getGlobal().setTimeout, - clearTimeout: jasmine.getGlobal().clearTimeout, - setInterval: jasmine.getGlobal().setInterval, - clearInterval: jasmine.getGlobal().clearInterval - }, - - assertInstalled: function() { - if (!jasmine.Clock.isInstalled()) { - throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); - } - }, - - isInstalled: function() { - return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; - }, - - installed: null -}; -jasmine.Clock.installed = jasmine.Clock.real; - -//else for IE support -jasmine.getGlobal().setTimeout = function(funcToCall, millis) { - if (jasmine.Clock.installed.setTimeout.apply) { - return jasmine.Clock.installed.setTimeout.apply(this, arguments); - } else { - return jasmine.Clock.installed.setTimeout(funcToCall, millis); - } -}; - -jasmine.getGlobal().setInterval = function(funcToCall, millis) { - if (jasmine.Clock.installed.setInterval.apply) { - return jasmine.Clock.installed.setInterval.apply(this, arguments); - } else { - return jasmine.Clock.installed.setInterval(funcToCall, millis); - } -}; - -jasmine.getGlobal().clearTimeout = function(timeoutKey) { - if (jasmine.Clock.installed.clearTimeout.apply) { - return jasmine.Clock.installed.clearTimeout.apply(this, arguments); - } else { - return jasmine.Clock.installed.clearTimeout(timeoutKey); - } -}; - -jasmine.getGlobal().clearInterval = function(timeoutKey) { - if (jasmine.Clock.installed.clearTimeout.apply) { - return jasmine.Clock.installed.clearInterval.apply(this, arguments); - } else { - return jasmine.Clock.installed.clearInterval(timeoutKey); - } -}; - diff --git a/tasks/jasmine_dev/sources.rb b/tasks/jasmine_dev/sources.rb index 06b65c10..dfd3e611 100644 --- a/tasks/jasmine_dev/sources.rb +++ b/tasks/jasmine_dev/sources.rb @@ -8,7 +8,6 @@ class JasmineDev < Thor "Reporter.js", "JsApiReporter.js", "Matchers.js", - "mock-timeout.js", "MultiReporter.js", "NestedResults.js", "PrettyPrinter.js", @@ -16,6 +15,8 @@ class JasmineDev < Thor "Runner.js", "Spec.js", "Suite.js", + "Clock.js", + "DelayedFunctionScheduler.js" ], :html => [ From c584f182ab47af427c60030cb63ea0ac1db19964 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Fri, 7 Dec 2012 11:11:09 -0800 Subject: [PATCH 41/55] Fix getFullName on spec. - Fixes specFiltering on nested specs --- lib/jasmine-core/jasmine.js | 17 +++++------------ spec/core/ClockSpec.js | 2 -- spec/core/EnvSpec.js | 26 +++++++++++++++++++++++++- spec/core/SpecSpec.js | 4 +--- src/core/Env.js | 12 +++--------- src/core/Spec.js | 5 ++--- 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index dae085c3..87401787 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -593,14 +593,8 @@ jasmine.buildExpectationResult = function(params) { var specConstructor = jasmine.Spec; - // TODO: this deserves a better name (not a Factory the way others are) - var fullNameFactory = function(spec, currentSuite) { - var descriptions = []; - for (var suite = currentSuite; suite; suite = suite.parentSuite) { - descriptions.push(suite.description) - } - descriptions.push(spec.description); - return descriptions.join(' ') + '.'; + var getSpecName = function(spec, currentSuite) { + return currentSuite.getFullName() + ' ' + spec.description + '.'; }; var buildExpectationResult = jasmine.buildExpectationResult; @@ -616,7 +610,7 @@ jasmine.buildExpectationResult = function(params) { expectationFactory: expectationFactory, exceptionFormatter: exceptionFormatter, resultCallback: specResultCallback, - fullNameFactory: function(spec) { return fullNameFactory(spec, suite) }, + getSpecName: function(spec) { return getSpecName(spec, suite) }, startCallback: startCallback, description: description, catchExceptions: self.catchExceptions, @@ -1933,7 +1927,7 @@ jasmine.Spec = function(attrs) { this.catchExceptions = attrs.catchExceptions; this.startCallback = attrs.startCallback || function() {}; this.exceptionFormatter = attrs.exceptionFormatter || function() {}; - this.fullNameFactory = attrs.fullNameFactory; + this.getSpecName = attrs.getSpecName; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; }; @@ -2013,9 +2007,8 @@ jasmine.Spec.prototype.status = function() { } }; -//TODO: remove jasmine.Spec.prototype.getFullName = function() { - return this.fullNameFactory(this); + return this.getSpecName(this); } /** * Internal representation of a Jasmine suite. diff --git a/spec/core/ClockSpec.js b/spec/core/ClockSpec.js index f5135c31..84cbf0a3 100644 --- a/spec/core/ClockSpec.js +++ b/spec/core/ClockSpec.js @@ -1,7 +1,5 @@ describe("Clock", function() { -// TODO: fullName/SpecFilter is broken, so don't nest describes you want to filter - it("calls the global setTimeout directly if Clock is not installed", function() { var setTimeout = jasmine.createSpy('setTimeout'), delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['scheduleFunction']), diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 3190a6dd..32c734c6 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -158,7 +158,7 @@ describe("jasmine.Env", function() { }); }); -describe("jasmine Env", function() { +describe("jasmine Env (integration)", function() { it("Mock clock can be installed and used in tests", function() { var setTimeout = jasmine.createSpy('setTimeout'), @@ -186,4 +186,28 @@ describe("jasmine Env", function() { expect(setTimeout).toHaveBeenCalledWith(globalTimeoutFn, 100); }); + it("should be possible to get full name from a spec", function() { + var env = new jasmine.Env({global: { setTimeout: setTimeout }}), + topLevelSpec, nestedSpec, doublyNestedSpec; + + env.describe("my tests", function() { + topLevelSpec = env.it("are sometimes top level", function() { + }); + env.describe("are sometimes", function() { + nestedSpec = env.it("singly nested", function() { + + }); + env.describe("even", function() { + doublyNestedSpec = env.it("doubly nested", function() { + + }); + }); + }); + }); + + env.execute(); + expect(topLevelSpec.getFullName()).toBe("my tests are sometimes top level."); + expect(nestedSpec.getFullName()).toBe("my tests are sometimes singly nested."); + expect(doublyNestedSpec.getFullName()).toBe("my tests are sometimes even doubly nested."); + }); }); diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 07d6a639..0b5c6ab0 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -166,10 +166,8 @@ describe("Spec (real-ish unit tests)", function() { }); it("can return its full name", function() { - //TODO: not convinced that a spec should provide this as part of its public interface, but adding temporarily - //until we fix the reporting var spec = new jasmine.Spec({ - fullNameFactory: function(passedVal) { + getSpecName: function(passedVal) { expect(passedVal).toBe(spec); return 'expected val'; } diff --git a/src/core/Env.js b/src/core/Env.js index 15eef30f..955a3384 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -78,14 +78,8 @@ var specConstructor = jasmine.Spec; - // TODO: this deserves a better name (not a Factory the way others are) - var fullNameFactory = function(spec, currentSuite) { - var descriptions = []; - for (var suite = currentSuite; suite; suite = suite.parentSuite) { - descriptions.push(suite.description) - } - descriptions.push(spec.description); - return descriptions.join(' ') + '.'; + var getSpecName = function(spec, currentSuite) { + return currentSuite.getFullName() + ' ' + spec.description + '.'; }; var buildExpectationResult = jasmine.buildExpectationResult; @@ -101,7 +95,7 @@ expectationFactory: expectationFactory, exceptionFormatter: exceptionFormatter, resultCallback: specResultCallback, - fullNameFactory: function(spec) { return fullNameFactory(spec, suite) }, + getSpecName: function(spec) { return getSpecName(spec, suite) }, startCallback: startCallback, description: description, catchExceptions: self.catchExceptions, diff --git a/src/core/Spec.js b/src/core/Spec.js index cdbfd113..65817175 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -11,7 +11,7 @@ jasmine.Spec = function(attrs) { this.catchExceptions = attrs.catchExceptions; this.startCallback = attrs.startCallback || function() {}; this.exceptionFormatter = attrs.exceptionFormatter || function() {}; - this.fullNameFactory = attrs.fullNameFactory; + this.getSpecName = attrs.getSpecName; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; }; @@ -91,7 +91,6 @@ jasmine.Spec.prototype.status = function() { } }; -//TODO: remove jasmine.Spec.prototype.getFullName = function() { - return this.fullNameFactory(this); + return this.getSpecName(this); } From 234f2a1585d946e941ac9bd43d88273a657b1d16 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Fri, 7 Dec 2012 12:26:05 -0800 Subject: [PATCH 42/55] Reintroduce fn that clears stack occasionally - setTimeout will clear stack, prevent overflow. We run this once every thousand specs. - Browser users will probably want a time-based clear rather than spec count based clear, as a thousand tests is typically quite slow. The reporter should provide this. --- lib/jasmine-core/jasmine.js | 21 ++++++++++++++++++--- spec/node_suite.js | 1 + src/core/Env.js | 21 ++++++++++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 87401787..49a7dc06 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -524,6 +524,8 @@ jasmine.buildExpectationResult = function(params) { var self = this; var global = options.global || jasmine.getGlobal(); + var encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; + this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler()); var suiteConstructor = jasmine.Suite; @@ -539,8 +541,6 @@ jasmine.buildExpectationResult = function(params) { this.reporter = new jasmine.MultiReporter(); - this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; - this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; this.lastUpdate = 0; this.specFilter = function() { return true; @@ -627,8 +627,11 @@ jasmine.buildExpectationResult = function(params) { function specResultCallback(result) { self.clock.uninstall(); self.currentSpec = null; - suite.specComplete(result); + encourageGC(function() { + suite.specComplete(result); + }); } + }; var queueConstructor = jasmine.Queue; @@ -639,6 +642,18 @@ jasmine.buildExpectationResult = function(params) { return new suiteConstructor(self, description, specDefinitions, self.currentSuite, queueFactory, isSuite); }; + var maximumSpecCallbackDepth = 100; + var currentSpecCallbackDepth = 0; + function encourageGarbageCollection(fn) { + currentSpecCallbackDepth++; + if (currentSpecCallbackDepth > maximumSpecCallbackDepth) { + currentSpecCallbackDepth = 0; + global.setTimeout(fn, 0); + } else { + fn(); + } + + } }; //TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc. diff --git a/spec/node_suite.js b/spec/node_suite.js index 09f6337d..5ae018fe 100644 --- a/spec/node_suite.js +++ b/spec/node_suite.js @@ -159,6 +159,7 @@ process.argv.forEach(function(arg) { } }); +// var specs = jasmine.getAllSpecFiles(__dirname + '/smoke', new RegExp("test.js$")); var specs = jasmine.getAllSpecFiles(__dirname, new RegExp("Spec.js$")); var domIndependentSpecs = []; for (var i = 0; i < specs.length; i++) { diff --git a/src/core/Env.js b/src/core/Env.js index 955a3384..1b01a40f 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -9,6 +9,8 @@ var self = this; var global = options.global || jasmine.getGlobal(); + var encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; + this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler()); var suiteConstructor = jasmine.Suite; @@ -24,8 +26,6 @@ this.reporter = new jasmine.MultiReporter(); - this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; - this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; this.lastUpdate = 0; this.specFilter = function() { return true; @@ -112,8 +112,11 @@ function specResultCallback(result) { self.clock.uninstall(); self.currentSpec = null; - suite.specComplete(result); + encourageGC(function() { + suite.specComplete(result); + }); } + }; var queueConstructor = jasmine.Queue; @@ -124,6 +127,18 @@ return new suiteConstructor(self, description, specDefinitions, self.currentSuite, queueFactory, isSuite); }; + var maximumSpecCallbackDepth = 100; + var currentSpecCallbackDepth = 0; + function encourageGarbageCollection(fn) { + currentSpecCallbackDepth++; + if (currentSpecCallbackDepth > maximumSpecCallbackDepth) { + currentSpecCallbackDepth = 0; + global.setTimeout(fn, 0); + } else { + fn(); + } + + } }; //TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc. From c2e1327f39cbd691a64b4deb3d8525006b403e1e Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Fri, 7 Dec 2012 13:53:26 -0800 Subject: [PATCH 43/55] Permit HTMLReporter to render every 250ms - This is necessary for the user to see spec results fill-in progressively. - There is a slight performance loss. 250 - 500ms seems to deliver the same amount of loss. This is still at parity with Jasmine 1.x --- lib/jasmine-core/jasmine-html.js | 16 ++++++++++++++-- spec/html/HTMLReporterSpec.js | 3 ++- src/html/HtmlReporter.js | 16 ++++++++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 40d2811f..5c068e9d 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -62,7 +62,7 @@ jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { } }; -jasmine.HtmlReporter = function(_doc, jasmine) { +jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { var self = this; this.jasmine = jasmine || window.jasmine; var doc = _doc || window.document; @@ -99,8 +99,20 @@ jasmine.HtmlReporter = function(_doc, jasmine) { self.reportSpecStarting = function(spec) { }; + var lastYieldForRender = 0; + var refreshInterval = 250; + yieldForRender = yieldForRender || function(fn) { + var now = Date.now(); + var delta = (now - lastYieldForRender); + if (delta > refreshInterval) { + lastYieldForRender = now; + setTimeout(fn, 0); + } else { + fn(); + } + } self.reportSpecResults = function(result) { - reporterView.specComplete(result); + yieldForRender(function() {reporterView.specComplete(result) }); }; self.log = function() { diff --git a/spec/html/HTMLReporterSpec.js b/spec/html/HTMLReporterSpec.js index 69232388..65424bc9 100644 --- a/spec/html/HTMLReporterSpec.js +++ b/spec/html/HTMLReporterSpec.js @@ -8,9 +8,10 @@ describe("HtmlReporter", function() { env = new jasmine.Env(); env.updateInterval = 0; + body = document.createElement("body"); fakeDocument = { body: body, location: { search: "" } }; - htmlReporter = new jasmine.HtmlReporter(fakeDocument); + htmlReporter = new jasmine.HtmlReporter(fakeDocument, null, function(fn) { fn() }); }); function fakeSpec(name) { diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 09abcab5..7b31b500 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -1,4 +1,4 @@ -jasmine.HtmlReporter = function(_doc, jasmine) { +jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { var self = this; this.jasmine = jasmine || window.jasmine; var doc = _doc || window.document; @@ -35,8 +35,20 @@ jasmine.HtmlReporter = function(_doc, jasmine) { self.reportSpecStarting = function(spec) { }; + var lastYieldForRender = 0; + var refreshInterval = 250; + yieldForRender = yieldForRender || function(fn) { + var now = Date.now(); + var delta = (now - lastYieldForRender); + if (delta > refreshInterval) { + lastYieldForRender = now; + setTimeout(fn, 0); + } else { + fn(); + } + } self.reportSpecResults = function(result) { - reporterView.specComplete(result); + yieldForRender(function() {reporterView.specComplete(result) }); }; self.log = function() { From a526ebf26179afaad719e73de198c265031e5241 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Fri, 7 Dec 2012 16:30:32 -0800 Subject: [PATCH 44/55] Re-add async support (achieved via done callbacks) - TODO: pull out queueRunner into a new object. --- lib/jasmine-core/boot/boot.js | 8 +- lib/jasmine-core/jasmine.js | 71 +++++++----- spec/core/SpecSpec.js | 212 +++++++++++++++++++++------------- spec/node_suite.js | 5 + src/core/Spec.js | 71 +++++++----- 5 files changed, 226 insertions(+), 141 deletions(-) diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index e3f95062..550544be 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -38,9 +38,11 @@ return env.spyOn(obj, methodName); }, - clock: function() { - return env.clock; - }, + clock: env.clock, + setTimeout: env.clock.setTimeout, + clearTimeout: env.clock.clearTimeout, + setInterval: env.clock.setInterval, + clearInterval: env.clock.clearInterval, jsApiReporter: new jasmine.JsApiReporter(jasmine) }; diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 49a7dc06..c7ba5ed7 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1958,47 +1958,60 @@ jasmine.Spec.prototype.expect = function(actual) { }; jasmine.Spec.prototype.execute = function() { + var self = this; if (this.disabled) { - resultCallback.call(this); + resultCallback(); return; } var befores = this.beforeFns() || [], afters = this.afterFns() || []; this.startCallback(this); - try { - for (var i = 0; i < befores.length; i++) { - befores[i].call(this); - } - this.fn.call(this); - for (i = 0; i < afters.length; i++) { - afters[i].call(this); - } - } catch (e) { - //TODO: weird. buildExpectationResult is really a presenter for expectations - //so this should take an expectation object. - this.addExpectationResult(false, this.expectationResultFactory({ - matcherName: "", - passed: false, - expected: "", - actual: "", - message: this.exceptionFormatter(e), - trace: e - })); - if (!this.catchExceptions) { - throw e; + var allFns = befores.concat(this.fn).concat(afters); + + queueRunner(allFns, 0); + + function attempt(fn) { + try { + fn(); + } catch (e) { + //TODO: weird. buildExpectationResult is really a presenter for expectations + //so this should take an expectation object. + self.addExpectationResult(false, self.expectationResultFactory({ + matcherName: "", + passed: false, + expected: "", + actual: "", + message: self.exceptionFormatter(e), + trace: e + })); + if (!self.catchExceptions) { + resultCallback(); + throw e; + } } } - finally { - resultCallback.call(this); + + function queueRunner(allFns, index) { + if (index >= allFns.length) { + resultCallback(); + return; + } + var fn = allFns[index]; + if (fn.length > 0) { + attempt(function() { fn.call(self, function() { queueRunner(allFns, index + 1) }) }); + } else { + attempt(function() { fn.call(self); }); + queueRunner(allFns, index + 1); + } } function resultCallback() { - this.resultCallback({ - id: this.id, - status: this.status(), - description: this.description, - failedExpectations: this.failedExpectations + self.resultCallback({ + id: self.id, + status: self.status(), + description: self.description, + failedExpectations: self.failedExpectations }); } }; diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 0b5c6ab0..68ce2f87 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -1,23 +1,23 @@ -describe("Spec (integration)", function() { +describe("Spec", function() { it("reports results for passing tests", function() { - var resultCallback = jasmine.createSpy('resultCallback'), - expectationFactory = function(actual, spec) { - expect(actual).toBe('some-actual'); - return { - pass: function() { - spec.addExpectationResult(true); - } + var resultCallback = originalJasmine.createSpy('resultCallback'), + expectationFactory = function(actual, spec) { + expect(actual).toBe('some-actual'); + return { + pass: function() { + spec.addExpectationResult(true); } + } + }, + spec = new jasmine.Spec({ + description: 'my test', + id: 'some-id', + fn: function() { + this.expect('some-actual').pass(); }, - spec = new jasmine.Spec({ - description: 'my test', - id: 'some-id', - fn: function() { - this.expect('some-actual').pass(); - }, - resultCallback: resultCallback, - expectationFactory: expectationFactory - }); + resultCallback: resultCallback, + expectationFactory: expectationFactory + }); spec.execute(); @@ -29,24 +29,24 @@ describe("Spec (integration)", function() { }); }); it("reports results for failing tests", function() { - var resultCallback = jasmine.createSpy('resultCallback'), - expectationFactory = function(actual, spec) { - expect(actual).toBe('some-actual'); - return { - fail: function() { - spec.addExpectationResult(true); - } + var resultCallback = originalJasmine.createSpy('resultCallback'), + expectationFactory = function(actual, spec) { + expect(actual).toBe('some-actual'); + return { + fail: function() { + spec.addExpectationResult(true); } + } + }, + spec = new jasmine.Spec({ + description: 'my test', + id: 'some-id', + fn: function() { + this.expect('some-actual').fail(); }, - spec = new jasmine.Spec({ - description: 'my test', - id: 'some-id', - fn: function() { - this.expect('some-actual').fail(); - }, - resultCallback: resultCallback, - expectationFactory: expectationFactory - }); + resultCallback: resultCallback, + expectationFactory: expectationFactory + }); spec.execute(); @@ -58,14 +58,13 @@ describe("Spec (integration)", function() { }); }); - //TODO: test order of befores, spec, after. it("executes before fns, after fns", function() { - var before = jasmine.createSpy('before'), - after = jasmine.createSpy('after'), - fn = originalJasmine.createSpy('test body').andCallFake(function() { - expect(before).toHaveBeenCalled(); - expect(after).not.toHaveBeenCalled(); - }); + var before = originalJasmine.createSpy('before'), + after = originalJasmine.createSpy('after'), + fn = originalJasmine.createSpy('test body').andCallFake(function() { + expect(before).toHaveBeenCalled(); + expect(after).not.toHaveBeenCalled(); + }); spec = new jasmine.Spec({ fn: fn, beforeFns: function() { @@ -86,9 +85,61 @@ describe("Spec (integration)", function() { expect(after).toHaveBeenCalled(); expect(after.mostRecentCall.object).toBe(spec); }); -}); -describe("Spec (real-ish unit tests)", function() { + it("passes an optional callback to spec bodies, befores, and afters", function() { + //TODO: it would be nice if spy arity could match the fake, so we could do something like: + //createSpy('asyncfn').andCallFake(function(done) {}); + var resultCallback = originalJasmine.createSpy('resultCallback'), + beforeCallback = originalJasmine.createSpy('beforeCallback'), + fnCallback = originalJasmine.createSpy('fnCallback'), + afterCallback = originalJasmine.createSpy('afterCallback'), + before = function(done) { + beforeCallback(); + setTimeout(function() { done() }, 100); + }, + fn = function(done) { + fnCallback(); + setTimeout(function() { done() }, 100); + }, + after = function(done) { + afterCallback(); + setTimeout(function() { done() }, 100); + }, + spec = new jasmine.Spec({ + resultCallback: resultCallback, + fn: fn, + beforeFns: function() { + return [before] + }, + afterFns: function() { + return [after] + } + }); + clock.install(); + + spec.execute(); + + expect(beforeCallback).toHaveBeenCalled(); + expect(fnCallback).not.toHaveBeenCalled(); + expect(afterCallback).not.toHaveBeenCalled(); + expect(resultCallback).not.toHaveBeenCalled(); + + clock.tick(100); + + expect(fnCallback).toHaveBeenCalled(); + expect(afterCallback).not.toHaveBeenCalled(); + expect(resultCallback).not.toHaveBeenCalled(); + + clock.tick(100); + + expect(afterCallback).toHaveBeenCalled(); + expect(resultCallback).not.toHaveBeenCalled(); + + clock.tick(100); + + expect(resultCallback).toHaveBeenCalled(); + }); + it("status returns null by default", function() { var spec = new jasmine.Spec({}); expect(spec.status()).toBeNull(); @@ -110,13 +161,13 @@ describe("Spec (real-ish unit tests)", function() { it("calls the resultCallback with a failure when an exception occurs in the spec fn", function() { //TODO: one day we should pass a stack with this. var resultCallback = originalJasmine.createSpy('resultCallback'), - spec = new jasmine.Spec({ - fn: function() { - throw new Error(); - }, - catchExceptions: true, - resultCallback: resultCallback - }); + spec = new jasmine.Spec({ + fn: function() { + throw new Error(); + }, + catchExceptions: true, + resultCallback: resultCallback + }); expect(resultCallback).not.toHaveBeenCalled(); spec.execute(); @@ -129,13 +180,13 @@ describe("Spec (real-ish unit tests)", function() { it("throws when an exception occurs in the spec fn if catchExceptions is false", function() { //TODO: one day we should pass a stack with this. var resultCallback = originalJasmine.createSpy('resultCallback'), - spec = new jasmine.Spec({ - fn: function() { - throw new Error(); - }, - catchExceptions: false, - resultCallback: resultCallback - }); + spec = new jasmine.Spec({ + fn: function() { + throw new Error(); + }, + catchExceptions: false, + resultCallback: resultCallback + }); expect(function() { spec.execute(); @@ -144,22 +195,22 @@ describe("Spec (real-ish unit tests)", function() { it("should call the start callback before any befores are called", function() { var beforesWereCalled = false, - startCallback = originalJasmine.createSpy('start-callback').andCallFake(function() { - expect(beforesWereCalled).toBe(false); - }), - spec = new jasmine.Spec({ - fn: function() { - }, - beforeFns: function() { - return [function() { - beforesWereCalled = true - }] - }, - startCallback: startCallback, - catchExceptions: false, - resultCallback: function() { - } - }); + startCallback = originalJasmine.createSpy('start-callback').andCallFake(function() { + expect(beforesWereCalled).toBe(false); + }), + spec = new jasmine.Spec({ + fn: function() { + }, + beforeFns: function() { + return [function() { + beforesWereCalled = true + }] + }, + startCallback: startCallback, + catchExceptions: false, + resultCallback: function() { + } + }); spec.execute(); expect(startCallback).toHaveBeenCalled(); @@ -177,15 +228,15 @@ describe("Spec (real-ish unit tests)", function() { }); it("can be disabled", function() { - var startCallback = jasmine.createSpy('startCallback'), - specBody = jasmine.createSpy('specBody'), - resultCallback = jasmine.createSpy('resultCallback'), - spec = new jasmine.Spec({ - startCallback: startCallback, - fn: specBody, - resultCallback: resultCallback + var startCallback = originalJasmine.createSpy('startCallback'), + specBody = originalJasmine.createSpy('specBody'), + resultCallback = originalJasmine.createSpy('resultCallback'), + spec = new jasmine.Spec({ + startCallback: startCallback, + fn: specBody, + resultCallback: resultCallback - }); + }); spec.disable(); expect(spec.status()).toBe('disabled'); @@ -198,3 +249,4 @@ describe("Spec (real-ish unit tests)", function() { expect(resultCallback).toHaveBeenCalled(); }); }); + diff --git a/spec/node_suite.js b/spec/node_suite.js index 5ae018fe..17c66512 100644 --- a/spec/node_suite.js +++ b/spec/node_suite.js @@ -49,6 +49,11 @@ var jasmineInterface = { return env.spyOn(obj, methodName); }, + clock: env.clock, + setTimeout: env.clock.setTimeout, + clearTimeout: env.clock.clearTimeout, + setInterval: env.clock.setInterval, + clearInterval: env.clock.clearInterval, jsApiReporter: new jasmine.JsApiReporter(jasmine) }; diff --git a/src/core/Spec.js b/src/core/Spec.js index 65817175..b95158ca 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -27,47 +27,60 @@ jasmine.Spec.prototype.expect = function(actual) { }; jasmine.Spec.prototype.execute = function() { + var self = this; if (this.disabled) { - resultCallback.call(this); + resultCallback(); return; } var befores = this.beforeFns() || [], afters = this.afterFns() || []; this.startCallback(this); - try { - for (var i = 0; i < befores.length; i++) { - befores[i].call(this); - } - this.fn.call(this); - for (i = 0; i < afters.length; i++) { - afters[i].call(this); - } - } catch (e) { - //TODO: weird. buildExpectationResult is really a presenter for expectations - //so this should take an expectation object. - this.addExpectationResult(false, this.expectationResultFactory({ - matcherName: "", - passed: false, - expected: "", - actual: "", - message: this.exceptionFormatter(e), - trace: e - })); - if (!this.catchExceptions) { - throw e; + var allFns = befores.concat(this.fn).concat(afters); + + queueRunner(allFns, 0); + + function attempt(fn) { + try { + fn(); + } catch (e) { + //TODO: weird. buildExpectationResult is really a presenter for expectations + //so this should take an expectation object. + self.addExpectationResult(false, self.expectationResultFactory({ + matcherName: "", + passed: false, + expected: "", + actual: "", + message: self.exceptionFormatter(e), + trace: e + })); + if (!self.catchExceptions) { + resultCallback(); + throw e; + } } } - finally { - resultCallback.call(this); + + function queueRunner(allFns, index) { + if (index >= allFns.length) { + resultCallback(); + return; + } + var fn = allFns[index]; + if (fn.length > 0) { + attempt(function() { fn.call(self, function() { queueRunner(allFns, index + 1) }) }); + } else { + attempt(function() { fn.call(self); }); + queueRunner(allFns, index + 1); + } } function resultCallback() { - this.resultCallback({ - id: this.id, - status: this.status(), - description: this.description, - failedExpectations: this.failedExpectations + self.resultCallback({ + id: self.id, + status: self.status(), + description: self.description, + failedExpectations: self.failedExpectations }); } }; From 4318de464727adf747939256ac14f9aaae95b1a0 Mon Sep 17 00:00:00 2001 From: Rajan Agaskar Date: Fri, 7 Dec 2012 16:40:58 -0800 Subject: [PATCH 45/55] Remove obsolete bindOriginal, timing bindings. - Handled by boot now. --- lib/jasmine-core/jasmine.js | 25 ------------------------- src/core/base.js | 25 ------------------------- 2 files changed, 50 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index c7ba5ed7..590a5fc8 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -61,31 +61,6 @@ jasmine.getGlobal = function() { return getGlobal(); }; -/** - * Allows for bound functions to be compared. Internal use only. - * - * @ignore - * @private - * @param base {Object} bound 'this' for the function - * @param name {Function} function to find - */ -jasmine.bindOriginal_ = function(base, name) { - var original = base[name]; - if (original.apply) { - return function() { - return original.apply(base, arguments); - }; - } else { - // IE support - return jasmine.getGlobal()[name]; - } -}; - -jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); -jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); -jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); -jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); - jasmine.MessageResult = function(values) { this.type = 'log'; this.values = values; diff --git a/src/core/base.js b/src/core/base.js index 255288f1..0a08b81d 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -61,31 +61,6 @@ jasmine.getGlobal = function() { return getGlobal(); }; -/** - * Allows for bound functions to be compared. Internal use only. - * - * @ignore - * @private - * @param base {Object} bound 'this' for the function - * @param name {Function} function to find - */ -jasmine.bindOriginal_ = function(base, name) { - var original = base[name]; - if (original.apply) { - return function() { - return original.apply(base, arguments); - }; - } else { - // IE support - return jasmine.getGlobal()[name]; - } -}; - -jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); -jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); -jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); -jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); - jasmine.MessageResult = function(values) { this.type = 'log'; this.values = values; From 98c99c4ebba67c4a64182a737bbf67afbcf26efe Mon Sep 17 00:00:00 2001 From: Rajan Agaskar Date: Fri, 7 Dec 2012 16:43:27 -0800 Subject: [PATCH 46/55] Remove obsolete MessageResult - jasmine.log is no longer supported. --- lib/jasmine-core/jasmine.js | 27 --------------------------- spec/core/BaseSpec.js | 19 ------------------- src/core/NestedResults.js | 8 -------- src/core/base.js | 19 ------------------- 4 files changed, 73 deletions(-) delete mode 100644 spec/core/BaseSpec.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 590a5fc8..765e98d7 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -61,25 +61,6 @@ jasmine.getGlobal = function() { return getGlobal(); }; -jasmine.MessageResult = function(values) { - this.type = 'log'; - this.values = values; - this.trace = new Error(); // todo: test better -}; - -jasmine.MessageResult.prototype.toString = function() { - var text = ""; - for (var i = 0; i < this.values.length; i++) { - if (i > 0) text += " "; - if (jasmine.isString_(this.values[i])) { - text += this.values[i]; - } else { - text += jasmine.pp(this.values[i]); - } - } - return text; -}; - /** * Getter for the Jasmine environment. Ensures one gets created */ @@ -1541,14 +1522,6 @@ jasmine.NestedResults.prototype.rollupCounts = function(result) { this.failedCount += result.failedCount; }; -/** - * Adds a log message. - * @param values Array of message parts which will be concatenated later. - */ -jasmine.NestedResults.prototype.log = function(values) { - this.items_.push(new jasmine.MessageResult(values)); -}; - /** * Getter for the results: message & results. */ diff --git a/spec/core/BaseSpec.js b/spec/core/BaseSpec.js deleted file mode 100644 index f0477e8b..00000000 --- a/spec/core/BaseSpec.js +++ /dev/null @@ -1,19 +0,0 @@ -describe("base.js", function() { - describe("jasmine.MessageResult", function() { - it("#toString should pretty-print and concatenate each part of the message", function() { - var values = ["log", "message", 123, {key: "value"}, "FTW!"]; - var messageResult = new jasmine.MessageResult(values); - expect(messageResult.toString()).toEqual("log message 123 { key : 'value' } FTW!"); - }); - }); - - describe("jasmine.getGlobal", function() { - it("should return the global object", function() { - var globalObject = (function() { - return this; - })(); - - expect(jasmine.getGlobal()).toBe(globalObject); - }); - }); -}); diff --git a/src/core/NestedResults.js b/src/core/NestedResults.js index 61d34f58..1b0867f1 100644 --- a/src/core/NestedResults.js +++ b/src/core/NestedResults.js @@ -37,14 +37,6 @@ jasmine.NestedResults.prototype.rollupCounts = function(result) { this.failedCount += result.failedCount; }; -/** - * Adds a log message. - * @param values Array of message parts which will be concatenated later. - */ -jasmine.NestedResults.prototype.log = function(values) { - this.items_.push(new jasmine.MessageResult(values)); -}; - /** * Getter for the results: message & results. */ diff --git a/src/core/base.js b/src/core/base.js index 0a08b81d..4e2dc0dd 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -61,25 +61,6 @@ jasmine.getGlobal = function() { return getGlobal(); }; -jasmine.MessageResult = function(values) { - this.type = 'log'; - this.values = values; - this.trace = new Error(); // todo: test better -}; - -jasmine.MessageResult.prototype.toString = function() { - var text = ""; - for (var i = 0; i < this.values.length; i++) { - if (i > 0) text += " "; - if (jasmine.isString_(this.values[i])) { - text += this.values[i]; - } else { - text += jasmine.pp(this.values[i]); - } - } - return text; -}; - /** * Getter for the Jasmine environment. Ensures one gets created */ From 43552494ee9e6bedd78e3e16ff45883d1edba62c Mon Sep 17 00:00:00 2001 From: Rajan Agaskar Date: Fri, 7 Dec 2012 17:26:59 -0800 Subject: [PATCH 47/55] Remove jasmine.CATCH_EXCEPTIONS - HTMLReporters should be rewritten to make this sort of thing easier. - Fix HTMLReporter try/catch switch - We can't really call resultCallback & throw, so that's been reverted for now. --- lib/jasmine-core/boot/boot.js | 2 +- lib/jasmine-core/jasmine-html.js | 38 ++++++++++++++++++-------------- lib/jasmine-core/jasmine.js | 26 ++++++++++++---------- spec/core/ExceptionsSpec.js | 7 +----- spec/core/SpecSpec.js | 19 ---------------- spec/html/HTMLReporterSpec.js | 5 ++++- spec/runner.html | 1 - src/core/Env.js | 12 ++++++++-- src/core/Spec.js | 7 +++--- src/core/base.js | 7 ------ src/html/HtmlReporter.js | 14 +++++++----- src/html/HtmlReporterHelpers.js | 2 +- src/html/ReporterView.js | 10 ++++----- src/html/SpecView.js | 7 ++++-- src/html/SuiteView.js | 5 +++-- 15 files changed, 78 insertions(+), 84 deletions(-) diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index 550544be..b0846e29 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -53,7 +53,7 @@ jasmine.util.extend(window, jasmineInterface); } - var htmlReporter = new jasmine.HtmlReporter(null, jasmine); + var htmlReporter = new jasmine.HtmlReporter(null, jasmine, env); env.addReporter(jasmineInterface.jsApiReporter); env.addReporter(htmlReporter); diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 5c068e9d..020a4327 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -46,7 +46,7 @@ jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { if (parent) { if (typeof this.views.suites[parent.id] == 'undefined') { - this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine); + this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine, this.catchExceptions); } parentDiv = this.views.suites[parent.id].element; } @@ -62,11 +62,13 @@ jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { } }; -jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { +jasmine.HtmlReporter = function(_doc, jasmine, env, options) { + options = options || {}; var self = this; this.jasmine = jasmine || window.jasmine; var doc = _doc || window.document; + var reporterView; var dom = {}; @@ -84,7 +86,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { doc.body.appendChild(dom.reporter); setExceptionHandling(); - reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine); + reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine, env.catchingExceptions()); reporterView.addSpecs(specs, self.specFilter); }; @@ -101,7 +103,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { var lastYieldForRender = 0; var refreshInterval = 250; - yieldForRender = yieldForRender || function(fn) { + var yieldForRender = options.yieldForRender || function(fn) { var now = Date.now(); var delta = (now - lastYieldForRender); if (delta > refreshInterval) { @@ -180,7 +182,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { } function searchWithCatch() { - var params = jasmine.HtmlReporter.parameters(window.document); + var params = self.jasmine.HtmlReporter.parameters(window.document); var removed = false; var i = 0; @@ -191,7 +193,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { } i++; } - if (self.jasmine.CATCH_EXCEPTIONS) { + if (env.catchingExceptions()) { params.push("catch=false"); } @@ -203,7 +205,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { if (noTryCatch()) { chxCatch.setAttribute('checked', true); - self.jasmine.CATCH_EXCEPTIONS = false; + env.catchExceptions(false); } chxCatch.onclick = function() { window.location.search = searchWithCatch(); @@ -236,7 +238,7 @@ jasmine.HtmlReporter.sectionLink = function(sectionName, catchExceptions) { return link; }; jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter); -jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { +jasmine.HtmlReporter.ReporterView = function(dom, jasmine, catchExceptions) { this.startedAt = new Date(); this.runningSpecCount = 0; this.completeSpecCount = 0; @@ -270,7 +272,7 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { for (var i = 0; i < specs.length; i++) { var spec = specs[i]; - this.views.specs[spec.id] = new this.jasmine.HtmlReporter.SpecView(spec, dom, this.views, this.jasmine); + this.views.specs[spec.id] = new this.jasmine.HtmlReporter.SpecView(spec, dom, this.views, this.jasmine, catchExceptions); if (specFilter(spec)) { this.runningSpecCount++; } @@ -320,14 +322,14 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { // currently running UI if (isUndefined(this.runningAlert)) { - this.runningAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, this.jasmine.CATCH_EXCEPTIONS), className: "runningAlert bar" }); + this.runningAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "runningAlert bar" }); dom.alert.appendChild(this.runningAlert); } this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); // skipped specs UI if (isUndefined(this.skippedAlert)) { - this.skippedAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, this.jasmine.CATCH_EXCEPTIONS), className: "skippedAlert bar" }); + this.skippedAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "skippedAlert bar" }); } this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; @@ -338,7 +340,7 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { // passing specs UI if (isUndefined(this.passedAlert)) { - this.passedAlert = this.createDom('span', { href: this.jasmine.HtmlReporter.sectionLink(null, this.jasmine.CATCH_EXCEPTIONS), className: "passingAlert bar" }); + this.passedAlert = this.createDom('span', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "passingAlert bar" }); } this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); @@ -401,11 +403,12 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); -jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine) { +jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine, catchExceptions) { this.spec = spec; this.dom = dom; this.views = views; this.jasmine = jasmine || {}; + this.catchExceptions = catchExceptions; this.symbol = this.createDom('li', { className: 'pending' }); this.dom.symbolSummary.appendChild(this.symbol); @@ -413,7 +416,9 @@ jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine) { this.summary = this.createDom('div', { className: 'specSummary' }, this.createDom('a', { className: 'description', - href: this.jasmine.HtmlReporter.sectionLink(this.spec.getFullName(), this.jasmine.CATCH_EXCEPTIONS), + //TODO: sectionLink is a dependency passed in that knows about catchingExceptions + //so we don't pass catchExceptions everywhere. + href: this.jasmine.HtmlReporter.sectionLink(this.spec.getFullName(), catchExceptions), title: this.spec.getFullName() }, this.spec.description) ); @@ -480,14 +485,15 @@ jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { }; jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView); -jasmine.HtmlReporter.SuiteView = function(suite, dom, views, jasmine) { +jasmine.HtmlReporter.SuiteView = function(suite, dom, views, jasmine, catchExceptions) { this.suite = suite; this.dom = dom; this.views = views; this.jasmine = jasmine || {}; + this.catchExceptions = catchExceptions; this.element = this.createDom('div', { className: 'suite' }, - this.createDom('a', { className: 'description', href: this.jasmine.HtmlReporter.sectionLink(this.suite.getFullName(), this.jasmine.CATCH_EXCEPTIONS) }, this.suite.description) + this.createDom('a', { className: 'description', href: this.jasmine.HtmlReporter.sectionLink(this.suite.getFullName(), catchExceptions) }, this.suite.description) ); this.appendToSummary(this.suite, this.element); diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 765e98d7..b21010c0 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -46,13 +46,6 @@ jasmine.MAX_PRETTY_PRINT_DEPTH = 40; */ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; -/** - * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite. - * Set to false to let the exception bubble up in the browser. - * - */ -jasmine.CATCH_EXCEPTIONS = true; - jasmine.getGlobal = function() { function getGlobal() { return this; @@ -480,6 +473,7 @@ jasmine.buildExpectationResult = function(params) { var self = this; var global = options.global || jasmine.getGlobal(); + var catchExceptions = true; var encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler()); @@ -492,7 +486,6 @@ jasmine.buildExpectationResult = function(params) { this.currentRunner_ = new jasmine.Runner(this, isSuite); this.spies_ = []; this.currentSpec = null; - this.catchExceptions = jasmine.CATCH_EXCEPTIONS; this.undefined = jasmine.undefined; this.reporter = new jasmine.MultiReporter(); @@ -558,6 +551,14 @@ jasmine.buildExpectationResult = function(params) { return buildExpectationResult(attrs); }; + this.catchExceptions = function(value) { + return catchExceptions = !!value; + } + + this.catchingExceptions = function(value) { + return catchExceptions; + } + this.specFactory = function(description, fn, suite) { var spec = new specConstructor({ id: self.nextSpecId(), @@ -569,7 +570,7 @@ jasmine.buildExpectationResult = function(params) { getSpecName: function(spec) { return getSpecName(spec, suite) }, startCallback: startCallback, description: description, - catchExceptions: self.catchExceptions, + catchingExceptions: this.catchingExceptions, expectationResultFactory: expectationResultFactory, fn: fn }); @@ -1887,7 +1888,7 @@ jasmine.Spec = function(attrs) { this.fn = attrs.fn; this.beforeFns = attrs.beforeFns || function() {}; this.afterFns = attrs.afterFns || function() {}; - this.catchExceptions = attrs.catchExceptions; + this.catchingExceptions = attrs.catchingExceptions; this.startCallback = attrs.startCallback || function() {}; this.exceptionFormatter = attrs.exceptionFormatter || function() {}; this.getSpecName = attrs.getSpecName; @@ -1933,8 +1934,9 @@ jasmine.Spec.prototype.execute = function() { message: self.exceptionFormatter(e), trace: e })); - if (!self.catchExceptions) { - resultCallback(); + if (!self.catchingExceptions()) { + //TODO: set a var when we catch an exception and + //use a finally block to close the loop in a nice way.. throw e; } } diff --git a/spec/core/ExceptionsSpec.js b/spec/core/ExceptionsSpec.js index 61b58344..d7dda80a 100644 --- a/spec/core/ExceptionsSpec.js +++ b/spec/core/ExceptionsSpec.js @@ -34,9 +34,7 @@ describe('Exceptions:', function() { describe('with break on exception', function() { it('should not catch the exception', function() { - var oldCatch = jasmine.CATCH_EXCEPTIONS; - jasmine.CATCH_EXCEPTIONS = false; - env = new jasmine.Env(); + env.catchExceptions(false); var suite = env.describe('suite for break on exceptions', function() { env.it('should break when an exception is thrown', function() { throw new Error('I should hit a breakpoint!'); @@ -50,9 +48,6 @@ describe('Exceptions:', function() { dont_change = 'oops I changed'; } catch (e) {} - finally { - jasmine.CATCH_EXCEPTIONS = oldCatch; - } expect(dont_change).toEqual('I will never change!'); }); diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 68ce2f87..c58bab68 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -158,25 +158,6 @@ describe("Spec", function() { expect(spec.status()).toBe('failed'); }); - it("calls the resultCallback with a failure when an exception occurs in the spec fn", function() { - //TODO: one day we should pass a stack with this. - var resultCallback = originalJasmine.createSpy('resultCallback'), - spec = new jasmine.Spec({ - fn: function() { - throw new Error(); - }, - catchExceptions: true, - resultCallback: resultCallback - }); - - expect(resultCallback).not.toHaveBeenCalled(); - spec.execute(); - expect(resultCallback).toHaveBeenCalledWith( - originalJasmine.objectContaining({status: 'failed'}) - ); - - }); - it("throws when an exception occurs in the spec fn if catchExceptions is false", function() { //TODO: one day we should pass a stack with this. var resultCallback = originalJasmine.createSpy('resultCallback'), diff --git a/spec/html/HTMLReporterSpec.js b/spec/html/HTMLReporterSpec.js index 65424bc9..4d7346cb 100644 --- a/spec/html/HTMLReporterSpec.js +++ b/spec/html/HTMLReporterSpec.js @@ -11,7 +11,10 @@ describe("HtmlReporter", function() { body = document.createElement("body"); fakeDocument = { body: body, location: { search: "" } }; - htmlReporter = new jasmine.HtmlReporter(fakeDocument, null, function(fn) { fn() }); + htmlReporter = new jasmine.HtmlReporter(fakeDocument, null, { + catchingExceptions: function() { return true; }, + catchExceptions: function() { } + }, {yieldForRender: function(fn) { fn() }}); }); function fakeSpec(name) { diff --git a/spec/runner.html b/spec/runner.html index 5df02a83..add81ca8 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -27,7 +27,6 @@ - diff --git a/src/core/Env.js b/src/core/Env.js index 1b01a40f..3e3a05da 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -9,6 +9,7 @@ var self = this; var global = options.global || jasmine.getGlobal(); + var catchExceptions = true; var encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler()); @@ -21,7 +22,6 @@ this.currentRunner_ = new jasmine.Runner(this, isSuite); this.spies_ = []; this.currentSpec = null; - this.catchExceptions = jasmine.CATCH_EXCEPTIONS; this.undefined = jasmine.undefined; this.reporter = new jasmine.MultiReporter(); @@ -87,6 +87,14 @@ return buildExpectationResult(attrs); }; + this.catchExceptions = function(value) { + return catchExceptions = !!value; + } + + this.catchingExceptions = function(value) { + return catchExceptions; + } + this.specFactory = function(description, fn, suite) { var spec = new specConstructor({ id: self.nextSpecId(), @@ -98,7 +106,7 @@ getSpecName: function(spec) { return getSpecName(spec, suite) }, startCallback: startCallback, description: description, - catchExceptions: self.catchExceptions, + catchingExceptions: this.catchingExceptions, expectationResultFactory: expectationResultFactory, fn: fn }); diff --git a/src/core/Spec.js b/src/core/Spec.js index b95158ca..4a751302 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -8,7 +8,7 @@ jasmine.Spec = function(attrs) { this.fn = attrs.fn; this.beforeFns = attrs.beforeFns || function() {}; this.afterFns = attrs.afterFns || function() {}; - this.catchExceptions = attrs.catchExceptions; + this.catchingExceptions = attrs.catchingExceptions; this.startCallback = attrs.startCallback || function() {}; this.exceptionFormatter = attrs.exceptionFormatter || function() {}; this.getSpecName = attrs.getSpecName; @@ -54,8 +54,9 @@ jasmine.Spec.prototype.execute = function() { message: self.exceptionFormatter(e), trace: e })); - if (!self.catchExceptions) { - resultCallback(); + if (!self.catchingExceptions()) { + //TODO: set a var when we catch an exception and + //use a finally block to close the loop in a nice way.. throw e; } } diff --git a/src/core/base.js b/src/core/base.js index 4e2dc0dd..c8d631fe 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -46,13 +46,6 @@ jasmine.MAX_PRETTY_PRINT_DEPTH = 40; */ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; -/** - * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite. - * Set to false to let the exception bubble up in the browser. - * - */ -jasmine.CATCH_EXCEPTIONS = true; - jasmine.getGlobal = function() { function getGlobal() { return this; diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 7b31b500..067b3f68 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -1,8 +1,10 @@ -jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { +jasmine.HtmlReporter = function(_doc, jasmine, env, options) { + options = options || {}; var self = this; this.jasmine = jasmine || window.jasmine; var doc = _doc || window.document; + var reporterView; var dom = {}; @@ -20,7 +22,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { doc.body.appendChild(dom.reporter); setExceptionHandling(); - reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine); + reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine, env.catchingExceptions()); reporterView.addSpecs(specs, self.specFilter); }; @@ -37,7 +39,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { var lastYieldForRender = 0; var refreshInterval = 250; - yieldForRender = yieldForRender || function(fn) { + var yieldForRender = options.yieldForRender || function(fn) { var now = Date.now(); var delta = (now - lastYieldForRender); if (delta > refreshInterval) { @@ -116,7 +118,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { } function searchWithCatch() { - var params = jasmine.HtmlReporter.parameters(window.document); + var params = self.jasmine.HtmlReporter.parameters(window.document); var removed = false; var i = 0; @@ -127,7 +129,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { } i++; } - if (self.jasmine.CATCH_EXCEPTIONS) { + if (env.catchingExceptions()) { params.push("catch=false"); } @@ -139,7 +141,7 @@ jasmine.HtmlReporter = function(_doc, jasmine, yieldForRender) { if (noTryCatch()) { chxCatch.setAttribute('checked', true); - self.jasmine.CATCH_EXCEPTIONS = false; + env.catchExceptions(false); } chxCatch.onclick = function() { window.location.search = searchWithCatch(); diff --git a/src/html/HtmlReporterHelpers.js b/src/html/HtmlReporterHelpers.js index 92f64e69..ce33af0f 100644 --- a/src/html/HtmlReporterHelpers.js +++ b/src/html/HtmlReporterHelpers.js @@ -46,7 +46,7 @@ jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { if (parent) { if (typeof this.views.suites[parent.id] == 'undefined') { - this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine); + this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine, this.catchExceptions); } parentDiv = this.views.suites[parent.id].element; } diff --git a/src/html/ReporterView.js b/src/html/ReporterView.js index 9aae1e23..9263b71c 100644 --- a/src/html/ReporterView.js +++ b/src/html/ReporterView.js @@ -1,4 +1,4 @@ -jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { +jasmine.HtmlReporter.ReporterView = function(dom, jasmine, catchExceptions) { this.startedAt = new Date(); this.runningSpecCount = 0; this.completeSpecCount = 0; @@ -32,7 +32,7 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { for (var i = 0; i < specs.length; i++) { var spec = specs[i]; - this.views.specs[spec.id] = new this.jasmine.HtmlReporter.SpecView(spec, dom, this.views, this.jasmine); + this.views.specs[spec.id] = new this.jasmine.HtmlReporter.SpecView(spec, dom, this.views, this.jasmine, catchExceptions); if (specFilter(spec)) { this.runningSpecCount++; } @@ -82,14 +82,14 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { // currently running UI if (isUndefined(this.runningAlert)) { - this.runningAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, this.jasmine.CATCH_EXCEPTIONS), className: "runningAlert bar" }); + this.runningAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "runningAlert bar" }); dom.alert.appendChild(this.runningAlert); } this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); // skipped specs UI if (isUndefined(this.skippedAlert)) { - this.skippedAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, this.jasmine.CATCH_EXCEPTIONS), className: "skippedAlert bar" }); + this.skippedAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "skippedAlert bar" }); } this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; @@ -100,7 +100,7 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine) { // passing specs UI if (isUndefined(this.passedAlert)) { - this.passedAlert = this.createDom('span', { href: this.jasmine.HtmlReporter.sectionLink(null, this.jasmine.CATCH_EXCEPTIONS), className: "passingAlert bar" }); + this.passedAlert = this.createDom('span', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "passingAlert bar" }); } this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); diff --git a/src/html/SpecView.js b/src/html/SpecView.js index 9d8741d2..d2c6fdfe 100644 --- a/src/html/SpecView.js +++ b/src/html/SpecView.js @@ -1,8 +1,9 @@ -jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine) { +jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine, catchExceptions) { this.spec = spec; this.dom = dom; this.views = views; this.jasmine = jasmine || {}; + this.catchExceptions = catchExceptions; this.symbol = this.createDom('li', { className: 'pending' }); this.dom.symbolSummary.appendChild(this.symbol); @@ -10,7 +11,9 @@ jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine) { this.summary = this.createDom('div', { className: 'specSummary' }, this.createDom('a', { className: 'description', - href: this.jasmine.HtmlReporter.sectionLink(this.spec.getFullName(), this.jasmine.CATCH_EXCEPTIONS), + //TODO: sectionLink is a dependency passed in that knows about catchingExceptions + //so we don't pass catchExceptions everywhere. + href: this.jasmine.HtmlReporter.sectionLink(this.spec.getFullName(), catchExceptions), title: this.spec.getFullName() }, this.spec.description) ); diff --git a/src/html/SuiteView.js b/src/html/SuiteView.js index df282bed..ffc31fca 100644 --- a/src/html/SuiteView.js +++ b/src/html/SuiteView.js @@ -1,11 +1,12 @@ -jasmine.HtmlReporter.SuiteView = function(suite, dom, views, jasmine) { +jasmine.HtmlReporter.SuiteView = function(suite, dom, views, jasmine, catchExceptions) { this.suite = suite; this.dom = dom; this.views = views; this.jasmine = jasmine || {}; + this.catchExceptions = catchExceptions; this.element = this.createDom('div', { className: 'suite' }, - this.createDom('a', { className: 'description', href: this.jasmine.HtmlReporter.sectionLink(this.suite.getFullName(), this.jasmine.CATCH_EXCEPTIONS) }, this.suite.description) + this.createDom('a', { className: 'description', href: this.jasmine.HtmlReporter.sectionLink(this.suite.getFullName(), catchExceptions) }, this.suite.description) ); this.appendToSummary(this.suite, this.element); From be6b87a31bc2b4ca9df367097aeb9c17f5451db1 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Fri, 7 Dec 2012 17:37:20 -0800 Subject: [PATCH 48/55] Remove obsolete NestedResults --- lib/jasmine-core/jasmine.js | 73 ---------------------------------- spec/core/NestedResultsSpec.js | 54 ------------------------- spec/runner.html | 1 - src/core/NestedResults.js | 73 ---------------------------------- tasks/jasmine_dev/sources.rb | 1 - 5 files changed, 202 deletions(-) delete mode 100644 spec/core/NestedResultsSpec.js delete mode 100644 src/core/NestedResults.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b21010c0..441b3152 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1484,79 +1484,6 @@ jasmine.MultiReporter.prototype.addReporter = function(reporter) { })(functionName); } })(); -/** - * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults - * - * @constructor - */ -jasmine.NestedResults = function() { - /** - * The total count of results - */ - this.totalCount = 0; - /** - * Number of passed results - */ - this.passedCount = 0; - /** - * Number of failed results - */ - this.failedCount = 0; - /** - * Was this suite/spec skipped? - */ - this.skipped = false; - /** - * @ignore - */ - this.items_ = []; -}; - -/** - * Roll up the result counts. - * - * @param result - */ -jasmine.NestedResults.prototype.rollupCounts = function(result) { - this.totalCount += result.totalCount; - this.passedCount += result.passedCount; - this.failedCount += result.failedCount; -}; - -/** - * Getter for the results: message & results. - */ -jasmine.NestedResults.prototype.getItems = function() { - return this.items_; -}; - -/** - * Adds a result, tracking counts (total, passed, & failed) - * @param {jasmine.ExpectationResult|jasmine.NestedResults} result - */ -//TODO: Results are meant for consumption by reporters, not internally. -jasmine.NestedResults.prototype.addResult = function(result) { - if (result.type != 'log') { - if (result.items_) { - this.rollupCounts(result); - } else { - this.totalCount++; - if (result.passed) { - this.passedCount++; - } else { - this.failedCount++; - } - } - } - this.items_.push(result); -}; - -/** - * @returns {Boolean} True if everything below passed - */ -jasmine.NestedResults.prototype.passed = function() { - return this.passedCount === this.totalCount; -}; /** * Base class for pretty printing for expectation results. */ diff --git a/spec/core/NestedResultsSpec.js b/spec/core/NestedResultsSpec.js deleted file mode 100644 index fc1e5607..00000000 --- a/spec/core/NestedResultsSpec.js +++ /dev/null @@ -1,54 +0,0 @@ -describe('jasmine.NestedResults', function() { - it('#addResult increments counters', function() { - // Leaf case - var results = new jasmine.NestedResults(); - - results.addResult(jasmine.buildExpectationResult({ - matcherName: "foo", passed: true, message: 'Passed.', actual: 'bar', expected: 'bar'} - )); - - expect(results.getItems().length).toEqual(1); - expect(results.totalCount).toEqual(1); - expect(results.passedCount).toEqual(1); - expect(results.failedCount).toEqual(0); - - results.addResult(jasmine.buildExpectationResult({ - matcherName: "baz", passed: false, message: 'FAIL.', actual: "corge", expected: "quux" - })); - - expect(results.getItems().length).toEqual(2); - expect(results.totalCount).toEqual(2); - expect(results.passedCount).toEqual(1); - expect(results.failedCount).toEqual(1); - }); - - it('should roll up counts for nested results', function() { - // Branch case - var leafResultsOne = new jasmine.NestedResults(); - leafResultsOne.addResult(jasmine.buildExpectationResult({ - matcherName: "toSomething", passed: true, message: 'message', actual: '', expected:'' - })); - - leafResultsOne.addResult(jasmine.buildExpectationResult({ - matcherName: "toSomethingElse", passed: false, message: 'message', actual: 'a', expected: 'b' - })); - - var leafResultsTwo = new jasmine.NestedResults(); - leafResultsTwo.addResult(jasmine.buildExpectationResult({ - matcherName: "toSomething", passed: true, message: 'message', actual: '', expected: '' - })); - leafResultsTwo.addResult(jasmine.buildExpectationResult({ - matcherName: "toSomethineElse", passed: false, message: 'message', actual: 'c', expected: 'd' - })); - - var branchResults = new jasmine.NestedResults(); - branchResults.addResult(leafResultsOne); - branchResults.addResult(leafResultsTwo); - - expect(branchResults.getItems().length).toEqual(2); - expect(branchResults.totalCount).toEqual(4); - expect(branchResults.passedCount).toEqual(2); - expect(branchResults.failedCount).toEqual(2); - }); - -}); diff --git a/spec/runner.html b/spec/runner.html index add81ca8..b462dac5 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -36,7 +36,6 @@ - diff --git a/src/core/NestedResults.js b/src/core/NestedResults.js deleted file mode 100644 index 1b0867f1..00000000 --- a/src/core/NestedResults.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults - * - * @constructor - */ -jasmine.NestedResults = function() { - /** - * The total count of results - */ - this.totalCount = 0; - /** - * Number of passed results - */ - this.passedCount = 0; - /** - * Number of failed results - */ - this.failedCount = 0; - /** - * Was this suite/spec skipped? - */ - this.skipped = false; - /** - * @ignore - */ - this.items_ = []; -}; - -/** - * Roll up the result counts. - * - * @param result - */ -jasmine.NestedResults.prototype.rollupCounts = function(result) { - this.totalCount += result.totalCount; - this.passedCount += result.passedCount; - this.failedCount += result.failedCount; -}; - -/** - * Getter for the results: message & results. - */ -jasmine.NestedResults.prototype.getItems = function() { - return this.items_; -}; - -/** - * Adds a result, tracking counts (total, passed, & failed) - * @param {jasmine.ExpectationResult|jasmine.NestedResults} result - */ -//TODO: Results are meant for consumption by reporters, not internally. -jasmine.NestedResults.prototype.addResult = function(result) { - if (result.type != 'log') { - if (result.items_) { - this.rollupCounts(result); - } else { - this.totalCount++; - if (result.passed) { - this.passedCount++; - } else { - this.failedCount++; - } - } - } - this.items_.push(result); -}; - -/** - * @returns {Boolean} True if everything below passed - */ -jasmine.NestedResults.prototype.passed = function() { - return this.passedCount === this.totalCount; -}; diff --git a/tasks/jasmine_dev/sources.rb b/tasks/jasmine_dev/sources.rb index dfd3e611..caf0cb1a 100644 --- a/tasks/jasmine_dev/sources.rb +++ b/tasks/jasmine_dev/sources.rb @@ -9,7 +9,6 @@ class JasmineDev < Thor "JsApiReporter.js", "Matchers.js", "MultiReporter.js", - "NestedResults.js", "PrettyPrinter.js", "Queue.js", "Runner.js", From 4ad43267ab2e3035c981061ebbb3133760ae96d1 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank & Rajan Agaskar" Date: Fri, 7 Dec 2012 17:51:17 -0800 Subject: [PATCH 49/55] Update immediate goals. - This commit should get rebased out before merging to master --- GOALS_2.0.md | 18 ++++++++++++++++++ src/html/ReporterView.js | 1 + 2 files changed, 19 insertions(+) diff --git a/GOALS_2.0.md b/GOALS_2.0.md index 98fa6193..cf8d97d7 100644 --- a/GOALS_2.0.md +++ b/GOALS_2.0.md @@ -7,4 +7,22 @@ * Properties aren't encapsulated -- can be mutated, unsafe. 1. Reporters get data objects (no methods). * easier to refactor as needed +1. More unit tests - fewer nasty integration tests +## Remaining non-story-able work: +* Make a `TODO` list + +### Hard +* Finish killing Globals + * Guidlines: everything that isn't a CTOR should be closed inside `Env`, and everything that is a CTOR needs to be `new`ed inside the `Env` + * Spies + * jasmine.util should be util closure inside of env or something +* Suites need to be unit-tested +* Remove Queue from Suite in favor of queuerunner refactoring +* Remover Runner in favor of a top-level Suite + * This means Env needs to `new` a `Suite` first thing +* get feature parity back on HTMLReporter + +### Easy + * Refactor `queuerunner` into a new object + * xdescribe / xit make skipped specs instead of empty blocks diff --git a/src/html/ReporterView.js b/src/html/ReporterView.js index 9263b71c..0d80d499 100644 --- a/src/html/ReporterView.js +++ b/src/html/ReporterView.js @@ -42,6 +42,7 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine, catchExceptions) { this.specComplete = function(result) { this.completeSpecCount++; + //TODO: this needs to work in order to get blanks for skipped specs. // if (isUndefined(this.views.specs[result.id])) { // this.views.specs[result.id] = new this.jasmine.HtmlReporter.SpecView(result, dom); // } From 668dd784ef0dcf031d805c3d3789aaec9d97f9cb Mon Sep 17 00:00:00 2001 From: "Davis W. Frank" Date: Sat, 8 Dec 2012 11:48:11 -0800 Subject: [PATCH 50/55] Remove jasmine.util.extend --- GOALS_2.0.md | 17 ++++++++++++++--- lib/jasmine-core/boot/boot.js | 9 +++++++-- lib/jasmine-core/jasmine-html.js | 1 + lib/jasmine-core/jasmine.js | 5 ----- spec/console/ConsoleReporterSpec.js | 13 +++++++++---- spec/core/UtilSpec.js | 22 ---------------------- spec/support/dev_boot.js | 3 --- src/core/util.js | 8 +------- 8 files changed, 32 insertions(+), 46 deletions(-) diff --git a/GOALS_2.0.md b/GOALS_2.0.md index cf8d97d7..9198a116 100644 --- a/GOALS_2.0.md +++ b/GOALS_2.0.md @@ -14,9 +14,13 @@ ### Hard * Finish killing Globals - * Guidlines: everything that isn't a CTOR should be closed inside `Env`, and everything that is a CTOR needs to be `new`ed inside the `Env` + * Guidelines: everything that isn't a CTOR should be closed inside `Env`, and everything that is a CTOR needs to be `new`ed inside the `Env` * Spies * jasmine.util should be util closure inside of env or something + * argsToArray is used for Spies and matching + * inherit is for how matchers are added/mixed in, reporters, and pretty printers + * formatException is used only inside Env/spec + * htmlEscape is for messages in matchers - should this be HTML at all? Is that Reporter responsibility? * Suites need to be unit-tested * Remove Queue from Suite in favor of queuerunner refactoring * Remover Runner in favor of a top-level Suite @@ -24,5 +28,12 @@ * get feature parity back on HTMLReporter ### Easy - * Refactor `queuerunner` into a new object - * xdescribe / xit make skipped specs instead of empty blocks +* Refactor `queuerunner` into a new object +* xdescribe / xit make skipped specs instead of empty blocks + +## Other Topics + +* Build - can we, should we redo the build and release process AGAIN in order to make it less arcane +* Docs + * JsDoc is a pain to host and RubyMine is pretty good at navigating. I say we kill it officially + * Docco has gone over well. Should we annotate all the sources and then have Pages be more complex, having tutorials and annotated source like Backbone? Are we small enough? diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index b0846e29..252f0435 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -48,9 +48,9 @@ }; if (typeof window == "undefined" && typeof exports == "object") { - jasmine.util.extend(exports, jasmineInterface); + extend(exports, jasmineInterface); } else { - jasmine.util.extend(window, jasmineInterface); + extend(window, jasmineInterface); } var htmlReporter = new jasmine.HtmlReporter(null, jasmine, env); @@ -71,4 +71,9 @@ env.execute(); }; + function extend(destination, source) { + for (var property in source) destination[property] = source[property]; + return destination; + } + }()); diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 020a4327..b4170fb6 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -282,6 +282,7 @@ jasmine.HtmlReporter.ReporterView = function(dom, jasmine, catchExceptions) { this.specComplete = function(result) { this.completeSpecCount++; + //TODO: this needs to work in order to get blanks for skipped specs. // if (isUndefined(this.views.specs[result.id])) { // this.views.specs[result.id] = new this.jasmine.HtmlReporter.SpecView(result, dom); // } diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 441b3152..59199582 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -445,11 +445,6 @@ jasmine.util.argsToArray = function(args) { return arrayOfArgs; }; -jasmine.util.extend = function(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; -}; - //TODO: expectation result may make more sense as a presentation of an expectation. jasmine.buildExpectationResult = function(params) { return { diff --git a/spec/console/ConsoleReporterSpec.js b/spec/console/ConsoleReporterSpec.js index d108c8e3..9b705b42 100644 --- a/spec/console/ConsoleReporterSpec.js +++ b/spec/console/ConsoleReporterSpec.js @@ -124,15 +124,15 @@ describe("ConsoleReporter", function() { }); it("prints the proper output under a failure scenario.", function() { - var base1 = jasmine.util.extend({}, failingSpec), - failingSpec1 = jasmine.util.extend(base1, { + var base1 = extend({}, failingSpec), + failingSpec1 = extend(base1, { fullName: 'The oven heats up', failedExpectations: [ {trace:{stack:"stack trace one\n second line"}}, {trace:{stack:"stack trace two"}} ]}), - base2 = jasmine.util.extend({}, failingSpec), - failingSpec2 = jasmine.util.extend(base2, { + base2 = extend({}, failingSpec), + failingSpec2 = extend(base2, { fullName: "The washing machine washes clothes", failedExpectations: [ {trace:{stack:"stack trace one"}} @@ -284,4 +284,9 @@ describe("ConsoleReporter", function() { }); }); }); + + function extend(destination, source) { + for (var property in source) destination[property] = source[property]; + return destination; + } }); diff --git a/spec/core/UtilSpec.js b/spec/core/UtilSpec.js index 551c2872..17694168 100644 --- a/spec/core/UtilSpec.js +++ b/spec/core/UtilSpec.js @@ -1,26 +1,4 @@ describe("jasmine.util", function() { - describe("extend", function () { - it("should add properies to a destination object ", function() { - var destination = {baz: 'baz'}; - jasmine.util.extend(destination, { - foo: 'foo', bar: 'bar' - }); - expect(destination).toEqual({foo: 'foo', bar: 'bar', baz: 'baz'}); - }); - - it("should replace properies that already exist on a destination object", function() { - var destination = {foo: 'foo'}; - jasmine.util.extend(destination, { - foo: 'bar' - }); - expect(destination).toEqual({foo: 'bar'}); - jasmine.util.extend(destination, { - foo: null - }); - expect(destination).toEqual({foo: null}); - }); - }); - describe("isArray_", function() { it("should return true if the argument is an array", function() { expect(jasmine.isArray_([])).toBe(true); diff --git a/spec/support/dev_boot.js b/spec/support/dev_boot.js index 471ca317..acbfb235 100644 --- a/spec/support/dev_boot.js +++ b/spec/support/dev_boot.js @@ -1,5 +1,2 @@ var originalJasmine = jasmine; -//copy clock methods back into window, -//so second jasmine load doesn't use jasmine clock methods. -jasmine.util.extend(window, jasmine.Clock.real); jasmine = null; diff --git a/src/core/util.js b/src/core/util.js index 067be2bb..fa9dd212 100644 --- a/src/core/util.js +++ b/src/core/util.js @@ -58,10 +58,4 @@ jasmine.util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); return arrayOfArgs; -}; - -jasmine.util.extend = function(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; -}; - +}; \ No newline at end of file From 30bf565e69d929de3b1500cca2b5e882349b88cd Mon Sep 17 00:00:00 2001 From: "Davis W. Frank" Date: Sat, 8 Dec 2012 12:02:42 -0800 Subject: [PATCH 51/55] removing jasmine.VERBOSE - not used --- GOALS_2.0.md | 6 ++++++ lib/jasmine-core/jasmine.js | 12 +++--------- src/core/base.js | 8 ++------ 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/GOALS_2.0.md b/GOALS_2.0.md index 9198a116..30244b98 100644 --- a/GOALS_2.0.md +++ b/GOALS_2.0.md @@ -16,6 +16,12 @@ * Finish killing Globals * Guidelines: everything that isn't a CTOR should be closed inside `Env`, and everything that is a CTOR needs to be `new`ed inside the `Env` * Spies + * isA functions: + * isArray_ - used in matchers and spies + * isString_ + * isDOMNode_ + * isA_ + * unimplementedMethod_, used by PrettyPrinter * jasmine.util should be util closure inside of env or something * argsToArray is used for Spies and matching * inherit is for how matchers are added/mixed in, reporters, and pretty printers diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 59199582..8ad75ad9 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -5,6 +5,8 @@ * @namespace */ var jasmine = {}; + +// TODO: do we need this now that we have boot.js? if (typeof window == "undefined" && typeof exports == "object") { exports.jasmine = jasmine } @@ -24,12 +26,6 @@ jasmine.unimplementedMethod_ = function() { */ jasmine.undefined = jasmine.___undefined___; -/** - * Show diagnostic messages in the console if set to true - * - */ -jasmine.VERBOSE = false; - /** * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. * @@ -443,9 +439,7 @@ jasmine.util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); return arrayOfArgs; -}; - -//TODO: expectation result may make more sense as a presentation of an expectation. +};//TODO: expectation result may make more sense as a presentation of an expectation. jasmine.buildExpectationResult = function(params) { return { type: 'expect', diff --git a/src/core/base.js b/src/core/base.js index c8d631fe..aab02e95 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -5,6 +5,8 @@ * @namespace */ var jasmine = {}; + +// TODO: do we need this now that we have boot.js? if (typeof window == "undefined" && typeof exports == "object") { exports.jasmine = jasmine } @@ -24,12 +26,6 @@ jasmine.unimplementedMethod_ = function() { */ jasmine.undefined = jasmine.___undefined___; -/** - * Show diagnostic messages in the console if set to true - * - */ -jasmine.VERBOSE = false; - /** * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. * From a9eaa66da59755c865847ba4aed2a92f76ee8aaa Mon Sep 17 00:00:00 2001 From: "Davis W. Frank" Date: Sun, 9 Dec 2012 09:29:05 -0800 Subject: [PATCH 52/55] removing the exception formatter from the util namespace --- lib/jasmine-core/jasmine.js | 16 ++++++++++++++-- pages | 1 + spec/core/ExceptionFormatterSpec.js | 26 ++++++++++++++++++++++++++ spec/core/ExceptionsSpec.js | 26 -------------------------- spec/runner.html | 1 + src/core/Env.js | 2 +- src/core/ExceptionFormatter.js | 12 ++++++++++++ tasks/jasmine_dev/sources.rb | 1 + 8 files changed, 56 insertions(+), 29 deletions(-) create mode 160000 pages create mode 100644 spec/core/ExceptionFormatterSpec.js create mode 100644 src/core/ExceptionFormatter.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 8ad75ad9..73a7031a 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -439,7 +439,19 @@ jasmine.util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); return arrayOfArgs; -};//TODO: expectation result may make more sense as a presentation of an expectation. +};jasmine.exceptionMessageFor = function(e) { + var message = e.name + + ': ' + + e.message + + ' in ' + + (e.fileName || e.sourceURL || '') + + ' (line ' + + (e.line || e.lineNumber || '') + + ')'; + + return message; +}; +//TODO: expectation result may make more sense as a presentation of an expectation. jasmine.buildExpectationResult = function(params) { return { type: 'expect', @@ -527,7 +539,7 @@ jasmine.buildExpectationResult = function(params) { } }; - var exceptionFormatter = jasmine.util.formatException; + var exceptionFormatter = jasmine.exceptionMessageFor; var specConstructor = jasmine.Spec; diff --git a/pages b/pages new file mode 160000 index 00000000..39dcf87b --- /dev/null +++ b/pages @@ -0,0 +1 @@ +Subproject commit 39dcf87b563e7cb0435208af562cc8ea033a47ff diff --git a/spec/core/ExceptionFormatterSpec.js b/spec/core/ExceptionFormatterSpec.js new file mode 100644 index 00000000..c3052c8c --- /dev/null +++ b/spec/core/ExceptionFormatterSpec.js @@ -0,0 +1,26 @@ +describe("ExceptionFormatter", function() { + + it('formats Firefox exception messages', function() { + var sampleFirefoxException = { + fileName: 'foo.js', + line: '1978', + message: 'you got your foo in my bar', + name: 'A Classic Mistake' + }, + message = jasmine.exceptionMessageFor(sampleFirefoxException); + + expect(message).toEqual('A Classic Mistake: you got your foo in my bar in foo.js (line 1978)'); + }); + + it('formats Webkit exception messages', function() { + var sampleWebkitException = { + sourceURL: 'foo.js', + lineNumber: '1978', + message: 'you got your foo in my bar', + name: 'A Classic Mistake' + }, + message = jasmine.exceptionMessageFor(sampleWebkitException); + + expect(message).toEqual('A Classic Mistake: you got your foo in my bar in foo.js (line 1978)'); + }); +}); \ No newline at end of file diff --git a/spec/core/ExceptionsSpec.js b/spec/core/ExceptionsSpec.js index d7dda80a..e06b1275 100644 --- a/spec/core/ExceptionsSpec.js +++ b/spec/core/ExceptionsSpec.js @@ -6,32 +6,6 @@ describe('Exceptions:', function() { env.updateInterval = 0; }); - it('jasmine.formatException formats Firefox exception messages as expected', function() { - var sampleFirefoxException = { - fileName: 'foo.js', - line: '1978', - message: 'you got your foo in my bar', - name: 'A Classic Mistake' - }; - - var expected = 'A Classic Mistake: you got your foo in my bar in foo.js (line 1978)'; - - expect(jasmine.util.formatException(sampleFirefoxException)).toEqual(expected); - }); - - it('jasmine.formatException formats Webkit exception messages as expected', function() { - var sampleWebkitException = { - sourceURL: 'foo.js', - lineNumber: '1978', - message: 'you got your foo in my bar', - name: 'A Classic Mistake' - }; - - var expected = 'A Classic Mistake: you got your foo in my bar in foo.js (line 1978)'; - - expect(jasmine.util.formatException(sampleWebkitException)).toEqual(expected); - }); - describe('with break on exception', function() { it('should not catch the exception', function() { env.catchExceptions(false); diff --git a/spec/runner.html b/spec/runner.html index b462dac5..0db56a4a 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -30,6 +30,7 @@ + diff --git a/src/core/Env.js b/src/core/Env.js index 3e3a05da..20ee75a1 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -74,7 +74,7 @@ } }; - var exceptionFormatter = jasmine.util.formatException; + var exceptionFormatter = jasmine.exceptionMessageFor; var specConstructor = jasmine.Spec; diff --git a/src/core/ExceptionFormatter.js b/src/core/ExceptionFormatter.js new file mode 100644 index 00000000..7cb6032c --- /dev/null +++ b/src/core/ExceptionFormatter.js @@ -0,0 +1,12 @@ +jasmine.exceptionMessageFor = function(e) { + var message = e.name + + ': ' + + e.message + + ' in ' + + (e.fileName || e.sourceURL || '') + + ' (line ' + + (e.line || e.lineNumber || '') + + ')'; + + return message; +}; diff --git a/tasks/jasmine_dev/sources.rb b/tasks/jasmine_dev/sources.rb index caf0cb1a..87aee274 100644 --- a/tasks/jasmine_dev/sources.rb +++ b/tasks/jasmine_dev/sources.rb @@ -3,6 +3,7 @@ class JasmineDev < Thor :core => [ "base.js", "util.js", + "ExceptionFormatter.js", "ExpectationResult.js", "Env.js", "Reporter.js", From 05977203a6a8556ddf8420192070a93a643e5671 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank" Date: Mon, 10 Dec 2012 08:14:39 -0800 Subject: [PATCH 53/55] Cleanup of Exception formatting (incl. better Browser support re: toString; NestedResults is dead, remove it from jasmine.yml --- spec/core/SuiteSpec.js | 320 +++++++++++++++++++++++++++-------------- src/core/Env.js | 34 +++-- src/core/Suite.js | 50 +++---- 3 files changed, 257 insertions(+), 147 deletions(-) diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index 36ef4683..766c9c93 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -1,113 +1,225 @@ -describe('Suite', function() { - var env; +//describe('Suite', function() { +// var env; +// +// beforeEach(function() { +// env = new jasmine.Env(); +// env.updateInterval = 0; +// }); +// +// describe('Specs', function () { +// var suite; +// +// beforeEach(function() { +// suite = env.describe('Suite 1', function () { +// env.it('Spec 1', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// env.it('Spec 2', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// env.describe('Suite 2', function () { +// env.it('Spec 3', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// }); +// env.it('Spec 4', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// }); +// }); +// +// it('#specs should return all immediate children that are specs.', function () { +// var suiteSpecs = suite.specs(); +// expect(suiteSpecs.length).toEqual(3); +// expect(suiteSpecs[0].description).toEqual('Spec 1'); +// expect(suiteSpecs[1].description).toEqual('Spec 2'); +// expect(suiteSpecs[2].description).toEqual('Spec 4'); +// }); +// +// it("#suites should return all immediate children that are suites.", function() { +// var nestedSuites = suite.suites(); +// expect(nestedSuites.length).toEqual(1); +// expect(nestedSuites[0].description).toEqual('Suite 2'); +// }); +// +// it("#children should return all immediate children including suites and specs.", function() { +// var children = suite.children(); +// expect(children.length).toEqual(4); +// expect(children[0].description).toEqual('Spec 1'); +// expect(children[1].description).toEqual('Spec 2'); +// expect(children[2].description).toEqual('Suite 2'); +// expect(children[3].description).toEqual('Spec 4'); +// }); +// }); +// +// describe('SpecCount', function () { +// +// it('should keep a count of the number of specs that are run', function() { +// var suite = env.describe('one suite description', function () { +// env.it('should be a test', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// env.it('should be another test', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// env.it('should be a third test', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// }); +// +// expect(suite.specs().length).toEqual(3); +// }); +// +// it('specCount should be correct even with runs/waits blocks', function() { +// var suite = env.describe('one suite description', function () { +// env.it('should be a test', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// env.it('should be another test', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// this.waits(10); +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// env.it('should be a third test', function() { +// this.runs(function () { +// this.expect(true).toEqual(true); +// }); +// }); +// }); +// +// expect(suite.specs().length).toEqual(3); +// }); +// }); +//}); - beforeEach(function() { - env = new jasmine.Env(); - env.updateInterval = 0; - }); +describe("Suite (unit tests)", function() { - describe('Specs', function () { - var suite; - - beforeEach(function() { - suite = env.describe('Suite 1', function () { - env.it('Spec 1', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - env.it('Spec 2', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - env.describe('Suite 2', function () { - env.it('Spec 3', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - env.it('Spec 4', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - }); - - it('#specs should return all immediate children that are specs.', function () { - var suiteSpecs = suite.specs(); - expect(suiteSpecs.length).toEqual(3); - expect(suiteSpecs[0].description).toEqual('Spec 1'); - expect(suiteSpecs[1].description).toEqual('Spec 2'); - expect(suiteSpecs[2].description).toEqual('Spec 4'); - }); - - it("#suites should return all immediate children that are suites.", function() { - var nestedSuites = suite.suites(); - expect(nestedSuites.length).toEqual(1); - expect(nestedSuites[0].description).toEqual('Suite 2'); - }); - - it("#children should return all immediate children including suites and specs.", function() { - var children = suite.children(); - expect(children.length).toEqual(4); - expect(children[0].description).toEqual('Spec 1'); - expect(children[1].description).toEqual('Spec 2'); - expect(children[2].description).toEqual('Suite 2'); - expect(children[3].description).toEqual('Spec 4'); - }); - }); - - describe('SpecCount', function () { - - it('should keep a count of the number of specs that are run', function() { - var suite = env.describe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - env.it('should be a third test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); + it("keeps its id", function() { + var env = new jasmine.Env(), + suite = new jasmine.Suite({ + env: env, + id: 456, + description: "I am a suite" }); - expect(suite.specs().length).toEqual(3); - }); + expect(suite.id).toEqual(456); + }); - it('specCount should be correct even with runs/waits blocks', function() { - var suite = env.describe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - this.waits(10); - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - env.it('should be a third test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); + it("returns its full name", function() { + var env = new jasmine.Env(), + suite = new jasmine.Suite({ + env: env, + description: "I am a suite" }); - expect(suite.specs().length).toEqual(3); - }); + expect(suite.getFullName()).toEqual("I am a suite"); }); + + it("returns its full name when it has parent suites", function() { + var env = new jasmine.Env(), + parentSuite = new jasmine.Suite({ + env: env, + description: "I am a suite" + }); + suite = new jasmine.Suite({ + env: env, + description: "I am a suite" + }); + + expect(suite.getFullName()).toEqual("I am a suite"); + + }); + + it("adds before functions in order of needed execution", function() { + var env = new jasmine.Env(), + suite = new jasmine.Suite({ + env: env, + description: "I am a suite" + }), + outerBefore = jasmine.createSpy('outerBeforeEach'), + innerBefore = jasmine.createSpy('insideBeforeEach'); + + suite.beforeEach(outerBefore); + suite.beforeEach(innerBefore); + + expect(suite.beforeFns).toEqual([innerBefore, outerBefore]); + }); + + it("adds after functions in order of needed execution", function() { + var env = new jasmine.Env(), + suite = new jasmine.Suite({ + env: env, + description: "I am a suite" + }), + outerAfter = jasmine.createSpy('outerAfterEach'), + innerAfter = jasmine.createSpy('insideAfterEach'); + + suite.afterEach(outerAfter); + suite.afterEach(innerAfter); + + expect(suite.afterFns).toEqual([innerAfter, outerAfter]); + }); + + it("adds specs", function() { + var env = new jasmine.Env(), + suite = new jasmine.Suite({ + env: env, + description: "I am a suite" + }), + fakeSpec = {}; + + expect(suite.specs.length).toEqual(0); + + suite.addSpec(fakeSpec); + + expect(suite.specs.length).toEqual(1);git + }); + }); + +// TODO: +describe("Suite (acceptance)", function() { + + it("can execute and run all of its befores, specs, and afters", function() { + var env = new jasmine.Env(), + calls = []; + + env.describe("A suite", function() { + env.beforeEach(function() { + calls.push('before'); + }); + + env.it("with a spec", function() { + calls.push('spec'); + }); + + env.afterEach(function() { + calls.push('after'); + }); + }); + + env.execute(); + expect(calls).toEqual(['before', 'spec', 'after']); + }); + +}); \ No newline at end of file diff --git a/src/core/Env.js b/src/core/Env.js index 20ee75a1..2fa62a60 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -74,7 +74,7 @@ } }; - var exceptionFormatter = jasmine.exceptionMessageFor; + var exceptionFormatter = jasmine.exceptionFormatter; var specConstructor = jasmine.Spec; @@ -89,11 +89,11 @@ this.catchExceptions = function(value) { return catchExceptions = !!value; - } + }; this.catchingExceptions = function(value) { return catchExceptions; - } + }; this.specFactory = function(description, fn, suite) { var spec = new specConstructor({ @@ -103,7 +103,9 @@ expectationFactory: expectationFactory, exceptionFormatter: exceptionFormatter, resultCallback: specResultCallback, - getSpecName: function(spec) { return getSpecName(spec, suite) }, + getSpecName: function(spec) { + return getSpecName(spec, suite) + }, startCallback: startCallback, description: description, catchingExceptions: this.catchingExceptions, @@ -131,12 +133,19 @@ var queueFactory = function() { return new queueConstructor(self); }; - this.suiteFactory = function(description, specDefinitions) { - return new suiteConstructor(self, description, specDefinitions, self.currentSuite, queueFactory, isSuite); + this.suiteFactory = function(description) { + return new suiteConstructor({ + env: self, + description: description, + currentSuite: self.currentSuite, + queueFactory: queueFactory, + isSuite: isSuite + }); }; var maximumSpecCallbackDepth = 100; var currentSpecCallbackDepth = 0; + function encourageGarbageCollection(fn) { currentSpecCallbackDepth++; if (currentSpecCallbackDepth > maximumSpecCallbackDepth) { @@ -145,7 +154,6 @@ } else { fn(); } - } }; @@ -162,7 +170,7 @@ /** * @returns an object containing jasmine version build info, if set. */ - jasmine.Env.prototype.version = function () { + jasmine.Env.prototype.version = function() { if (this.jasmine.version_) { return this.jasmine.version_; } else { @@ -171,7 +179,7 @@ }; jasmine.Env.prototype.expect = function(actual) { - return this.currentSpec.expect(actual); + return this.currentSpec.expect(actual); }; jasmine.Env.prototype.spyOn = function(obj, methodName) { @@ -227,14 +235,14 @@ /** * @returns a sequential integer starting at 0 */ - jasmine.Env.prototype.nextSpecId = function () { + jasmine.Env.prototype.nextSpecId = function() { return this.nextSpecId_++; }; /** * @returns a sequential integer starting at 0 */ - jasmine.Env.prototype.nextSuiteId = function () { + jasmine.Env.prototype.nextSuiteId = function() { return this.nextSuiteId_++; }; @@ -265,7 +273,7 @@ var declarationError = null; try { specDefinitions.call(suite); - } catch(e) { + } catch (e) { declarationError = e; } @@ -288,7 +296,7 @@ } }; - jasmine.Env.prototype.currentRunner = function () { + jasmine.Env.prototype.currentRunner = function() { return this.currentRunner_; }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 8da0fc13..68d36fbc 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -1,27 +1,19 @@ -/** - * Internal representation of a Jasmine suite. - * - * @constructor - * @param {jasmine.Env} env - * @param {String} description - * @param {Function} specDefinitions - * @param {jasmine.Suite} parentSuite - */ -jasmine.Suite = function(env, description, specDefinitions, parentSuite, queueFactory, isSuite) { - var self = this; - //TODO: remove once we unit test Suite - var queueFactory = queueFactory || function() {}; - self.id = env.nextSuiteId ? env.nextSuiteId() : null; - self.description = description; - self.queue = queueFactory(); - self.parentSuite = parentSuite; - self.env = env; - self.isSuite = isSuite || function() {}; - self.before_ = []; - self.after_ = []; - self.children_ = []; - self.suites_ = []; - self.specs_ = []; +jasmine.Suite = function(attrs) { + this.env = attrs.env; + this.id = attrs.id; + this.parentSuite = attrs.parentSuite; + this.description = attrs.description; + this.beforeFns = []; + this.afterFns = []; + + var queueFactory = attrs.queueFactory || function() {}; + this.queue = queueFactory(); + + this.isSuite = attrs.isSuite || function() {}; + + this.children_ = []; // TODO: used by current reporters; keep for now + this.suites_ = []; + this.specs_ = []; }; jasmine.Suite.prototype.getFullName = function() { @@ -40,14 +32,12 @@ jasmine.Suite.prototype.finish = function(onComplete) { } }; -jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.unshift(beforeEachFunction); +jasmine.Suite.prototype.beforeEach = function(fn) { + this.beforeFns.unshift(fn); }; -jasmine.Suite.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.unshift(afterEachFunction); +jasmine.Suite.prototype.afterEach = function(fn) { + this.afterFns.unshift(fn); }; //TODO: interface should be addSpec or addSuite methods. From 3fc79bac9e3097d75fffcfc774ac77743d55e596 Mon Sep 17 00:00:00 2001 From: "Davis W. Frank" Date: Mon, 10 Dec 2012 22:43:03 -0800 Subject: [PATCH 54/55] * Removed old Queue & Runner in favor of Suite using the new QueueRunner * New reporter interface across all reporters * xdescribe & xit now store disabled specs * Rewrite of HtmlReporter to support new interface and be more performant --- GOALS_2.0.md | 19 +- lib/jasmine-core/boot/boot.js | 15 +- lib/jasmine-core/jasmine-html.js | 741 ++++++++-------------- lib/jasmine-core/jasmine.css | 101 +-- lib/jasmine-core/jasmine.js | 949 +++++++++++----------------- spec/console/ConsoleReporterSpec.js | 423 +++++-------- spec/core/EnvSpec.js | 180 +++++- spec/core/JsApiReporterSpec.js | 108 +++- spec/core/MultiReporterSpec.js | 45 -- spec/core/QueueRunnerSpec.js | 132 ++++ spec/core/ReportDispatcherSpec.js | 40 ++ spec/core/ReporterSpec.js | 56 -- spec/core/RunnerSpec.js | 168 ----- spec/core/SpecRunningSpec.js | 42 +- spec/core/SpecSpec.js | 323 ++++------ spec/core/SuiteSpec.js | 295 ++++----- spec/html/HTMLReporterSpec.js | 155 ----- spec/html/HtmlReporterSpec.js | 571 +++++++++++++++++ spec/html/QueryStringSpec.js | 43 ++ spec/html/ResultsNodeSpec.js | 62 ++ spec/jasmine.yml | 8 +- spec/node_performance_suite.js | 6 +- spec/node_suite.js | 8 +- spec/runner.html | 81 +-- src/console/ConsoleReporter.js | 226 ++----- src/core/Clock.js | 30 +- src/core/Env.js | 262 ++++---- src/core/JsApiReporter.js | 136 ++-- src/core/MultiReporter.js | 35 - src/core/Queue.js | 111 ---- src/core/QueueRunner.js | 40 ++ src/core/ReportDispatcher.js | 30 + src/core/Reporter.js | 31 - src/core/Runner.js | 80 --- src/core/Spec.js | 80 +-- src/core/Suite.js | 99 +-- src/html/HtmlReporter.js | 391 +++++++----- src/html/HtmlReporterHelpers.js | 64 -- src/html/QueryString.js | 43 ++ src/html/ResultsNode.js | 15 + src/html/_HTMLReporter.scss | 188 +++--- src/html/jasmine.css | 101 +-- tasks/jasmine_dev/sources.rb | 14 +- 43 files changed, 3229 insertions(+), 3318 deletions(-) delete mode 100644 spec/core/MultiReporterSpec.js create mode 100644 spec/core/QueueRunnerSpec.js create mode 100644 spec/core/ReportDispatcherSpec.js delete mode 100644 spec/core/ReporterSpec.js delete mode 100644 spec/core/RunnerSpec.js delete mode 100644 spec/html/HTMLReporterSpec.js create mode 100644 spec/html/HtmlReporterSpec.js create mode 100644 spec/html/QueryStringSpec.js create mode 100644 spec/html/ResultsNodeSpec.js delete mode 100644 src/core/MultiReporter.js delete mode 100644 src/core/Queue.js create mode 100644 src/core/QueueRunner.js create mode 100644 src/core/ReportDispatcher.js delete mode 100644 src/core/Reporter.js delete mode 100644 src/core/Runner.js delete mode 100644 src/html/HtmlReporterHelpers.js create mode 100644 src/html/QueryString.js create mode 100644 src/html/ResultsNode.js diff --git a/GOALS_2.0.md b/GOALS_2.0.md index 30244b98..e6e9a45a 100644 --- a/GOALS_2.0.md +++ b/GOALS_2.0.md @@ -14,7 +14,10 @@ ### Hard * Finish killing Globals - * Guidelines: everything that isn't a CTOR should be closed inside `Env`, and everything that is a CTOR needs to be `new`ed inside the `Env` + * Guidelines: + * New objects can have constructors on `jasmine` + * Top level functions can live on `jasmine` + * Top level (i.e., any `jasmine` property) should only be referenced inside the `Env` constructor * Spies * isA functions: * isArray_ - used in matchers and spies @@ -26,20 +29,18 @@ * argsToArray is used for Spies and matching * inherit is for how matchers are added/mixed in, reporters, and pretty printers * formatException is used only inside Env/spec - * htmlEscape is for messages in matchers - should this be HTML at all? Is that Reporter responsibility? -* Suites need to be unit-tested -* Remove Queue from Suite in favor of queuerunner refactoring -* Remover Runner in favor of a top-level Suite - * This means Env needs to `new` a `Suite` first thing -* get feature parity back on HTMLReporter + * htmlEscape is for messages in matchers - should this be HTML at all? Is that * Matchers improvements + * move AddMatchers to Env & global (away from spec) + * make matchers unit-testable + * write doc on how to make a matcher ### Easy -* Refactor `queuerunner` into a new object -* xdescribe / xit make skipped specs instead of empty blocks ## Other Topics * Build - can we, should we redo the build and release process AGAIN in order to make it less arcane + * Want to add JSHint to build + * Use a standard JS/Node based concat system instead of custom Ruby? * Docs * JsDoc is a pain to host and RubyMine is pretty good at navigating. I say we kill it officially * Docco has gone over well. Should we annotate all the sources and then have Pages be more complex, having tutorials and annotated source like Backbone? Are we small enough? diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index 252f0435..bd649473 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -53,7 +53,19 @@ extend(window, jasmineInterface); } - var htmlReporter = new jasmine.HtmlReporter(null, jasmine, env); + var queryString = new jasmine.QueryString({ + getWindowLocation: function() { return window.location; } + }); + + env.catchExceptions(queryString.getParam("catch")); + + var htmlReporter = new jasmine.HtmlReporter({ + env: env, + queryString: queryString, + getContainer: function() { return document.body; }, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } + }); env.addReporter(jasmineInterface.jsApiReporter); env.addReporter(htmlReporter); @@ -68,6 +80,7 @@ if (currentWindowOnload) { currentWindowOnload(); } + htmlReporter.initialize(); env.execute(); }; diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index b4170fb6..17b91020 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -1,512 +1,319 @@ -jasmine.HtmlReporterHelpers = {}; +jasmine.HtmlReporter = function(options) { + var env = options.env || {}, + getContainer = options.getContainer, + now = options.now || function() { return new Date().getTime();}, + createElement = options.createElement, + createTextNode = options.createTextNode, + results = [], + queryString = options.queryString, + startTime, + specsExecuted = 0, + failureCount = 0, + htmlReporterMain, + symbols; -jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { - var el = document.createElement(type); + this.initialize = function() { + htmlReporterMain = createDom("div", {className: "html-reporter"}, + createDom("div", {className: "banner"}, + createDom("span", {className: "title"}, "Jasmine"), + createDom("span", {className: "version"}, env.versionString()) + ), + createDom("ul", {className: "symbol-summary"}), + createDom("div", {className: "alert"}), + createDom("div", {className: "results"}, + createDom("div", {className: "failures"}) + ) + ); + getContainer().appendChild(htmlReporterMain); - for (var i = 2; i < arguments.length; i++) { - var child = arguments[i]; - - if (typeof child === 'string') { - el.appendChild(document.createTextNode(child)); - } else { - if (child) { - el.appendChild(child); - } - } - } - - for (var attr in attrs) { - if (attr == "className") { - el[attr] = attrs[attr]; - } else { - el.setAttribute(attr, attrs[attr]); - } - } - - return el; -}; - -jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { - if (!child.results) { - return; - } - var results = child.results(); - var status = results.passed() ? 'passed' : 'failed'; - if (results.skipped) { - status = 'skipped'; - } - - return status; -}; - -jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { - var parentDiv = this.dom.summary; - var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; - var parent = child[parentSuite]; - - if (parent) { - if (typeof this.views.suites[parent.id] == 'undefined') { - this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine, this.catchExceptions); - } - parentDiv = this.views.suites[parent.id].element; - } - - parentDiv.appendChild(childElement); -}; - - -jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { - //TODO: not really a helper, thus, no this.jasmine - for(var fn in jasmine.HtmlReporterHelpers) { - ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; - } -}; - -jasmine.HtmlReporter = function(_doc, jasmine, env, options) { - options = options || {}; - var self = this; - this.jasmine = jasmine || window.jasmine; - var doc = _doc || window.document; - - - var reporterView; - - var dom = {}; - - // Jasmine Reporter Public Interface - - self.reportRunnerStarting = function(runner) { - var specs = runner.specs() || []; - - if (specs.length == 0) { - return; - } - - createReporterDom(runner.env.versionString()); - doc.body.appendChild(dom.reporter); - setExceptionHandling(); - - reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine, env.catchingExceptions()); - reporterView.addSpecs(specs, self.specFilter); + symbols = find(".symbol-summary")[0]; }; - self.reportRunnerResults = function(runner) { - reporterView && reporterView.complete(); - }; + var specFilterPattern; - self.reportSuiteResults = function(suite) { - reporterView.suiteComplete(suite); - }; - - self.reportSpecStarting = function(spec) { - }; - - var lastYieldForRender = 0; - var refreshInterval = 250; - var yieldForRender = options.yieldForRender || function(fn) { - var now = Date.now(); - var delta = (now - lastYieldForRender); - if (delta > refreshInterval) { - lastYieldForRender = now; - setTimeout(fn, 0); - } else { - fn(); - } - } - self.reportSpecResults = function(result) { - yieldForRender(function() {reporterView.specComplete(result) }); - }; - - self.log = function() { - var console = self.jasmine.getGlobal().console; - if (console && console.log) { - if (console.log.apply) { - console.log.apply(console, arguments); - } else { - console.log(arguments); // ie fix: console.log.apply doesn't exist on ie - } - } - }; - - self.specFilter = function(spec) { - if (!focusedSpecName()) { + this.specFilter = function(spec) { + if (!isFiltered()) { return true; } - return spec.getFullName().indexOf(focusedSpecName()) === 0; + var specName = spec.getFullName(); + + return !!(specName.match(specFilterPattern)); }; - return self; - - function focusedSpecName() { - var specName; - - (function memoizeFocusedSpec() { - if (specName) { - return; - } - - var paramMap = []; - var params = self.jasmine.HtmlReporter.parameters(doc); - - for (var i = 0; i < params.length; i++) { - var p = params[i].split('='); - paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); - } - - specName = paramMap.spec; - })(); - - return specName; - } - - function createReporterDom(version) { - dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, - dom.banner = self.createDom('div', { className: 'banner' }, - self.createDom('span', { className: 'title' }, "Jasmine "), - self.createDom('span', { className: 'version' }, version)), - - dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), - dom.alert = self.createDom('div', {className: 'alert'}, - self.createDom('span', { className: 'exceptions' }, - self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), - self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), - dom.results = self.createDom('div', {className: 'results'}, - dom.summary = self.createDom('div', { className: 'summary' }), - dom.details = self.createDom('div', { id: 'details' })) - ); - } - - function noTryCatch() { - return window.location.search.match(/catch=false/); - } - - function searchWithCatch() { - var params = self.jasmine.HtmlReporter.parameters(window.document); - var removed = false; - var i = 0; - - while (!removed && i < params.length) { - if (params[i].match(/catch=/)) { - params.splice(i, 1); - removed = true; - } - i++; - } - if (env.catchingExceptions()) { - params.push("catch=false"); - } - - return params.join("&"); - } - - function setExceptionHandling() { - var chxCatch = document.getElementById('no_try_catch'); - - if (noTryCatch()) { - chxCatch.setAttribute('checked', true); - env.catchExceptions(false); - } - chxCatch.onclick = function() { - window.location.search = searchWithCatch(); - }; - } -}; -jasmine.HtmlReporter.parameters = function(doc) { - var paramStr = doc.location.search.substring(1); - var params = []; - - if (paramStr.length > 0) { - params = paramStr.split('&'); - } - return params; -} -jasmine.HtmlReporter.sectionLink = function(sectionName, catchExceptions) { - var link = '?'; - var params = []; - - if (sectionName) { - params.push('spec=' + encodeURIComponent(sectionName)); - } - if (!catchExceptions) { - params.push("catch=false"); - } - if (params.length > 0) { - link += params.join("&"); - } - - return link; -}; -jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter); -jasmine.HtmlReporter.ReporterView = function(dom, jasmine, catchExceptions) { - this.startedAt = new Date(); - this.runningSpecCount = 0; - this.completeSpecCount = 0; - this.passedCount = 0; - this.failedCount = 0; - this.skippedCount = 0; - this.jasmine = jasmine || {}; - - this.createResultsMenu = function() { - this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'}, - this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'), - ' | ', - this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing')); - - this.summaryMenuItem.onclick = function() { - dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, ''); - }; - - this.detailsMenuItem.onclick = function() { - showDetails(); - }; + var totalSpecsDefined; + this.jasmineStarted = function(options) { + totalSpecsDefined = options.totalSpecsDefined || 0; + startTime = now(); }; - this.addSpecs = function(specs, specFilter) { - this.totalSpecCount = specs.length; + var summary = createDom("div", {className: "summary"}); - this.views = { - specs: {}, - suites: {} - }; + var topResults = new jasmine.ResultsNode({}, "", null), + currentParent = topResults; - for (var i = 0; i < specs.length; i++) { - var spec = specs[i]; - this.views.specs[spec.id] = new this.jasmine.HtmlReporter.SpecView(spec, dom, this.views, this.jasmine, catchExceptions); - if (specFilter(spec)) { - this.runningSpecCount++; - } - } + this.suiteStarted = function(result) { + currentParent.addChild(result, "suite"); + currentParent = currentParent.last(); }; - this.specComplete = function(result) { - this.completeSpecCount++; - - //TODO: this needs to work in order to get blanks for skipped specs. - // if (isUndefined(this.views.specs[result.id])) { - // this.views.specs[result.id] = new this.jasmine.HtmlReporter.SpecView(result, dom); - // } - - var specView = this.views.specs[result.id]; - - switch (specView.status()) { - case 'passed': - this.passedCount++; - break; - - case 'failed': - this.failedCount++; - break; - - case 'disabled': - this.skippedCount++; - break; - } - - specView.refresh(); - this.refresh(); - }; - - this.suiteComplete = function(suite) { - var suiteView = this.views.suites[suite.id]; - if (isUndefined(suiteView)) { + this.suiteDone = function(result) { + if (currentParent == topResults) { return; } - suiteView.refresh(); + + currentParent = currentParent.parent; }; - this.refresh = function() { - - if (isUndefined(this.resultsMenu)) { - this.createResultsMenu(); - } - - // currently running UI - if (isUndefined(this.runningAlert)) { - this.runningAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "runningAlert bar" }); - dom.alert.appendChild(this.runningAlert); - } - this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); - - // skipped specs UI - if (isUndefined(this.skippedAlert)) { - this.skippedAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "skippedAlert bar" }); - } - - this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; - - if (this.skippedCount === 1 && isDefined(dom.alert)) { - dom.alert.appendChild(this.skippedAlert); - } - - // passing specs UI - if (isUndefined(this.passedAlert)) { - this.passedAlert = this.createDom('span', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "passingAlert bar" }); - } - this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); - - // failing specs UI - if (isUndefined(this.failedAlert)) { - this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"}); - } - this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount); - - if (this.failedCount === 1 && isDefined(dom.alert)) { - dom.alert.appendChild(this.failedAlert); - dom.alert.appendChild(this.resultsMenu); - } - - // summary info - this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount); - this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing"; + this.specStarted = function(result) { + currentParent.addChild(result, "spec"); }; - this.complete = function() { - dom.alert.removeChild(this.runningAlert); - - this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; - - if (this.failedCount === 0) { - dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount))); - } else { - showDetails(); + var failures = []; + this.specDone = function(result) { + if (result.status != "disabled") { + specsExecuted++; } - dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s")); + symbols.appendChild(createDom("li", { + className: result.status, + id: "spec_" + result.id} + )); + + if (result.status == "failed") { + failureCount++; + + var failure = + createDom("div", {className: "spec-detail failed"}, + createDom("a", {className: "description", title: result.fullName, href: specHref(result)}, result.fullName), + createDom("div", {className: "messages"}) + ); + var messages = failure.childNodes[1]; + + for (var i = 0; i < result.failedExpectations.length; i++) { + var expectation = result.failedExpectations[i]; + var stack = (expectation.trace && expectation.trace.stack) || ""; + messages.appendChild(createDom("div", {className: "result-message"}, expectation.message)); + messages.appendChild(createDom("div", {className: "stack-trace"}, stack)); + } + + failures.push(failure); + } + }; + + this.jasmineDone = function() { + var elapsed = now() - startTime; + + var banner = find(".banner")[0]; + banner.appendChild(createDom("span", {className: "duration"}, "finished in " + elapsed / 1000 + "s")); + + var alert = find(".alert")[0]; + + alert.appendChild(createDom("span", { className: "exceptions" }, + createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"), + createDom("input", { + className: "raise", + id: "raise-exceptions", + type: "checkbox" + }) + )); + var checkbox = find("input")[0]; + + checkbox.checked = !env.catchingExceptions(); + checkbox.onclick = function() { + queryString.setParam("catch", !checkbox.checked); + }; + + if (specsExecuted < totalSpecsDefined) { + var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all"; + alert.appendChild( + createDom("span", {className: "bar skipped"}, + createDom("a", {href: "?", title: "Run all specs"}, skippedMessage) + ) + ); + } + var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount), + statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed"); + alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage)); + + var results = find(".results")[0]; + results.appendChild(summary); + + summaryList(topResults, summary); + + function summaryList(resultsTree, domParent) { + var specListNode; + for (var i = 0; i < resultsTree.children.length; i++) { + var resultNode = resultsTree.children[i]; + if (resultNode.type == "suite") { + var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id}, + createDom("li", {className: "suite-detail"}, + createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) + ) + ); + + summaryList(resultNode, suiteListNode); + domParent.appendChild(suiteListNode); + } + if (resultNode.type == "spec") { + if (domParent.getAttribute("class") != "specs") { + specListNode = createDom("ul", {className: "specs"}); + domParent.appendChild(specListNode); + } + specListNode.appendChild( + createDom("li", { + className: resultNode.result.status, + id: "spec-" + resultNode.result.id + }, + createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) + ) + ); + } + } + } + + if (failures.length) { + alert.appendChild( + createDom('span', {className: "menu bar spec-list"}, + createDom("span", {}, "Spec List | "), + createDom('a', {className: "failures-menu", href: "#"}, "Failures"))); + alert.appendChild( + createDom('span', {className: "menu bar failure-list"}, + createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"), + createDom("span", {}, " | Failures "))); + + find(".failures-menu")[0].onclick = function() { + setMenuModeTo('failure-list'); + }; + find(".spec-list-menu")[0].onclick = function() { + setMenuModeTo('spec-list'); + }; + + setMenuModeTo('failure-list'); + + var failureNode = find(".failures")[0]; + for (var i = 0; i < failures.length; i++) { + failureNode.appendChild(failures[i]); + } + } }; return this; - function showDetails() { - if (dom.reporter.className.search(/showDetails/) === -1) { - dom.reporter.className += " showDetails"; + function find(selector) { + if (selector.match(/^\./)) { + var className = selector.substring(1); + return getContainer().getElementsByClassName(className); + } else { + return getContainer().getElementsByTagName(selector); } } - function isUndefined(obj) { - return typeof obj === 'undefined'; - } + function createDom(type, attrs, childrenVarArgs) { + var el = createElement(type); - function isDefined(obj) { - return !isUndefined(obj); - } + for (var i = 2; i < arguments.length; i++) { + var child = arguments[i]; - function specPluralizedFor(count) { - var str = count + " spec"; - if (count > 1) { - str += "s" - } - return str; - } - -}; - -jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); - - -jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine, catchExceptions) { - this.spec = spec; - this.dom = dom; - this.views = views; - this.jasmine = jasmine || {}; - this.catchExceptions = catchExceptions; - - this.symbol = this.createDom('li', { className: 'pending' }); - this.dom.symbolSummary.appendChild(this.symbol); - - this.summary = this.createDom('div', { className: 'specSummary' }, - this.createDom('a', { - className: 'description', - //TODO: sectionLink is a dependency passed in that knows about catchingExceptions - //so we don't pass catchExceptions everywhere. - href: this.jasmine.HtmlReporter.sectionLink(this.spec.getFullName(), catchExceptions), - title: this.spec.getFullName() - }, this.spec.description) - ); - - this.detail = this.createDom('div', { className: 'specDetail' }, - this.createDom('a', { - className: 'description', - href: '?spec=' + encodeURIComponent(this.spec.getFullName()), - title: this.spec.getFullName() - }, this.spec.getFullName()) - ); -}; - -jasmine.HtmlReporter.SpecView.prototype.status = function() { - return this.spec.status(); -}; - -jasmine.HtmlReporter.SpecView.prototype.refresh = function() { - this.symbol.className = this.status(); - - switch (this.status()) { - case 'disabled': - break; - case 'passed': - this.appendSummaryToSuiteDiv(); - break; - - case 'failed': - this.appendSummaryToSuiteDiv(); - this.appendFailureDetail(); - break; - } -}; - -jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() { - this.summary.className += ' ' + this.status(); - this.appendToSummary(this.spec, this.summary); -}; - -jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { - this.detail.className += ' ' + this.status(); - - var resultItems = this.spec.failedExpectations; - var messagesDiv = this.createDom('div', { className: 'messages' }); - - for (var i = 0; i < resultItems.length; i++) { - var result = resultItems[i]; - - if (result.type == 'log') { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && !result.passed) { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); - - if (result.trace.stack) { - messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); + if (typeof child === 'string') { + el.appendChild(createTextNode(child)); + } else { + if (child) { + el.appendChild(child); + } } } + + for (var attr in attrs) { + if (attr == "className") { + el[attr] = attrs[attr]; + } else { + el.setAttribute(attr, attrs[attr]); + } + } + + return el; } - if (messagesDiv.childNodes.length > 0) { - this.detail.appendChild(messagesDiv); - this.dom.details.appendChild(this.detail); + function pluralize(singular, count) { + var word = (count == 1 ? singular : singular + "s"); + + return "" + count + " " + word; } -}; -jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView); -jasmine.HtmlReporter.SuiteView = function(suite, dom, views, jasmine, catchExceptions) { - this.suite = suite; - this.dom = dom; - this.views = views; - this.jasmine = jasmine || {}; - this.catchExceptions = catchExceptions; + function specHref(result) { + return "?spec=" + encodeURIComponent(result.fullName); + } - this.element = this.createDom('div', { className: 'suite' }, - this.createDom('a', { className: 'description', href: this.jasmine.HtmlReporter.sectionLink(this.suite.getFullName(), catchExceptions) }, this.suite.description) - ); + function isFiltered() { + buildSpecFilter(); - this.appendToSummary(this.suite, this.element); -}; + return !!specFilterPattern; + } -jasmine.HtmlReporter.SuiteView.prototype.status = function() { - return this.getSpecStatus(this.suite); -}; + function buildSpecFilter() { + var specFilterParam = queryString.getParam("spec") || ""; -jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { - this.element.className += " " + this.status(); -}; + specFilterPattern = new RegExp(specFilterParam); + } -jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); + function setMenuModeTo(mode) { + htmlReporterMain.setAttribute("class", "html-reporter " + mode); + } +};jasmine.ResultsNode = function(result, type, parent) { + this.result = result; + this.type = type; + this.parent = parent; + this.children = []; + + this.addChild = function(result, type) { + this.children.push(new jasmine.ResultsNode(result, type, this)); + }; + + this.last = function() { + return this.children[this.children.length-1]; + } +};jasmine.QueryString = function(options) { + + this.setParam = function(key, value) { + var paramMap = queryStringToParamMap(); + paramMap[key] = value; + options.getWindowLocation().search = toQueryString(paramMap); + }; + + this.getParam = function(key) { + return queryStringToParamMap()[key]; + }; + + return this; + + function toQueryString(paramMap) { + var qStrPairs = []; + for (var prop in paramMap) { + qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop])); + } + return "?" + qStrPairs.join('&'); + } + + function queryStringToParamMap() { + var paramStr = options.getWindowLocation().search.substring(1), + params = [], + paramMap = {}; + + if (paramStr.length > 0) { + params = paramStr.split('&'); + for (var i = 0; i < params.length; i++) { + var p = params[i].split('='); + var value = decodeURIComponent(p[1]); + if (value === "true" || value === "false") { + value = JSON.parse(value); + } + paramMap[decodeURIComponent(p[0])] = value; + } + } + + return paramMap; + } + +}; \ No newline at end of file diff --git a/lib/jasmine-core/jasmine.css b/lib/jasmine-core/jasmine.css index 69e6db8b..91147778 100644 --- a/lib/jasmine-core/jasmine.css +++ b/lib/jasmine-core/jasmine.css @@ -1,52 +1,53 @@ body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } -#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } -#HTMLReporter a { text-decoration: none; } -#HTMLReporter a:hover { text-decoration: underline; } -#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; } -#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; } -#HTMLReporter #jasmine_content { position: fixed; right: 100%; } -#HTMLReporter .version { color: #aaaaaa; } -#HTMLReporter .banner { margin-top: 14px; } -#HTMLReporter .duration { color: #aaaaaa; float: right; } -#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; } -#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } -#HTMLReporter .symbolSummary li.passed { font-size: 14px; } -#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; } -#HTMLReporter .symbolSummary li.failed { line-height: 9px; } -#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } -#HTMLReporter .symbolSummary li.skipped { font-size: 14px; } -#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; } -#HTMLReporter .symbolSummary li.pending { line-height: 11px; } -#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; } -#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } -#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } -#HTMLReporter .runningAlert { background-color: #666666; } -#HTMLReporter .skippedAlert { background-color: #aaaaaa; } -#HTMLReporter .skippedAlert:first-child { background-color: #333333; } -#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; } -#HTMLReporter .passingAlert { background-color: #a6b779; } -#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; } -#HTMLReporter .failingAlert { background-color: #cf867e; } -#HTMLReporter .failingAlert:first-child { background-color: #b03911; } -#HTMLReporter .results { margin-top: 14px; } -#HTMLReporter #details { display: none; } -#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; } -#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } -#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } -#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } -#HTMLReporter.showDetails .summary { display: none; } -#HTMLReporter.showDetails #details { display: block; } -#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } -#HTMLReporter .summary { margin-top: 14px; } -#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; } -#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; } -#HTMLReporter .summary .specSummary.failed a { color: #b03911; } -#HTMLReporter .description + .suite { margin-top: 0; } -#HTMLReporter .suite { margin-top: 14px; } -#HTMLReporter .suite a { color: #333333; } -#HTMLReporter #details .specDetail { margin-bottom: 28px; } -#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; } -#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } -#HTMLReporter .resultMessage span.result { display: block; } -#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } +.html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } +.html-reporter a { text-decoration: none; } +.html-reporter a:hover { text-decoration: underline; } +.html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; } +.html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; } +.html-reporter .banner .version { margin-left: 14px; } +.html-reporter #jasmine_content { position: fixed; right: 100%; } +.html-reporter .version { color: #aaaaaa; } +.html-reporter .banner { margin-top: 14px; } +.html-reporter .duration { color: #aaaaaa; float: right; } +.html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; } +.html-reporter .symbol-summary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } +.html-reporter .symbol-summary li.passed { font-size: 14px; } +.html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; } +.html-reporter .symbol-summary li.failed { line-height: 9px; } +.html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } +.html-reporter .symbol-summary li.disabled { font-size: 14px; } +.html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; } +.html-reporter .symbol-summary li.pending { line-height: 11px; } +.html-reporter .symbol-summary li.pending:before { color: #aaaaaa; content: "-"; } +.html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } +.html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } +.html-reporter .bar.failed { background-color: #b03911; } +.html-reporter .bar.passed { background-color: #a6b779; } +.html-reporter .bar.skipped { background-color: #bababa; } +.html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; } +.html-reporter .bar.menu a { color: #333333; } +.html-reporter .bar a { color: white; } +.html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; } +.html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; } +.html-reporter .running-alert { background-color: #666666; } +.html-reporter .results { margin-top: 14px; } +.html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } +.html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } +.html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } +.html-reporter.showDetails .summary { display: none; } +.html-reporter.showDetails #details { display: block; } +.html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } +.html-reporter .summary { margin-top: 14px; } +.html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } +.html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; } +.html-reporter .summary li.passed a { color: #5e7d00; } +.html-reporter .summary li.failed a { color: #b03911; } +.html-reporter .description + .suite { margin-top: 0; } +.html-reporter .suite { margin-top: 14px; } +.html-reporter .suite a { color: #333333; } +.html-reporter .failures .spec-detail { margin-bottom: 28px; } +.html-reporter .failures .spec-detail .description { display: block; color: white; background-color: #b03911; } +.html-reporter .result-message { padding-top: 14px; color: #333333; } +.html-reporter .result-message span.result { display: block; } +.html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 73a7031a..e3db7790 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -439,15 +439,18 @@ jasmine.util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); return arrayOfArgs; -};jasmine.exceptionMessageFor = function(e) { - var message = e.name - + ': ' - + e.message - + ' in ' - + (e.fileName || e.sourceURL || '') - + ' (line ' - + (e.line || e.lineNumber || '') - + ')'; +};jasmine.exceptionFormatter = function(e) { + var file = e.fileName || e.sourceURL || '', + line = e.lineNumber || e.line || '', + message = e.toString(); + + if (file.length && line.length) { + message += ' (' + + file + + ':' + + line + + ')'; + } return message; }; @@ -463,11 +466,6 @@ jasmine.buildExpectationResult = function(params) { passed: params.passed }; }; -/** - * Environment for Jasmine - * - * @constructor - */ (function() { jasmine.Env = function(options) { options = options || {}; @@ -475,21 +473,23 @@ jasmine.buildExpectationResult = function(params) { var global = options.global || jasmine.getGlobal(); var catchExceptions = true; - var encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler()); - var suiteConstructor = jasmine.Suite; - var isSuite = function(thing) { - return thing instanceof suiteConstructor; - }; this.jasmine = jasmine; - this.currentRunner_ = new jasmine.Runner(this, isSuite); this.spies_ = []; this.currentSpec = null; + this.undefined = jasmine.undefined; - this.reporter = new jasmine.MultiReporter(); + this.reporter = new jasmine.ReportDispatcher([ + "jasmineStarted", + "jasmineDone", + "suiteStarted", + "suiteDone", + "specStarted", + "specDone" + ]); this.lastUpdate = 0; this.specFilter = function() { @@ -514,18 +514,18 @@ jasmine.buildExpectationResult = function(params) { return expect; }; - var startCallback = function(spec) { + var specStarted = function(spec) { self.currentSpec = spec; - self.reporter.reportSpecStarting(spec); + self.reporter.specStarted(spec.result); }; var beforeFns = function(currentSuite) { return function() { var befores = []; for (var suite = currentSuite; suite; suite = suite.parentSuite) { - befores = befores.concat(suite.before_) + befores = befores.concat(suite.beforeFns) } - return befores.concat(self.currentRunner_.before_).reverse(); + return befores.reverse(); } }; @@ -533,13 +533,13 @@ jasmine.buildExpectationResult = function(params) { return function() { var afters = []; for (var suite = currentSuite; suite; suite = suite.parentSuite) { - afters = afters.concat(suite.after_) + afters = afters.concat(suite.afterFns) } - return afters.concat(self.currentRunner_.after_) + return afters; } }; - var exceptionFormatter = jasmine.exceptionMessageFor; + var exceptionFormatter = jasmine.exceptionFormatter; var specConstructor = jasmine.Spec; @@ -552,15 +552,41 @@ jasmine.buildExpectationResult = function(params) { return buildExpectationResult(attrs); }; + // TODO: fix this naming, and here's where the value comes in this.catchExceptions = function(value) { - return catchExceptions = !!value; - } - - this.catchingExceptions = function(value) { + catchExceptions = !!value; return catchExceptions; + }; + + this.catchingExceptions = function() { + return catchExceptions; + }; + + var maximumSpecCallbackDepth = 100; + var currentSpecCallbackDepth = 0; + + function encourageGarbageCollection(fn) { + currentSpecCallbackDepth++; + if (currentSpecCallbackDepth > maximumSpecCallbackDepth) { + currentSpecCallbackDepth = 0; + global.setTimeout(fn, 0); + } else { + fn(); + } } + var queueRunnerFactory = function(options) { + options.catchingExceptions = self.catchingExceptions; + options.encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; + + new jasmine.QueueRunner(options).run(options.fns, 0); + }; + + + var totalSpecsDefined = 0; this.specFactory = function(description, fn, suite) { + totalSpecsDefined++; + var spec = new specConstructor({ id: self.nextSpecId(), beforeFns: beforeFns(suite), @@ -568,11 +594,13 @@ jasmine.buildExpectationResult = function(params) { expectationFactory: expectationFactory, exceptionFormatter: exceptionFormatter, resultCallback: specResultCallback, - getSpecName: function(spec) { return getSpecName(spec, suite) }, - startCallback: startCallback, + getSpecName: function(spec) { + return getSpecName(spec, suite) + }, + onStart: specStarted, description: description, - catchingExceptions: this.catchingExceptions, expectationResultFactory: expectationResultFactory, + queueRunner: queueRunnerFactory, fn: fn }); @@ -583,35 +611,49 @@ jasmine.buildExpectationResult = function(params) { return spec; function specResultCallback(result) { + self.removeAllSpies(); self.clock.uninstall(); self.currentSpec = null; - encourageGC(function() { - suite.specComplete(result); - }); + self.reporter.specDone(result); } - }; - var queueConstructor = jasmine.Queue; - var queueFactory = function() { - return new queueConstructor(self); - }; - this.suiteFactory = function(description, specDefinitions) { - return new suiteConstructor(self, description, specDefinitions, self.currentSuite, queueFactory, isSuite); + var suiteStarted = function(suite) { + self.reporter.suiteStarted(suite.result); }; - var maximumSpecCallbackDepth = 100; - var currentSpecCallbackDepth = 0; - function encourageGarbageCollection(fn) { - currentSpecCallbackDepth++; - if (currentSpecCallbackDepth > maximumSpecCallbackDepth) { - currentSpecCallbackDepth = 0; - global.setTimeout(fn, 0); - } else { - fn(); - } + var suiteConstructor = jasmine.Suite; - } + this.topSuite = new jasmine.Suite({ + env: this, + id: this.nextSuiteId(), + description: 'Jasmine__TopLevel__Suite', + queueRunner: queueRunnerFactory, + completeCallback: function() {}, // TODO - hook this up + resultCallback: function() {} // TODO - hook this up + }); + this.currentSuite = this.topSuite; + + this.suiteFactory = function(description) { + return new suiteConstructor({ + env: self, + id: self.nextSuiteId(), + description: description, + parentSuite: self.currentSuite, + queueRunner: queueRunnerFactory, + onStart: suiteStarted, + resultCallback: function(attrs) { + self.reporter.suiteDone(attrs); + } + }); + }; + + this.execute = function() { + this.reporter.jasmineStarted({ + totalSpecsDefined: totalSpecsDefined + }); + this.topSuite.execute(this.reporter.jasmineDone); + }; }; //TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc. @@ -624,10 +666,8 @@ jasmine.buildExpectationResult = function(params) { jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); this.matchersClass = newMatchersClass; }; - /** - * @returns an object containing jasmine version build info, if set. - */ - jasmine.Env.prototype.version = function () { + + jasmine.Env.prototype.version = function() { if (this.jasmine.version_) { return this.jasmine.version_; } else { @@ -636,7 +676,7 @@ jasmine.buildExpectationResult = function(params) { }; jasmine.Env.prototype.expect = function(actual) { - return this.currentSpec.expect(actual); + return this.currentSpec.expect(actual); }; jasmine.Env.prototype.spyOn = function(obj, methodName) { @@ -665,6 +705,7 @@ jasmine.buildExpectationResult = function(params) { return spyObj; }; + // TODO: move this to closure jasmine.Env.prototype.removeAllSpies = function() { for (var i = 0; i < this.spies_.length; i++) { var spy = this.spies_[i]; @@ -672,9 +713,8 @@ jasmine.buildExpectationResult = function(params) { } this.spies_ = []; }; - /** - * @returns string containing jasmine version build info, if set. - */ + + // TODO: move this to closure jasmine.Env.prototype.versionString = function() { if (!this.jasmine.version_) { return "version unknown"; @@ -689,48 +729,33 @@ jasmine.buildExpectationResult = function(params) { return versionString; }; - /** - * @returns a sequential integer starting at 0 - */ - jasmine.Env.prototype.nextSpecId = function () { + // TODO: move this to closure + jasmine.Env.prototype.nextSpecId = function() { return this.nextSpecId_++; }; - /** - * @returns a sequential integer starting at 0 - */ - jasmine.Env.prototype.nextSuiteId = function () { + // TODO: move this to closure + jasmine.Env.prototype.nextSuiteId = function() { return this.nextSuiteId_++; }; - /** - * Register a reporter to receive status updates from Jasmine. - * @param {jasmine.Reporter} reporter An object which will receive status updates. - */ + // TODO: move this to closure jasmine.Env.prototype.addReporter = function(reporter) { this.reporter.addReporter(reporter); }; - jasmine.Env.prototype.execute = function() { - this.currentRunner_.execute(); - }; - + // TODO: move this to closure jasmine.Env.prototype.describe = function(description, specDefinitions) { var suite = this.suiteFactory(description, specDefinitions); var parentSuite = this.currentSuite; - if (parentSuite) { - parentSuite.add(suite); - } else { - this.currentRunner_.addSuite(suite); - } - + parentSuite.addSuite(suite); this.currentSuite = suite; var declarationError = null; try { specDefinitions.call(suite); - } catch(e) { + } catch (e) { declarationError = e; } @@ -745,46 +770,40 @@ jasmine.buildExpectationResult = function(params) { return suite; }; - jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { - if (this.currentSuite) { - this.currentSuite.beforeEach(beforeEachFunction); - } else { - this.currentRunner_.beforeEach(beforeEachFunction); - } - }; - - jasmine.Env.prototype.currentRunner = function () { - return this.currentRunner_; - }; - - jasmine.Env.prototype.afterEach = function(afterEachFunction) { - if (this.currentSuite) { - this.currentSuite.afterEach(afterEachFunction); - } else { - this.currentRunner_.afterEach(afterEachFunction); - } - - }; - - jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { - return { - execute: function() { - } - }; + // TODO: move this to closure + jasmine.Env.prototype.xdescribe = function(description, specDefinitions) { + var suite = this.describe(description, specDefinitions); + suite.disable(); + return suite; }; + // TODO: move this to closure jasmine.Env.prototype.it = function(description, fn) { var spec = this.specFactory(description, fn, this.currentSuite); - this.currentSuite.add(spec); + this.currentSuite.addSpec(spec); return spec; }; - jasmine.Env.prototype.xit = function(desc, func) { - return { - id: this.nextSpecId(), - runs: function() { - } - }; + // TODO: move this to closure + jasmine.Env.prototype.xit = function(description, fn) { + var spec = this.it(description, fn); + spec.disable(); + return spec; + }; + + // TODO: move this to closure + jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { + this.currentSuite.beforeEach(beforeEachFunction); + }; + + // TODO: move this to closure + jasmine.Env.prototype.afterEach = function(afterEachFunction) { + this.currentSuite.afterEach(afterEachFunction); + }; + + // TODO: Still needed? + jasmine.Env.prototype.currentRunner = function() { + return this.topSuite; }; jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { @@ -918,142 +937,66 @@ jasmine.buildExpectationResult = function(params) { this.equalityTesters_.push(equalityTester); }; }()); -/** No-op base class for Jasmine reporters. - * - * @constructor - */ -jasmine.Reporter = function() { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerResults = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecStarting = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecResults = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.log = function(str) { -}; - -/** JavaScript API reporter. - * - * @constructor - */ jasmine.JsApiReporter = function(jasmine) { this.jasmine = jasmine || {}; this.started = false; this.finished = false; this.suites_ = []; this.results_ = {}; -}; -jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { - this.started = true; - var suites = runner.topLevelSuites(); - for (var i = 0; i < suites.length; i++) { - var suite = suites[i]; - this.suites_.push(this.summarize_(suite)); - } -}; + var status = 'loaded'; -jasmine.JsApiReporter.prototype.suites = function() { - return this.suites_; -}; - -jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { - var isSuite = suiteOrSpec instanceof this.jasmine.Suite; - var summary = { - id: suiteOrSpec.id, - name: suiteOrSpec.description, - type: isSuite ? 'suite' : 'spec', - children: [] + this.jasmineStarted = function() { + this.started = true; + status = 'started'; }; - if (isSuite) { - var children = suiteOrSpec.children(); - for (var i = 0; i < children.length; i++) { - summary.children.push(this.summarize_(children[i])); - } - } - return summary; -}; - -jasmine.JsApiReporter.prototype.results = function() { - return this.results_; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { - this.finished = true; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSpecResults = function(result) { - this.results_[result.id] = { - messages: result.failedExpectations, - //result is status - result: result.status + this.jasmineDone = function() { + this.finished = true; + status = 'done'; }; -}; -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.log = function(str) { -}; - -//TODO: make work with new presenter. -jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ - var results = {}; - for (var i = 0; i < specIds.length; i++) { - var specId = specIds[i]; - results[specId] = this.summarizeResult_(this.results_[specId]); - } - return results; -}; - -jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ - var summaryMessages = []; - var messagesLength = result.messages.length; - for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { - var resultMessage = result.messages[messageIndex]; - //TODO: use result presenter here, not a bunch of spec crap - summaryMessages.push({ - //TODO: remove text. - text: resultMessage.type == 'log' ? resultMessage.toString() : this.jasmine.undefined, - //TODO: wat? in theory this is saying non-expect results should always be considered passed, but that's weird. - passed: resultMessage.passed || true, //status === 'passed' - type: resultMessage.type, - message: resultMessage.message, - trace: { - stack: !resultMessage.passed ? resultMessage.trace.stack : this.jasmine.undefined - } - }); - } - - return { - result : result.result, - messages : summaryMessages + this.status = function() { + return status; }; -}; -/** + var suites = {}; + + this.suiteStarted = function(result) { + storeSuite(result); + }; + + this.suiteDone = function(result) { + storeSuite(result); + }; + + function storeSuite(result) { + suites[result.id] = result; + } + + this.suites = function() { + return suites; + }; + + var specs = {}; + + this.specStarted = function(result) { + storeSpec(result); + }; + + this.specDone = function(result) { + storeSpec(result); + }; + + function storeSpec(result) { + specs[result.id] = result; + } + + this.specs = function() { + return specs; + }; + +};/** * @constructor * @param {jasmine.Env} env * @param actual @@ -1450,41 +1393,6 @@ jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mis jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () { return ""; }; -/** - * @constructor - */ -jasmine.MultiReporter = function() { - this.subReporters_ = []; -}; -jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); - -jasmine.MultiReporter.prototype.addReporter = function(reporter) { - this.subReporters_.push(reporter); -}; - -(function() { - var functionNames = [ - "reportRunnerStarting", - "reportRunnerResults", - "reportSuiteResults", - "reportSpecStarting", - "reportSpecResults", - "log" - ]; - for (var i = 0; i < functionNames.length; i++) { - var functionName = functionNames[i]; - jasmine.MultiReporter.prototype[functionName] = (function(functionName) { - return function() { - for (var j = 0; j < this.subReporters_.length; j++) { - var subReporter = this.subReporters_[j]; - if (subReporter[functionName]) { - subReporter[functionName].apply(subReporter, arguments); - } - } - }; - })(functionName); - } -})(); /** * Base class for pretty printing for expectation results. */ @@ -1615,218 +1523,76 @@ jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { jasmine.StringPrettyPrinter.prototype.append = function(value) { this.string += value; }; -jasmine.Queue = function(env) { - this.env = env; - - // parallel to blocks. each true value in this array means the block will - // get executed even if we abort - this.ensured = []; - this.blocks = []; - this.running = false; - this.index = 0; - this.offset = 0; - this.abort = false; +jasmine.QueueRunner = function(attrs) { + this.fns = attrs.fns || []; + this.onComplete = attrs.onComplete || function() {}; + this.encourageGC = attrs.encourageGC || function(fn) {fn()}; + this.onException = attrs.onException || function() {}; + this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; }; -jasmine.Queue.prototype.addBefore = function(block, ensure) { - if (ensure === this.env.undefined) { - ensure = false; +jasmine.QueueRunner.prototype.execute = function() { + this.run(this.fns, 0) +}; + +jasmine.QueueRunner.prototype.run = function(fns, index) { + if (index >= fns.length) { + this.encourageGC(this.onComplete); + return; } - this.blocks.unshift(block); - this.ensured.unshift(ensure); -}; - -jasmine.Queue.prototype.add = function(block, ensure) { - if (ensure === this.env.undefined) { - ensure = false; - } - - this.blocks.push(block); - this.ensured.push(ensure); -}; - -jasmine.Queue.prototype.insertNext = function(block, ensure) { - if (ensure === this.env.undefined) { - ensure = false; - } - - this.ensured.splice((this.index + this.offset + 1), 0, ensure); - this.blocks.splice((this.index + this.offset + 1), 0, block); - this.offset++; -}; - -jasmine.Queue.prototype.start = function(onComplete) { - this.running = true; - this.onComplete = onComplete; - this.next_(); -}; - -jasmine.Queue.prototype.isRunning = function() { - return this.running; -}; - -jasmine.Queue.LOOP_DONT_RECURSE = true; - -jasmine.Queue.prototype.incrementQueue = function() { - if (this.blocks[this.index].abort) { - this.abort = true; - } - this.offset = 0; - this.index++; - this.next_(); -} - -jasmine.Queue.prototype.next_ = function() { + var fn = fns[index]; var self = this; - // var goAgain = true; + if (fn.length > 0) { + attempt(function() { fn.call(self, function() { self.run(fns, index + 1) }) }); + } else { + attempt(function() { fn.call(self); }); + self.run(fns, index + 1); + } - // while (goAgain) { - // goAgain = false; - - if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { - // var calledSynchronously = true; - // var completedSynchronously = false; - - // var onComplete = function () { - // if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { - // completedSynchronously = true; - // return; - // } - - self.blocks[self.index].execute(function() { self.incrementQueue() }); - - - // var now = new Date().getTime(); - // if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { - // self.env.lastUpdate = now; - // self.env.setTimeout(function() { - // self.next_(); - // }, 0); - // } else { - // if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { - // goAgain = true; - // } else { - // self.next_(); - // } - // } - // }; - // self.blocks[self.index].execute(function() { self.next_(); }); - - // calledSynchronously = false; - // if (completedSynchronously) { - // onComplete(); - // } - - } else { - self.running = false; - if (self.onComplete) { - self.onComplete(); + function attempt(fn) { + try { + fn(); + } catch (e) { + self.onException(e); + if (!self.catchingExceptions()) { + //TODO: set a var when we catch an exception and + //use a finally block to close the loop in a nice way.. + throw e; } } - // } -}; -//TODO: runner is a special case of suite. -/** - * Runner - * - * @constructor - * @param {jasmine.Env} env - */ -jasmine.Runner = function(env, isSuite) { - var self = this; - self.env = env; - self.queue = new jasmine.Queue(env); - self.before_ = []; - self.after_ = []; - self.suites_ = []; - self.isSuite = isSuite || function() {}; -}; - -jasmine.Runner.prototype.execute = function() { - var self = this; - if (self.env.reporter.reportRunnerStarting) { - self.env.reporter.reportRunnerStarting(this); } - self.queue.start(function () { - self.finishCallback(); - }); -}; - -jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.splice(0,0,beforeEachFunction); -}; - -jasmine.Runner.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.splice(0,0,afterEachFunction); -}; - - -jasmine.Runner.prototype.finishCallback = function() { - this.env.reporter.reportRunnerResults(this); -}; - -jasmine.Runner.prototype.addSuite = function(suite) { - this.suites_.push(suite); - this.queue.add(suite); -}; - - -//TODO: runner should die a slow unhappy death. -//Nobody should ever call instanceof. -jasmine.Runner.prototype.add = function(block) { - if (this.isSuite(block)) { - this.addSuite(block); - } else { - this.queue.add(block); - } -}; - -jasmine.Runner.prototype.specs = function () { - var suites = this.suites(); - var specs = []; - for (var i = 0; i < suites.length; i++) { - specs = specs.concat(suites[i].specs()); - } - return specs; -}; - -jasmine.Runner.prototype.suites = function() { - return this.suites_; -}; - -jasmine.Runner.prototype.topLevelSuites = function() { - var topLevelSuites = []; - for (var i = 0; i < this.suites_.length; i++) { - if (!this.suites_[i].parentSuite) { - topLevelSuites.push(this.suites_[i]); - } - } - return topLevelSuites; }; jasmine.Spec = function(attrs) { - this.failedExpectations = []; this.encounteredExpectations = false; this.expectationFactory = attrs.expectationFactory; - this.resultCallback = attrs.resultCallback || function() {}; + this.resultCallback = attrs.resultCallback || function() {}; this.id = attrs.id; - this.description = attrs.description; + this.description = attrs.description || ''; this.fn = attrs.fn; this.beforeFns = attrs.beforeFns || function() {}; this.afterFns = attrs.afterFns || function() {}; this.catchingExceptions = attrs.catchingExceptions; - this.startCallback = attrs.startCallback || function() {}; + this.onStart = attrs.onStart || function() {}; this.exceptionFormatter = attrs.exceptionFormatter || function() {}; - this.getSpecName = attrs.getSpecName; + this.getSpecName = attrs.getSpecName || function() { return ''; }; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; + this.queueRunner = attrs.queueRunner || { execute: function() {}}; + this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; + + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + status: this.status(), + failedExpectations: [] + }; }; jasmine.Spec.prototype.addExpectationResult = function(passed, data) { this.encounteredExpectations = true; if (!passed) { - this.failedExpectations.push(data); + this.result.failedExpectations.push(data); } }; @@ -1834,26 +1600,22 @@ jasmine.Spec.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; -jasmine.Spec.prototype.execute = function() { +jasmine.Spec.prototype.execute = function(onComplete) { var self = this; + if (this.disabled) { - resultCallback(); + complete(); return; } var befores = this.beforeFns() || [], - afters = this.afterFns() || []; - this.startCallback(this); + afters = this.afterFns() || []; var allFns = befores.concat(this.fn).concat(afters); - queueRunner(allFns, 0); - - function attempt(fn) { - try { - fn(); - } catch (e) { - //TODO: weird. buildExpectationResult is really a presenter for expectations - //so this should take an expectation object. + this.onStart(this); + this.queueRunner({ + fns: allFns, + onException: function(e) { self.addExpectationResult(false, self.expectationResultFactory({ matcherName: "", passed: false, @@ -1862,35 +1624,17 @@ jasmine.Spec.prototype.execute = function() { message: self.exceptionFormatter(e), trace: e })); - if (!self.catchingExceptions()) { - //TODO: set a var when we catch an exception and - //use a finally block to close the loop in a nice way.. - throw e; - } - } - } + }, + onComplete: complete + }); - function queueRunner(allFns, index) { - if (index >= allFns.length) { - resultCallback(); - return; - } - var fn = allFns[index]; - if (fn.length > 0) { - attempt(function() { fn.call(self, function() { queueRunner(allFns, index + 1) }) }); - } else { - attempt(function() { fn.call(self); }); - queueRunner(allFns, index + 1); - } - } + function complete() { + self.result.status = self.status(); + self.resultCallback(self.result); - function resultCallback() { - self.resultCallback({ - id: self.id, - status: self.status(), - description: self.description, - failedExpectations: self.failedExpectations - }); + if (onComplete) { + onComplete(); + } } }; @@ -1906,7 +1650,8 @@ jasmine.Spec.prototype.status = function() { if (!this.encounteredExpectations) { return null; } - if (this.failedExpectations.length > 0) { + + if (this.result.failedExpectations.length > 0) { return 'failed'; } else { return 'passed'; @@ -1915,85 +1660,65 @@ jasmine.Spec.prototype.status = function() { jasmine.Spec.prototype.getFullName = function() { return this.getSpecName(this); -} -/** - * Internal representation of a Jasmine suite. - * - * @constructor - * @param {jasmine.Env} env - * @param {String} description - * @param {Function} specDefinitions - * @param {jasmine.Suite} parentSuite - */ -jasmine.Suite = function(env, description, specDefinitions, parentSuite, queueFactory, isSuite) { - var self = this; - //TODO: remove once we unit test Suite - var queueFactory = queueFactory || function() {}; - self.id = env.nextSuiteId ? env.nextSuiteId() : null; - self.description = description; - self.queue = queueFactory(); - self.parentSuite = parentSuite; - self.env = env; - self.isSuite = isSuite || function() {}; - self.before_ = []; - self.after_ = []; - self.children_ = []; - self.suites_ = []; - self.specs_ = []; +}; +jasmine.Suite = function(attrs) { + this.env = attrs.env; + this.id = attrs.id; + this.parentSuite = attrs.parentSuite; + this.description = attrs.description; + this.onStart = attrs.onStart || function() {}; + this.completeCallback = attrs.completeCallback || function() {}; + this.resultCallback = attrs.resultCallback || function() {}; + this.encourageGC = attrs.encourageGC || function(fn) {fn();}; + + this.beforeFns = []; + this.afterFns = []; + this.queueRunner = attrs.queueRunner || function() {}; + this.disabled = false; + + this.children_ = []; // TODO: rename + this.suites = []; // TODO: needed? + this.specs = []; // TODO: needed? + + this.result = { + id: this.id, + status: this.disabled ? 'disabled' : '', + description: this.description, + fullName: this.getFullName() + }; }; jasmine.Suite.prototype.getFullName = function() { var fullName = this.description; for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { - fullName = parentSuite.description + ' ' + fullName; + if (parentSuite.parentSuite) { + fullName = parentSuite.description + ' ' + fullName; + } } return fullName; }; -jasmine.Suite.prototype.finish = function(onComplete) { - this.env.reporter.reportSuiteResults(this); - this.finished = true; - if (typeof(onComplete) == 'function') { - onComplete(); - } +jasmine.Suite.prototype.disable = function() { + this.disabled = true; }; -jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.unshift(beforeEachFunction); +jasmine.Suite.prototype.beforeEach = function(fn) { + this.beforeFns.unshift(fn); }; -jasmine.Suite.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.unshift(afterEachFunction); +jasmine.Suite.prototype.afterEach = function(fn) { + this.afterFns.unshift(fn); }; -//TODO: interface should be addSpec or addSuite methods. -jasmine.Suite.prototype.add = function(suiteOrSpec) { - this.children_.push(suiteOrSpec); - if (this.isSuite(suiteOrSpec)) { - this.suites_.push(suiteOrSpec); - this.env.currentRunner().addSuite(suiteOrSpec); - } else { - this.specs_.push(suiteOrSpec); - } - this.queue.add(suiteOrSpec); +jasmine.Suite.prototype.addSpec = function(spec) { + this.children_.push(spec); + this.specs.push(spec); // TODO: needed? }; -jasmine.Suite.prototype.specComplete = function(specResult) { - specResult.fullName = this.getFullName() + ' ' + specResult.description + '.'; - specResult.suite = this; - this.env.removeAllSpies(); - this.env.reporter.reportSpecResults(specResult); - this.queue.incrementQueue(); -}; - -jasmine.Suite.prototype.specs = function() { - return this.specs_; -}; - -jasmine.Suite.prototype.suites = function() { - return this.suites_; +jasmine.Suite.prototype.addSuite = function(suite) { + suite.parentSuite = this; + this.children_.push(suite); + this.suites.push(suite); // TODO: needed? }; jasmine.Suite.prototype.children = function() { @@ -2002,26 +1727,55 @@ jasmine.Suite.prototype.children = function() { jasmine.Suite.prototype.execute = function(onComplete) { var self = this; - this.queue.start(function () { - self.finish(onComplete); + if (this.disabled) { + complete(); + return; + } + + var allFns = [], + children = this.children_; + + for (var i = 0; i < children.length; i++) { + allFns.push(wrapChild(children[i])); + + function wrapChild(child) { + return function(done) { + child.execute(done); + } + } + } + + this.onStart(this); + + this.queueRunner({ + fns: allFns, + onComplete: complete }); + + function complete() { + self.resultCallback(self.result); + + if (onComplete) { + onComplete(); + } + } }; jasmine.Clock = function(global, delayedFunctionScheduler) { var self = this, - realTimingFunctions = { - setTimeout: global.setTimeout, - clearTimeout: global.clearTimeout, - setInterval: global.setInterval, - clearInterval: global.clearInterval - }, - fakeTimingFunctions = { - setTimeout: setTimeout, - clearTimeout: clearTimeout, - setInterval: setInterval, - clearInterval: clearInterval - }, - timer = realTimingFunctions, - installed = false; + realTimingFunctions = { + setTimeout: global.setTimeout, + clearTimeout: global.clearTimeout, + setInterval: global.setInterval, + clearInterval: global.clearInterval + }, + fakeTimingFunctions = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setInterval: setInterval, + clearInterval: clearInterval + }, + timer = realTimingFunctions, + installed = false; self.install = function() { installed = true; @@ -2080,7 +1834,7 @@ jasmine.Clock = function(global, delayedFunctionScheduler) { } function setTimeout(fn, delay) { - return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments,2)); + return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2)); } function clearTimeout(id) { @@ -2201,7 +1955,36 @@ jasmine.DelayedFunctionScheduler = function() { } } }; +jasmine.ReportDispatcher = function(methods) { + var dispatchedMethods = methods || []; + + for (var i = 0; i < dispatchedMethods.length; i++) { + var method = dispatchedMethods[i]; + this[method] = function(m) { + return function() { + dispatch(m, arguments); + }; + }(method); + } + + var reporters = []; + + this.addReporter = function(reporter) { + reporters.push(reporter); + }; + + return this; + + function dispatch(method, args) { + for (var i = 0; i < reporters.length; i++) { + var reporter = reporters[i]; + if (reporter[method]) { + reporter[method].apply(reporter, args); + } + } + } +}; jasmine.version_= { "major": 1, "minor": 3, diff --git a/spec/console/ConsoleReporterSpec.js b/spec/console/ConsoleReporterSpec.js index 9b705b42..07ca1427 100644 --- a/spec/console/ConsoleReporterSpec.js +++ b/spec/console/ConsoleReporterSpec.js @@ -1,292 +1,207 @@ describe("ConsoleReporter", function() { - //keep these literal. otherwise the test loses value as a test. - function green(str) { - return '\033[32m' + str + '\033[0m'; - } - - function red(str) { - return '\033[31m' + str + '\033[0m'; - } - - function yellow(str) { - return '\033[33m' + str + '\033[0m'; - } - - function prefixGreen(str) { - return '\033[32m' + str; - } - - function prefixRed(str) { - return '\033[31m' + str; - } - - var newline = "\n"; - - var passingSpec = { status: 'passed' }, - failingSpec = { status: 'failed' }, - skippedSpec = { status: 'disabled' }, - passingRun = { - specs: function() { - return [null, null, null]; - }, - results: function() { - return {failedCount: 0, items_: [null, null, null]}; - } - }, - failingRun = { - specs: function() { - return [null, null, null]; - }, - results: function() { - return { - failedCount: 7, items_: [null, null, null]}; - } - }; - - function repeatedlyInvoke(f, times) { - for (var i = 0; i < times; i++) f(times + 1); - } - - function repeat(thing, times) { - var arr = []; - for (var i = 0; i < times; i++) arr.push(thing); - return arr; - } - - function simulateRun(reporter, specResults, suiteResults, finalRunner, startTime, endTime) { - reporter.reportRunnerStarting(); - for (var i = 0; i < specResults.length; i++) { - reporter.reportSpecResults(specResults[i]); - } - for (i = 0; i < suiteResults.length; i++) { - reporter.reportSuiteResults(suiteResults[i]); - } - reporter.runnerStartTime = startTime; - reporter.now = function() { - return endTime; - }; - reporter.reportRunnerResults(finalRunner); - } - - var reporter, out, done; + var out; beforeEach(function() { out = (function() { var output = ""; return { - print:function(str) { + print: function(str) { output += str; }, - getOutput:function() { + getOutput: function() { return output; }, clear: function() { output = ""; } }; - })(); - - done = false; - reporter = new jasmine.ConsoleReporter(out.print, function(runner) { - done = true - }); + }()); }); - - describe('Integration', function() { - it("prints the proper output under a pass scenario - small numbers.", function() { - simulateRun(reporter, - repeat(passingSpec, 3), - [], - { }, - 1000, - 1777 - ); - - var output = out.getOutput(); - expect(output).toMatch(/^Started/); - expect(output).toMatch(/\.\.\./); - expect(output).toMatch(/3 specs, 0 failures/); + it("reports that the suite has started to the console", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print }); - it("prints the proper output under a pass scenario. large numbers.", function() { - simulateRun(reporter, - repeat(passingSpec, 57), - [], - {}, - 1000, - 1777); + reporter.jasmineStarted(); - var output = out.getOutput(); - expect(output).toMatch(/^Started/); - expect(output).toMatch(/\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\./); - expect(output).toMatch(/57 specs, 0 failures/); - }); - - it("prints the proper output under a failure scenario.", function() { - var base1 = extend({}, failingSpec), - failingSpec1 = extend(base1, { - fullName: 'The oven heats up', - failedExpectations: [ - {trace:{stack:"stack trace one\n second line"}}, - {trace:{stack:"stack trace two"}} - ]}), - base2 = extend({}, failingSpec), - failingSpec2 = extend(base2, { - fullName: "The washing machine washes clothes", - failedExpectations: [ - {trace:{stack:"stack trace one"}} - ]}); - - simulateRun(reporter, - [failingSpec1, passingSpec, failingSpec2], - [ - {description:"The oven", - results:function() { - return { - items_:[ - {failedCount:2, - description:"heats up", - items_:[ - {trace:{stack:"stack trace one\n second line"}}, - {trace:{stack:"stack trace two"}} - ]} - ] - }; - }}, - {description:"The washing machine", - results:function() { - return { - items_:[ - {failedCount:2, - description:"washes clothes", - items_:[ - {trace:{stack:"stack trace one"}} - ]} - ] - }; - }} - ], - { - specs: function() { - return [null, null, null]; - }, - results:function() { - return { - items_: [null, null, null], - totalCount: 7, - failedCount: 2 - }; - } - }, - 1000, - 1777); - - var output = out.getOutput(); - expect(output).toMatch(/^Started/); - expect(output).toMatch(/F\.F/); - expect(output).toMatch(/The oven heats up\n stack trace one\n second line\n stack trace two/); - expect(output).toMatch(/The washing machine washes clothes\n stack trace one/); - expect(output).toMatch(/3 specs, 2 failures/); - }); + expect(out.getOutput()).toEqual("Started\n"); }); - describe('When a Jasmine environment executes', function() { - beforeEach(function() { - reporter.reportRunnerStarting(); + it("reports a passing spec as a dot", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print }); - it("should print 'Started' to the console", function() { - expect(out.getOutput()).toEqual("Started" + newline); + reporter.specDone({status: "passed"}); + + expect(out.getOutput()).toEqual("."); + }); + + it("does not report a disabled spec", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print }); - describe('when a spec reports', function() { - beforeEach(function() { - out.clear(); - }); + reporter.specDone({status: "disabled"}); - it("prints a green dot if the spec passes", function() { - reporter.reportSpecResults(passingSpec); + expect(out.getOutput()).toEqual(""); + }); - expect(out.getOutput()).toMatch(/\./); - }); - - it("prints a red dot if the spec fails", function() { - reporter.reportSpecResults(failingSpec); - - expect(out.getOutput()).toMatch(/F/); - }); - - it("prints a yellow star if the spec was skipped", function() { - reporter.reportSpecResults(skippedSpec); - - expect(out.getOutput()).toMatch(/\*/); - }); + it("reports a failing spec as an 'F'", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print }); + reporter.specDone({status: "failed"}); - describe('and finishes', function() { + expect(out.getOutput()).toEqual("F"); + }); - describe('when reporting the execution time', function() { + it("reports a summary when done (singluar spec and time)", function() { + var fakeNow = jasmine.createSpy('fake Date.now'), + reporter = new jasmine.ConsoleReporter({ + print: out.print, + now: fakeNow + }); - it("prints the full finished message", function() { - reporter.now = function() { - return 1000; - }; - reporter.reportRunnerStarting(); - reporter.now = function() { - return 1777; - }; - reporter.reportRunnerResults(failingRun); - expect(out.getOutput()).toContain("Finished in 0.777 seconds"); - }); + fakeNow.andReturn(500); - it("prints round time numbers correctly", function() { - function run(startTime, endTime) { - out.clear(); - reporter.runnerStartTime = startTime; - reporter.now = function() { - return endTime; - }; - reporter.reportRunnerResults(passingRun); + reporter.jasmineStarted(); + reporter.specDone({status: "passed"}); + fakeNow.andReturn(1500); + + out.clear(); + reporter.jasmineDone(); + + expect(out.getOutput()).toMatch(/1 spec, 0 failures/); + expect(out.getOutput()).toMatch("Finished in 1 second\n"); + }); + + it("reports a summary when done (pluralized specs and seconds)", function() { + var fakeNow = jasmine.createSpy('fake Date.now'), + reporter = new jasmine.ConsoleReporter({ + print: out.print, + now: fakeNow + }); + + fakeNow.andReturn(500); + reporter.jasmineStarted(); + reporter.specDone({status: "passed"}); + reporter.specDone({ + status: "failed", + description: "with a failing spec", + fullName: "A suite with a failing spec", + failedExpectations: [ + { + passed: false, + message: "Expected true to be false.", + expected: false, + actual: true, + trace: { + stack: "foo\nbar\nbaz" } - - run(1000, 11000); - expect(out.getOutput()).toContain("10 seconds"); - - run(1000, 2000); - expect(out.getOutput()).toContain("1 seconds"); - - run(1000, 1100); - expect(out.getOutput()).toContain("0.1 seconds"); - - run(1000, 1010); - expect(out.getOutput()).toContain("0.01 seconds"); - - run(1000, 1001); - expect(out.getOutput()).toContain("0.001 seconds"); - }); - }); - - describe("done callback", function() { - it("calls back when done", function() { - expect(done).toBeFalsy(); - reporter.reportRunnerResults({ - specs: function() { - return [null, null, null]; - }, - results:function() { - return {items_: [null, null, null], totalCount: 7, failedCount: 0}; - } - }); - expect(done).toBeTruthy(); - }); - }); + } + ] }); + + out.clear(); + + fakeNow.andReturn(600); + reporter.jasmineDone(); + + expect(out.getOutput()).toMatch(/2 specs, 1 failure/); + expect(out.getOutput()).toMatch("Finished in 0.1 seconds\n"); }); - function extend(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; - } + it("reports a summary when done that includes stack traces for a failing suite", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print + }); + + reporter.jasmineStarted(); + reporter.specDone({status: "passed"}); + reporter.specDone({ + status: "failed", + description: "with a failing spec", + fullName: "A suite with a failing spec", + failedExpectations: [ + { + passed: false, + message: "Expected true to be false.", + expected: false, + actual: true, + trace: { + stack: "foo bar baz" + } + } + ] + }); + + out.clear(); + + reporter.jasmineDone(); + + expect(out.getOutput()).toMatch(/foo bar baz/); + }); + + it("calls the onComplete callback when the suite is done", function() { + var onComplete = jasmine.createSpy('onComplete'), + reporter = new jasmine.ConsoleReporter({ + print: out.print, + onComplete: onComplete + }); + + reporter.jasmineDone(); + + expect(onComplete).toHaveBeenCalled(); + }); + + + describe("with color", function() { + + it("reports that the suite has started to the console", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print, + showColors: true + }); + + reporter.jasmineStarted(); + + expect(out.getOutput()).toEqual("Started\n"); + }); + + it("reports a passing spec as a dot", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print, + showColors: true + }); + + reporter.specDone({status: "passed"}); + + expect(out.getOutput()).toEqual("\033[32m.\033[0m"); + }); + + it("does not report a disabled spec", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print, + showColors: true + }); + + reporter.specDone({status: 'disabled'}); + + expect(out.getOutput()).toEqual(""); + }); + + it("reports a failing spec as an 'F'", function() { + var reporter = new jasmine.ConsoleReporter({ + print: out.print, + showColors: true + }); + + reporter.specDone({status: 'failed'}); + + expect(out.getOutput()).toEqual("\033[31mF\033[0m"); + }); + }); }); diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 32c734c6..b9611489 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -1,12 +1,13 @@ -describe("jasmine.Env", function() { +// TODO: Fix these unit tests! +describe("Env", function() { var env; beforeEach(function() { env = new jasmine.Env(); env.updateInterval = 0; }); - describe('ids', function () { - it('nextSpecId should return consecutive integers, starting at 0', function () { + describe('ids', function() { + it('nextSpecId should return consecutive integers, starting at 0', function() { expect(env.nextSpecId()).toEqual(0); expect(env.nextSpecId()).toEqual(1); expect(env.nextSpecId()).toEqual(2); @@ -17,21 +18,21 @@ describe("jasmine.Env", function() { var fakeReporter; beforeEach(function() { - fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log"]); + fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["jasmineStarted"]); }); - describe('version', function () { + describe('version', function() { var oldVersion; - beforeEach(function () { + beforeEach(function() { oldVersion = jasmine.version_; }); - afterEach(function () { + afterEach(function() { jasmine.version_ = oldVersion; }); - it('should raise an error if version is not set', function () { + it('should raise an error if version is not set', function() { jasmine.version_ = null; var exception; try { @@ -79,8 +80,8 @@ describe("jasmine.Env", function() { it("should allow reporters to be registered", function() { env.addReporter(fakeReporter); - env.reporter.log("message"); - expect(fakeReporter.log).toHaveBeenCalledWith("message"); + env.reporter.jasmineStarted(); + expect(fakeReporter.jasmineStarted).toHaveBeenCalled(); }); }); @@ -138,8 +139,12 @@ describe("jasmine.Env", function() { describe("even if there are several", function() { beforeEach(function() { - env.addEqualityTester(function(a, b) { return jasmine.undefined; }); - env.addEqualityTester(function(a, b) { return jasmine.undefined; }); + env.addEqualityTester(function(a, b) { + return jasmine.undefined; + }); + env.addEqualityTester(function(a, b) { + return jasmine.undefined; + }); }); it("should use normal equality rules", function() { @@ -151,61 +156,180 @@ describe("jasmine.Env", function() { it("should evaluate custom equality testers in the order they are declared", function() { isEqual = false; - env.addEqualityTester(function(a, b) { return true; }); + env.addEqualityTester(function(a, b) { + return true; + }); expect(env.equals_('abc', 'abc')).toBeFalsy(); }); }); }); }); -describe("jasmine Env (integration)", function() { +describe("Env (integration)", function() { + + it("Suites execute as expected (no nesting)", function() { + var env = new jasmine.Env(), + calls = []; + + env.describe("A Suite", function() { + env.it("with a spec", function() { + calls.push("with a spec"); + }); + env.it("and another spec", function() { + calls.push("and another spec"); + }); + }); + + env.execute(); + + expect(calls).toEqual([ + "with a spec", + "and another spec" + ]); + }); + + it("Nested Suites execute as expected", function() { + var env = new jasmine.Env(), + calls = []; + + env.describe("Outer suite", function() { + env.it("an outer spec", function() { + calls.push('an outer spec') + }); + env.describe("Inner suite", function() { + env.it("an inner spec", function() { + calls.push('an inner spec'); + }); + env.it("another inner spec", function() { + calls.push('another inner spec'); + }); + }); + }); + + env.execute(); + + expect(calls).toEqual([ + 'an outer spec', + 'an inner spec', + 'another inner spec' + ]); + + }); + + it("Multiple top-level Suites execute as expected", function() { + var env = new jasmine.Env(), + calls = []; + + env.describe("Outer suite", function() { + env.it("an outer spec", function() { + calls.push('an outer spec') + }); + env.describe("Inner suite", function() { + env.it("an inner spec", function() { + calls.push('an inner spec'); + }); + env.it("another inner spec", function() { + calls.push('another inner spec'); + }); + }); + }); + + env.describe("Another outer suite", function() { + env.it("a 2nd outer spec", function() { + calls.push('a 2nd outer spec') + }); + }); + + env.execute(); + + expect(calls).toEqual([ + 'an outer spec', + 'an inner spec', + 'another inner spec', + 'a 2nd outer spec' + ]); + }); it("Mock clock can be installed and used in tests", function() { - var setTimeout = jasmine.createSpy('setTimeout'), - globalTimeoutFn = jasmine.createSpy('globalTimeoutFn'), - fakeTimeoutFn = jasmine.createSpy('fakeTimeoutFn'), - env = new jasmine.Env({global: { setTimeout: setTimeout }}); + var globalSetTimeout = jasmine.createSpy('globalSetTimeout'), + delayedFunctionForGlobalClock = jasmine.createSpy('delayedFunctionForGlobalClock'), + delayedFunctionForMockClock = jasmine.createSpy('delayedFunctionForMockClock'), + env = new jasmine.Env({global: { setTimeout: globalSetTimeout }}); env.describe("tests", function() { env.it("test with mock clock", function() { env.clock.install(); - env.clock.setTimeout(fakeTimeoutFn, 100); + env.clock.setTimeout(delayedFunctionForMockClock, 100); env.clock.tick(100); }); env.it("test without mock clock", function() { - env.clock.setTimeout(globalTimeoutFn, 100); + env.clock.setTimeout(delayedFunctionForGlobalClock, 100); }); }); - expect(setTimeout).not.toHaveBeenCalled(); - expect(fakeTimeoutFn).not.toHaveBeenCalled(); + expect(globalSetTimeout).not.toHaveBeenCalled(); + expect(delayedFunctionForMockClock).not.toHaveBeenCalled(); env.execute(); - expect(fakeTimeoutFn).toHaveBeenCalled(); - expect(setTimeout).toHaveBeenCalledWith(globalTimeoutFn, 100); + expect(delayedFunctionForMockClock).toHaveBeenCalled(); + expect(globalSetTimeout).toHaveBeenCalledWith(delayedFunctionForGlobalClock, 100); + }); + + it("should report as expected", function() { + var env = new jasmine.Env(), + reporter = jasmine.createSpyObj('fakeReproter', [ + "jasmineStarted", + "jasmineDone", + "suiteStarted", + "suiteDone", + "specStarted", + "specDone" + ]); + + env.addReporter(reporter); + + env.describe("A Suite", function() { + env.it("with a top level spec", function() { + env.expect(true).toBe(true); + }); + env.describe("with a nested suite", function() { + env.xit("with a disabled spec", function() { + env.expect(true).toBe(true); + }); + env.it("with a spec", function() { + env.expect(true).toBe(false); + }); + }); + }); + + env.execute(); + + expect(reporter.jasmineStarted).toHaveBeenCalledWith({ + totalSpecsDefined: 3 + }); + var suiteResult = reporter.suiteStarted.calls[0].args[0]; + expect(suiteResult.description).toEqual("A Suite"); + expect(reporter.jasmineDone).toHaveBeenCalled(); }); it("should be possible to get full name from a spec", function() { var env = new jasmine.Env({global: { setTimeout: setTimeout }}), - topLevelSpec, nestedSpec, doublyNestedSpec; + topLevelSpec, nestedSpec, doublyNestedSpec; env.describe("my tests", function() { topLevelSpec = env.it("are sometimes top level", function() { }); env.describe("are sometimes", function() { nestedSpec = env.it("singly nested", function() { - }); env.describe("even", function() { doublyNestedSpec = env.it("doubly nested", function() { - }); }); }); }); - env.execute(); expect(topLevelSpec.getFullName()).toBe("my tests are sometimes top level."); expect(nestedSpec.getFullName()).toBe("my tests are sometimes singly nested."); expect(doublyNestedSpec.getFullName()).toBe("my tests are sometimes even doubly nested."); diff --git a/spec/core/JsApiReporterSpec.js b/spec/core/JsApiReporterSpec.js index 61844b5a..bf7f9f5a 100644 --- a/spec/core/JsApiReporterSpec.js +++ b/spec/core/JsApiReporterSpec.js @@ -1,5 +1,5 @@ -describe('jasmine.jsApiReporter', function() { - describe('results', function () { +xdescribe('JsApiReporter (integration specs)', function() { + describe('results', function() { var reporter, spec1, spec2; var env; var suite, nestedSuite, nestedSpec; @@ -33,13 +33,13 @@ describe('jasmine.jsApiReporter', function() { }); - it('results() should return a hash of all results, indexed by spec id', function () { + it('results() should return a hash of all results, indexed by spec id', function() { var expectedSpec1Results = { - result: "passed" - }, - expectedSpec2Results = { - result: "failed" - }; + result: "passed" + }, + expectedSpec2Results = { + result: "failed" + }; expect(reporter.results()[spec1.id].result).toEqual('passed'); expect(reporter.results()[spec2.id].result).toEqual('failed'); }); @@ -78,3 +78,95 @@ describe('jasmine.jsApiReporter', function() { }); }); }); + + +describe("JsApiReporter", function() { + + it("knows when a full environment is started", function() { + var reporter = new jasmine.JsApiReporter(); + + expect(reporter.started).toBe(false); + expect(reporter.finished).toBe(false); + + reporter.jasmineStarted(); + + expect(reporter.started).toBe(true); + expect(reporter.finished).toBe(false); + }); + + it("knows when a full environment is done", function() { + var reporter = new jasmine.JsApiReporter(); + + expect(reporter.started).toBe(false); + expect(reporter.finished).toBe(false); + + reporter.jasmineStarted(); + reporter.jasmineDone(); + + expect(reporter.finished).toBe(true); + }); + + it("defaults to 'loaded' status", function() { + var reporter = new jasmine.JsApiReporter(); + + expect(reporter.status()).toEqual('loaded'); + }); + + it("reports 'started' when Jasmine has started", function() { + var reporter = new jasmine.JsApiReporter(); + + reporter.jasmineStarted(); + + expect(reporter.status()).toEqual('started'); + }); + + it("reports 'done' when Jasmine is done", function() { + var reporter = new jasmine.JsApiReporter(); + + reporter.jasmineDone(); + + expect(reporter.status()).toEqual('done'); + }); + + it("tracks a suite", function() { + var reporter = new jasmine.JsApiReporter(); + + reporter.suiteStarted({ + id: 123, + description: "A suite" + }); + + var suites = reporter.suites(); + + expect(suites).toEqual({123: {id: 123, description: "A suite"}}); + + reporter.suiteDone({ + id: 123, + description: "A suite", + status: 'passed' + }); + + expect(suites).toEqual({123: {id: 123, description: "A suite", status: 'passed'}}); + }); + + it("tracks a spec", function() { + var reporter = new jasmine.JsApiReporter(); + + reporter.specStarted({ + id: 123, + description: "A spec" + }); + + var specs = reporter.specs(); + + expect(specs).toEqual({123: {id: 123, description: "A spec"}}); + + reporter.specDone({ + id: 123, + description: "A spec", + status: 'passed' + }); + + expect(specs).toEqual({123: {id: 123, description: "A spec", status: 'passed'}}); + }); +}); diff --git a/spec/core/MultiReporterSpec.js b/spec/core/MultiReporterSpec.js deleted file mode 100644 index c5b54e4d..00000000 --- a/spec/core/MultiReporterSpec.js +++ /dev/null @@ -1,45 +0,0 @@ -describe("jasmine.MultiReporter", function() { - var multiReporter, fakeReporter1, fakeReporter2; - - beforeEach(function() { - multiReporter = new jasmine.MultiReporter(); - fakeReporter1 = originalJasmine.createSpyObj("fakeReporter1", ["reportSpecResults"]); - fakeReporter2 = originalJasmine.createSpyObj("fakeReporter2", ["reportSpecResults", "reportRunnerStarting"]); - multiReporter.addReporter(fakeReporter1); - multiReporter.addReporter(fakeReporter2); - }); - - it("should support all the method calls that jasmine.Reporter supports", function() { - var delegate = {}; - multiReporter.addReporter(delegate); - - addMatchers({ - toDelegateMethod: function(methodName) { - delegate[methodName] = originalJasmine.createSpy(methodName); - this.actual[methodName]("whatever argument"); - - return delegate[methodName].wasCalled && - delegate[methodName].mostRecentCall.args.length == 1 && - delegate[methodName].mostRecentCall.args[0] == "whatever argument"; - } - }); - - expect(multiReporter).toDelegateMethod('reportRunnerStarting'); - expect(multiReporter).toDelegateMethod('reportRunnerResults'); - expect(multiReporter).toDelegateMethod('reportSuiteResults'); - expect(multiReporter).toDelegateMethod('reportSpecStarting'); - expect(multiReporter).toDelegateMethod('reportSpecResults'); - expect(multiReporter).toDelegateMethod('log'); - }); - - it("should delegate to any and all subreporters", function() { - multiReporter.reportSpecResults('blah', 'foo'); - expect(fakeReporter1.reportSpecResults).toHaveBeenCalledWith('blah', 'foo'); - expect(fakeReporter2.reportSpecResults).toHaveBeenCalledWith('blah', 'foo'); - }); - - it("should quietly skip delegating to any subreporters which lack the given method", function() { - multiReporter.reportRunnerStarting('blah', 'foo'); - expect(fakeReporter2.reportRunnerStarting).toHaveBeenCalledWith('blah', 'foo'); - }); -}); diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js new file mode 100644 index 00000000..933f3e67 --- /dev/null +++ b/spec/core/QueueRunnerSpec.js @@ -0,0 +1,132 @@ +describe("QueueRunner", function() { + + it("runs all the functions it's passed", function() { + var calls = [], + fn1 = jasmine.createSpy('fn1'), + fn2 = jasmine.createSpy('fn2'), + queueRunner = new jasmine.QueueRunner({ + fns: [fn1, fn2] + }); + fn1.andCallFake(function() { + calls.push('fn1'); + }); + fn2.andCallFake(function() { + calls.push('fn2'); + }); + + queueRunner.execute(); + + expect(calls).toEqual(['fn1', 'fn2']); + }); + + it("supports asynchronous functions, only advancing to next function after a done() callback", function() { + //TODO: it would be nice if spy arity could match the fake, so we could do something like: + //createSpy('asyncfn').andCallFake(function(done) {}); + + var onComplete = originalJasmine.createSpy('onComplete'), + beforeCallback = originalJasmine.createSpy('beforeCallback'), + fnCallback = originalJasmine.createSpy('fnCallback'), + afterCallback = originalJasmine.createSpy('afterCallback'), + fn1 = function(done) { + beforeCallback(); + setTimeout(function() { + done() + }, 100); + }, + fn2 = function(done) { + fnCallback(); + setTimeout(function() { + done() + }, 100); + }, + fn3 = function(done) { + afterCallback(); + setTimeout(function() { + done() + }, 100); + }, + queueRunner = new jasmine.QueueRunner({ + fns: [fn1, fn2, fn3], + onComplete: onComplete + }); + + clock.install(); + + queueRunner.execute(); + + expect(beforeCallback).toHaveBeenCalled(); + expect(fnCallback).not.toHaveBeenCalled(); + expect(afterCallback).not.toHaveBeenCalled(); + expect(onComplete).not.toHaveBeenCalled(); + + clock.tick(100); + + expect(fnCallback).toHaveBeenCalled(); + expect(afterCallback).not.toHaveBeenCalled(); + expect(onComplete).not.toHaveBeenCalled(); + + clock.tick(100); + + expect(afterCallback).toHaveBeenCalled(); + expect(onComplete).not.toHaveBeenCalled(); + + clock.tick(100); + + expect(onComplete).toHaveBeenCalled(); + }); + + it("calls an exception handler when an exception is thrown in a fn", function() { + var fn = function() { + throw new Error('fake error'); + }, + exceptionCallback = jasmine.createSpy('exception callback'), + queueRunner = new jasmine.QueueRunner({ + fns: [fn], + onException: exceptionCallback + }); + + queueRunner.execute(); + + expect(exceptionCallback).toHaveBeenCalledWith(jasmine.any(Error)); + }); + + it("rethrows an exception if told to", function() { + var fn = function() { + throw new Error('fake error'); + }, + queueRunner = new jasmine.QueueRunner({ + fns: [fn], + catchingExceptions: function() { return false; } + }); + + expect(function() { queueRunner.execute(); }).toThrow(); + }); + + it("calls a provided complete callback when done", function() { + var fn = jasmine.createSpy('fn'), + completeCallback = jasmine.createSpy('completeCallback'), + queueRunner = new jasmine.QueueRunner({ + fns: [fn], + onComplete: completeCallback + }); + + queueRunner.execute(); + + expect(completeCallback).toHaveBeenCalled(); + }); + + it("calls a provided garbage collection function with the complete callback when done", function() { + var fn = jasmine.createSpy('fn'), + completeCallback = jasmine.createSpy('completeCallback'), + encourageGC = jasmine.createSpy('encourageGC'), + queueRunner = new jasmine.QueueRunner({ + fns: [fn], + encourageGC: encourageGC, + onComplete: completeCallback + }); + + queueRunner.execute(); + + expect(encourageGC).toHaveBeenCalledWith(completeCallback); + }); +}); diff --git a/spec/core/ReportDispatcherSpec.js b/spec/core/ReportDispatcherSpec.js new file mode 100644 index 00000000..62b0d463 --- /dev/null +++ b/spec/core/ReportDispatcherSpec.js @@ -0,0 +1,40 @@ +describe("ReportDispatcher", function() { + + it("builds an interface of requested methods", function() { + var dispatcher = new jasmine.ReportDispatcher(['foo', 'bar', 'baz']); + + expect(dispatcher.foo).toBeDefined(); + expect(dispatcher.bar).toBeDefined(); + expect(dispatcher.baz).toBeDefined(); + }); + + it("dispatches requested methods to added reporters", function() { + var dispatcher = new jasmine.ReportDispatcher(['foo', 'bar']), + reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']), + anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']); + + dispatcher.addReporter(reporter); + dispatcher.addReporter(anotherReporter); + + dispatcher.foo(123, 456); + + expect(reporter.foo).toHaveBeenCalledWith(123, 456); + expect(anotherReporter.foo).toHaveBeenCalledWith(123, 456); + + dispatcher.bar('a', 'b'); + + expect(reporter.bar).toHaveBeenCalledWith('a', 'b'); + expect(anotherReporter.bar).toHaveBeenCalledWith('a', 'b'); + }); + + it("does not dispatch to a reporter if the reporter doesn't accept the method", function() { + var dispatcher = new jasmine.ReportDispatcher(['foo']), + reporter = jasmine.createSpyObj('reporter', ['baz']); + + dispatcher.addReporter(reporter); + + expect(function() { + dispatcher.foo(123, 456); + }).not.toThrow(); + }); +}); \ No newline at end of file diff --git a/spec/core/ReporterSpec.js b/spec/core/ReporterSpec.js deleted file mode 100644 index 26cdd17c..00000000 --- a/spec/core/ReporterSpec.js +++ /dev/null @@ -1,56 +0,0 @@ -describe('jasmine.Reporter', function() { - var env; - - - beforeEach(function() { - env = new jasmine.Env(); - env.updateInterval = 0; - }); - - it('should get called from the test runner', function() { - env.describe('Suite for JSON Reporter with Callbacks', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - env.it('should be a failing test', function() { - this.runs(function () { - this.expect(false).toEqual(true); - }); - }); - }); - env.describe('Suite for JSON Reporter with Callbacks 2', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - - }); - - var foo = 0; - var bar = 0; - var baz = 0; - - env.addReporter({ - reportSpecResults: function() { - foo++; - }, - reportSuiteResults: function() { - bar++; - }, - reportRunnerResults: function() { - baz++; - } - }); - - var runner = env.currentRunner(); - runner.execute(); - - expect(foo).toEqual(3); // 'foo was expected to be 3, was ' + foo); - expect(bar).toEqual(2); // 'bar was expected to be 2, was ' + bar); - expect(baz).toEqual(1); // 'baz was expected to be 1, was ' + baz); - }); - -}); \ No newline at end of file diff --git a/spec/core/RunnerSpec.js b/spec/core/RunnerSpec.js deleted file mode 100644 index 36984a3d..00000000 --- a/spec/core/RunnerSpec.js +++ /dev/null @@ -1,168 +0,0 @@ -describe('RunnerTest', function() { - var fakeTimer; - var env; - - beforeEach(function() { - env = new jasmine.Env(); - env.updateInterval = 0; - }); - - describe('beforeEach', function() { - it('should run before each spec for all suites', function() { - var foo; - env.beforeEach(function() { - foo = 0; - }); - - env.describe('suite 1', function() { - env.it('test 1-1', function() { - foo++; - expect(foo).toEqual(1); - }); - env.it('test 1-2', function() { - foo++; - expect(foo).toEqual(1); - }); - }); - - env.describe('suite 2', function() { - env.it('test 2-1', function() { - foo++; - expect(foo).toEqual(1); - }); - }); - - env.currentRunner().execute(); - }); - - it('should provide all specs', function() { - - env.describe('suite 1', function() { - env.it('test 1-1', function() { - }); - env.it('test 1-2', function() { - }); - }); - - env.describe('suite 2', function() { - env.it('test 2-1', function() { - }); - }); - - expect(env.currentRunner().specs().length).toEqual(3); - }); - }); - - describe('afterEach', function() { - it('should run after each spec for all suites', function() { - var foo = 3; - env.afterEach(function() { - foo = foo - 1; - }); - - env.describe('suite 1', function() { - env.it('test 1-1', function() { - expect(foo).toEqual(3); - }); - env.it('test 1-2', function() { - expect(foo).toEqual(2); - }); - }); - - env.describe('suite 2', function() { - env.it('test 2-1', function() { - expect(foo).toEqual(1); - }); - }); - - env.currentRunner().execute(); - }); - - it('should run after a failing spec', function () { - var afterEach = originalJasmine.createSpy(); - env.afterEach(afterEach); - - env.describe('suite',function() { - env.it('fails', function() { - this.expect(true).toBe(false); - }); - }).execute(); - - expect(afterEach).toHaveBeenCalled(); - }); - }); - - it('should ignore suites that have been x\'d', function() { - var disabledDescribe = jasmine.createSpy('xdescribe'); - env.xdescribe('one suite description', disabledDescribe); - env.currentRunner().execute(); - expect(disabledDescribe).not.toHaveBeenCalled(); - }); - - describe('reporting', function() { - var fakeReporter; - beforeEach(function() { - fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting", "reportRunnerResults"]); - env.addReporter(fakeReporter); - }); - - it('should report runner results when the runner has completed running', function() { - var specSpy = originalJasmine.createSpy('spec').andCallFake(function() { - expect(fakeReporter.reportRunnerResults).not.toHaveBeenCalled(); - }); - env.describe('description', function() { - env.it('should be a test', specSpy); - }); - env.currentRunner().execute(); - expect(specSpy).toHaveBeenCalled(); - expect(fakeReporter.reportRunnerResults).toHaveBeenCalledWith(env.currentRunner()); - }); - }); - - it("should report when the tests start running", function() { - var fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting"]); - env.addReporter(fakeReporter); - - - var runner = new jasmine.Runner(env); - runner.arbitraryVariable = 'foo'; - spyOn(runner.queue, 'start'); - expect(fakeReporter.reportRunnerStarting).not.toHaveBeenCalled(); - runner.execute(); - expect(fakeReporter.reportRunnerStarting).toHaveBeenCalled(); - var reportedRunner = fakeReporter.reportRunnerStarting.mostRecentCall.args[0]; - expect(reportedRunner.arbitraryVariable).toEqual('foo'); - expect(runner.queue.start).toHaveBeenCalled(); - }); - - describe("when suites are nested", function() { - var suite1, suite2, suite3; - - function suiteNames(suites) { - var suiteDescriptions = []; - for (var i = 0; i < suites.length; i++) { - suiteDescriptions.push(suites[i].getFullName()); - } - return suiteDescriptions; - } - - beforeEach(function() { - suite1 = env.describe("suite 1", function() { - suite2 = env.describe("suite 2", function() { - }); - }); - suite3 = env.describe("suite 3", function() { - }); - }); - - it("#suites should return a flat array of all suites, including nested suites", function() { - var suites = env.currentRunner().suites(); - expect(suiteNames(suites)).toEqual([suite1.getFullName(), suite2.getFullName(), suite3.getFullName()]); - }); - - it("#topLevelSuites should return a flat array of all top-level suites only", function() { - var suites = env.currentRunner().topLevelSuites(); - expect(suiteNames(suites)).toEqual([suite1.getFullName(), suite3.getFullName()]); - }); - }); -}); diff --git a/spec/core/SpecRunningSpec.js b/spec/core/SpecRunningSpec.js index a33efe18..32e69f7c 100644 --- a/spec/core/SpecRunningSpec.js +++ b/spec/core/SpecRunningSpec.js @@ -1,3 +1,4 @@ +// TODO: This should really be part of the Env Integration Spec describe("jasmine spec running", function () { var env; var fakeTimer; @@ -74,11 +75,11 @@ describe("jasmine spec running", function () { var actions = []; env.beforeEach(function () { - actions.push('runner beforeEach'); + actions.push('topSuite beforeEach'); }); env.afterEach(function () { - actions.push('runner afterEach'); + actions.push('topSuite afterEach'); }); env.describe('Something', function() { @@ -131,33 +132,33 @@ describe("jasmine spec running", function () { var expected = [ - "runner beforeEach", + "topSuite beforeEach", "outer beforeEach", "outer it 1", "outer afterEach", - "runner afterEach", + "topSuite afterEach", - "runner beforeEach", + "topSuite beforeEach", "outer beforeEach", "inner 1 beforeEach", "inner 1 it", "inner 1 afterEach", "outer afterEach", - "runner afterEach", + "topSuite afterEach", - "runner beforeEach", + "topSuite beforeEach", "outer beforeEach", "outer it 2", "outer afterEach", - "runner afterEach", + "topSuite afterEach", - "runner beforeEach", + "topSuite beforeEach", "outer beforeEach", "inner 2 beforeEach", "inner 2 it", "inner 2 afterEach", "outer afterEach", - "runner afterEach" + "topSuite afterEach" ]; expect(actions).toEqual(expected); }); @@ -219,16 +220,30 @@ describe("jasmine spec running", function () { expect(actions).toEqual(expected); }); + it("shouldn't run disabled suites", function() { + var specInADisabledSuite = originalJasmine.createSpy("specInADisabledSuite"), + suite = env.describe('A Suite', function() { + env.xdescribe('with a disabled suite', function(){ + env.it('disabled spec', specInADisabledSuite); + }); + }); + + suite.execute(); + + expect(specInADisabledSuite).not.toHaveBeenCalled(); + }); + it("shouldn't run disabled tests", function() { var disabledSpec = originalJasmine.createSpy('disabledSpec'), suite = env.describe('default current suite', function() { - env.xit('disabled spec').runs(disabledSpec); + env.xit('disabled spec', disabledSpec); }); suite.execute(); expect(disabledSpec).not.toHaveBeenCalled(); }); - it("should recover gracefully when there are errors in describe functions", function() { + // TODO: is this useful? It doesn't catch syntax errors + xit("should recover gracefully when there are errors in describe functions", function() { var specs = []; var superSimpleReporter = new jasmine.Reporter(); superSimpleReporter.reportSpecResults = function(result) { @@ -275,5 +290,4 @@ describe("jasmine spec running", function () { )); }); - -}); +}); \ No newline at end of file diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index c58bab68..949b81cb 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -1,233 +1,184 @@ describe("Spec", function() { - it("reports results for passing tests", function() { - var resultCallback = originalJasmine.createSpy('resultCallback'), - expectationFactory = function(actual, spec) { - expect(actual).toBe('some-actual'); - return { - pass: function() { - spec.addExpectationResult(true); - } - } - }, - spec = new jasmine.Spec({ - description: 'my test', - id: 'some-id', - fn: function() { - this.expect('some-actual').pass(); - }, - resultCallback: resultCallback, - expectationFactory: expectationFactory - }); + + it("delegates execution to a QueueRunner", function() { + var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), + spec = new jasmine.Spec({ + description: 'my test', + id: 'some-id', + fn: function() {}, + queueRunner: fakeQueueRunner + }); spec.execute(); - expect(resultCallback).toHaveBeenCalledWith({ - id: "some-id", - status: "passed", - description: "my test", - failedExpectations: [] - }); - }); - it("reports results for failing tests", function() { - var resultCallback = originalJasmine.createSpy('resultCallback'), - expectationFactory = function(actual, spec) { - expect(actual).toBe('some-actual'); - return { - fail: function() { - spec.addExpectationResult(true); - } - } - }, - spec = new jasmine.Spec({ - description: 'my test', - id: 'some-id', - fn: function() { - this.expect('some-actual').fail(); - }, - resultCallback: resultCallback, - expectationFactory: expectationFactory - }); - - spec.execute(); - - expect(resultCallback).toHaveBeenCalledWith({ - id: "some-id", - status: "passed", - description: "my test", - failedExpectations: [] - }); + expect(fakeQueueRunner).toHaveBeenCalled(); }); - it("executes before fns, after fns", function() { - var before = originalJasmine.createSpy('before'), - after = originalJasmine.createSpy('after'), - fn = originalJasmine.createSpy('test body').andCallFake(function() { - expect(before).toHaveBeenCalled(); - expect(after).not.toHaveBeenCalled(); - }); - spec = new jasmine.Spec({ - fn: fn, - beforeFns: function() { - return [before] - }, - afterFns: function() { - return [after] - } - }); + it("should call the start callback on execution", function() { + var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), + beforesWereCalled = false, + startCallback = originalJasmine.createSpy('startCallback'), + spec = new jasmine.Spec({ + id: 123, + description: 'foo bar', + fn: function() {}, + onStart: startCallback, + queueRunner: fakeQueueRunner + }); spec.execute(); - expect(before).toHaveBeenCalled(); - expect(before.mostRecentCall.object).toBe(spec); - - expect(fn).toHaveBeenCalled(); - - expect(after).toHaveBeenCalled(); - expect(after.mostRecentCall.object).toBe(spec); + expect(startCallback).toHaveBeenCalledWith(spec); }); - it("passes an optional callback to spec bodies, befores, and afters", function() { - //TODO: it would be nice if spy arity could match the fake, so we could do something like: - //createSpy('asyncfn').andCallFake(function(done) {}); - var resultCallback = originalJasmine.createSpy('resultCallback'), - beforeCallback = originalJasmine.createSpy('beforeCallback'), - fnCallback = originalJasmine.createSpy('fnCallback'), - afterCallback = originalJasmine.createSpy('afterCallback'), - before = function(done) { - beforeCallback(); - setTimeout(function() { done() }, 100); - }, - fn = function(done) { - fnCallback(); - setTimeout(function() { done() }, 100); - }, - after = function(done) { - afterCallback(); - setTimeout(function() { done() }, 100); - }, - spec = new jasmine.Spec({ - resultCallback: resultCallback, - fn: fn, - beforeFns: function() { - return [before] - }, - afterFns: function() { - return [after] - } - }); - clock.install(); + it("should call the start callback on execution but before any befores are called", function() { + var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), + beforesWereCalled = false, + startCallback = originalJasmine.createSpy('start-callback').andCallFake(function() { + expect(beforesWereCalled).toBe(false); + }), + spec = new jasmine.Spec({ + fn: function() {}, + beforeFns: function() { + return [function() { + beforesWereCalled = true + }] + }, + onStart: startCallback, + queueRunner: fakeQueueRunner + }); spec.execute(); - expect(beforeCallback).toHaveBeenCalled(); - expect(fnCallback).not.toHaveBeenCalled(); - expect(afterCallback).not.toHaveBeenCalled(); - expect(resultCallback).not.toHaveBeenCalled(); + expect(startCallback).toHaveBeenCalled(); + }); - clock.tick(100); + it("provides all before fns and after fns to be run", function() { + var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), + before = originalJasmine.createSpy('before'), + after = originalJasmine.createSpy('after'), + fn = originalJasmine.createSpy('test body').andCallFake(function() { + expect(before).toHaveBeenCalled(); + expect(after).not.toHaveBeenCalled(); + }), + spec = new jasmine.Spec({ + fn: fn, + beforeFns: function() { + return [before] + }, + afterFns: function() { + return [after] + }, + queueRunner: fakeQueueRunner + }); - expect(fnCallback).toHaveBeenCalled(); - expect(afterCallback).not.toHaveBeenCalled(); - expect(resultCallback).not.toHaveBeenCalled(); + spec.execute(); - clock.tick(100); + var allSpecFns = fakeQueueRunner.mostRecentCall.args[0].fns; + expect(allSpecFns).toEqual([before, fn, after]); + }); - expect(afterCallback).toHaveBeenCalled(); - expect(resultCallback).not.toHaveBeenCalled(); + it("can be disabled, but still calls callbacks", function() { + var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), - clock.tick(100); + startCallback = originalJasmine.createSpy('startCallback'), + specBody = originalJasmine.createSpy('specBody'), + resultCallback = originalJasmine.createSpy('resultCallback'), + spec = new jasmine.Spec({ + onStart:startCallback, + fn: specBody, + resultCallback: resultCallback, + queueRunner: fakeQueueRunner + }); + + spec.disable(); + + expect(spec.status()).toBe('disabled'); + + spec.execute(); + + expect(startCallback).not.toHaveBeenCalled(); + expect(fakeQueueRunner).not.toHaveBeenCalled(); + expect(specBody).not.toHaveBeenCalled(); expect(resultCallback).toHaveBeenCalled(); }); - it("status returns null by default", function() { + it("should call the results callback on execution complete", function() { + var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), + + startCallback = originalJasmine.createSpy('startCallback'), + specBody = originalJasmine.createSpy('specBody'), + resultCallback = originalJasmine.createSpy('resultCallback'), + spec = new jasmine.Spec({ + onStart:startCallback, + fn: specBody, + resultCallback: resultCallback, + description: "with a spec", + getSpecName: function() { return "a suite with a spec"}, + queueRunner: fakeQueueRunner + }); + + spec.disable(); + + expect(spec.status()).toBe('disabled'); + + spec.execute(); + + expect(startCallback).not.toHaveBeenCalled(); + expect(fakeQueueRunner).not.toHaveBeenCalled(); + expect(specBody).not.toHaveBeenCalled(); + + expect(resultCallback).toHaveBeenCalledWith({ + id: spec.id, + status: 'disabled', + description: 'with a spec', + fullName: 'a suite with a spec', + failedExpectations: [] + }); + }); + + it("should call the done callback on execution complete", function() { + var done = originalJasmine.createSpy('done callback'), + spec = new jasmine.Spec({ + fn: function() {}, + catchExceptions: function() { return false; }, + resultCallback: function() {}, + queueRunner: function(attrs) { attrs.onComplete(); } + }); + + spec.execute(done); + + expect(done).toHaveBeenCalled(); + }); + + it("#status returns null by default", function() { var spec = new jasmine.Spec({}); expect(spec.status()).toBeNull(); }); - it("status returns passed if all expectations in the spec have passed", function() { + it("#status returns passed if all expectations in the spec have passed", function() { var spec = new jasmine.Spec({}); spec.addExpectationResult(true); expect(spec.status()).toBe('passed'); }); - it("status returns failed if any expectations in the spec have failed", function() { + it("#status returns failed if any expectations in the spec have failed", function() { var spec = new jasmine.Spec({}); spec.addExpectationResult(true); spec.addExpectationResult(false); expect(spec.status()).toBe('failed'); }); - it("throws when an exception occurs in the spec fn if catchExceptions is false", function() { - //TODO: one day we should pass a stack with this. - var resultCallback = originalJasmine.createSpy('resultCallback'), - spec = new jasmine.Spec({ - fn: function() { - throw new Error(); - }, - catchExceptions: false, - resultCallback: resultCallback - }); - - expect(function() { - spec.execute(); - }).toThrow(); - }); - - it("should call the start callback before any befores are called", function() { - var beforesWereCalled = false, - startCallback = originalJasmine.createSpy('start-callback').andCallFake(function() { - expect(beforesWereCalled).toBe(false); - }), - spec = new jasmine.Spec({ - fn: function() { - }, - beforeFns: function() { - return [function() { - beforesWereCalled = true - }] - }, - startCallback: startCallback, - catchExceptions: false, - resultCallback: function() { - } - }); - - spec.execute(); - expect(startCallback).toHaveBeenCalled(); - }); - it("can return its full name", function() { - var spec = new jasmine.Spec({ + var spec; + spec = new jasmine.Spec({ getSpecName: function(passedVal) { - expect(passedVal).toBe(spec); +// expect(passedVal).toBe(spec); TODO: a exec time, spec is undefined WTF? return 'expected val'; } }); expect(spec.getFullName()).toBe('expected val'); }); - - it("can be disabled", function() { - var startCallback = originalJasmine.createSpy('startCallback'), - specBody = originalJasmine.createSpy('specBody'), - resultCallback = originalJasmine.createSpy('resultCallback'), - spec = new jasmine.Spec({ - startCallback: startCallback, - fn: specBody, - resultCallback: resultCallback - - }); - - spec.disable(); - expect(spec.status()).toBe('disabled'); - - spec.execute(); - - expect(startCallback).not.toHaveBeenCalled(); - expect(specBody).not.toHaveBeenCalled(); - //TODO: with expected data. - expect(resultCallback).toHaveBeenCalled(); - }); }); - diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index 766c9c93..b09e4f62 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -1,118 +1,4 @@ -//describe('Suite', function() { -// var env; -// -// beforeEach(function() { -// env = new jasmine.Env(); -// env.updateInterval = 0; -// }); -// -// describe('Specs', function () { -// var suite; -// -// beforeEach(function() { -// suite = env.describe('Suite 1', function () { -// env.it('Spec 1', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// env.it('Spec 2', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// env.describe('Suite 2', function () { -// env.it('Spec 3', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// }); -// env.it('Spec 4', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// }); -// }); -// -// it('#specs should return all immediate children that are specs.', function () { -// var suiteSpecs = suite.specs(); -// expect(suiteSpecs.length).toEqual(3); -// expect(suiteSpecs[0].description).toEqual('Spec 1'); -// expect(suiteSpecs[1].description).toEqual('Spec 2'); -// expect(suiteSpecs[2].description).toEqual('Spec 4'); -// }); -// -// it("#suites should return all immediate children that are suites.", function() { -// var nestedSuites = suite.suites(); -// expect(nestedSuites.length).toEqual(1); -// expect(nestedSuites[0].description).toEqual('Suite 2'); -// }); -// -// it("#children should return all immediate children including suites and specs.", function() { -// var children = suite.children(); -// expect(children.length).toEqual(4); -// expect(children[0].description).toEqual('Spec 1'); -// expect(children[1].description).toEqual('Spec 2'); -// expect(children[2].description).toEqual('Suite 2'); -// expect(children[3].description).toEqual('Spec 4'); -// }); -// }); -// -// describe('SpecCount', function () { -// -// it('should keep a count of the number of specs that are run', function() { -// var suite = env.describe('one suite description', function () { -// env.it('should be a test', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// env.it('should be another test', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// env.it('should be a third test', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// }); -// -// expect(suite.specs().length).toEqual(3); -// }); -// -// it('specCount should be correct even with runs/waits blocks', function() { -// var suite = env.describe('one suite description', function () { -// env.it('should be a test', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// env.it('should be another test', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// this.waits(10); -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// env.it('should be a third test', function() { -// this.runs(function () { -// this.expect(true).toEqual(true); -// }); -// }); -// }); -// -// expect(suite.specs().length).toEqual(3); -// }); -// }); -//}); - -describe("Suite (unit tests)", function() { +describe("Suite", function() { it("keeps its id", function() { var env = new jasmine.Env(), @@ -139,15 +25,16 @@ describe("Suite (unit tests)", function() { var env = new jasmine.Env(), parentSuite = new jasmine.Suite({ env: env, - description: "I am a suite" + description: "I am a parent suite", + parentSuite: jasmine.createSpy('pretend top level suite') + }), + suite = new jasmine.Suite({ + env: env, + description: "I am a suite", + parentSuite: parentSuite }); - suite = new jasmine.Suite({ - env: env, - description: "I am a suite" - }); - - expect(suite.getFullName()).toEqual("I am a suite"); + expect(suite.getFullName()).toEqual("I am a parent suite I am a suite"); }); it("adds before functions in order of needed execution", function() { @@ -182,9 +69,15 @@ describe("Suite (unit tests)", function() { it("adds specs", function() { var env = new jasmine.Env(), + fakeQueue = { + add: jasmine.createSpy() + }, suite = new jasmine.Suite({ env: env, - description: "I am a suite" + description: "I am a suite", + queueFactory: function() { + return fakeQueue + } }), fakeSpec = {}; @@ -192,34 +85,146 @@ describe("Suite (unit tests)", function() { suite.addSpec(fakeSpec); - expect(suite.specs.length).toEqual(1);git + expect(suite.specs.length).toEqual(1); }); -}); - -// TODO: -describe("Suite (acceptance)", function() { - - it("can execute and run all of its befores, specs, and afters", function() { + it("adds suites", function() { var env = new jasmine.Env(), - calls = []; - - env.describe("A suite", function() { - env.beforeEach(function() { - calls.push('before'); + fakeQueue = { + add: jasmine.createSpy() + }, + suite = new jasmine.Suite({ + env: env, + description: "I am a suite", + queueFactory: function() { + return fakeQueue + } + }), + anotherSuite = new jasmine.Suite({ + env: env, + description: "I am another suite", + queueFactory: function() { + return fakeQueue + } }); - env.it("with a spec", function() { - calls.push('spec'); - }); + expect(suite.suites.length).toEqual(0); - env.afterEach(function() { - calls.push('after'); - }); - }); + suite.addSuite(anotherSuite); - env.execute(); - expect(calls).toEqual(['before', 'spec', 'after']); + expect(suite.suites.length).toEqual(1); }); -}); \ No newline at end of file + it("can be disabled", function() { + var env = new jasmine.Env(), + fakeQueueRunner = jasmine.createSpy('fake queue runner'), + suite = new jasmine.Suite({ + env: env, + description: "with a child suite", + queueRunner: fakeQueueRunner + }); + + suite.disable(); + + expect(suite.disabled).toBe(true); + + suite.execute(); + + expect(fakeQueueRunner).not.toHaveBeenCalled(); + }); + + it("delegates execution of its specs and suites", function() { + var env = new jasmine.Env(), + parentSuiteDone = jasmine.createSpy('parent suite done'), + fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'), + parentSuite = new jasmine.Suite({ + env: env, + description: "I am a parent suite", + queueRunner: fakeQueueRunnerForParent + }), + fakeQueueRunner = jasmine.createSpy('fake queue runner'), + suite = new jasmine.Suite({ + env: env, + description: "with a child suite", + queueRunner: fakeQueueRunner + }), + fakeSpec1 = { + execute: jasmine.createSpy('fakeSpec1') + }; + + spyOn(suite, "execute"); + + parentSuite.addSpec(fakeSpec1); + parentSuite.addSuite(suite); + + parentSuite.execute(parentSuiteDone); + + var parentSuiteFns = fakeQueueRunnerForParent.mostRecentCall.args[0].fns; + + parentSuiteFns[0](); + expect(fakeSpec1.execute).toHaveBeenCalled(); + parentSuiteFns[1](); + expect(suite.execute).toHaveBeenCalled(); + }); + + it("calls a provided onStart callback when starting", function() { + var env = new jasmine.Env(), + suiteStarted = jasmine.createSpy('suiteStarted'), + fakeQueueRunner = function(attrs) { attrs.onComplete(); }, + suite = new jasmine.Suite({ + env: env, + description: "with a child suite", + onStart: suiteStarted, + queueRunner: fakeQueueRunner + }), + fakeSpec1 = { + execute: jasmine.createSpy('fakeSpec1') + }; + + suite.execute(); + + expect(suiteStarted).toHaveBeenCalledWith(suite); + }); + + it("calls a provided onComplete callback when done", function() { + var env = new jasmine.Env(), + suiteCompleted = jasmine.createSpy('parent suite done'), + fakeQueueRunner = function(attrs) { attrs.onComplete(); }, + suite = new jasmine.Suite({ + env: env, + description: "with a child suite", + queueRunner: fakeQueueRunner + }), + fakeSpec1 = { + execute: jasmine.createSpy('fakeSpec1') + }; + + suite.execute(suiteCompleted); + + expect(suiteCompleted).toHaveBeenCalled(); + }); + + it("calls a provided result callback when done", function() { + var env = new jasmine.Env(), + suiteResultsCallback = jasmine.createSpy('suite result callback'), + fakeQueueRunner = function(attrs) { attrs.onComplete(); }, + suite = new jasmine.Suite({ + env: env, + description: "with a child suite", + queueRunner: fakeQueueRunner, + resultCallback: suiteResultsCallback + }), + fakeSpec1 = { + execute: jasmine.createSpy('fakeSpec1') + }; + + suite.execute(); + + expect(suiteResultsCallback).toHaveBeenCalledWith({ + id: suite.id, + status: '', + description: "with a child suite", + fullName: "with a child suite" + }); + }); +}); diff --git a/spec/html/HTMLReporterSpec.js b/spec/html/HTMLReporterSpec.js deleted file mode 100644 index 4d7346cb..00000000 --- a/spec/html/HTMLReporterSpec.js +++ /dev/null @@ -1,155 +0,0 @@ -describe("HtmlReporter", function() { - var env; - var htmlReporter; - var body; - var fakeDocument; - - beforeEach(function() { - env = new jasmine.Env(); - env.updateInterval = 0; - - - body = document.createElement("body"); - fakeDocument = { body: body, location: { search: "" } }; - htmlReporter = new jasmine.HtmlReporter(fakeDocument, null, { - catchingExceptions: function() { return true; }, - catchExceptions: function() { } - }, {yieldForRender: function(fn) { fn() }}); - }); - - function fakeSpec(name) { - return { - getFullName: function() { - return name; - } - }; - } - - function findElements(divs, withClass) { - var els = []; - for (var i = 0; i < divs.length; i++) { - if (divs[i].className == withClass) els.push(divs[i]); - } - return els; - } - - function findElement(divs, withClass) { - var els = findElements(divs, withClass); - if (els.length > 0) { - return els[0]; - } - throw new Error("couldn't find div with class " + withClass); - } - - it("should run only specs beginning with spec parameter", function() { - fakeDocument.location.search = "?spec=run%20this"; - expect(htmlReporter.specFilter(fakeSpec("run this"))).toBeTruthy(); - expect(htmlReporter.specFilter(fakeSpec("not the right spec"))).toBeFalsy(); - expect(htmlReporter.specFilter(fakeSpec("not run this"))).toBeFalsy(); - }); - - describe("running without any specs", function() { - var runner; - beforeEach(function() { - runner = env.currentRunner(); - env.addReporter(htmlReporter); - }); - - it("should not error", function() { - var exec = function() { - runner.execute(); - }; - expect(exec).not.toThrow(); - }); - }); - - describe('Matcher reporting', function() { - var getResultMessageDiv = function(body) { - var divs = body.getElementsByTagName("div"); - for (var i = 0; i < divs.length; i++) { - if (divs[i].className.match(/resultMessage/)) { - return divs[i]; - } - } - }; - - var runner, spec, fakeTimer; - beforeEach(function() { - env.addReporter(htmlReporter); - }); - - describe('toContain', function() { - it('should show actual and expected', function() { - env.describe('test suite', function() { - env.it('spec 0', function() { - this.expect('foo').toContain('bar'); - }); - }); - - env.execute(); - - var resultEl = getResultMessageDiv(body); - expect(resultEl.innerHTML).toMatch(/foo/); - expect(resultEl.innerHTML).toMatch(/bar/); - }); - }); - }); - - describe("failure messages (integration)", function() { - var spec, results, expectationResult; - - it("should add the failure message to the DOM (non-toEquals matchers)", function() { - env.describe("suite", function() { - env.it("will have log messages", function() { - this.expect('a').toBeNull(); - }); - }); - - env.addReporter(htmlReporter); - env.execute(); - - var divs = body.getElementsByTagName("div"); - var errorDiv = findElement(divs, 'resultMessage fail'); - expect(errorDiv.innerHTML).toMatch(/Expected 'a' to be null/); - }); - - it("should add the failure message to the DOM (non-toEquals matchers) html escaping", function() { - env.describe("suite", function() { - env.it("will have log messages", function() { - this.expect('1 < 2').toBeNull(); - }); - }); - - env.addReporter(htmlReporter); - env.execute(); - - var divs = body.getElementsByTagName("div"); - var errorDiv = findElement(divs, 'resultMessage fail'); - expect(errorDiv.innerHTML).toMatch(/Expected '1 < 2' to be null/); - }); - }); - - describe("duplicate example names", function() { - it("should report failures correctly", function() { - var suite1 = env.describe("suite", function() { - env.it("will have log messages", function() { - this.expect(true).toBeFalsy(); - }); - }); - - var suite2 = env.describe("suite", function() { - env.it("will have log messages", function() { - this.expect(true).toBeTruthy(); - }); - }); - - env.addReporter(htmlReporter); - env.execute(); - - var divs = body.getElementsByTagName("div"); - var failedSpecDiv = findElement(divs, 'specDetail failed'); - expect(failedSpecDiv.className).toEqual('specDetail failed'); - expect(failedSpecDiv.innerHTML).not.toContain("this one passes!"); - }); - }); -}); diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js new file mode 100644 index 00000000..389fa278 --- /dev/null +++ b/spec/html/HtmlReporterSpec.js @@ -0,0 +1,571 @@ +describe("New HtmlReporter", function() { + + it("builds the initial DOM elements, including the title banner", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + 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); } + }); + reporter.initialize(); + + // Main top-level elements + var divs = container.getElementsByTagName("div"); + expect(findElement(divs, "html-reporter")).toBeTruthy(); + expect(findElement(divs, "banner")).toBeTruthy(); + expect(findElement(divs, "alert")).toBeTruthy(); + expect(findElement(divs, "results")).toBeTruthy(); + + var uls = container.getElementsByTagName("ul"); + expect(findElement(uls, "symbol-summary")).toBeTruthy(); + + // title banner + var banner = container.getElementsByClassName("banner")[0]; + + var title = banner.getElementsByClassName("title")[0]; + expect(title.innerHTML).toMatch(/Jasmine/); + + var version = banner.getElementsByClassName("version")[0]; + expect(version.innerHTML).toMatch(/\d+\.\d+\.\d+\srevision\s+\d+/); + }); + + describe("when a spec is done", function() { + it("reports the status symbol of a disabled spec", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + getContainer = function() { return container; }, + 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); } + }); + reporter.initialize(); + + reporter.specDone({id: 789, status: "disabled"}); + + var statuses = container.getElementsByClassName('symbol-summary')[0]; + var specEl = statuses.getElementsByTagName('li')[0]; + expect(specEl.getAttribute("class")).toEqual("disabled"); + expect(specEl.getAttribute("id")).toEqual("spec_789"); + }); + + it("reports the status symbol of a passing spec", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + getContainer = function() { return container; }, + 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); } + }); + reporter.initialize(); + + reporter.specDone({id: 123, status: "passed"}); + + var statuses = container.getElementsByClassName("symbol-summary")[0]; + var specEl = statuses.getElementsByTagName("li")[0]; + expect(specEl.getAttribute("class")).toEqual("passed"); + expect(specEl.getAttribute("id")).toEqual("spec_123"); + }); + + it("reports the status symbol of a failing spec", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + getContainer = function() { return container; }, + 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); } + }); + + reporter.initialize(); + + reporter.specDone({ + id: 345, + status: "failed", + failedExpectations: [] + }); + + var statuses = container.getElementsByClassName('symbol-summary')[0]; + var specEl = statuses.getElementsByTagName('li')[0]; + expect(specEl.getAttribute("class")).toEqual("failed"); + expect(specEl.getAttribute("id")).toEqual("spec_345"); + }); + }); + + describe("when Jasmine is done", function() { + it("reports the run time", function() { + var env = new jasmine.Env(), + fakeNow = jasmine.createSpy('fake Date.now'), + container = document.createElement("div"), + getContainer = function() { return container; }, + reporter = new jasmine.HtmlReporter({ + env: env, + getContainer: getContainer, + now: fakeNow, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } + }); + + reporter.initialize(); + + fakeNow.andReturn(500); + reporter.jasmineStarted({}); + fakeNow.andReturn(600); + reporter.jasmineDone(); + + var banner = container.getElementsByClassName("banner")[0]; + var duration = banner.getElementsByClassName("duration")[0]; + expect(duration.innerHTML).toMatch(/finished in 0.1s/); + }); + + it("reports the suite and spec names with status", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + 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); } + }); + reporter.initialize(); + + reporter.jasmineStarted({}); + reporter.suiteStarted({ + id: 1, + description: "A Suite", + fullName: "A Suite" + }); + + var specResult = { + id: 123, + description: "with a spec", + fullName: "A Suite with a spec", + status: "passed" + }; + reporter.specStarted(specResult); + reporter.specDone(specResult); + + reporter.suiteStarted({ + id: 2, + description: "inner suite", + fullName: "A Suite inner suite" + }); + + var specResult = { + id: 124, + description: "with another spec", + fullName: "A Suite inner suite with another spec", + status: "passed" + }; + reporter.specStarted(specResult); + reporter.specDone(specResult); + + reporter.suiteDone({id: 2}); + + specResult = { + id: 209, + description: "with a failing spec", + fullName: "A Suite inner with a failing spec", + status: "failed", + failedExpectations: [] + }; + reporter.specStarted(specResult); + reporter.specDone(specResult); + + reporter.suiteDone({id: 1}); + + reporter.jasmineDone(); + var summary = container.getElementsByClassName("summary")[0]; + + console.error("=============>", summary); + expect(summary.childNodes.length).toEqual(1); + + var outerSuite = summary.childNodes[0]; + expect(outerSuite.childNodes.length).toEqual(4); + + var classes = []; + for (var i = 0; i < outerSuite.childNodes.length; i++) { + var node = outerSuite.childNodes[i]; + classes.push(node.getAttribute("class")); + } + expect(classes).toEqual(["suite-detail", "specs", "suite", "specs"]); + + var suiteDetail = outerSuite.childNodes[0]; + var suiteLink = suiteDetail.childNodes[0]; + expect(suiteLink.text).toEqual("A Suite"); + expect(suiteLink.getAttribute('href')).toEqual("?spec=A%20Suite"); + + var specs = outerSuite.childNodes[1]; + var spec = specs.childNodes[0]; + expect(spec.getAttribute("class")).toEqual("passed"); + expect(spec.getAttribute("id")).toEqual("spec-123"); + + var specLink = spec.childNodes[0]; + expect(specLink.text).toEqual("with a spec"); + expect(specLink.getAttribute("href")).toEqual("?spec=A%20Suite%20with%20a%20spec"); +// expect(specLink.getAttribute("title")).toEqual("A Suite with a spec"); + }); + + describe("UI for raising/catching exceptions", function() { + it("should be unchecked if the env is catching", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + 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); } + }); + + reporter.initialize(); + reporter.jasmineDone(); + + var raisingExceptionsUI = container.getElementsByClassName("raise")[0]; + expect(raisingExceptionsUI.checked).toBe(false); + }); + + it("should be checked if the env is not catching", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + fakeQueryString = "", + fakeWindowLocation = { + search: fakeQueryString + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return fakeWindowLocation; } + }), + getContainer = function() { return container; }, + reporter = new jasmine.HtmlReporter({ + env: env, + getContainer: getContainer, + queryString: queryString, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } + }); + + reporter.initialize(); + env.catchExceptions(false); + reporter.jasmineDone(); + + var raisingExceptionsUI = container.getElementsByClassName("raise")[0]; + expect(raisingExceptionsUI.checked).toBe(true); + }); + + it("should affect the query param for catching exceptions", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + fakeQueryString = "", + fakeWindowLocation = { + search: fakeQueryString + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return fakeWindowLocation; } + }), + getContainer = function() { return container; }, + reporter = new jasmine.HtmlReporter({ + env: env, + getContainer: getContainer, + queryString: queryString, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } + }); + + reporter.initialize(); + reporter.jasmineDone(); + + var input = container.getElementsByClassName("raise")[0]; + input.click(); + expect(queryString.getParam("catch")).toEqual(false); + + input.click(); + expect(queryString.getParam("catch")).toEqual(true); + }); + }); + + describe("and all specs pass", function() { + var env, container, reporter; + beforeEach(function() { + env = new jasmine.Env(); + container = document.createElement("div"); + 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); } + }); + reporter.initialize(); + + reporter.jasmineStarted({}); + reporter.specDone({ + id: 123, + description: "with a spec", + fullName: "A Suite with a spec", + status: "passed" + }); + reporter.specDone({ + id: 124, + description: "with another spec", + fullName: "A Suite inner suite with another spec", + status: "passed" + }); + reporter.jasmineDone(); + }); + + it("reports the specs counts", function() { + var alert = container.getElementsByClassName("alert")[0]; + var alertBars = alert.getElementsByClassName("bar"); + + expect(alertBars.length).toEqual(1); + expect(alertBars[0].getAttribute('class')).toMatch(/passed/); + expect(alertBars[0].innerHTML).toMatch(/2 specs, 0 failures/); + }); + + it("reports no failure details", function() { + var specFailure = container.getElementsByClassName("failures")[0]; + + expect(specFailure.childNodes.length).toEqual(0); + }); + }); + + describe("and some tests fail", function() { + var env, container, reporter; + + beforeEach(function() { + env = new jasmine.Env(); + container = document.createElement("div"); + 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); } + }); + reporter.initialize(); + + reporter.jasmineStarted({}); + + var passingResult = {id: 123, status: "passed"}; + reporter.specStarted(passingResult); + reporter.specDone(passingResult); + + var failingResult = { + id: 124, + status: "failed", + description: "a failing spec", + fullName: "a suite with a failing spec", + failedExpectations: [ + { + message: "a failure message", + trace: { + stack: "a stack trace" + } + } + ] + }; + reporter.specStarted(failingResult); + reporter.specDone(failingResult); + reporter.jasmineDone(); + }); + + it("reports the specs counts", function() { + var alert = container.getElementsByClassName("alert")[0]; + var alertBars = alert.getElementsByClassName("bar"); + + expect(alertBars[0].getAttribute('class')).toMatch(/failed/); + expect(alertBars[0].innerHTML).toMatch(/2 specs, 1 failure/); + }); + + it("reports failure messages and stack traces", function() { + var specFailures = container.getElementsByClassName("failures")[0]; + + var failure = specFailures.childNodes[0]; + expect(failure.getAttribute("class")).toMatch(/failed/); + expect(failure.getAttribute("class")).toMatch(/spec-detail/); + + var specLink = failure.childNodes[0]; + expect(specLink.getAttribute("class")).toEqual("description"); + expect(specLink.getAttribute("title")).toEqual("a suite with a failing spec"); + expect(specLink.getAttribute("href")).toEqual("?spec=a%20suite%20with%20a%20failing%20spec"); + + var message = failure.childNodes[1].childNodes[0]; + expect(message.getAttribute("class")).toEqual("result-message"); + expect(message.innerHTML).toEqual("a failure message"); + + var stackTrace = failure.childNodes[1].childNodes[1]; + expect(stackTrace.getAttribute("class")).toEqual("stack-trace"); + expect(stackTrace.innerHTML).toEqual("a stack trace"); + }); + + it("allows switching between failure details and the spec summary", function() { + var menuBar = container.getElementsByClassName("bar")[1]; + + expect(menuBar.getAttribute("class")).not.toMatch(/hidden/); + + var link = menuBar.getElementsByTagName('a')[0]; + expect(link.text).toEqual("Failures"); + expect(link.getAttribute("href")).toEqual("#"); + }); + + it("sets the reporter to 'Failures List' mode", function() { + var reporterNode = container.getElementsByClassName("html-reporter")[0]; + expect(reporterNode.getAttribute("class")).toMatch("failure-list"); + }); + }); + }); + + describe("specFilter", function() { + + it("always returns true if there is no filter", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + fakeQueryString = "", + fakeWindowLocation = { + search: fakeQueryString + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return fakeWindowLocation; } + }), + getContainer = function() { return container; }, + reporter = new jasmine.HtmlReporter({ + env: env, + getContainer: getContainer, + queryString: queryString, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } + }), + fakeSpec = { + getFullName: function() { return "A suite with a spec"} + }; + + expect(reporter.specFilter(fakeSpec)).toBe(true); + }); + + it("matches a focused spec name", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + fakeWindowLocation = { + search: "?spec=A%20suite%20with%20a%20spec" + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return fakeWindowLocation; } + }), + getContainer = function() { return container; }, + reporter = new jasmine.HtmlReporter({ + env: env, + getContainer: getContainer, + queryString: queryString, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } + }), + fakeMatchingSpec = { + getFullName: function() { return "A suite with a spec"} + }, + fakeNonMatchingSpec = { + getFullName: function() { return "sasquatch"} + }; + + expect(reporter.specFilter(fakeMatchingSpec)).toBe(true); + expect(reporter.specFilter(fakeNonMatchingSpec)).toBe(false); + }); + + it("matches a substring of a spec name", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + fakeWindowLocation = { + search: "?spec=with" + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return fakeWindowLocation; } + }), + getContainer = function() { return container; }, + reporter = new jasmine.HtmlReporter({ + env: env, + getContainer: getContainer, + queryString: queryString, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } + }), + fakeMatchingSpec = { + getFullName: function() { return "A suite with a spec" } + }, + fakeNonMatchingSpec = { + getFullName: function() { return "sasquatch"} + }; + + expect(reporter.specFilter(fakeMatchingSpec)).toBe(true); + expect(reporter.specFilter(fakeNonMatchingSpec)).toBe(false); + }); + }); + + describe("when specs are filtered", function() { + it("shows the count of run specs and defined specs", function() { + var env = new jasmine.Env(), + container = document.createElement("div"), + 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); } + }); + + reporter.initialize(); + + reporter.jasmineStarted({ + totalSpecsDefined: 2 + }); + reporter.specDone({ + id: 123, + description: "with a spec", + fullName: "A Suite with a spec", + status: "passed" + }); + reporter.specDone({ + id: 124, + description: "with another spec", + fullName: "A Suite inner suite with another spec", + status: "disabled" + }); + reporter.jasmineDone(); + + var skippedBar = container.getElementsByClassName("bar")[0]; + expect(skippedBar.getAttribute("class")).toMatch(/skipped/); + + var runAllLink = skippedBar.childNodes[0]; + expect(runAllLink.getAttribute("href")).toEqual("?"); + expect(runAllLink.text).toMatch(/Ran \d+ of \d+ specs - run all/); + }); + }); + + // try/catch + + // utility functions + function findElements(divs, withClass) { + var els = []; + for (var i = 0; i < divs.length; i++) { + if (divs[i].className == withClass) els.push(divs[i]); + } + return els; + } + + function findElement(divs, withClass) { + var els = findElements(divs, withClass); + if (els.length > 0) { + return els[0]; + } + throw new Error("couldn't find div with class " + withClass); + } +}); diff --git a/spec/html/QueryStringSpec.js b/spec/html/QueryStringSpec.js new file mode 100644 index 00000000..e95d1811 --- /dev/null +++ b/spec/html/QueryStringSpec.js @@ -0,0 +1,43 @@ +describe("QueryString", function() { + + describe("#setParam", function() { + + it("sets the query string to include the given key/value pair", function() { + var windowLocation = { + search: "" + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return windowLocation } + }); + + queryString.setParam("foo", "bar baz"); + + expect(windowLocation.search).toMatch(/foo=bar%20baz/); + }); + }); + + describe("#getParam", function() { + + it("returns the value of the requested key", function() { + var windowLocation = { + search: "?baz=quux%20corge" + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return windowLocation } + }); + + expect(queryString.getParam("baz")).toEqual("quux corge"); + }); + + it("returns null if the key is not present", function() { + var windowLocation = { + search: "" + }, + queryString = new jasmine.QueryString({ + getWindowLocation: function() { return windowLocation } + }); + + expect(queryString.getParam("baz")).toBeFalsy(); + }); + }); +}); \ No newline at end of file diff --git a/spec/html/ResultsNodeSpec.js b/spec/html/ResultsNodeSpec.js new file mode 100644 index 00000000..db46bc13 --- /dev/null +++ b/spec/html/ResultsNodeSpec.js @@ -0,0 +1,62 @@ +describe("ResultsNode", function() { + it("wraps a result", function() { + var fakeResult = { + id: 123, + message: "foo" + }, + node = new jasmine.ResultsNode(fakeResult, "suite", null); + + expect(node.result).toBe(fakeResult); + expect(node.type).toEqual("suite"); + }); + + it("can add children with a type", function() { + var fakeResult = { + id: 123, + message: "foo" + }, + fakeChildResult = { + id: 456, + message: "bar" + }, + node = new jasmine.ResultsNode(fakeResult, "suite", null); + + node.addChild(fakeChildResult, "spec"); + + expect(node.children.length).toEqual(1); + expect(node.children[0].result).toEqual(fakeChildResult); + expect(node.children[0].type).toEqual("spec"); + }); + + it("has a pointer back to its parent ResultNode", function() { + var fakeResult = { + id: 123, + message: "foo" + }, + fakeChildResult = { + id: 456, + message: "bar" + }, + node = new jasmine.ResultsNode(fakeResult, "suite", null); + + node.addChild(fakeChildResult, "spec"); + + expect(node.children[0].parent).toBe(node); + }); + + it("can provide the most recent child", function() { + var fakeResult = { + id: 123, + message: "foo" + }, + fakeChildResult = { + id: 456, + message: "bar" + }, + node = new jasmine.ResultsNode(fakeResult, "suite", null); + + node.addChild(fakeChildResult, "spec"); + + expect(node.last()).toBe(node.children[node.children.length - 1]); + }); +}); \ No newline at end of file diff --git a/spec/jasmine.yml b/spec/jasmine.yml index 134bd2c2..3561922e 100644 --- a/spec/jasmine.yml +++ b/spec/jasmine.yml @@ -5,20 +5,14 @@ src_dir: src_files: - 'core/base.js' - 'core/util.js' - - 'core/Reporter.js' #end of known dependencies - 'core/Spec.js' - 'core/Env.js' - 'core/JsApiReporter.js' - 'core/Matchers.js' - - 'core/MultiReporter.js' - - 'core/NestedResults.js' - 'core/PrettyPrinter.js' - - 'core/Queue.js' - - 'core/Runner.js' - 'core/Suite.js' - - 'html/HtmlReporterHelpers.js' - - 'html/HtmlReporter.js' + - 'html/**.js' - '**/*.js' stylesheets: boot_dir: 'spec/support' diff --git a/spec/node_performance_suite.js b/spec/node_performance_suite.js index 7797cec4..15678385 100644 --- a/spec/node_performance_suite.js +++ b/spec/node_performance_suite.js @@ -86,7 +86,11 @@ jasmine.executeSpecs = function(specs, done, isVerbose, showColors) { } var jasmineEnv = jasmine.getEnv(); - var consoleReporter = new jasmine.ConsoleReporter(util.print, done, showColors); + var consoleReporter = new jasmine.ConsoleReporter({ + print: util.print, + onComplete: done, + showColors: showColors + }); jasmineEnv.addReporter(consoleReporter); jasmineEnv.execute(); diff --git a/spec/node_suite.js b/spec/node_suite.js index 17c66512..569f03c6 100644 --- a/spec/node_suite.js +++ b/spec/node_suite.js @@ -91,7 +91,11 @@ jasmine.executeSpecs = function(specs, done, isVerbose, showColors) { } var jasmineEnv = jasmine.getEnv(); - var consoleReporter = new jasmine.ConsoleReporter(util.print, done, showColors); + var consoleReporter = new jasmine.ConsoleReporter({ + print: util.print, + onComplete: done, + showColors: showColors + }); jasmineEnv.addReporter(consoleReporter); jasmineEnv.execute(); @@ -168,7 +172,7 @@ process.argv.forEach(function(arg) { var specs = jasmine.getAllSpecFiles(__dirname, new RegExp("Spec.js$")); var domIndependentSpecs = []; for (var i = 0; i < specs.length; i++) { - if (fs.readFileSync(specs[i], "utf8").indexOf("document.createElement") < 0) { + if (!specs[i].match('html')) { domIndependentSpecs.push(specs[i]); } } diff --git a/spec/runner.html b/spec/runner.html index 0db56a4a..461632ad 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -1,54 +1,55 @@ + "http://www.w3.org/TR/html4/loose.dtd"> - Jasmine Spec Runner: Jasmine Core + Jasmine Spec Runner: Jasmine Core - + - - - - + + + + - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/console/ConsoleReporter.js b/src/console/ConsoleReporter.js index 64053f98..a41e32d1 100644 --- a/src/console/ConsoleReporter.js +++ b/src/console/ConsoleReporter.js @@ -1,55 +1,72 @@ -jasmine.ConsoleReporter = function(print, doneCallback, showColors) { - //inspired by mhevery's jasmine-node reporter - //https://github.com/mhevery/jasmine-node - - doneCallback = doneCallback || function() {}; - - var ansi = { +jasmine.ConsoleReporter = function(options) { + var print = options.print, + showColors = options.showColors || false, + onComplete = options.onComplete || function() {}, + now = options.now || function() { return new Date().getTime();}, + startTime = 0, + specCount, + failureCount, + failedSpecs = [], + ansi = { green: '\033[32m', red: '\033[31m', yellow: '\033[33m', none: '\033[0m' - }, - language = { - spec: "spec", - failure: "failure" }; - function coloredStr(color, str) { - return showColors ? (ansi[color] + str + ansi.none) : str; - } + this.jasmineStarted = function() { + startTime = now(); + specCount = 0; + failureCount = 0; + print("Started"); + printNewline(); + }; - function greenStr(str) { - return coloredStr("green", str); - } + this.jasmineDone = function() { + var elapsed = now() - startTime; - function redStr(str) { - return coloredStr("red", str); - } + printNewline(); + for (var i = 0; i < failedSpecs.length; i++) { + specFailureDetails(failedSpecs[i]); + } - function yellowStr(str) { - return coloredStr("yellow", str); - } + printNewline(); + var specCounts = specCount + " " + plural("spec", specCount) + ", " + + failureCount + " " + plural("failure", failureCount); + print(specCounts); - function newline() { + printNewline(); + var seconds = elapsed / 1000; + print("Finished in " + seconds + " " + plural("second", seconds)); + + printNewline(); + + onComplete(); + }; + + this.specDone = function(result) { + specCount++; + + if (result.status == "passed") { + print(colored("green", '.')); + return; + } + + if (result.status == "failed") { + failureCount++; + failedSpecs.push(result); + print(colored("red", 'F')); + } + }; + + return this; + + function printNewline() { print("\n"); } - function started() { - print("Started"); - newline(); - } - - function greenDot() { - print(greenStr(".")); - } - - function redF() { - print(redStr("F")); - } - - function yellowStar() { - print(yellowStr("*")); + function colored(color, str) { + return showColors ? (ansi[color] + str + ansi.none) : str; } function plural(str, count) { @@ -73,129 +90,16 @@ jasmine.ConsoleReporter = function(print, doneCallback, showColors) { return newArr.join("\n"); } - // function specFailureDetails(suiteDescription, specDescription, stackTraces) { - // newline(); - // print(suiteDescription + " " + specDescription); - // newline(); - // for (var i = 0; i < stackTraces.length; i++) { - // print(indent(stackTraces[i], 2)); - // newline(); - // } - // } - function specFailureDetails(specFailure) { - newline(); - print(specFailure.fullName); - newline(); - for (var i = 0; i < specFailure.failedExpectations.length; i++) { - var failedExpectation = specFailure.failedExpectations[i]; + function specFailureDetails(result) { + printNewline(); + print(result.fullName); + + for (var i = 0; i < result.failedExpectations.length; i++) { + var failedExpectation = result.failedExpectations[i]; + printNewline(); print(indent(failedExpectation.trace.stack, 2)); - newline(); - } - } - - function finished(elapsed) { - newline(); - print("Finished in " + elapsed / 1000 + " seconds"); - } - - function summary(colorF, specs, failed) { - newline(); - print(colorF(specs + " " + plural(language.spec, specs) + ", " + - failed + " " + plural(language.failure, failed))); - newline(); - newline(); - } - - function greenSummary(specs, failed) { - summary(greenStr, specs, failed); - } - - function redSummary(specs, failed) { - summary(redStr, specs, failed); - } - - function fullSuiteDescription(suite) { - var fullDescription = suite.description; - if (suite.parentSuite) fullDescription = fullSuiteDescription(suite.parentSuite) + " " + fullDescription; - return fullDescription; - } - - this.now = function() { - return new Date().getTime(); - }; - - this.reportRunnerStarting = function() { - this.runnerStartTime = this.now(); - started(); - }; - - this.reportSpecStarting = function() { /* do nothing */ - }; - - this.specFailures = []; - this.specCount = 0; - this.reportSpecResults = function(result) { - this.specCount++; - if (result.status === 'disabled') { - yellowStar(); - } else if (result.status === 'passed') { - greenDot(); - } else { - redF(); - this.specFailures.push(result); - } - }; - - // this.suiteResults = []; - - this.reportSuiteResults = function(suite) { - // var suiteResult = { - // description: fullSuiteDescription(suite), - // failedSpecResults: [] - // }; - - // suite.results().items_.forEach(function(spec) { - // if (spec.failedCount > 0 && spec.description) suiteResult.failedSpecResults.push(spec); - // }); - - // this.suiteResults.push(suiteResult); - }; - - // function eachSpecFailure(suiteResults, callback) { - // for (var i = 0; i < suiteResults.length; i++) { - // var suiteResult = suiteResults[i]; - // for (var j = 0; j < suiteResult.failedSpecResults.length; j++) { - // var failedSpecResult = suiteResult.failedSpecResults[j]; - // var stackTraces = []; - // for (var k = 0; k < failedSpecResult.items_.length; k++) stackTraces.push(failedSpecResult.items_[k].trace.stack); - // callback(suiteResult.description, failedSpecResult.description, stackTraces); - // } - // } - // } - - function eachSpecFailure(specResult, callback) { - for (var i = 0; i < suiteResults.length; i++) { - var suiteResult = suiteResults[i]; - for (var j = 0; j < suiteResult.failedSpecResults.length; j++) { - var failedSpecResult = suiteResult.failedSpecResults[j]; - var stackTraces = []; - for (var k = 0; k < failedSpecResult.items_.length; k++) stackTraces.push(failedSpecResult.items_[k].trace.stack); - callback(suiteResult.description, failedSpecResult.description, stackTraces); - } - } - } - - this.reportRunnerResults = function(runner) { - newline(); - - for (var i = 0; i < this.specFailures.length; i++) { - specFailureDetails(this.specFailures[i]); } - finished(this.now() - this.runnerStartTime); - - var summaryFunction = this.specFailures.length === 0 ? greenSummary : redSummary; - summaryFunction(this.specCount, this.specFailures.length); - doneCallback(!!this.specFailures.length); - }; + printNewline(); + } }; diff --git a/src/core/Clock.js b/src/core/Clock.js index 47608b89..23f3affa 100644 --- a/src/core/Clock.js +++ b/src/core/Clock.js @@ -1,19 +1,19 @@ jasmine.Clock = function(global, delayedFunctionScheduler) { var self = this, - realTimingFunctions = { - setTimeout: global.setTimeout, - clearTimeout: global.clearTimeout, - setInterval: global.setInterval, - clearInterval: global.clearInterval - }, - fakeTimingFunctions = { - setTimeout: setTimeout, - clearTimeout: clearTimeout, - setInterval: setInterval, - clearInterval: clearInterval - }, - timer = realTimingFunctions, - installed = false; + realTimingFunctions = { + setTimeout: global.setTimeout, + clearTimeout: global.clearTimeout, + setInterval: global.setInterval, + clearInterval: global.clearInterval + }, + fakeTimingFunctions = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setInterval: setInterval, + clearInterval: clearInterval + }, + timer = realTimingFunctions, + installed = false; self.install = function() { installed = true; @@ -72,7 +72,7 @@ jasmine.Clock = function(global, delayedFunctionScheduler) { } function setTimeout(fn, delay) { - return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments,2)); + return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2)); } function clearTimeout(id) { diff --git a/src/core/Env.js b/src/core/Env.js index 2fa62a60..c23bd6da 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -1,8 +1,3 @@ -/** - * Environment for Jasmine - * - * @constructor - */ (function() { jasmine.Env = function(options) { options = options || {}; @@ -10,21 +5,23 @@ var global = options.global || jasmine.getGlobal(); var catchExceptions = true; - var encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler()); - var suiteConstructor = jasmine.Suite; - var isSuite = function(thing) { - return thing instanceof suiteConstructor; - }; this.jasmine = jasmine; - this.currentRunner_ = new jasmine.Runner(this, isSuite); this.spies_ = []; this.currentSpec = null; + this.undefined = jasmine.undefined; - this.reporter = new jasmine.MultiReporter(); + this.reporter = new jasmine.ReportDispatcher([ + "jasmineStarted", + "jasmineDone", + "suiteStarted", + "suiteDone", + "specStarted", + "specDone" + ]); this.lastUpdate = 0; this.specFilter = function() { @@ -49,18 +46,18 @@ return expect; }; - var startCallback = function(spec) { + var specStarted = function(spec) { self.currentSpec = spec; - self.reporter.reportSpecStarting(spec); + self.reporter.specStarted(spec.result); }; var beforeFns = function(currentSuite) { return function() { var befores = []; for (var suite = currentSuite; suite; suite = suite.parentSuite) { - befores = befores.concat(suite.before_) + befores = befores.concat(suite.beforeFns) } - return befores.concat(self.currentRunner_.before_).reverse(); + return befores.reverse(); } }; @@ -68,9 +65,9 @@ return function() { var afters = []; for (var suite = currentSuite; suite; suite = suite.parentSuite) { - afters = afters.concat(suite.after_) + afters = afters.concat(suite.afterFns) } - return afters.concat(self.currentRunner_.after_) + return afters; } }; @@ -87,60 +84,14 @@ return buildExpectationResult(attrs); }; + // TODO: fix this naming, and here's where the value comes in this.catchExceptions = function(value) { - return catchExceptions = !!value; - }; - - this.catchingExceptions = function(value) { + catchExceptions = !!value; return catchExceptions; }; - this.specFactory = function(description, fn, suite) { - var spec = new specConstructor({ - id: self.nextSpecId(), - beforeFns: beforeFns(suite), - afterFns: afterFns(suite), - expectationFactory: expectationFactory, - exceptionFormatter: exceptionFormatter, - resultCallback: specResultCallback, - getSpecName: function(spec) { - return getSpecName(spec, suite) - }, - startCallback: startCallback, - description: description, - catchingExceptions: this.catchingExceptions, - expectationResultFactory: expectationResultFactory, - fn: fn - }); - - if (!self.specFilter(spec)) { - spec.disable(); - } - - return spec; - - function specResultCallback(result) { - self.clock.uninstall(); - self.currentSpec = null; - encourageGC(function() { - suite.specComplete(result); - }); - } - - }; - - var queueConstructor = jasmine.Queue; - var queueFactory = function() { - return new queueConstructor(self); - }; - this.suiteFactory = function(description) { - return new suiteConstructor({ - env: self, - description: description, - currentSuite: self.currentSuite, - queueFactory: queueFactory, - isSuite: isSuite - }); + this.catchingExceptions = function() { + return catchExceptions; }; var maximumSpecCallbackDepth = 100; @@ -155,6 +106,86 @@ fn(); } } + + var queueRunnerFactory = function(options) { + options.catchingExceptions = self.catchingExceptions; + options.encourageGC = options.encourageGarbageCollection || encourageGarbageCollection; + + new jasmine.QueueRunner(options).run(options.fns, 0); + }; + + + var totalSpecsDefined = 0; + this.specFactory = function(description, fn, suite) { + totalSpecsDefined++; + + var spec = new specConstructor({ + id: self.nextSpecId(), + beforeFns: beforeFns(suite), + afterFns: afterFns(suite), + expectationFactory: expectationFactory, + exceptionFormatter: exceptionFormatter, + resultCallback: specResultCallback, + getSpecName: function(spec) { + return getSpecName(spec, suite) + }, + onStart: specStarted, + description: description, + expectationResultFactory: expectationResultFactory, + queueRunner: queueRunnerFactory, + fn: fn + }); + + if (!self.specFilter(spec)) { + spec.disable(); + } + + return spec; + + function specResultCallback(result) { + self.removeAllSpies(); + self.clock.uninstall(); + self.currentSpec = null; + self.reporter.specDone(result); + } + }; + + var suiteStarted = function(suite) { + self.reporter.suiteStarted(suite.result); + }; + + var suiteConstructor = jasmine.Suite; + + this.topSuite = new jasmine.Suite({ + env: this, + id: this.nextSuiteId(), + description: 'Jasmine__TopLevel__Suite', + queueRunner: queueRunnerFactory, + completeCallback: function() {}, // TODO - hook this up + resultCallback: function() {} // TODO - hook this up + }); + this.currentSuite = this.topSuite; + + this.suiteFactory = function(description) { + return new suiteConstructor({ + env: self, + id: self.nextSuiteId(), + description: description, + parentSuite: self.currentSuite, + queueRunner: queueRunnerFactory, + onStart: suiteStarted, + resultCallback: function(attrs) { + self.reporter.suiteDone(attrs); + } + }); + }; + + this.execute = function() { + this.reporter.jasmineStarted({ + totalSpecsDefined: totalSpecsDefined + }); + this.topSuite.execute(this.reporter.jasmineDone); + }; }; //TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc. @@ -167,9 +198,7 @@ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); this.matchersClass = newMatchersClass; }; - /** - * @returns an object containing jasmine version build info, if set. - */ + jasmine.Env.prototype.version = function() { if (this.jasmine.version_) { return this.jasmine.version_; @@ -208,6 +237,7 @@ return spyObj; }; + // TODO: move this to closure jasmine.Env.prototype.removeAllSpies = function() { for (var i = 0; i < this.spies_.length; i++) { var spy = this.spies_[i]; @@ -215,9 +245,8 @@ } this.spies_ = []; }; - /** - * @returns string containing jasmine version build info, if set. - */ + + // TODO: move this to closure jasmine.Env.prototype.versionString = function() { if (!this.jasmine.version_) { return "version unknown"; @@ -232,42 +261,27 @@ return versionString; }; - /** - * @returns a sequential integer starting at 0 - */ + // TODO: move this to closure jasmine.Env.prototype.nextSpecId = function() { return this.nextSpecId_++; }; - /** - * @returns a sequential integer starting at 0 - */ + // TODO: move this to closure jasmine.Env.prototype.nextSuiteId = function() { return this.nextSuiteId_++; }; - /** - * Register a reporter to receive status updates from Jasmine. - * @param {jasmine.Reporter} reporter An object which will receive status updates. - */ + // TODO: move this to closure jasmine.Env.prototype.addReporter = function(reporter) { this.reporter.addReporter(reporter); }; - jasmine.Env.prototype.execute = function() { - this.currentRunner_.execute(); - }; - + // TODO: move this to closure jasmine.Env.prototype.describe = function(description, specDefinitions) { var suite = this.suiteFactory(description, specDefinitions); var parentSuite = this.currentSuite; - if (parentSuite) { - parentSuite.add(suite); - } else { - this.currentRunner_.addSuite(suite); - } - + parentSuite.addSuite(suite); this.currentSuite = suite; var declarationError = null; @@ -288,46 +302,40 @@ return suite; }; - jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { - if (this.currentSuite) { - this.currentSuite.beforeEach(beforeEachFunction); - } else { - this.currentRunner_.beforeEach(beforeEachFunction); - } - }; - - jasmine.Env.prototype.currentRunner = function() { - return this.currentRunner_; - }; - - jasmine.Env.prototype.afterEach = function(afterEachFunction) { - if (this.currentSuite) { - this.currentSuite.afterEach(afterEachFunction); - } else { - this.currentRunner_.afterEach(afterEachFunction); - } - - }; - - jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { - return { - execute: function() { - } - }; + // TODO: move this to closure + jasmine.Env.prototype.xdescribe = function(description, specDefinitions) { + var suite = this.describe(description, specDefinitions); + suite.disable(); + return suite; }; + // TODO: move this to closure jasmine.Env.prototype.it = function(description, fn) { var spec = this.specFactory(description, fn, this.currentSuite); - this.currentSuite.add(spec); + this.currentSuite.addSpec(spec); return spec; }; - jasmine.Env.prototype.xit = function(desc, func) { - return { - id: this.nextSpecId(), - runs: function() { - } - }; + // TODO: move this to closure + jasmine.Env.prototype.xit = function(description, fn) { + var spec = this.it(description, fn); + spec.disable(); + return spec; + }; + + // TODO: move this to closure + jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { + this.currentSuite.beforeEach(beforeEachFunction); + }; + + // TODO: move this to closure + jasmine.Env.prototype.afterEach = function(afterEachFunction) { + this.currentSuite.afterEach(afterEachFunction); + }; + + // TODO: Still needed? + jasmine.Env.prototype.currentRunner = function() { + return this.topSuite; }; jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { diff --git a/src/core/JsApiReporter.js b/src/core/JsApiReporter.js index c4b655e1..01f41e97 100644 --- a/src/core/JsApiReporter.js +++ b/src/core/JsApiReporter.js @@ -1,104 +1,60 @@ -/** JavaScript API reporter. - * - * @constructor - */ jasmine.JsApiReporter = function(jasmine) { this.jasmine = jasmine || {}; this.started = false; this.finished = false; this.suites_ = []; this.results_ = {}; -}; -jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { - this.started = true; - var suites = runner.topLevelSuites(); - for (var i = 0; i < suites.length; i++) { - var suite = suites[i]; - this.suites_.push(this.summarize_(suite)); - } -}; + var status = 'loaded'; -jasmine.JsApiReporter.prototype.suites = function() { - return this.suites_; -}; - -jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { - var isSuite = suiteOrSpec instanceof this.jasmine.Suite; - var summary = { - id: suiteOrSpec.id, - name: suiteOrSpec.description, - type: isSuite ? 'suite' : 'spec', - children: [] + this.jasmineStarted = function() { + this.started = true; + status = 'started'; }; - if (isSuite) { - var children = suiteOrSpec.children(); - for (var i = 0; i < children.length; i++) { - summary.children.push(this.summarize_(children[i])); - } - } - return summary; -}; - -jasmine.JsApiReporter.prototype.results = function() { - return this.results_; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { - this.finished = true; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSpecResults = function(result) { - this.results_[result.id] = { - messages: result.failedExpectations, - //result is status - result: result.status + this.jasmineDone = function() { + this.finished = true; + status = 'done'; }; -}; -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.log = function(str) { -}; - -//TODO: make work with new presenter. -jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ - var results = {}; - for (var i = 0; i < specIds.length; i++) { - var specId = specIds[i]; - results[specId] = this.summarizeResult_(this.results_[specId]); - } - return results; -}; - -jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ - var summaryMessages = []; - var messagesLength = result.messages.length; - for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { - var resultMessage = result.messages[messageIndex]; - //TODO: use result presenter here, not a bunch of spec crap - summaryMessages.push({ - //TODO: remove text. - text: resultMessage.type == 'log' ? resultMessage.toString() : this.jasmine.undefined, - //TODO: wat? in theory this is saying non-expect results should always be considered passed, but that's weird. - passed: resultMessage.passed || true, //status === 'passed' - type: resultMessage.type, - message: resultMessage.message, - trace: { - stack: !resultMessage.passed ? resultMessage.trace.stack : this.jasmine.undefined - } - }); - } - - return { - result : result.result, - messages : summaryMessages + this.status = function() { + return status; }; -}; + var suites = {}; + + this.suiteStarted = function(result) { + storeSuite(result); + }; + + this.suiteDone = function(result) { + storeSuite(result); + }; + + function storeSuite(result) { + suites[result.id] = result; + } + + this.suites = function() { + return suites; + }; + + var specs = {}; + + this.specStarted = function(result) { + storeSpec(result); + }; + + this.specDone = function(result) { + storeSpec(result); + }; + + function storeSpec(result) { + specs[result.id] = result; + } + + this.specs = function() { + return specs; + }; + +}; \ No newline at end of file diff --git a/src/core/MultiReporter.js b/src/core/MultiReporter.js deleted file mode 100644 index a47650e3..00000000 --- a/src/core/MultiReporter.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @constructor - */ -jasmine.MultiReporter = function() { - this.subReporters_ = []; -}; -jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); - -jasmine.MultiReporter.prototype.addReporter = function(reporter) { - this.subReporters_.push(reporter); -}; - -(function() { - var functionNames = [ - "reportRunnerStarting", - "reportRunnerResults", - "reportSuiteResults", - "reportSpecStarting", - "reportSpecResults", - "log" - ]; - for (var i = 0; i < functionNames.length; i++) { - var functionName = functionNames[i]; - jasmine.MultiReporter.prototype[functionName] = (function(functionName) { - return function() { - for (var j = 0; j < this.subReporters_.length; j++) { - var subReporter = this.subReporters_[j]; - if (subReporter[functionName]) { - subReporter[functionName].apply(subReporter, arguments); - } - } - }; - })(functionName); - } -})(); diff --git a/src/core/Queue.js b/src/core/Queue.js deleted file mode 100644 index ee588069..00000000 --- a/src/core/Queue.js +++ /dev/null @@ -1,111 +0,0 @@ -jasmine.Queue = function(env) { - this.env = env; - - // parallel to blocks. each true value in this array means the block will - // get executed even if we abort - this.ensured = []; - this.blocks = []; - this.running = false; - this.index = 0; - this.offset = 0; - this.abort = false; -}; - -jasmine.Queue.prototype.addBefore = function(block, ensure) { - if (ensure === this.env.undefined) { - ensure = false; - } - - this.blocks.unshift(block); - this.ensured.unshift(ensure); -}; - -jasmine.Queue.prototype.add = function(block, ensure) { - if (ensure === this.env.undefined) { - ensure = false; - } - - this.blocks.push(block); - this.ensured.push(ensure); -}; - -jasmine.Queue.prototype.insertNext = function(block, ensure) { - if (ensure === this.env.undefined) { - ensure = false; - } - - this.ensured.splice((this.index + this.offset + 1), 0, ensure); - this.blocks.splice((this.index + this.offset + 1), 0, block); - this.offset++; -}; - -jasmine.Queue.prototype.start = function(onComplete) { - this.running = true; - this.onComplete = onComplete; - this.next_(); -}; - -jasmine.Queue.prototype.isRunning = function() { - return this.running; -}; - -jasmine.Queue.LOOP_DONT_RECURSE = true; - -jasmine.Queue.prototype.incrementQueue = function() { - if (this.blocks[this.index].abort) { - this.abort = true; - } - this.offset = 0; - this.index++; - this.next_(); -} - -jasmine.Queue.prototype.next_ = function() { - var self = this; - // var goAgain = true; - - // while (goAgain) { - // goAgain = false; - - if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { - // var calledSynchronously = true; - // var completedSynchronously = false; - - // var onComplete = function () { - // if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { - // completedSynchronously = true; - // return; - // } - - self.blocks[self.index].execute(function() { self.incrementQueue() }); - - - // var now = new Date().getTime(); - // if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { - // self.env.lastUpdate = now; - // self.env.setTimeout(function() { - // self.next_(); - // }, 0); - // } else { - // if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { - // goAgain = true; - // } else { - // self.next_(); - // } - // } - // }; - // self.blocks[self.index].execute(function() { self.next_(); }); - - // calledSynchronously = false; - // if (completedSynchronously) { - // onComplete(); - // } - - } else { - self.running = false; - if (self.onComplete) { - self.onComplete(); - } - } - // } -}; diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js new file mode 100644 index 00000000..e6db4fd2 --- /dev/null +++ b/src/core/QueueRunner.js @@ -0,0 +1,40 @@ +jasmine.QueueRunner = function(attrs) { + this.fns = attrs.fns || []; + this.onComplete = attrs.onComplete || function() {}; + this.encourageGC = attrs.encourageGC || function(fn) {fn()}; + this.onException = attrs.onException || function() {}; + this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; +}; + +jasmine.QueueRunner.prototype.execute = function() { + this.run(this.fns, 0) +}; + +jasmine.QueueRunner.prototype.run = function(fns, index) { + if (index >= fns.length) { + this.encourageGC(this.onComplete); + return; + } + + var fn = fns[index]; + var self = this; + if (fn.length > 0) { + attempt(function() { fn.call(self, function() { self.run(fns, index + 1) }) }); + } else { + attempt(function() { fn.call(self); }); + self.run(fns, index + 1); + } + + function attempt(fn) { + try { + fn(); + } catch (e) { + self.onException(e); + if (!self.catchingExceptions()) { + //TODO: set a var when we catch an exception and + //use a finally block to close the loop in a nice way.. + throw e; + } + } + } +}; diff --git a/src/core/ReportDispatcher.js b/src/core/ReportDispatcher.js new file mode 100644 index 00000000..af904838 --- /dev/null +++ b/src/core/ReportDispatcher.js @@ -0,0 +1,30 @@ +jasmine.ReportDispatcher = function(methods) { + + var dispatchedMethods = methods || []; + + for (var i = 0; i < dispatchedMethods.length; i++) { + var method = dispatchedMethods[i]; + this[method] = function(m) { + return function() { + dispatch(m, arguments); + }; + }(method); + } + + var reporters = []; + + this.addReporter = function(reporter) { + reporters.push(reporter); + }; + + return this; + + function dispatch(method, args) { + for (var i = 0; i < reporters.length; i++) { + var reporter = reporters[i]; + if (reporter[method]) { + reporter[method].apply(reporter, args); + } + } + } +}; \ No newline at end of file diff --git a/src/core/Reporter.js b/src/core/Reporter.js deleted file mode 100644 index 7bfc669b..00000000 --- a/src/core/Reporter.js +++ /dev/null @@ -1,31 +0,0 @@ -/** No-op base class for Jasmine reporters. - * - * @constructor - */ -jasmine.Reporter = function() { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerResults = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecStarting = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecResults = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.log = function(str) { -}; - diff --git a/src/core/Runner.js b/src/core/Runner.js deleted file mode 100644 index 3bf9a665..00000000 --- a/src/core/Runner.js +++ /dev/null @@ -1,80 +0,0 @@ -//TODO: runner is a special case of suite. -/** - * Runner - * - * @constructor - * @param {jasmine.Env} env - */ -jasmine.Runner = function(env, isSuite) { - var self = this; - self.env = env; - self.queue = new jasmine.Queue(env); - self.before_ = []; - self.after_ = []; - self.suites_ = []; - self.isSuite = isSuite || function() {}; -}; - -jasmine.Runner.prototype.execute = function() { - var self = this; - if (self.env.reporter.reportRunnerStarting) { - self.env.reporter.reportRunnerStarting(this); - } - self.queue.start(function () { - self.finishCallback(); - }); -}; - -jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.splice(0,0,beforeEachFunction); -}; - -jasmine.Runner.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.splice(0,0,afterEachFunction); -}; - - -jasmine.Runner.prototype.finishCallback = function() { - this.env.reporter.reportRunnerResults(this); -}; - -jasmine.Runner.prototype.addSuite = function(suite) { - this.suites_.push(suite); - this.queue.add(suite); -}; - - -//TODO: runner should die a slow unhappy death. -//Nobody should ever call instanceof. -jasmine.Runner.prototype.add = function(block) { - if (this.isSuite(block)) { - this.addSuite(block); - } else { - this.queue.add(block); - } -}; - -jasmine.Runner.prototype.specs = function () { - var suites = this.suites(); - var specs = []; - for (var i = 0; i < suites.length; i++) { - specs = specs.concat(suites[i].specs()); - } - return specs; -}; - -jasmine.Runner.prototype.suites = function() { - return this.suites_; -}; - -jasmine.Runner.prototype.topLevelSuites = function() { - var topLevelSuites = []; - for (var i = 0; i < this.suites_.length; i++) { - if (!this.suites_[i].parentSuite) { - topLevelSuites.push(this.suites_[i]); - } - } - return topLevelSuites; -}; diff --git a/src/core/Spec.js b/src/core/Spec.js index 4a751302..bc39cad3 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -1,24 +1,33 @@ jasmine.Spec = function(attrs) { - this.failedExpectations = []; this.encounteredExpectations = false; this.expectationFactory = attrs.expectationFactory; - this.resultCallback = attrs.resultCallback || function() {}; + this.resultCallback = attrs.resultCallback || function() {}; this.id = attrs.id; - this.description = attrs.description; + this.description = attrs.description || ''; this.fn = attrs.fn; this.beforeFns = attrs.beforeFns || function() {}; this.afterFns = attrs.afterFns || function() {}; this.catchingExceptions = attrs.catchingExceptions; - this.startCallback = attrs.startCallback || function() {}; + this.onStart = attrs.onStart || function() {}; this.exceptionFormatter = attrs.exceptionFormatter || function() {}; - this.getSpecName = attrs.getSpecName; + this.getSpecName = attrs.getSpecName || function() { return ''; }; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; + this.queueRunner = attrs.queueRunner || { execute: function() {}}; + this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; + + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + status: this.status(), + failedExpectations: [] + }; }; jasmine.Spec.prototype.addExpectationResult = function(passed, data) { this.encounteredExpectations = true; if (!passed) { - this.failedExpectations.push(data); + this.result.failedExpectations.push(data); } }; @@ -26,26 +35,22 @@ jasmine.Spec.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; -jasmine.Spec.prototype.execute = function() { +jasmine.Spec.prototype.execute = function(onComplete) { var self = this; + if (this.disabled) { - resultCallback(); + complete(); return; } var befores = this.beforeFns() || [], - afters = this.afterFns() || []; - this.startCallback(this); + afters = this.afterFns() || []; var allFns = befores.concat(this.fn).concat(afters); - queueRunner(allFns, 0); - - function attempt(fn) { - try { - fn(); - } catch (e) { - //TODO: weird. buildExpectationResult is really a presenter for expectations - //so this should take an expectation object. + this.onStart(this); + this.queueRunner({ + fns: allFns, + onException: function(e) { self.addExpectationResult(false, self.expectationResultFactory({ matcherName: "", passed: false, @@ -54,35 +59,17 @@ jasmine.Spec.prototype.execute = function() { message: self.exceptionFormatter(e), trace: e })); - if (!self.catchingExceptions()) { - //TODO: set a var when we catch an exception and - //use a finally block to close the loop in a nice way.. - throw e; - } - } - } + }, + onComplete: complete + }); - function queueRunner(allFns, index) { - if (index >= allFns.length) { - resultCallback(); - return; - } - var fn = allFns[index]; - if (fn.length > 0) { - attempt(function() { fn.call(self, function() { queueRunner(allFns, index + 1) }) }); - } else { - attempt(function() { fn.call(self); }); - queueRunner(allFns, index + 1); - } - } + function complete() { + self.result.status = self.status(); + self.resultCallback(self.result); - function resultCallback() { - self.resultCallback({ - id: self.id, - status: self.status(), - description: self.description, - failedExpectations: self.failedExpectations - }); + if (onComplete) { + onComplete(); + } } }; @@ -98,7 +85,8 @@ jasmine.Spec.prototype.status = function() { if (!this.encounteredExpectations) { return null; } - if (this.failedExpectations.length > 0) { + + if (this.result.failedExpectations.length > 0) { return 'failed'; } else { return 'passed'; diff --git a/src/core/Suite.js b/src/core/Suite.js index 68d36fbc..5fbdaabf 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -3,33 +3,40 @@ jasmine.Suite = function(attrs) { this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; + this.onStart = attrs.onStart || function() {}; + this.completeCallback = attrs.completeCallback || function() {}; + this.resultCallback = attrs.resultCallback || function() {}; + this.encourageGC = attrs.encourageGC || function(fn) {fn();}; + this.beforeFns = []; this.afterFns = []; + this.queueRunner = attrs.queueRunner || function() {}; + this.disabled = false; - var queueFactory = attrs.queueFactory || function() {}; - this.queue = queueFactory(); + this.children_ = []; // TODO: rename + this.suites = []; // TODO: needed? + this.specs = []; // TODO: needed? - this.isSuite = attrs.isSuite || function() {}; - - this.children_ = []; // TODO: used by current reporters; keep for now - this.suites_ = []; - this.specs_ = []; + this.result = { + id: this.id, + status: this.disabled ? 'disabled' : '', + description: this.description, + fullName: this.getFullName() + }; }; jasmine.Suite.prototype.getFullName = function() { var fullName = this.description; for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { - fullName = parentSuite.description + ' ' + fullName; + if (parentSuite.parentSuite) { + fullName = parentSuite.description + ' ' + fullName; + } } return fullName; }; -jasmine.Suite.prototype.finish = function(onComplete) { - this.env.reporter.reportSuiteResults(this); - this.finished = true; - if (typeof(onComplete) == 'function') { - onComplete(); - } +jasmine.Suite.prototype.disable = function() { + this.disabled = true; }; jasmine.Suite.prototype.beforeEach = function(fn) { @@ -40,32 +47,15 @@ jasmine.Suite.prototype.afterEach = function(fn) { this.afterFns.unshift(fn); }; -//TODO: interface should be addSpec or addSuite methods. -jasmine.Suite.prototype.add = function(suiteOrSpec) { - this.children_.push(suiteOrSpec); - if (this.isSuite(suiteOrSpec)) { - this.suites_.push(suiteOrSpec); - this.env.currentRunner().addSuite(suiteOrSpec); - } else { - this.specs_.push(suiteOrSpec); - } - this.queue.add(suiteOrSpec); +jasmine.Suite.prototype.addSpec = function(spec) { + this.children_.push(spec); + this.specs.push(spec); // TODO: needed? }; -jasmine.Suite.prototype.specComplete = function(specResult) { - specResult.fullName = this.getFullName() + ' ' + specResult.description + '.'; - specResult.suite = this; - this.env.removeAllSpies(); - this.env.reporter.reportSpecResults(specResult); - this.queue.incrementQueue(); -}; - -jasmine.Suite.prototype.specs = function() { - return this.specs_; -}; - -jasmine.Suite.prototype.suites = function() { - return this.suites_; +jasmine.Suite.prototype.addSuite = function(suite) { + suite.parentSuite = this; + this.children_.push(suite); + this.suites.push(suite); // TODO: needed? }; jasmine.Suite.prototype.children = function() { @@ -74,7 +64,36 @@ jasmine.Suite.prototype.children = function() { jasmine.Suite.prototype.execute = function(onComplete) { var self = this; - this.queue.start(function () { - self.finish(onComplete); + if (this.disabled) { + complete(); + return; + } + + var allFns = [], + children = this.children_; + + for (var i = 0; i < children.length; i++) { + allFns.push(wrapChild(children[i])); + + function wrapChild(child) { + return function(done) { + child.execute(done); + } + } + } + + this.onStart(this); + + this.queueRunner({ + fns: allFns, + onComplete: complete }); + + function complete() { + self.resultCallback(self.result); + + if (onComplete) { + onComplete(); + } + } }; diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 067b3f68..d1e4e074 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -1,176 +1,263 @@ -jasmine.HtmlReporter = function(_doc, jasmine, env, options) { - options = options || {}; - var self = this; - this.jasmine = jasmine || window.jasmine; - var doc = _doc || window.document; +jasmine.HtmlReporter = function(options) { + var env = options.env || {}, + getContainer = options.getContainer, + now = options.now || function() { return new Date().getTime();}, + createElement = options.createElement, + createTextNode = options.createTextNode, + results = [], + queryString = options.queryString, + startTime, + specsExecuted = 0, + failureCount = 0, + htmlReporterMain, + symbols; + this.initialize = function() { + htmlReporterMain = createDom("div", {className: "html-reporter"}, + createDom("div", {className: "banner"}, + createDom("span", {className: "title"}, "Jasmine"), + createDom("span", {className: "version"}, env.versionString()) + ), + createDom("ul", {className: "symbol-summary"}), + createDom("div", {className: "alert"}), + createDom("div", {className: "results"}, + createDom("div", {className: "failures"}) + ) + ); + getContainer().appendChild(htmlReporterMain); - var reporterView; - - var dom = {}; - - // Jasmine Reporter Public Interface - - self.reportRunnerStarting = function(runner) { - var specs = runner.specs() || []; - - if (specs.length == 0) { - return; - } - - createReporterDom(runner.env.versionString()); - doc.body.appendChild(dom.reporter); - setExceptionHandling(); - - reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine, env.catchingExceptions()); - reporterView.addSpecs(specs, self.specFilter); + symbols = find(".symbol-summary")[0]; }; - self.reportRunnerResults = function(runner) { - reporterView && reporterView.complete(); - }; + var specFilterPattern; - self.reportSuiteResults = function(suite) { - reporterView.suiteComplete(suite); - }; - - self.reportSpecStarting = function(spec) { - }; - - var lastYieldForRender = 0; - var refreshInterval = 250; - var yieldForRender = options.yieldForRender || function(fn) { - var now = Date.now(); - var delta = (now - lastYieldForRender); - if (delta > refreshInterval) { - lastYieldForRender = now; - setTimeout(fn, 0); - } else { - fn(); - } - } - self.reportSpecResults = function(result) { - yieldForRender(function() {reporterView.specComplete(result) }); - }; - - self.log = function() { - var console = self.jasmine.getGlobal().console; - if (console && console.log) { - if (console.log.apply) { - console.log.apply(console, arguments); - } else { - console.log(arguments); // ie fix: console.log.apply doesn't exist on ie - } - } - }; - - self.specFilter = function(spec) { - if (!focusedSpecName()) { + this.specFilter = function(spec) { + if (!isFiltered()) { return true; } - return spec.getFullName().indexOf(focusedSpecName()) === 0; + var specName = spec.getFullName(); + + return !!(specName.match(specFilterPattern)); }; - return self; + var totalSpecsDefined; + this.jasmineStarted = function(options) { + totalSpecsDefined = options.totalSpecsDefined || 0; + startTime = now(); + }; - function focusedSpecName() { - var specName; + var summary = createDom("div", {className: "summary"}); - (function memoizeFocusedSpec() { - if (specName) { - return; - } + var topResults = new jasmine.ResultsNode({}, "", null), + currentParent = topResults; - var paramMap = []; - var params = self.jasmine.HtmlReporter.parameters(doc); + this.suiteStarted = function(result) { + currentParent.addChild(result, "suite"); + currentParent = currentParent.last(); + }; - for (var i = 0; i < params.length; i++) { - var p = params[i].split('='); - paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); - } - - specName = paramMap.spec; - })(); - - return specName; - } - - function createReporterDom(version) { - dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, - dom.banner = self.createDom('div', { className: 'banner' }, - self.createDom('span', { className: 'title' }, "Jasmine "), - self.createDom('span', { className: 'version' }, version)), - - dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), - dom.alert = self.createDom('div', {className: 'alert'}, - self.createDom('span', { className: 'exceptions' }, - self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), - self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), - dom.results = self.createDom('div', {className: 'results'}, - dom.summary = self.createDom('div', { className: 'summary' }), - dom.details = self.createDom('div', { id: 'details' })) - ); - } - - function noTryCatch() { - return window.location.search.match(/catch=false/); - } - - function searchWithCatch() { - var params = self.jasmine.HtmlReporter.parameters(window.document); - var removed = false; - var i = 0; - - while (!removed && i < params.length) { - if (params[i].match(/catch=/)) { - params.splice(i, 1); - removed = true; - } - i++; - } - if (env.catchingExceptions()) { - params.push("catch=false"); + this.suiteDone = function(result) { + if (currentParent == topResults) { + return; } - return params.join("&"); - } + currentParent = currentParent.parent; + }; - function setExceptionHandling() { - var chxCatch = document.getElementById('no_try_catch'); + this.specStarted = function(result) { + currentParent.addChild(result, "spec"); + }; - if (noTryCatch()) { - chxCatch.setAttribute('checked', true); - env.catchExceptions(false); + var failures = []; + this.specDone = function(result) { + if (result.status != "disabled") { + specsExecuted++; } - chxCatch.onclick = function() { - window.location.search = searchWithCatch(); + + symbols.appendChild(createDom("li", { + className: result.status, + id: "spec_" + result.id} + )); + + if (result.status == "failed") { + failureCount++; + + var failure = + createDom("div", {className: "spec-detail failed"}, + createDom("a", {className: "description", title: result.fullName, href: specHref(result)}, result.fullName), + createDom("div", {className: "messages"}) + ); + var messages = failure.childNodes[1]; + + for (var i = 0; i < result.failedExpectations.length; i++) { + var expectation = result.failedExpectations[i]; + var stack = (expectation.trace && expectation.trace.stack) || ""; + messages.appendChild(createDom("div", {className: "result-message"}, expectation.message)); + messages.appendChild(createDom("div", {className: "stack-trace"}, stack)); + } + + failures.push(failure); + } + }; + + this.jasmineDone = function() { + var elapsed = now() - startTime; + + var banner = find(".banner")[0]; + banner.appendChild(createDom("span", {className: "duration"}, "finished in " + elapsed / 1000 + "s")); + + var alert = find(".alert")[0]; + + alert.appendChild(createDom("span", { className: "exceptions" }, + createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"), + createDom("input", { + className: "raise", + id: "raise-exceptions", + type: "checkbox" + }) + )); + var checkbox = find("input")[0]; + + checkbox.checked = !env.catchingExceptions(); + checkbox.onclick = function() { + queryString.setParam("catch", !checkbox.checked); }; - } -}; -jasmine.HtmlReporter.parameters = function(doc) { - var paramStr = doc.location.search.substring(1); - var params = []; - if (paramStr.length > 0) { - params = paramStr.split('&'); - } - return params; -} -jasmine.HtmlReporter.sectionLink = function(sectionName, catchExceptions) { - var link = '?'; - var params = []; + if (specsExecuted < totalSpecsDefined) { + var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all"; + alert.appendChild( + createDom("span", {className: "bar skipped"}, + createDom("a", {href: "?", title: "Run all specs"}, skippedMessage) + ) + ); + } + var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount), + statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed"); + alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage)); - if (sectionName) { - params.push('spec=' + encodeURIComponent(sectionName)); - } - if (!catchExceptions) { - params.push("catch=false"); - } - if (params.length > 0) { - link += params.join("&"); + var results = find(".results")[0]; + results.appendChild(summary); + + summaryList(topResults, summary); + + function summaryList(resultsTree, domParent) { + var specListNode; + for (var i = 0; i < resultsTree.children.length; i++) { + var resultNode = resultsTree.children[i]; + if (resultNode.type == "suite") { + var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id}, + createDom("li", {className: "suite-detail"}, + createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) + ) + ); + + summaryList(resultNode, suiteListNode); + domParent.appendChild(suiteListNode); + } + if (resultNode.type == "spec") { + if (domParent.getAttribute("class") != "specs") { + specListNode = createDom("ul", {className: "specs"}); + domParent.appendChild(specListNode); + } + specListNode.appendChild( + createDom("li", { + className: resultNode.result.status, + id: "spec-" + resultNode.result.id + }, + createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) + ) + ); + } + } + } + + if (failures.length) { + alert.appendChild( + createDom('span', {className: "menu bar spec-list"}, + createDom("span", {}, "Spec List | "), + createDom('a', {className: "failures-menu", href: "#"}, "Failures"))); + alert.appendChild( + createDom('span', {className: "menu bar failure-list"}, + createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"), + createDom("span", {}, " | Failures "))); + + find(".failures-menu")[0].onclick = function() { + setMenuModeTo('failure-list'); + }; + find(".spec-list-menu")[0].onclick = function() { + setMenuModeTo('spec-list'); + }; + + setMenuModeTo('failure-list'); + + var failureNode = find(".failures")[0]; + for (var i = 0; i < failures.length; i++) { + failureNode.appendChild(failures[i]); + } + } + }; + + return this; + + function find(selector) { + if (selector.match(/^\./)) { + var className = selector.substring(1); + return getContainer().getElementsByClassName(className); + } else { + return getContainer().getElementsByTagName(selector); + } } - return link; -}; -jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter); + function createDom(type, attrs, childrenVarArgs) { + var el = createElement(type); + + for (var i = 2; i < arguments.length; i++) { + var child = arguments[i]; + + if (typeof child === 'string') { + el.appendChild(createTextNode(child)); + } else { + if (child) { + el.appendChild(child); + } + } + } + + for (var attr in attrs) { + if (attr == "className") { + el[attr] = attrs[attr]; + } else { + el.setAttribute(attr, attrs[attr]); + } + } + + return el; + } + + function pluralize(singular, count) { + var word = (count == 1 ? singular : singular + "s"); + + return "" + count + " " + word; + } + + function specHref(result) { + return "?spec=" + encodeURIComponent(result.fullName); + } + + function isFiltered() { + buildSpecFilter(); + + return !!specFilterPattern; + } + + function buildSpecFilter() { + var specFilterParam = queryString.getParam("spec") || ""; + + specFilterPattern = new RegExp(specFilterParam); + } + + function setMenuModeTo(mode) { + htmlReporterMain.setAttribute("class", "html-reporter " + mode); + } +}; \ No newline at end of file diff --git a/src/html/HtmlReporterHelpers.js b/src/html/HtmlReporterHelpers.js deleted file mode 100644 index ce33af0f..00000000 --- a/src/html/HtmlReporterHelpers.js +++ /dev/null @@ -1,64 +0,0 @@ -jasmine.HtmlReporterHelpers = {}; - -jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { - var el = document.createElement(type); - - for (var i = 2; i < arguments.length; i++) { - var child = arguments[i]; - - if (typeof child === 'string') { - el.appendChild(document.createTextNode(child)); - } else { - if (child) { - el.appendChild(child); - } - } - } - - for (var attr in attrs) { - if (attr == "className") { - el[attr] = attrs[attr]; - } else { - el.setAttribute(attr, attrs[attr]); - } - } - - return el; -}; - -jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { - if (!child.results) { - return; - } - var results = child.results(); - var status = results.passed() ? 'passed' : 'failed'; - if (results.skipped) { - status = 'skipped'; - } - - return status; -}; - -jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { - var parentDiv = this.dom.summary; - var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; - var parent = child[parentSuite]; - - if (parent) { - if (typeof this.views.suites[parent.id] == 'undefined') { - this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine, this.catchExceptions); - } - parentDiv = this.views.suites[parent.id].element; - } - - parentDiv.appendChild(childElement); -}; - - -jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { - //TODO: not really a helper, thus, no this.jasmine - for(var fn in jasmine.HtmlReporterHelpers) { - ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; - } -}; - diff --git a/src/html/QueryString.js b/src/html/QueryString.js new file mode 100644 index 00000000..53accf05 --- /dev/null +++ b/src/html/QueryString.js @@ -0,0 +1,43 @@ +jasmine.QueryString = function(options) { + + this.setParam = function(key, value) { + var paramMap = queryStringToParamMap(); + paramMap[key] = value; + options.getWindowLocation().search = toQueryString(paramMap); + }; + + this.getParam = function(key) { + return queryStringToParamMap()[key]; + }; + + return this; + + function toQueryString(paramMap) { + var qStrPairs = []; + for (var prop in paramMap) { + qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop])); + } + return "?" + qStrPairs.join('&'); + } + + function queryStringToParamMap() { + var paramStr = options.getWindowLocation().search.substring(1), + params = [], + paramMap = {}; + + if (paramStr.length > 0) { + params = paramStr.split('&'); + for (var i = 0; i < params.length; i++) { + var p = params[i].split('='); + var value = decodeURIComponent(p[1]); + if (value === "true" || value === "false") { + value = JSON.parse(value); + } + paramMap[decodeURIComponent(p[0])] = value; + } + } + + return paramMap; + } + +}; \ No newline at end of file diff --git a/src/html/ResultsNode.js b/src/html/ResultsNode.js new file mode 100644 index 00000000..c205e617 --- /dev/null +++ b/src/html/ResultsNode.js @@ -0,0 +1,15 @@ +jasmine.ResultsNode = function(result, type, parent) { + this.result = result; + this.type = type; + this.parent = parent; + + this.children = []; + + this.addChild = function(result, type) { + this.children.push(new jasmine.ResultsNode(result, type, this)); + }; + + this.last = function() { + return this.children[this.children.length-1]; + } +}; \ No newline at end of file diff --git a/src/html/_HTMLReporter.scss b/src/html/_HTMLReporter.scss index 04f42cca..a9d84fcc 100644 --- a/src/html/_HTMLReporter.scss +++ b/src/html/_HTMLReporter.scss @@ -3,7 +3,7 @@ $line-height: 14px; $margin-unit: 14px; -$feint-text-color: #aaa; +$faint-text-color: #aaa; $light-text-color: #666; $text-color: #333; @@ -27,7 +27,7 @@ body { overflow-y: scroll; } -#HTMLReporter { +.html-reporter { font-size: $font-size; font-family: Monaco, "Lucida Console", monospace; @@ -36,101 +36,104 @@ body { a { text-decoration: none; - + &:hover { text-decoration: underline; } } - + p, h1, h2, h3, h4, h5, h6 { margin: 0; line-height: $line-height; } - + .banner, - .symbolSummary, + .symbol-summary, .summary, - .resultMessage, - .specDetail .description, + .result-message, + .spec .description, + .spec-detail .description, .alert .bar, - .stackTrace { + .stack-trace { padding-left: $margin-unit - 5px; padding-right: $margin-unit - 5px; } - + + .banner .version { + margin-left: $margin-unit; + }; + // This div is available for testing elements that must be added to the DOM. // We position it out of view, so it doesn't obstruct the runner. #jasmine_content { position: fixed; right: 100%; } - + .version { - color: $feint-text-color; + color: $faint-text-color; } - + //--- Banner ---// - + .banner { margin-top: $line-height; } - + .duration { - color: $feint-text-color; + color: $faint-text-color; float: right; } - + //--- Symbol summary ---// - - .symbolSummary { + + .symbol-summary { @include clearfix; margin: $line-height 0; - + li { display: block; float: left; height: $line-height / 2; width: $line-height; margin-bottom: $line-height / 2; - - //opacity: .9; - + font-size: 16px; - + &.passed { font-size: 14px; - - &:before{ + + &:before { color: $passing-color; content: "\02022"; } } - + &.failed { line-height: ($line-height / 2) + 2; - - &:before{ + + &:before { color: $failing-color; content: "x"; font-weight: bold; margin-left: -1px; } } - - &.skipped { + + &.disabled { font-size: 14px; - - &:before{ + + &:before { color: $neutral-color; content: "\02022"; } } - - &.pending{ + + &.pending { line-height: ($line-height / 2) + 4; - + &:before { - color: $feint-text-color; + color: $faint-text-color; content: "-"; } } @@ -144,7 +147,7 @@ body { margin-right: 5px; } - //--- Alert ---// + //--- Alerts: status bars ---// .bar { line-height: $line-height * 2; @@ -152,40 +155,50 @@ body { display: block; color: #eee; - } - .runningAlert { - background-color: $light-text-color; - } - - .skippedAlert { - background-color: $feint-text-color; - - &:first-child { - background-color: $text-color; - } - - &:hover { - text-decoration: none; - color: white; - text-decoration: underline; - } - } - - .passingAlert { - background-color: $light-passing-color; - - &:first-child { - background-color: $passing-color; - } - } - - .failingAlert { - background-color: $light-failing-color; - - &:first-child { + &.failed { background-color: $failing-color } + + &.passed { + background-color: $light-passing-color; + } + + &.skipped { + background-color: $neutral-color; + } + + &.menu { + background-color: #fff; + color: $faint-text-color; + + a { + color: $text-color; + } + } + + a { + color: white; + } + } + + // simplify toggle control between the two menu bars + &.spec-list { + .bar.menu.failure-list, + .results .failures { + display: none; + } + } + + &.failure-list { + .bar.menu.spec-list, + .summary { + display: none; + } + } + + .running-alert { + background-color: $light-text-color; } //--- Results ---// @@ -196,16 +209,6 @@ body { //--- Results menu ---// - #details { - display: none; - } - - .resultsMenu, - .resultsMenu a { - background-color: #fff; - color: $text-color; - } - &.showDetails { .summaryMenuItem { @@ -236,19 +239,28 @@ body { text-decoration: underline; } - //--- Results summary ---// + //--- Results summary: Suites and Specs names/links ---// .summary { margin-top: $margin-unit; - .suite .suite, .specSummary { + ul { + list-style-type: none; margin-left: $margin-unit; + padding-top: 0; + padding-left: 0; + + &.suite { + margin-top: $margin-unit/2; + margin-bottom: $margin-unit/2 + } } - .specSummary { + li { &.passed a { color: $passing-color; } + &.failed a { color: $failing-color; } @@ -267,10 +279,10 @@ body { } } - //--- Results details ---// + //--- Failure details ---// - #details { - .specDetail { + .failures { + .spec-detail { margin-bottom: $line-height * 2; .description { @@ -285,17 +297,17 @@ body { } } - .resultMessage { + .result-message { padding-top: $line-height; color: $text-color; } - .resultMessage span.result { + .result-message span.result { display: block; } - .stackTrace { + .stack-trace { margin: 5px 0 0 0; max-height: $line-height * 16; overflow: auto; diff --git a/src/html/jasmine.css b/src/html/jasmine.css index 69e6db8b..91147778 100644 --- a/src/html/jasmine.css +++ b/src/html/jasmine.css @@ -1,52 +1,53 @@ body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } -#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } -#HTMLReporter a { text-decoration: none; } -#HTMLReporter a:hover { text-decoration: underline; } -#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; } -#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; } -#HTMLReporter #jasmine_content { position: fixed; right: 100%; } -#HTMLReporter .version { color: #aaaaaa; } -#HTMLReporter .banner { margin-top: 14px; } -#HTMLReporter .duration { color: #aaaaaa; float: right; } -#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; } -#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } -#HTMLReporter .symbolSummary li.passed { font-size: 14px; } -#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; } -#HTMLReporter .symbolSummary li.failed { line-height: 9px; } -#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } -#HTMLReporter .symbolSummary li.skipped { font-size: 14px; } -#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; } -#HTMLReporter .symbolSummary li.pending { line-height: 11px; } -#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; } -#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } -#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } -#HTMLReporter .runningAlert { background-color: #666666; } -#HTMLReporter .skippedAlert { background-color: #aaaaaa; } -#HTMLReporter .skippedAlert:first-child { background-color: #333333; } -#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; } -#HTMLReporter .passingAlert { background-color: #a6b779; } -#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; } -#HTMLReporter .failingAlert { background-color: #cf867e; } -#HTMLReporter .failingAlert:first-child { background-color: #b03911; } -#HTMLReporter .results { margin-top: 14px; } -#HTMLReporter #details { display: none; } -#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; } -#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } -#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } -#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } -#HTMLReporter.showDetails .summary { display: none; } -#HTMLReporter.showDetails #details { display: block; } -#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } -#HTMLReporter .summary { margin-top: 14px; } -#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; } -#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; } -#HTMLReporter .summary .specSummary.failed a { color: #b03911; } -#HTMLReporter .description + .suite { margin-top: 0; } -#HTMLReporter .suite { margin-top: 14px; } -#HTMLReporter .suite a { color: #333333; } -#HTMLReporter #details .specDetail { margin-bottom: 28px; } -#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; } -#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } -#HTMLReporter .resultMessage span.result { display: block; } -#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } +.html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } +.html-reporter a { text-decoration: none; } +.html-reporter a:hover { text-decoration: underline; } +.html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; } +.html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; } +.html-reporter .banner .version { margin-left: 14px; } +.html-reporter #jasmine_content { position: fixed; right: 100%; } +.html-reporter .version { color: #aaaaaa; } +.html-reporter .banner { margin-top: 14px; } +.html-reporter .duration { color: #aaaaaa; float: right; } +.html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; } +.html-reporter .symbol-summary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } +.html-reporter .symbol-summary li.passed { font-size: 14px; } +.html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; } +.html-reporter .symbol-summary li.failed { line-height: 9px; } +.html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } +.html-reporter .symbol-summary li.disabled { font-size: 14px; } +.html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; } +.html-reporter .symbol-summary li.pending { line-height: 11px; } +.html-reporter .symbol-summary li.pending:before { color: #aaaaaa; content: "-"; } +.html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } +.html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } +.html-reporter .bar.failed { background-color: #b03911; } +.html-reporter .bar.passed { background-color: #a6b779; } +.html-reporter .bar.skipped { background-color: #bababa; } +.html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; } +.html-reporter .bar.menu a { color: #333333; } +.html-reporter .bar a { color: white; } +.html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; } +.html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; } +.html-reporter .running-alert { background-color: #666666; } +.html-reporter .results { margin-top: 14px; } +.html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } +.html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } +.html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } +.html-reporter.showDetails .summary { display: none; } +.html-reporter.showDetails #details { display: block; } +.html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } +.html-reporter .summary { margin-top: 14px; } +.html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } +.html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; } +.html-reporter .summary li.passed a { color: #5e7d00; } +.html-reporter .summary li.failed a { color: #b03911; } +.html-reporter .description + .suite { margin-top: 0; } +.html-reporter .suite { margin-top: 14px; } +.html-reporter .suite a { color: #333333; } +.html-reporter .failures .spec-detail { margin-bottom: 28px; } +.html-reporter .failures .spec-detail .description { display: block; color: white; background-color: #b03911; } +.html-reporter .result-message { padding-top: 14px; color: #333333; } +.html-reporter .result-message span.result { display: block; } +.html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } diff --git a/tasks/jasmine_dev/sources.rb b/tasks/jasmine_dev/sources.rb index 87aee274..dcba3026 100644 --- a/tasks/jasmine_dev/sources.rb +++ b/tasks/jasmine_dev/sources.rb @@ -6,25 +6,21 @@ class JasmineDev < Thor "ExceptionFormatter.js", "ExpectationResult.js", "Env.js", - "Reporter.js", "JsApiReporter.js", "Matchers.js", - "MultiReporter.js", "PrettyPrinter.js", - "Queue.js", - "Runner.js", + "QueueRunner.js", "Spec.js", "Suite.js", "Clock.js", - "DelayedFunctionScheduler.js" + "DelayedFunctionScheduler.js", + "ReportDispatcher.js" ], :html => [ - "HtmlReporterHelpers.js", "HtmlReporter.js", - "ReporterView.js", - "SpecView.js", - "SuiteView.js", + "ResultsNode.js", + "QueryString.js" ] } end From f865758124545099040564629b0c7062dbda8375 Mon Sep 17 00:00:00 2001 From: "Dan Hansen and Davis W. Frank" Date: Tue, 19 Feb 2013 11:52:16 -0800 Subject: [PATCH 55/55] Updated jasmine.js --- lib/jasmine-core/jasmine.js | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index e3db7790..d5f4f8d2 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -439,18 +439,15 @@ jasmine.util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); return arrayOfArgs; -};jasmine.exceptionFormatter = function(e) { - var file = e.fileName || e.sourceURL || '', - line = e.lineNumber || e.line || '', - message = e.toString(); - - if (file.length && line.length) { - message += ' (' - + file - + ':' - + line - + ')'; - } +};jasmine.exceptionMessageFor = function(e) { + var message = e.name + + ': ' + + e.message + + ' in ' + + (e.fileName || e.sourceURL || '') + + ' (line ' + + (e.line || e.lineNumber || '') + + ')'; return message; }; @@ -1660,7 +1657,7 @@ jasmine.Spec.prototype.status = function() { jasmine.Spec.prototype.getFullName = function() { return this.getSpecName(this); -}; +} jasmine.Suite = function(attrs) { this.env = attrs.env; this.id = attrs.id;