From cbe9af32a0287766c1ae25a79f8f5f9d71f472e5 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Thu, 23 Feb 2012 22:41:37 -0500 Subject: [PATCH 1/5] added jasmine-headless-webkit, which lets you run specs headlessly (shares the jasmine.yml config used by the official jasmine gem). To run it, just run: bundle exec jasmine-headless-webkit Goes great with guard, as well. --- .gitignore | 1 + Gemfile | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 312359b..5aedb51 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.swo *.orig Gemfile.lock +.jhw-cache \ No newline at end of file diff --git a/Gemfile b/Gemfile index 578fdaf..c60d148 100644 --- a/Gemfile +++ b/Gemfile @@ -4,5 +4,6 @@ gem 'rake' group :development do gem 'jasmine', '~>1.0' + gem 'jasmine-headless-webkit' end From beadb92452dc9cf491fdd526941b5199421d3117 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Thu, 23 Feb 2012 22:42:43 -0500 Subject: [PATCH 2/5] Wanted to learn what the callback received, so I replaced the boolean flag with a spy and set an expectation on the args. --- spec/javascripts/attributeHandlers.spec.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/spec/javascripts/attributeHandlers.spec.js b/spec/javascripts/attributeHandlers.spec.js index fab0e59..469e140 100644 --- a/spec/javascripts/attributeHandlers.spec.js +++ b/spec/javascripts/attributeHandlers.spec.js @@ -8,13 +8,12 @@ describe("attribute handlers", function(){ }); describe("when registering an attribute handler", function(){ - var handlerWascalled; - - Backbone.Phoenix.addAttributeHandler("fn", function(config, value){ - handlerWasCalled = true; - }); + var handler; beforeEach(function(){ + handler = jasmine.createSpy(); + Backbone.Phoenix.addAttributeHandler("fn", handler); + this.model = new Backbone.Model(); this.view = new View({ model: this.model @@ -25,7 +24,7 @@ describe("attribute handlers", function(){ }); it("should call the registered handler", function(){ - expect(handlerWasCalled).toBeTruthy(); + expect(handler).toHaveBeenCalledWith('foo','foo bar'); }); }); From f53044286258a1e140efb86f2bfb933e5913003f Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Thu, 23 Feb 2012 22:50:02 -0500 Subject: [PATCH 3/5] adds `rake jasmine:headless` --- Rakefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Rakefile b/Rakefile index 12dc73a..f8b2645 100644 --- a/Rakefile +++ b/Rakefile @@ -1,2 +1,7 @@ require 'jasmine' load 'jasmine/tasks/jasmine.rake' + +require 'jasmine-headless-webkit' +Jasmine::Headless::Task.new('jasmine:headless') do |t| + t.colors = true +end \ No newline at end of file From f8e0e76cb6cb736f84da135b2385032062edd7e1 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Thu, 23 Feb 2012 23:03:09 -0500 Subject: [PATCH 4/5] added guard-jasmine-headless-webkit Can now run jasmine tests as files are changed: `bundle exec guard` --- Gemfile | 1 + Guardfile | 7 +++++++ spec/javascripts/support/jasmine.yml | 1 + 3 files changed, 9 insertions(+) create mode 100644 Guardfile diff --git a/Gemfile b/Gemfile index c60d148..d69f1e4 100644 --- a/Gemfile +++ b/Gemfile @@ -5,5 +5,6 @@ gem 'rake' group :development do gem 'jasmine', '~>1.0' gem 'jasmine-headless-webkit' + gem 'guard-jasmine-headless-webkit' end diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..79fc25f --- /dev/null +++ b/Guardfile @@ -0,0 +1,7 @@ +spec_location = "spec/javascripts/%s.spec" + +guard 'jasmine-headless-webkit' do + watch(%r{^public/javascripts/(.*)\.js$}) { |m| newest_js_file(spec_location % m[1]) } + watch(%r{^spec/javascripts/helpers*}) + watch(%r{^spec/javascripts/(.*)\.spec\..*}) { |m| newest_js_file(spec_location % m[1]) } +end \ No newline at end of file diff --git a/spec/javascripts/support/jasmine.yml b/spec/javascripts/support/jasmine.yml index 734e26d..5d6ef5e 100644 --- a/spec/javascripts/support/jasmine.yml +++ b/spec/javascripts/support/jasmine.yml @@ -52,6 +52,7 @@ helpers: # - **/*[sS]pec.js # spec_files: + - "**/*[sS]pec.{js,coffee}" # src_dir # From 7b636e11e8e0bf5db0ffbb269442d218dfed5d61 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Thu, 23 Feb 2012 23:04:37 -0500 Subject: [PATCH 5/5] re-imagined the attribute handlers spec in coffee- script, using the jasmine-given DSL --- .../javascripts/attributeHandlers.spec.coffee | 16 +++ spec/javascripts/attributeHandlers.spec.js | 31 ----- spec/javascripts/helpers/SpecHelper.js | 3 + .../helpers/jasmine-given-0.0.6.js | 108 ++++++++++++++++++ 4 files changed, 127 insertions(+), 31 deletions(-) create mode 100644 spec/javascripts/attributeHandlers.spec.coffee delete mode 100644 spec/javascripts/attributeHandlers.spec.js create mode 100644 spec/javascripts/helpers/jasmine-given-0.0.6.js diff --git a/spec/javascripts/attributeHandlers.spec.coffee b/spec/javascripts/attributeHandlers.spec.coffee new file mode 100644 index 0000000..542773f --- /dev/null +++ b/spec/javascripts/attributeHandlers.spec.coffee @@ -0,0 +1,16 @@ +class View extends Backbone.View + render: -> + @$el.html("
") + Backbone.Phoenix.bind(this) + +describe "attribute handlers", -> + + context "registering an attribute handler", -> + Given -> Backbone.Phoenix.addAttributeHandler "fn", @handler = jasmine.createSpy() + Given -> @model = new Backbone.Model() + Given -> new View(model: @model).render() + + When -> @model.set("fn-test": "foo bar") + + Then -> expect(@handler).toHaveBeenCalledWith("foo", "foo bar") + diff --git a/spec/javascripts/attributeHandlers.spec.js b/spec/javascripts/attributeHandlers.spec.js deleted file mode 100644 index 469e140..0000000 --- a/spec/javascripts/attributeHandlers.spec.js +++ /dev/null @@ -1,31 +0,0 @@ -describe("attribute handlers", function(){ - - var View = Backbone.View.extend({ - render: function(){ - this.$el.html("
"); - Backbone.Phoenix.bind(this); - } - }); - - describe("when registering an attribute handler", function(){ - var handler; - - beforeEach(function(){ - handler = jasmine.createSpy(); - Backbone.Phoenix.addAttributeHandler("fn", handler); - - this.model = new Backbone.Model(); - this.view = new View({ - model: this.model - }); - this.view.render(); - - this.model.set({"fn-test": "foo bar"}); - }); - - it("should call the registered handler", function(){ - expect(handler).toHaveBeenCalledWith('foo','foo bar'); - }); - }); - -}); diff --git a/spec/javascripts/helpers/SpecHelper.js b/spec/javascripts/helpers/SpecHelper.js index b9fd62c..5664af6 100644 --- a/spec/javascripts/helpers/SpecHelper.js +++ b/spec/javascripts/helpers/SpecHelper.js @@ -1,3 +1,6 @@ +window.context = window.describe; +window.xcontext = window.xdescribe; + beforeEach(function() { this.addMatchers({ }) diff --git a/spec/javascripts/helpers/jasmine-given-0.0.6.js b/spec/javascripts/helpers/jasmine-given-0.0.6.js new file mode 100644 index 0000000..1604c4a --- /dev/null +++ b/spec/javascripts/helpers/jasmine-given-0.0.6.js @@ -0,0 +1,108 @@ +(function() { + + (function(jasmine) { + var mostRecentlyUsed, o, stringifyExpectation; + stringifyExpectation = function(expectation) { + var matches; + matches = expectation.toString().replace(/\n/g, '').match(/function\s?\(\)\s?{\s*(return\s+)?(.*?)(;)?\s*}/i); + if (matches && matches.length >= 3) { + return matches[2]; + } else { + return ""; + } + }; + beforeEach(function() { + return this.addMatchers({ + toHaveReturnedFalseFromThen: function(context, n) { + var exception, result; + result = false; + exception = void 0; + try { + result = this.actual.call(context); + } catch (e) { + exception = e; + } + this.message = function() { + var msg; + msg = "Then clause " + (n > 1 ? " #" + n : "") + " `" + (stringifyExpectation(this.actual)) + "` failed by "; + if (exception) { + msg += "throwing: " + exception.toString(); + } else { + msg += "returning false"; + } + return msg; + }; + return result === false; + } + }); + }); + window.When = window.Given = function() { + var assignResultTo, mostRecentlyUsed, setupFunction; + setupFunction = o(arguments).firstThat(function(arg) { + return o(arg).isFunction(); + }); + assignResultTo = o(arguments).firstThat(function(arg) { + return o(arg).isString(); + }); + mostRecentlyUsed = window.Given; + return beforeEach(function() { + var context, result; + context = jasmine.getEnv().currentSpec; + result = setupFunction.call(context); + if (assignResultTo) { + if (!context[assignResultTo]) { + return context[assignResultTo] = result; + } else { + throw new Error("Unfortunately, the variable '" + assignResultTo + "' is already assigned to: " + context[assignResultTo]); + } + } + }); + }; + window.Then = function(expectationFunction) { + var expectations, mostRecentlyUsed, subsequentThen; + mostRecentlyUsed = window.Then; + expectations = [expectationFunction]; + subsequentThen = function(additionalExpectation) { + expectations.push(additionalExpectation); + return this; + }; + it("then " + (stringifyExpectation(expectations)), function() { + var i, _results; + i = 0; + _results = []; + while (i < expectations.length) { + expect(expectations[i]).not.toHaveReturnedFalseFromThen(jasmine.getEnv().currentSpec, i + 1); + _results.push(i++); + } + return _results; + }); + return { + Then: subsequentThen, + And: subsequentThen + }; + }; + mostRecentlyUsed = window.Given; + window.And = function() { + return mostRecentlyUsed.apply(this, jasmine.util.argsToArray(arguments)); + }; + return o = function(thing) { + return { + isFunction: function() { + return Object.prototype.toString.call(thing) === "[object Function]"; + }, + isString: function() { + return Object.prototype.toString.call(thing) === "[object String]"; + }, + firstThat: function(test) { + var i; + i = 0; + while (i < thing.length) { + if (test(thing[i]) === true) return thing[i]; + i++; + } + } + }; + }; + })(jasmine); + +}).call(this);