spinach 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|

|
5
5
|
|
6
|
+
# Documentation
|
7
|
+
[Spinach documentation at rubydoc.info](http://rubydoc.info/github/codegram/spinach/master/frames)
|
8
|
+
|
6
9
|
# Testimonials
|
7
|
-

|
10
|
+

|
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
|