spinach 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +10 -0
- data/Guardfile +5 -0
- data/Readme.md +4 -1
- data/bin/spinach +12 -5
- data/lib/spinach.rb +18 -0
- data/lib/spinach/capybara.rb +37 -0
- data/lib/spinach/config.rb +51 -1
- data/lib/spinach/dsl.rb +32 -9
- data/lib/spinach/feature.rb +5 -0
- data/lib/spinach/parser.rb +8 -0
- data/lib/spinach/reporter.rb +81 -0
- data/lib/spinach/runner.rb +60 -15
- data/lib/spinach/version.rb +1 -1
- data/spinach.gemspec +3 -0
- data/test/spinach/capybara_test.rb +27 -0
- data/test/spinach/config_test.rb +9 -0
- data/test/spinach/dsl_test.rb +7 -5
- data/test/spinach/reporter_test.rb +91 -0
- data/test/spinach/runner_test.rb +63 -9
- data/test/test_helper.rb +16 -0
- metadata +52 -12
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -3,6 +3,16 @@ source 'http://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in spinach.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
group :test do
|
7
|
+
gem 'guard'
|
8
|
+
gem 'guard-minitest'
|
9
|
+
end
|
10
|
+
|
11
|
+
group :darwin do
|
12
|
+
gem 'rb-fsevent'
|
13
|
+
gem 'growl'
|
14
|
+
end
|
15
|
+
|
6
16
|
group :docs do
|
7
17
|
gem 'yard'
|
8
18
|
end
|
data/Guardfile
ADDED
data/Readme.md
CHANGED
@@ -3,7 +3,10 @@ Spinach is a BDD framework on top of gherkin
|
|
3
3
|
|
4
4
|
![](http://farm1.static.flickr.com/58/200481513_a1a0aa265a.jpg)
|
5
5
|
|
6
|
+
# Documentation
|
7
|
+
[Spinach documentation at rubydoc.info](http://rubydoc.info/github/codegram/spinach/master/frames)
|
8
|
+
|
6
9
|
# Testimonials
|
7
|
-
![](http://www.80stees.com/images/products/Popeye_the_Sailor_Man_I_Popeye_Spinach-T-link.jpg)
|
10
|
+
![](http://www.80stees.com/images/products/Popeye_the_Sailor_Man_I_Popeye_Spinach-T-link.jpg)
|
8
11
|
|
9
12
|
*Popeye the Sailor*
|
data/bin/spinach
CHANGED
@@ -4,11 +4,18 @@ begin
|
|
4
4
|
require 'spinach'
|
5
5
|
rescue LoadError
|
6
6
|
require_relative '../lib/spinach'
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
end
|
8
|
+
|
9
|
+
Dir.glob(
|
10
|
+
File.expand_path File.join(Spinach.config[:step_definitions_path], '**', '*.rb')
|
11
|
+
).each do |file|
|
12
|
+
require file
|
13
|
+
end
|
14
|
+
|
15
|
+
Dir.glob(
|
16
|
+
File.expand_path File.join(Spinach.config[:support_path], '**', '*.rb')
|
17
|
+
).each do |file|
|
18
|
+
require file
|
12
19
|
end
|
13
20
|
|
14
21
|
ARGV.each do |file|
|
data/lib/spinach.rb
CHANGED
@@ -4,18 +4,36 @@ require_relative 'spinach/runner'
|
|
4
4
|
require_relative 'spinach/parser'
|
5
5
|
require_relative 'spinach/dsl'
|
6
6
|
require_relative 'spinach/feature'
|
7
|
+
require_relative 'spinach/reporter'
|
7
8
|
|
9
|
+
# Spinach is a BDD framework in top of gherkin. Its main goals are:
|
10
|
+
# * No magic: All features are implemented using actual classes.
|
11
|
+
# * Reusability: Steps are methods, so they can be put inside modules.
|
12
|
+
# * Proper encapsulation: No conflicts between steps from different
|
13
|
+
# scenarios.
|
14
|
+
#
|
8
15
|
module Spinach
|
9
16
|
@@features = []
|
10
17
|
|
18
|
+
# @return [Array<Spinach::Feature>]
|
19
|
+
# all the registered features
|
20
|
+
#
|
11
21
|
def self.features
|
12
22
|
@@features
|
13
23
|
end
|
14
24
|
|
25
|
+
# Resets Spinach to a pristine state, as if any feature was registered.
|
26
|
+
# Mostly useful in Spinach's own testing.
|
27
|
+
#
|
15
28
|
def self.reset_features
|
16
29
|
@@features = []
|
17
30
|
end
|
18
31
|
|
32
|
+
# Finds a feature given a feature name
|
33
|
+
#
|
34
|
+
# @param [String] name
|
35
|
+
# the feature name
|
36
|
+
#
|
19
37
|
def self.find_feature(name)
|
20
38
|
@@features.detect do |feature|
|
21
39
|
feature.feature_name.to_s == name.to_s
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require 'capybara/dsl'
|
3
|
+
require_relative 'feature'
|
4
|
+
|
5
|
+
module Spinach
|
6
|
+
class Feature
|
7
|
+
|
8
|
+
# Spinach's capybara module integrates capybara into all features
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# require 'spinach/capybara'
|
12
|
+
# class CapybaraFeature < Spinach::Feature
|
13
|
+
# Given "I go to the home page" do
|
14
|
+
# visit '/'
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
module Capybara
|
19
|
+
def self.included(base)
|
20
|
+
base.class_eval do
|
21
|
+
include ::Capybara::DSL
|
22
|
+
include InstanceMethods
|
23
|
+
|
24
|
+
def before
|
25
|
+
end
|
26
|
+
def after
|
27
|
+
::Capybara.current_session.reset! if ::Capybara.app
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
module InstanceMethods
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Spinach::Feature.send(:include, Spinach::Feature::Capybara)
|
data/lib/spinach/config.rb
CHANGED
@@ -1,15 +1,65 @@
|
|
1
1
|
module Spinach
|
2
|
+
|
3
|
+
# Accesses spinach config. Allows you to configure several runtime options,
|
4
|
+
# like the step definitions path.
|
5
|
+
#
|
6
|
+
# @return [Spinach::Config]
|
7
|
+
# the config object
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# Spinach.config[:step_definitions_path]
|
11
|
+
# # => 'features/steps'
|
12
|
+
# Spinach.config[:step_definitions_path] = 'integration/steps'
|
13
|
+
# # => 'integration/steps'
|
14
|
+
#
|
2
15
|
def self.config
|
3
16
|
@config ||= Config.new
|
4
17
|
end
|
18
|
+
|
19
|
+
# The config object holds all the runtime configurations needed for spinach
|
20
|
+
# to run.
|
21
|
+
#
|
5
22
|
class Config
|
6
|
-
attr_writer :step_definitions_path
|
23
|
+
attr_writer :step_definitions_path, :default_reporter, :support_path
|
24
|
+
|
25
|
+
# The "step definitions path" helds the place where your feature classes
|
26
|
+
# will be searched for. Defaults to 'features/steps'
|
27
|
+
#
|
7
28
|
def step_definitions_path
|
8
29
|
@step_definitions_path || 'features/steps'
|
9
30
|
end
|
31
|
+
|
32
|
+
# The "support path" helds the place where your can put your configuration
|
33
|
+
# files
|
34
|
+
#
|
35
|
+
def support_path
|
36
|
+
@support_path || 'features/support'
|
37
|
+
end
|
38
|
+
|
39
|
+
# The default reporter is the reporter spinach will use if there's no other
|
40
|
+
# specified. Defaults to Spinach::Reporter::Stdout, which will print all
|
41
|
+
# output to the standard output
|
42
|
+
#
|
43
|
+
def default_reporter
|
44
|
+
@default_reporter || Spinach::Reporter::Stdout
|
45
|
+
end
|
46
|
+
|
47
|
+
# Allows you to read the config object using a hash-like syntax.
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# Spinach.config[:step_definitions_path]
|
51
|
+
# # => 'features/steps'
|
52
|
+
#
|
10
53
|
def [](attribute)
|
11
54
|
self.send(attribute)
|
12
55
|
end
|
56
|
+
|
57
|
+
# Allows you to set config properties using a hash-like syntax
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# Spinach.config[:step_definitions_path] = 'integration/steps'
|
61
|
+
# # => 'integration/steps'
|
62
|
+
#
|
13
63
|
def []=(attribute, params)
|
14
64
|
self.send("#{attribute}=", params)
|
15
65
|
end
|
data/lib/spinach/dsl.rb
CHANGED
@@ -1,19 +1,42 @@
|
|
1
1
|
module Spinach
|
2
|
+
# Spinach DSL aims to provide an easy way to define steps and other domain
|
3
|
+
# specific actions into your feature classes
|
4
|
+
#
|
2
5
|
module DSL
|
3
|
-
|
4
|
-
|
6
|
+
|
7
|
+
# Defines an action to perform given a particular step literal.
|
8
|
+
#
|
9
|
+
# @param [String] step name
|
10
|
+
# The step literal
|
11
|
+
# @param [Proc] block
|
12
|
+
# action to perform in that step
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# class MyFeature << Spinach::Feature
|
16
|
+
# When "I go to the toilet" do
|
17
|
+
# @sittin_on_the_toilet.must_equal true
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
%w{When Given Then And But}.each do |connector|
|
22
|
+
define_method connector do |string, &block|
|
23
|
+
define_method("#{connector} #{string}", &block)
|
24
|
+
end
|
5
25
|
end
|
6
|
-
alias_method :Given, :When
|
7
|
-
alias_method :Then, :When
|
8
|
-
alias_method :And, :When
|
9
|
-
alias_method :But, :When
|
10
26
|
|
27
|
+
# Defines this feature's name
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# class MyFeature < Spinach::Feature
|
31
|
+
# feature "Satisfy needs"
|
32
|
+
# end
|
33
|
+
#
|
11
34
|
def feature(name)
|
12
35
|
@feature_name = name
|
13
36
|
end
|
14
37
|
|
15
|
-
|
16
|
-
|
17
|
-
|
38
|
+
# @return [String] this feature's name
|
39
|
+
#
|
40
|
+
attr_reader :feature_name
|
18
41
|
end
|
19
42
|
end
|
data/lib/spinach/feature.rb
CHANGED
@@ -2,10 +2,15 @@ require 'minitest/spec'
|
|
2
2
|
MiniTest::Spec.new nil
|
3
3
|
|
4
4
|
module Spinach
|
5
|
+
# The feature class is the class where all the features must inherit from.
|
6
|
+
#
|
5
7
|
class Feature
|
6
8
|
extend DSL
|
7
9
|
include MiniTest::Assertions
|
8
10
|
|
11
|
+
def before; end;
|
12
|
+
def after; end;
|
13
|
+
|
9
14
|
def self.inherited(base)
|
10
15
|
Spinach.features << base
|
11
16
|
end
|
data/lib/spinach/parser.rb
CHANGED
@@ -2,6 +2,9 @@ require 'gherkin'
|
|
2
2
|
require 'gherkin/formatter/json_formatter'
|
3
3
|
|
4
4
|
module Spinach
|
5
|
+
# Spinach's parser uses Gherkin in the guts to extract all the information
|
6
|
+
# needed from the plain feature definition.
|
7
|
+
#
|
5
8
|
class Parser
|
6
9
|
def initialize(filename)
|
7
10
|
@filename = filename
|
@@ -9,10 +12,15 @@ module Spinach
|
|
9
12
|
@parser = Gherkin::Parser::Parser.new(@formatter)
|
10
13
|
end
|
11
14
|
|
15
|
+
# Gets the plain text content of the feature file.
|
16
|
+
# @return [String]
|
17
|
+
# the plain feature content
|
18
|
+
#
|
12
19
|
def content
|
13
20
|
File.read(@filename)
|
14
21
|
end
|
15
22
|
|
23
|
+
# @return [Hash] the parsed gerkin output
|
16
24
|
def parse
|
17
25
|
@parser.parse(content, @filename, __LINE__-1)
|
18
26
|
@formatter.gherkin_object
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'colorize'
|
3
|
+
|
4
|
+
module Spinach
|
5
|
+
# Spinach reporter collects information from Runner hooks and outputs the
|
6
|
+
# results
|
7
|
+
#
|
8
|
+
class Reporter
|
9
|
+
|
10
|
+
# Receives this hook when a feature is invoked
|
11
|
+
# @param [String] name
|
12
|
+
# the feature name
|
13
|
+
#
|
14
|
+
def feature(name)
|
15
|
+
raise "Abstract method!"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Receives this hook when a scenario is invoked
|
19
|
+
# @param [String] name
|
20
|
+
# the scenario name
|
21
|
+
#
|
22
|
+
def scenario(name)
|
23
|
+
raise "Abstract method!"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Receives this hook when a step is invoked
|
27
|
+
# @param [String] name
|
28
|
+
# the scenario name
|
29
|
+
# @param [Symbol] result
|
30
|
+
# the step name and its finishing state. May be :success or :failure
|
31
|
+
#
|
32
|
+
def step(name, result)
|
33
|
+
raise "Abstract method!"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Receives this hook when a feature reaches its end
|
37
|
+
#
|
38
|
+
def end
|
39
|
+
raise "Abstract method!"
|
40
|
+
end
|
41
|
+
|
42
|
+
# The Stdout reporter outputs the runner results to the standard output
|
43
|
+
#
|
44
|
+
class Stdout < Reporter
|
45
|
+
|
46
|
+
# Prints the feature name to the standard output
|
47
|
+
#
|
48
|
+
def feature(name)
|
49
|
+
puts "\nFeature: #{name}".white.underline
|
50
|
+
end
|
51
|
+
|
52
|
+
# Prints the scenario name to the standard ouput
|
53
|
+
#
|
54
|
+
def scenario(name)
|
55
|
+
puts " Scenario: #{name}".white
|
56
|
+
end
|
57
|
+
|
58
|
+
# Prints the step name to the standard output. If failed, it puts an
|
59
|
+
# F! before
|
60
|
+
#
|
61
|
+
def step(name, result)
|
62
|
+
words = name.split(" ")
|
63
|
+
connector = words.shift
|
64
|
+
phrase = words.join(" ")
|
65
|
+
if result == :success
|
66
|
+
puts " ✔ #{connector} #{phrase}".green
|
67
|
+
elsif result == :failure
|
68
|
+
puts " ✘ #{connector} #{phrase}".red
|
69
|
+
elsif result == :skip
|
70
|
+
puts " ~ #{connector} #{phrase}".yellow
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Prints a blank line at the end
|
75
|
+
#
|
76
|
+
def end
|
77
|
+
puts ""
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/spinach/runner.rb
CHANGED
@@ -1,41 +1,86 @@
|
|
1
1
|
module Spinach
|
2
|
+
# Spinach's runner gets the parsed data from the feature and performs the
|
3
|
+
# actual calls to the feature classes.
|
4
|
+
#
|
2
5
|
class Runner
|
6
|
+
# Initializes the runner with a parsed feature
|
7
|
+
# @param [Hash] data
|
8
|
+
# the parsed feature data
|
9
|
+
#
|
3
10
|
def initialize(data)
|
4
11
|
@feature_name = data['name']
|
5
12
|
@scenarios = data['elements']
|
13
|
+
@reporter = Spinach::config.default_reporter.new
|
6
14
|
end
|
7
15
|
|
16
|
+
# The default reporter associated to this run
|
17
|
+
attr_reader :reporter
|
18
|
+
|
19
|
+
# Returns the feature class for the provided feature data
|
20
|
+
# @return [Spinach::Feature] feature
|
21
|
+
# this runner's feature
|
22
|
+
#
|
8
23
|
def feature
|
9
24
|
@feature ||= Spinach.find_feature(@feature_name)
|
10
25
|
end
|
11
26
|
|
27
|
+
# @return [Hash]
|
28
|
+
# the parsed scenarios for this runner's feature
|
29
|
+
#
|
12
30
|
def scenarios
|
13
31
|
@scenarios
|
14
32
|
end
|
15
33
|
|
34
|
+
# Runs this runner and outputs the results in a colorful manner.
|
35
|
+
#
|
16
36
|
def run
|
17
37
|
step_count = 0
|
18
38
|
reports = []
|
19
39
|
|
40
|
+
reporter.feature(@feature_name)
|
41
|
+
|
20
42
|
scenarios.each do |scenario|
|
21
|
-
|
22
|
-
scenario['steps'].each do |step|
|
23
|
-
begin
|
24
|
-
instance.send(step['name'])
|
25
|
-
print "\e[32m."
|
26
|
-
rescue MiniTest::Assertion=>e
|
27
|
-
reports << e
|
28
|
-
print "\e[31mF"
|
29
|
-
end
|
30
|
-
end
|
43
|
+
Scenario.new(self, scenario).run
|
31
44
|
end
|
45
|
+
reporter.end
|
32
46
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
47
|
+
end
|
48
|
+
|
49
|
+
class Scenario
|
50
|
+
attr_reader :name, :steps
|
51
|
+
|
52
|
+
def initialize(runner, data)
|
53
|
+
@name = data['name']
|
54
|
+
@steps = data['steps']
|
55
|
+
@runner = runner
|
56
|
+
end
|
57
|
+
|
58
|
+
def reporter; @runner.reporter; end;
|
59
|
+
|
60
|
+
def feature
|
61
|
+
@feature ||= @runner.feature.new
|
62
|
+
end
|
63
|
+
|
64
|
+
def run
|
65
|
+
reporter.scenario(name)
|
66
|
+
feature.send(:before)
|
67
|
+
steps.each do |step|
|
68
|
+
step_name = "#{step['keyword'].strip} #{step['name']}"
|
69
|
+
unless @failed
|
70
|
+
begin
|
71
|
+
feature.send(step_name)
|
72
|
+
reporter.step(step_name, :success)
|
73
|
+
rescue MiniTest::Assertion=>e
|
74
|
+
reporter.step(step_name, :failure)
|
75
|
+
@failed = true
|
76
|
+
end
|
77
|
+
else
|
78
|
+
reporter.step(step_name, :skip)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
feature.send(:after)
|
38
82
|
end
|
39
83
|
end
|
84
|
+
|
40
85
|
end
|
41
86
|
end
|
data/lib/spinach/version.rb
CHANGED
data/spinach.gemspec
CHANGED
@@ -10,9 +10,12 @@ Gem::Specification.new do |gem|
|
|
10
10
|
|
11
11
|
gem.add_runtime_dependency 'gherkin'
|
12
12
|
gem.add_runtime_dependency 'minitest'
|
13
|
+
gem.add_runtime_dependency 'colorize'
|
13
14
|
gem.add_development_dependency 'purdytest'
|
14
15
|
gem.add_development_dependency 'rake'
|
15
16
|
gem.add_development_dependency 'mocha'
|
17
|
+
gem.add_development_dependency 'sinatra'
|
18
|
+
gem.add_development_dependency 'capybara'
|
16
19
|
|
17
20
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
21
|
gem.files = `git ls-files`.split("\n")
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'spinach/capybara'
|
3
|
+
require 'sinatra'
|
4
|
+
|
5
|
+
describe Spinach::Feature::Capybara do
|
6
|
+
before do
|
7
|
+
@sinatra_app = Sinatra::Application.new do
|
8
|
+
get '/' do
|
9
|
+
'Hello world!'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
Capybara.app = @sinatra_app
|
13
|
+
@feature = Class.new(Spinach::Feature) do
|
14
|
+
def go_home
|
15
|
+
visit "/"
|
16
|
+
page
|
17
|
+
end
|
18
|
+
end.new
|
19
|
+
end
|
20
|
+
it "includes capybara into all features" do
|
21
|
+
@feature.kind_of? Capybara
|
22
|
+
end
|
23
|
+
it "goes to a capybara page and returns its result" do
|
24
|
+
page = @feature.go_home
|
25
|
+
page.has_content?('Hello world').must_equal true
|
26
|
+
end
|
27
|
+
end
|
data/test/spinach/config_test.rb
CHANGED
@@ -10,4 +10,13 @@ describe Spinach::Config do
|
|
10
10
|
Spinach.config[:step_definitions_path].must_equal 'steps'
|
11
11
|
end
|
12
12
|
end
|
13
|
+
describe "#support_path" do
|
14
|
+
it "returns a default" do
|
15
|
+
(Spinach.config[:support_path].kind_of? String).must_equal true
|
16
|
+
end
|
17
|
+
it "can be overwritten" do
|
18
|
+
Spinach.config[:support_path] = 'support'
|
19
|
+
Spinach.config[:support_path].must_equal 'support'
|
20
|
+
end
|
21
|
+
end
|
13
22
|
end
|
data/test/spinach/dsl_test.rb
CHANGED
@@ -6,12 +6,14 @@ describe Spinach::DSL do
|
|
6
6
|
extend Spinach::DSL
|
7
7
|
end
|
8
8
|
end
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
"
|
9
|
+
%w{When Given Then And But}.each do |connector|
|
10
|
+
describe "##{connector}" do
|
11
|
+
it "should define a method with the step name" do
|
12
|
+
@feature.send(connector, "I say goodbye") do
|
13
|
+
"You say hello"
|
14
|
+
end
|
15
|
+
@feature.new.send("#{connector} I say goodbye").must_equal "You say hello"
|
13
16
|
end
|
14
|
-
@feature.new.send("I say goodbye").must_equal "You say hello"
|
15
17
|
end
|
16
18
|
end
|
17
19
|
describe "#Given, #Then, #And, #But" do
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative '../test_helper'
|
3
|
+
|
4
|
+
describe Spinach::Reporter do
|
5
|
+
describe "abstract methods" do
|
6
|
+
before do
|
7
|
+
@reporter = Spinach::Reporter.new
|
8
|
+
end
|
9
|
+
%w{feature scenario}.each do |abstract_method|
|
10
|
+
describe "#{abstract_method}" do
|
11
|
+
it "raises an error" do
|
12
|
+
Proc.new{
|
13
|
+
@reporter.send(abstract_method, "arbitrary name")
|
14
|
+
}.must_raise RuntimeError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
describe "#step" do
|
19
|
+
it "raises an error" do
|
20
|
+
Proc.new{
|
21
|
+
@reporter.step("arbitrary name", :success)
|
22
|
+
}.must_raise RuntimeError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
describe "#end" do
|
26
|
+
it "raises an error" do
|
27
|
+
Proc.new{
|
28
|
+
@reporter.end
|
29
|
+
}.must_raise RuntimeError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
describe Spinach::Reporter::Stdout do
|
34
|
+
before do
|
35
|
+
@reporter = Spinach::Reporter::Stdout.new
|
36
|
+
end
|
37
|
+
describe "#feature" do
|
38
|
+
it "outputs a feature name" do
|
39
|
+
out = capture_stdout do
|
40
|
+
@reporter.feature "User authentication"
|
41
|
+
end
|
42
|
+
out.string.must_include "\nFeature: User authentication"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
describe "#scenario" do
|
46
|
+
it "outputs a scenario name" do
|
47
|
+
out = capture_stdout do
|
48
|
+
@reporter.scenario "User logs in"
|
49
|
+
end
|
50
|
+
out.string.must_include " Scenario: User logs in"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
describe "#step" do
|
54
|
+
describe "when succeeding" do
|
55
|
+
it "outputs the step name" do
|
56
|
+
out = capture_stdout do
|
57
|
+
@reporter.step "Given I say goodbye", :success
|
58
|
+
end
|
59
|
+
out.string.must_include "✔"
|
60
|
+
out.string.must_include "Given I say goodbye"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe "when failing" do
|
64
|
+
it "outputs the step name with a failure mark" do
|
65
|
+
out = capture_stdout do
|
66
|
+
@reporter.step "Given I say goodbye", :failure
|
67
|
+
end
|
68
|
+
out.string.must_include "✘"
|
69
|
+
out.string.must_include "Given I say goodbye"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
describe "when skipping" do
|
73
|
+
it "outputs the step name with a failure mark" do
|
74
|
+
out = capture_stdout do
|
75
|
+
@reporter.step "Given I say nothing", :skip
|
76
|
+
end
|
77
|
+
out.string.must_include "~"
|
78
|
+
out.string.must_include "Given I say nothing"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
describe "#end" do
|
83
|
+
it "outputs a blank line" do
|
84
|
+
out = capture_stdout do
|
85
|
+
@reporter.end
|
86
|
+
end
|
87
|
+
out.string.must_include "\n"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/test/spinach/runner_test.rb
CHANGED
@@ -6,33 +6,87 @@ describe Spinach::Runner do
|
|
6
6
|
@feature = Class.new(Spinach::Feature) do
|
7
7
|
feature "A new feature"
|
8
8
|
When "I say hello" do
|
9
|
+
@when_called = true
|
9
10
|
end
|
10
|
-
Then "
|
11
|
+
Then "you say goodbye" do
|
12
|
+
@then_called = true
|
13
|
+
true.must_equal false
|
11
14
|
end
|
15
|
+
attr_accessor :when_called, :then_called
|
12
16
|
end
|
13
17
|
data = {
|
14
18
|
'name' => "A new feature",
|
15
|
-
'elements' => [
|
16
|
-
{'name' =>
|
17
|
-
|
19
|
+
'elements' => [
|
20
|
+
{'name' => 'First scenario', 'steps' => [
|
21
|
+
{'keyword' => 'When ', 'name' => "I say hello"},
|
22
|
+
{'keyword' => 'Then ', 'name' => "you say goodbye"}]
|
23
|
+
}
|
24
|
+
]
|
18
25
|
}
|
19
26
|
@runner = Spinach::Runner.new(data)
|
20
27
|
end
|
21
28
|
describe "#feature" do
|
22
29
|
it "returns a Spinach feature" do
|
23
|
-
@runner.feature.
|
30
|
+
@runner.feature.ancestors.must_include @feature
|
24
31
|
end
|
25
32
|
end
|
26
33
|
describe "#scenarios" do
|
27
34
|
it "should return the scenarios" do
|
28
|
-
@runner.scenarios.must_equal [
|
29
|
-
{'name' =>
|
30
|
-
|
35
|
+
@runner.scenarios.must_equal [
|
36
|
+
{'name' => 'First scenario', 'steps' => [
|
37
|
+
{'keyword' => 'When ', 'name' => "I say hello"},
|
38
|
+
{'keyword' => 'Then ', 'name' => "you say goodbye"} ]
|
39
|
+
}
|
40
|
+
]
|
31
41
|
end
|
32
42
|
end
|
33
43
|
describe "#run" do
|
34
|
-
it "should
|
44
|
+
it "should hook into the reporter" do
|
45
|
+
reporter = stub_everything
|
46
|
+
@runner.stubs(reporter: reporter)
|
47
|
+
reporter.expects(:feature).with("A new feature")
|
48
|
+
reporter.expects(:end).once
|
35
49
|
@runner.run
|
36
50
|
end
|
37
51
|
end
|
52
|
+
describe Spinach::Runner::Scenario do
|
53
|
+
before do
|
54
|
+
@data = {'name' => 'First scenario', 'steps' => [
|
55
|
+
{'keyword' => 'When ', 'name' => "I say hello"},
|
56
|
+
{'keyword' => 'Then ', 'name' => "you say goodbye"}]
|
57
|
+
}
|
58
|
+
@reporter = stub_everything
|
59
|
+
@runner = stub(reporter: @reporter, feature: @feature)
|
60
|
+
@scenario = Spinach::Runner::Scenario.new(@runner, @data)
|
61
|
+
end
|
62
|
+
it "should call every step on the feature" do
|
63
|
+
@scenario.run
|
64
|
+
@scenario.feature.when_called.must_equal true
|
65
|
+
@scenario.feature.then_called.must_equal true
|
66
|
+
end
|
67
|
+
it "calls the appropiate methods of the reporter" do
|
68
|
+
@reporter.expects(:scenario).with("First scenario")
|
69
|
+
@reporter.expects(:step).once.with("When I say hello", :success)
|
70
|
+
@reporter.expects(:step).once.with("Then you say goodbye", :failure)
|
71
|
+
@scenario.run
|
72
|
+
end
|
73
|
+
it "stops the run when finds an error" do
|
74
|
+
@feature = Class.new(Spinach::Feature) do
|
75
|
+
feature "A new feature"
|
76
|
+
When "I say hello" do
|
77
|
+
@when_called = true
|
78
|
+
true.must_equal false
|
79
|
+
end
|
80
|
+
Then "you say goodbye" do
|
81
|
+
@then_called = true
|
82
|
+
end
|
83
|
+
attr_accessor :when_called, :then_called
|
84
|
+
end
|
85
|
+
@runner.stubs(feature: @feature)
|
86
|
+
@scenario = Spinach::Runner::Scenario.new(@runner, @data)
|
87
|
+
@scenario.run
|
88
|
+
@scenario.feature.when_called.must_equal true
|
89
|
+
@scenario.feature.then_called.wont_equal true
|
90
|
+
end
|
91
|
+
end
|
38
92
|
end
|
data/test/test_helper.rb
CHANGED
@@ -6,3 +6,19 @@ require 'ostruct'
|
|
6
6
|
require 'purdytest'
|
7
7
|
|
8
8
|
require 'spinach'
|
9
|
+
require 'spinach/capybara'
|
10
|
+
|
11
|
+
require 'stringio'
|
12
|
+
|
13
|
+
module Kernel
|
14
|
+
|
15
|
+
def capture_stdout
|
16
|
+
out = StringIO.new
|
17
|
+
$stdout = out
|
18
|
+
yield
|
19
|
+
return out
|
20
|
+
ensure
|
21
|
+
$stdout = STDOUT
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spinach
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2011-09-
|
14
|
+
date: 2011-09-26 00:00:00.000000000Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: gherkin
|
18
|
-
requirement: &
|
18
|
+
requirement: &70223546997620 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: '0'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *70223546997620
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest
|
29
|
-
requirement: &
|
29
|
+
requirement: &70223546997200 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ! '>='
|
@@ -34,10 +34,21 @@ dependencies:
|
|
34
34
|
version: '0'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *70223546997200
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: colorize
|
40
|
+
requirement: &70223546996780 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
type: :runtime
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *70223546996780
|
38
49
|
- !ruby/object:Gem::Dependency
|
39
50
|
name: purdytest
|
40
|
-
requirement: &
|
51
|
+
requirement: &70223546996360 !ruby/object:Gem::Requirement
|
41
52
|
none: false
|
42
53
|
requirements:
|
43
54
|
- - ! '>='
|
@@ -45,10 +56,10 @@ dependencies:
|
|
45
56
|
version: '0'
|
46
57
|
type: :development
|
47
58
|
prerelease: false
|
48
|
-
version_requirements: *
|
59
|
+
version_requirements: *70223546996360
|
49
60
|
- !ruby/object:Gem::Dependency
|
50
61
|
name: rake
|
51
|
-
requirement: &
|
62
|
+
requirement: &70223546995940 !ruby/object:Gem::Requirement
|
52
63
|
none: false
|
53
64
|
requirements:
|
54
65
|
- - ! '>='
|
@@ -56,10 +67,32 @@ dependencies:
|
|
56
67
|
version: '0'
|
57
68
|
type: :development
|
58
69
|
prerelease: false
|
59
|
-
version_requirements: *
|
70
|
+
version_requirements: *70223546995940
|
60
71
|
- !ruby/object:Gem::Dependency
|
61
72
|
name: mocha
|
62
|
-
requirement: &
|
73
|
+
requirement: &70223546995520 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: *70223546995520
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: sinatra
|
84
|
+
requirement: &70223546995100 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: *70223546995100
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: capybara
|
95
|
+
requirement: &70223546994680 !ruby/object:Gem::Requirement
|
63
96
|
none: false
|
64
97
|
requirements:
|
65
98
|
- - ! '>='
|
@@ -67,7 +100,7 @@ dependencies:
|
|
67
100
|
version: '0'
|
68
101
|
type: :development
|
69
102
|
prerelease: false
|
70
|
-
version_requirements: *
|
103
|
+
version_requirements: *70223546994680
|
71
104
|
description: Spinach is a BDD framework on top of gherkin
|
72
105
|
email:
|
73
106
|
- info@codegram.com
|
@@ -79,6 +112,7 @@ files:
|
|
79
112
|
- .gitignore
|
80
113
|
- .rvmrc
|
81
114
|
- Gemfile
|
115
|
+
- Guardfile
|
82
116
|
- Rakefile
|
83
117
|
- Readme.md
|
84
118
|
- bin/spinach
|
@@ -86,17 +120,21 @@ files:
|
|
86
120
|
- examples/user_logs_in.feature
|
87
121
|
- examples/user_logs_in.rb
|
88
122
|
- lib/spinach.rb
|
123
|
+
- lib/spinach/capybara.rb
|
89
124
|
- lib/spinach/config.rb
|
90
125
|
- lib/spinach/dsl.rb
|
91
126
|
- lib/spinach/feature.rb
|
92
127
|
- lib/spinach/parser.rb
|
128
|
+
- lib/spinach/reporter.rb
|
93
129
|
- lib/spinach/runner.rb
|
94
130
|
- lib/spinach/version.rb
|
95
131
|
- spinach.gemspec
|
132
|
+
- test/spinach/capybara_test.rb
|
96
133
|
- test/spinach/config_test.rb
|
97
134
|
- test/spinach/dsl_test.rb
|
98
135
|
- test/spinach/feature_test.rb
|
99
136
|
- test/spinach/parser_test.rb
|
137
|
+
- test/spinach/reporter_test.rb
|
100
138
|
- test/spinach/runner_test.rb
|
101
139
|
- test/spinach_test.rb
|
102
140
|
- test/test_helper.rb
|
@@ -125,10 +163,12 @@ signing_key:
|
|
125
163
|
specification_version: 3
|
126
164
|
summary: Spinach is a BDD framework on top of gherkin
|
127
165
|
test_files:
|
166
|
+
- test/spinach/capybara_test.rb
|
128
167
|
- test/spinach/config_test.rb
|
129
168
|
- test/spinach/dsl_test.rb
|
130
169
|
- test/spinach/feature_test.rb
|
131
170
|
- test/spinach/parser_test.rb
|
171
|
+
- test/spinach/reporter_test.rb
|
132
172
|
- test/spinach/runner_test.rb
|
133
173
|
- test/spinach_test.rb
|
134
174
|
- test/test_helper.rb
|