initial commit
This commit is contained in:
commit
ccd63b9393
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
*.gem
|
||||||
|
*.rbc
|
||||||
|
.bundle
|
||||||
|
.config
|
||||||
|
.yardoc
|
||||||
|
Gemfile.lock
|
||||||
|
InstalledFiles
|
||||||
|
_yardoc
|
||||||
|
coverage
|
||||||
|
doc/
|
||||||
|
lib/bundler/man
|
||||||
|
pkg
|
||||||
|
rdoc
|
||||||
|
spec/reports
|
||||||
|
test/tmp
|
||||||
|
test/version_tmp
|
||||||
|
tmp
|
4
Gemfile
Normal file
4
Gemfile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
# Specify your gem's dependencies in jasmine-gwt.gemspec
|
||||||
|
gemspec
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Copyright (c) 2012 John Bintz
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
84
README.md
Normal file
84
README.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
`jasmine-gwt` provides a cool Given-When-Then syntax not dissimilar to [Cucumber](http://cukes.info/), but
|
||||||
|
running entirely in [Jasmine](http://pivotal.github.com/jasmine/). No other dependencies (except CoffeeScript,
|
||||||
|
but that'll change.) Also, writing these in CoffeeScript gives you an experience really close to Cucumber, so yeah.
|
||||||
|
|
||||||
|
Import the library, say by using Sprockets in your `spec_helper.js.coffee`:
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
#= require jasmine-gwt
|
||||||
|
#= require_tree ./steps
|
||||||
|
```
|
||||||
|
|
||||||
|
Then create some features for a thing:
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
Feature 'Complex Backbone View', ->
|
||||||
|
Background ->
|
||||||
|
Given 'I have a model', ->
|
||||||
|
@model = new Backbone.Model()
|
||||||
|
Given 'I have a view', ->
|
||||||
|
@view = new ComplexBackboneView(model: @model)
|
||||||
|
|
||||||
|
Scenario 'Basics', ->
|
||||||
|
When 'I render the view'
|
||||||
|
Then 'the view should return itself'
|
||||||
|
Then 'the view should contain ".loader"'
|
||||||
|
|
||||||
|
Scenario 'Model has a name', ->
|
||||||
|
Given 'the model has the name "John"'
|
||||||
|
When 'I render the view'
|
||||||
|
Then 'the view has ".name" with the text "John"'
|
||||||
|
```
|
||||||
|
|
||||||
|
Run it and you'll be told you need to define some steps, Cucumber-style:
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
When /I render the view/, ->
|
||||||
|
@result = @view.render()
|
||||||
|
|
||||||
|
Then /the view should return itself/, ->
|
||||||
|
expect(@result).toEqual(@view)
|
||||||
|
|
||||||
|
Then /the view should contain "([^"]+)"/, (selector) ->
|
||||||
|
expect($(@view.el)).toContain(selector)
|
||||||
|
|
||||||
|
Given /the model has the name "([^"]+)"/, (name) ->
|
||||||
|
@model.set(name: name)
|
||||||
|
|
||||||
|
Then /the view has the "([^"]+)" with the text "([^"]+)"/, (selector, text) ->
|
||||||
|
expect(view.$(selector)).toHaveText(text)
|
||||||
|
```
|
||||||
|
|
||||||
|
If you give a step a callback in the `Scenario` or `Background` block, it'll just run that code.
|
||||||
|
|
||||||
|
Then write your usual Jasmine specs to test from bottom-up, and use the features to test from the top-down.
|
||||||
|
It's awesome! Errors are reported along with the rest of your Jasmine specs, since `jasmine-gwt` just generates
|
||||||
|
`describe` and `it` blocks for each of the steps.
|
||||||
|
|
||||||
|
You also have `Before` and `After` hooks for each scenario. Here's a handy one for Sinon.JS fake server support.
|
||||||
|
|
||||||
|
```
|
||||||
|
Before ->
|
||||||
|
@server = sinon.fakeServer.create()
|
||||||
|
|
||||||
|
After ->
|
||||||
|
@server.restore()
|
||||||
|
|
||||||
|
*Important*: Use single-arrows when defining steps. Each block of code is executed in the same context, and mucking
|
||||||
|
with that would make thing probably not work too well.
|
||||||
|
|
||||||
|
## Why not another GWT library, or Cucumber itself?
|
||||||
|
|
||||||
|
I wanted something that worked as much like Cucumber as possible without actually bringing in Cucumber. Bringing in
|
||||||
|
Cucumber into my toolchain would be more work right now than I want to deal with (making `jasmine-headless-webkit` support
|
||||||
|
CommonJS `require`, for instance), but I also wanted as much of the cool magic that Cucumber had. Therefore, this library.
|
||||||
|
|
||||||
|
Todo:
|
||||||
|
|
||||||
|
* Test the code (I cowboyed it! Yeehaw!)
|
||||||
|
* Step hooks (`BeforeEach` and `AfterEach`)
|
||||||
|
* Tagged scenarios
|
||||||
|
* Hooks that only react to certain tags
|
||||||
|
|
||||||
|
So alpha it's pretty much the letter before alpha.
|
||||||
|
|
17
jasmine-gwt.gemspec
Normal file
17
jasmine-gwt.gemspec
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
require File.expand_path('../lib/jasmine-gwt/version', __FILE__)
|
||||||
|
|
||||||
|
Gem::Specification.new do |gem|
|
||||||
|
gem.authors = ["John Bintz"]
|
||||||
|
gem.email = ["john@coswellproductions.com"]
|
||||||
|
gem.description = %q{Given-When-Then syntax for Jasmine that looks suspiciously like Cucumber}
|
||||||
|
gem.summary = %q{Given-When-Then syntax for Jasmine that looks suspiciously like Cucumber}
|
||||||
|
gem.homepage = ""
|
||||||
|
|
||||||
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||||
|
gem.files = `git ls-files`.split("\n")
|
||||||
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
||||||
|
gem.name = "jasmine-gwt"
|
||||||
|
gem.require_paths = ["lib"]
|
||||||
|
gem.version = Jasmine::GWT::VERSION
|
||||||
|
end
|
175
lib/assets/javascripts/jasmine-gwt.js.coffee
Normal file
175
lib/assets/javascripts/jasmine-gwt.js.coffee
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
jasmine.GWT =
|
||||||
|
Step: (type, name, parameter) ->
|
||||||
|
if scenario = jasmine.GWT.currentScenario_
|
||||||
|
scenario[type](name, parameter)
|
||||||
|
else
|
||||||
|
jasmine.GWT.Steps[type] ||= []
|
||||||
|
jasmine.GWT.Steps[type].push([ name, parameter ])
|
||||||
|
Hook: (type, code) ->
|
||||||
|
jasmine.GWT.Hooks[type] ||= []
|
||||||
|
jasmine.GWT.Hooks[type].push(code)
|
||||||
|
|
||||||
|
runHook: (type, context) ->
|
||||||
|
for code in (jasmine.GWT.Hooks[type] || [])
|
||||||
|
code.apply(context)
|
||||||
|
|
||||||
|
Steps: {}
|
||||||
|
Hooks: {}
|
||||||
|
|
||||||
|
class jasmine.GWT.Feature
|
||||||
|
constructor: (@name, code) ->
|
||||||
|
jasmine.GWT.currentFeature_ = this
|
||||||
|
|
||||||
|
@background = null
|
||||||
|
code.apply(this)
|
||||||
|
|
||||||
|
jasmine.GWT.currentFeature_ = null
|
||||||
|
|
||||||
|
Scenario: (name, code) ->
|
||||||
|
new jasmine.GWT.Scenario(name, code, this)
|
||||||
|
|
||||||
|
Background: (code) ->
|
||||||
|
@background = new jasmine.GWT.Background(code)
|
||||||
|
|
||||||
|
class jasmine.GWT.Background
|
||||||
|
constructor: (code) ->
|
||||||
|
@statements = []
|
||||||
|
|
||||||
|
jasmine.GWT.currentScenario_ = this
|
||||||
|
|
||||||
|
code.apply(this)
|
||||||
|
|
||||||
|
jasmine.GWT.currentScenario_ = null
|
||||||
|
|
||||||
|
Given: (name, code) ->
|
||||||
|
@statements.push([ 'Given', name, code ])
|
||||||
|
When: (name, code) ->
|
||||||
|
@statements.push([ 'When', name, code ])
|
||||||
|
Then: (name, code) ->
|
||||||
|
@statements.push([ 'Then', name, code ])
|
||||||
|
|
||||||
|
class jasmine.GWT.Scenario extends jasmine.GWT.Background
|
||||||
|
constructor: (scenarioName, code, @feature) ->
|
||||||
|
super(code)
|
||||||
|
|
||||||
|
_statements = this.allStatements()
|
||||||
|
_this = this
|
||||||
|
|
||||||
|
describe @feature.name, ->
|
||||||
|
it scenarioName, ->
|
||||||
|
jasmine.GWT.runHook('Before', _this)
|
||||||
|
|
||||||
|
for [ type, name, param ] in _statements
|
||||||
|
_this._type = type
|
||||||
|
_this._name = name
|
||||||
|
|
||||||
|
runCode = (param, args = []) ->
|
||||||
|
resultsIndex = jasmine.getEnv().currentSpec.results().getItems().length
|
||||||
|
|
||||||
|
param.apply(_this, args)
|
||||||
|
|
||||||
|
for index in [ resultsIndex...(jasmine.getEnv().currentSpec.results().getItems().length) ]
|
||||||
|
result = jasmine.getEnv().currentSpec.results().getItems()[index]
|
||||||
|
result.message = "[#{type} #{name}] " + result.message
|
||||||
|
|
||||||
|
args = []
|
||||||
|
|
||||||
|
if param?
|
||||||
|
if typeof param == "function"
|
||||||
|
runCode(param)
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
args = [ param ]
|
||||||
|
|
||||||
|
found = false
|
||||||
|
|
||||||
|
if jasmine.GWT.Steps[type]
|
||||||
|
for [ match, code ] in jasmine.GWT.Steps[type]
|
||||||
|
if match.constructor == RegExp
|
||||||
|
if result = name.match(match)
|
||||||
|
result.shift()
|
||||||
|
runCode(code, result.concat(args))
|
||||||
|
found = true
|
||||||
|
|
||||||
|
break
|
||||||
|
else
|
||||||
|
if name == match
|
||||||
|
runCode(code)
|
||||||
|
found = true
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
if !found
|
||||||
|
output = [ "", "No step defined for #{type} #{name}. Define one using the following:", '' ]
|
||||||
|
|
||||||
|
argCount = args.length
|
||||||
|
|
||||||
|
name = name.replace /\d+/g, (match) ->
|
||||||
|
argCount += 1
|
||||||
|
"(\\d+)"
|
||||||
|
|
||||||
|
name = name.replace /\"[^"]+\"/g, (match) ->
|
||||||
|
argCount += 1
|
||||||
|
'"([^"]+)"'
|
||||||
|
|
||||||
|
if argCount == 0
|
||||||
|
output.push("#{type} /#{name}/, ->")
|
||||||
|
else
|
||||||
|
args = ("arg#{i}" for i in [ 1..(argCount) ])
|
||||||
|
|
||||||
|
output.push("#{type} /#{name}/, (#{args.join(', ')}) ->")
|
||||||
|
|
||||||
|
output.push(" @not_defined()")
|
||||||
|
output.push("")
|
||||||
|
|
||||||
|
fakeResult = new jasmine.ExpectationResult(
|
||||||
|
matcherName: 'steps',
|
||||||
|
passed: false,
|
||||||
|
expected: 'to be defined',
|
||||||
|
actual: "#{type} #{name}",
|
||||||
|
message: output.join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
jasmine.getEnv().currentSpec.addMatcherResult(fakeResult)
|
||||||
|
|
||||||
|
jasmine.GWT.runHook('After', _this)
|
||||||
|
|
||||||
|
allStatements: =>
|
||||||
|
allStatements = []
|
||||||
|
|
||||||
|
if @feature.background?
|
||||||
|
allStatements = @feature.background.statements
|
||||||
|
|
||||||
|
allStatements.concat(@statements)
|
||||||
|
|
||||||
|
not_defined: =>
|
||||||
|
fakeResult = new jasmine.ExpectationResult(
|
||||||
|
matcherName: 'step',
|
||||||
|
passed: false,
|
||||||
|
expected: 'to be defined',
|
||||||
|
actual: "#{@_type} #{@_name}",
|
||||||
|
message: "has no code defined."
|
||||||
|
)
|
||||||
|
|
||||||
|
jasmine.getEnv().currentSpec.addMatcherResult(fakeResult)
|
||||||
|
|
||||||
|
jasmine.GWT.globals =
|
||||||
|
Feature: (args...) ->
|
||||||
|
new jasmine.GWT.Feature(args...)
|
||||||
|
|
||||||
|
Background: (args...) ->
|
||||||
|
jasmine.GWT.currentFeature_.Background(args...)
|
||||||
|
|
||||||
|
Scenario: (args...) ->
|
||||||
|
jasmine.GWT.currentFeature_.Scenario(args...)
|
||||||
|
|
||||||
|
Given: (args...) -> jasmine.GWT.Step('Given', args...)
|
||||||
|
When: (args...) -> jasmine.GWT.Step('When', args...)
|
||||||
|
Then: (args...) -> jasmine.GWT.Step('Then', args...)
|
||||||
|
|
||||||
|
Before: (args...) -> jasmine.GWT.Hook('Before', args...)
|
||||||
|
After: (args...) -> jasmine.GWT.Hook('After', args...)
|
||||||
|
|
||||||
|
for method, code of jasmine.GWT.globals
|
||||||
|
(exports ? this)[method] = code
|
||||||
|
|
7
lib/jasmine-gwt.rb
Normal file
7
lib/jasmine-gwt.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require "jasmine-gwt/version"
|
||||||
|
|
||||||
|
module Jasmine
|
||||||
|
module GWT
|
||||||
|
# Your code goes here...
|
||||||
|
end
|
||||||
|
end
|
5
lib/jasmine-gwt/version.rb
Normal file
5
lib/jasmine-gwt/version.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module Jasmine
|
||||||
|
module GWT
|
||||||
|
VERSION = "0.0.1"
|
||||||
|
end
|
||||||
|
end
|
0
spec/javascripts/jasmine-gwt_spec.js.coffee
Normal file
0
spec/javascripts/jasmine-gwt_spec.js.coffee
Normal file
0
spec/javascripts/support/jasmine.yml
Normal file
0
spec/javascripts/support/jasmine.yml
Normal file
Loading…
Reference in New Issue
Block a user