spinach 0.0.6 → 0.1.0
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/Gemfile +1 -0
- data/Readme.md +3 -0
- data/bin/spinach +3 -1
- data/features/steps/error_reporting.rb +4 -8
- data/features/steps/exit_status.rb +0 -1
- data/features/steps/feature_name_guessing.rb +1 -2
- data/features/support/spinach_runner.rb +0 -2
- data/lib/spinach/capybara.rb +8 -8
- data/lib/spinach/cli.rb +30 -18
- data/lib/spinach/config.rb +29 -10
- data/lib/spinach/dsl.rb +45 -21
- data/lib/spinach/exceptions.rb +21 -8
- data/lib/spinach/feature.rb +8 -4
- data/lib/spinach/parser.rb +13 -7
- data/lib/spinach/reporter/stdout.rb +251 -53
- data/lib/spinach/reporter.rb +43 -26
- data/lib/spinach/runner/feature.rb +39 -26
- data/lib/spinach/runner/scenario.rb +43 -28
- data/lib/spinach/runner.rb +40 -20
- data/lib/spinach/support.rb +8 -7
- data/lib/spinach/version.rb +2 -1
- data/lib/spinach.rb +17 -9
- data/spinach.gemspec +2 -1
- data/test/spinach/capybara_test.rb +32 -3
- data/test/spinach/cli_test.rb +32 -11
- data/test/spinach/config_test.rb +9 -6
- data/test/spinach/dsl_test.rb +8 -1
- data/test/spinach/feature_test.rb +14 -11
- data/test/spinach/parser_test.rb +33 -20
- data/test/spinach/reporter/stdout_test.rb +364 -103
- data/test/spinach/reporter_test.rb +145 -20
- data/test/spinach/runner/feature_test.rb +26 -51
- data/test/spinach/runner/scenario_test.rb +64 -35
- data/test/spinach/runner_test.rb +41 -32
- data/test/spinach/support_test.rb +2 -10
- data/test/spinach_test.rb +14 -14
- data/test/test_helper.rb +13 -5
- metadata +36 -28
- data/examples/steps/user_logs_in.rb +0 -23
- data/examples/user_logs_in.feature +0 -6
- data/examples/user_logs_in.rb +0 -23
data/Gemfile
CHANGED
data/Readme.md
CHANGED
@@ -10,3 +10,6 @@ Spinach is a BDD framework on top of gherkin
|
|
10
10
|

|
11
11
|
|
12
12
|
*Popeye the Sailor*
|
13
|
+
|
14
|
+
# Build status
|
15
|
+
[](http://travis-ci.org/codegram/spinach)
|
data/bin/spinach
CHANGED
@@ -32,7 +32,7 @@ Feature "Error reporting" do
|
|
32
32
|
|
33
33
|
Then 'I should see the error count along with their messages' do
|
34
34
|
check_error_messages
|
35
|
-
|
35
|
+
all_stderr.wont_match /gems.*minitest.*assert_equal/
|
36
36
|
end
|
37
37
|
|
38
38
|
Then 'I should see the error count along with their messages and backtrace' do
|
@@ -41,16 +41,12 @@ Feature "Error reporting" do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
private
|
44
|
-
|
45
44
|
def check_error_messages
|
46
|
-
|
47
|
-
all_stdout.must_match /errors.*This scenario will fail.*line 4/
|
45
|
+
all_stderr.must_match /Failures \(1\)/
|
48
46
|
end
|
49
47
|
|
50
48
|
def check_backtrace
|
51
|
-
|
52
|
-
|
53
|
-
all_stdout.must_match /gems.*minitest.*assert_equal/
|
49
|
+
all_stderr.must_match /Failures \(1\)/
|
50
|
+
all_stderr.must_match /gems.*minitest.*assert_equal/
|
54
51
|
end
|
55
|
-
|
56
52
|
end
|
data/lib/spinach/capybara.rb
CHANGED
@@ -4,8 +4,7 @@ require_relative 'feature'
|
|
4
4
|
|
5
5
|
module Spinach
|
6
6
|
class Feature
|
7
|
-
|
8
|
-
# Spinach's capybara module integrates capybara into all features
|
7
|
+
# Spinach's capybara module makes Capybara DSL available in all features.
|
9
8
|
#
|
10
9
|
# @example
|
11
10
|
# require 'spinach/capybara'
|
@@ -16,20 +15,21 @@ module Spinach
|
|
16
15
|
# end
|
17
16
|
#
|
18
17
|
module Capybara
|
18
|
+
# Enhances a Feature with Capybara goodness.
|
19
|
+
#
|
20
|
+
# @param [Class] base
|
21
|
+
# The host class.
|
22
|
+
#
|
23
|
+
# @api public
|
19
24
|
def self.included(base)
|
20
25
|
base.class_eval do
|
21
26
|
include ::Capybara::DSL
|
22
|
-
include InstanceMethods
|
23
27
|
|
24
|
-
|
28
|
+
after_scenario do
|
25
29
|
::Capybara.current_session.reset! if ::Capybara.app
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
29
|
-
module InstanceMethods
|
30
|
-
end
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
34
|
-
|
35
|
-
Spinach::Feature.send(:include, Spinach::Feature::Capybara)
|
data/lib/spinach/cli.rb
CHANGED
@@ -2,21 +2,24 @@ require 'optparse'
|
|
2
2
|
|
3
3
|
module Spinach
|
4
4
|
# The cli is a class responsible of handling all the command line interface
|
5
|
-
# logic
|
5
|
+
# logic.
|
6
6
|
#
|
7
7
|
class Cli
|
8
8
|
# @param [Array<String>] arguments
|
9
|
-
#
|
9
|
+
# The command line arguments
|
10
|
+
#
|
11
|
+
# @api public
|
10
12
|
def initialize(args = ARGV)
|
11
13
|
@args = args
|
12
14
|
end
|
13
15
|
|
14
|
-
# Runs all the
|
16
|
+
# Runs all the features.
|
17
|
+
#
|
18
|
+
# @return [true, false]
|
19
|
+
# The exit status - true for success, false for failure.
|
15
20
|
#
|
16
|
-
# @
|
17
|
-
# the exit status - true for success, false for failure
|
21
|
+
# @api public
|
18
22
|
def run
|
19
|
-
init_reporter
|
20
23
|
parse_options
|
21
24
|
features = if @args.any?
|
22
25
|
@args
|
@@ -26,42 +29,51 @@ module Spinach
|
|
26
29
|
Spinach::Runner.new(features).run
|
27
30
|
end
|
28
31
|
|
29
|
-
# Inits the reporter with a default one
|
32
|
+
# Inits the reporter with a default one.
|
33
|
+
#
|
34
|
+
# @api public
|
30
35
|
def init_reporter
|
31
|
-
|
36
|
+
reporter =
|
32
37
|
Spinach::Reporter::Stdout.new(options[:reporter])
|
38
|
+
Spinach.config.default_reporter = reporter
|
39
|
+
reporter.bind
|
33
40
|
end
|
34
41
|
|
35
|
-
#
|
42
|
+
# @return [Hash]
|
43
|
+
# A hash of options separated by its type.
|
36
44
|
#
|
37
45
|
# @example
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# }
|
46
|
+
# Cli.new.options
|
47
|
+
# # => { reporter: { backtrace: true } }
|
41
48
|
#
|
42
|
-
# @
|
49
|
+
# @api public
|
43
50
|
def options
|
44
51
|
@options ||= parse_options
|
45
52
|
end
|
46
53
|
|
47
|
-
|
54
|
+
private
|
48
55
|
|
56
|
+
# Parses the arguments into options.
|
57
|
+
#
|
58
|
+
# @return [Hash]
|
59
|
+
# A hash of options separated by its type.
|
60
|
+
#
|
61
|
+
# @api private
|
49
62
|
def parse_options
|
50
63
|
reporter_options = {}
|
51
64
|
reporter_options[:backtrace] = false
|
52
65
|
|
53
66
|
OptionParser.new do |opts|
|
54
|
-
opts.on('-b', '--backtrace',
|
67
|
+
opts.on('-b', '--backtrace', 'Show backtrace of errors') do |v|
|
55
68
|
reporter_options[:backtrace] = v
|
56
69
|
end
|
57
|
-
opts.on_tail('--version',
|
70
|
+
opts.on_tail('--version', 'Show version') do
|
58
71
|
puts Spinach::VERSION
|
59
72
|
exit
|
60
73
|
end
|
61
74
|
end.parse!(@args)
|
75
|
+
|
62
76
|
{reporter: reporter_options}
|
63
77
|
end
|
64
|
-
|
65
|
-
|
66
78
|
end
|
67
79
|
end
|
data/lib/spinach/config.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
module Spinach
|
2
|
-
|
3
2
|
# Accesses spinach config. Allows you to configure several runtime options,
|
4
3
|
# like the step definitions path.
|
5
4
|
#
|
6
|
-
# @return [
|
7
|
-
#
|
5
|
+
# @return [Config]
|
6
|
+
# The config object
|
8
7
|
#
|
9
8
|
# @example
|
10
9
|
# Spinach.config[:step_definitions_path]
|
@@ -12,6 +11,7 @@ module Spinach
|
|
12
11
|
# Spinach.config[:step_definitions_path] = 'integration/steps'
|
13
12
|
# # => 'integration/steps'
|
14
13
|
#
|
14
|
+
# @api public
|
15
15
|
def self.config
|
16
16
|
@config ||= Config.new
|
17
17
|
end
|
@@ -22,16 +22,24 @@ module Spinach
|
|
22
22
|
class Config
|
23
23
|
attr_writer :step_definitions_path, :default_reporter, :support_path
|
24
24
|
|
25
|
-
# The "step definitions path"
|
25
|
+
# The "step definitions path" holds the place where your feature classes
|
26
26
|
# will be searched for. Defaults to 'features/steps'
|
27
27
|
#
|
28
|
+
# @return [String]
|
29
|
+
# The step definitions path.
|
30
|
+
#
|
31
|
+
# @api public
|
28
32
|
def step_definitions_path
|
29
33
|
@step_definitions_path || 'features/steps'
|
30
34
|
end
|
31
35
|
|
32
|
-
# The "support path" helds the place where
|
33
|
-
# files
|
36
|
+
# The "support path" helds the place where you can put your configuration
|
37
|
+
# files.
|
38
|
+
#
|
39
|
+
# @return [String]
|
40
|
+
# The support file path.
|
34
41
|
#
|
42
|
+
# @api public
|
35
43
|
def support_path
|
36
44
|
@support_path || 'features/support'
|
37
45
|
end
|
@@ -46,22 +54,33 @@ module Spinach
|
|
46
54
|
|
47
55
|
# Allows you to read the config object using a hash-like syntax.
|
48
56
|
#
|
57
|
+
# @param [String] attribute
|
58
|
+
# The attribute to fetch.
|
59
|
+
#
|
49
60
|
# @example
|
50
61
|
# Spinach.config[:step_definitions_path]
|
51
|
-
#
|
62
|
+
# # => 'features/steps'
|
52
63
|
#
|
64
|
+
# @api public
|
53
65
|
def [](attribute)
|
54
66
|
self.send(attribute)
|
55
67
|
end
|
56
68
|
|
57
|
-
# Allows you to set config properties using a hash-like syntax
|
69
|
+
# Allows you to set config properties using a hash-like syntax.
|
70
|
+
#
|
71
|
+
# @param [#to_s] attribute
|
72
|
+
# The attribute to set.
|
73
|
+
#
|
74
|
+
# @param [Object] value
|
75
|
+
# The value to set the attribute to.
|
58
76
|
#
|
59
77
|
# @example
|
60
78
|
# Spinach.config[:step_definitions_path] = 'integration/steps'
|
61
79
|
# # => 'integration/steps'
|
62
80
|
#
|
63
|
-
|
64
|
-
|
81
|
+
# @api public
|
82
|
+
def []=(attribute, value)
|
83
|
+
self.send("#{attribute}=", value)
|
65
84
|
end
|
66
85
|
end
|
67
86
|
end
|
data/lib/spinach/dsl.rb
CHANGED
@@ -1,34 +1,53 @@
|
|
1
|
+
require 'hooks'
|
2
|
+
|
1
3
|
module Spinach
|
2
|
-
# Spinach DSL aims to provide an easy way to define steps and
|
3
|
-
#
|
4
|
+
# Spinach DSL aims to provide an easy way to define steps and hooks into your
|
5
|
+
# feature classes.
|
4
6
|
#
|
5
7
|
module DSL
|
6
|
-
|
8
|
+
# @param [Class] base
|
9
|
+
# The host class.
|
10
|
+
#
|
11
|
+
# @api public
|
7
12
|
def self.included(base)
|
8
13
|
base.class_eval do
|
9
14
|
include InstanceMethods
|
10
15
|
extend ClassMethods
|
16
|
+
include Hooks
|
17
|
+
|
18
|
+
define_hook :before
|
19
|
+
define_hook :after
|
20
|
+
define_hook :before_scenario
|
21
|
+
define_hook :after_scenario
|
22
|
+
define_hook :before_step
|
23
|
+
define_hook :after_step
|
24
|
+
|
11
25
|
end
|
12
26
|
end
|
13
27
|
|
28
|
+
# Class methods to extend the host class.
|
29
|
+
#
|
14
30
|
module ClassMethods
|
15
|
-
|
31
|
+
# The feature name.
|
32
|
+
attr_reader :feature_name
|
16
33
|
# Defines an action to perform given a particular step literal.
|
17
34
|
#
|
18
|
-
# @param [String] step
|
19
|
-
# The step
|
35
|
+
# @param [String] step
|
36
|
+
# The step name.
|
37
|
+
#
|
20
38
|
# @param [Proc] block
|
21
|
-
#
|
39
|
+
# Action to perform in that step.
|
22
40
|
#
|
23
41
|
# @example
|
24
|
-
# class MyFeature
|
42
|
+
# class MyFeature < Spinach::Feature
|
25
43
|
# When "I go to the toilet" do
|
26
44
|
# @sittin_on_the_toilet.must_equal true
|
27
45
|
# end
|
28
46
|
# end
|
29
47
|
#
|
30
|
-
|
31
|
-
|
48
|
+
# @api public
|
49
|
+
def Given(step, &block)
|
50
|
+
define_method(step, &block)
|
32
51
|
end
|
33
52
|
|
34
53
|
alias_method :When, :Given
|
@@ -36,39 +55,44 @@ module Spinach
|
|
36
55
|
alias_method :And, :Given
|
37
56
|
alias_method :But, :Given
|
38
57
|
|
39
|
-
#
|
58
|
+
# Sets the feature name.
|
59
|
+
#
|
60
|
+
# @param [String] name
|
61
|
+
# The name.
|
40
62
|
#
|
41
63
|
# @example
|
42
64
|
# class MyFeature < Spinach::Feature
|
43
65
|
# feature "Satisfy needs"
|
44
66
|
# end
|
45
67
|
#
|
68
|
+
# @api public
|
46
69
|
def feature(name)
|
47
70
|
@feature_name = name
|
48
71
|
end
|
49
|
-
|
50
|
-
# @return [String] this feature's name
|
51
|
-
#
|
52
|
-
attr_reader :feature_name
|
53
72
|
end
|
54
73
|
|
74
|
+
# Instance methods to include in the host class.
|
75
|
+
#
|
55
76
|
module InstanceMethods
|
56
|
-
|
57
|
-
# Execute a given step.
|
77
|
+
# Executes a given step.
|
58
78
|
#
|
59
79
|
# @param [String] step
|
60
|
-
#
|
80
|
+
# The step name to execute.
|
81
|
+
#
|
82
|
+
# @return [String]
|
83
|
+
# The file and line where the step was defined.
|
61
84
|
#
|
85
|
+
# @api public
|
62
86
|
def execute_step(step)
|
63
87
|
if self.respond_to?(step)
|
64
88
|
self.send(step)
|
65
89
|
else
|
66
|
-
raise Spinach::StepNotDefinedException.new(
|
67
|
-
self, step
|
68
|
-
)
|
90
|
+
raise Spinach::StepNotDefinedException.new(self, step)
|
69
91
|
end
|
70
92
|
end
|
71
93
|
|
94
|
+
# @return [String]
|
95
|
+
# The feature name.
|
72
96
|
def name
|
73
97
|
self.class.feature_name
|
74
98
|
end
|
data/lib/spinach/exceptions.rb
CHANGED
@@ -1,28 +1,41 @@
|
|
1
1
|
module Spinach
|
2
|
-
# This class represents the
|
2
|
+
# This class represents the exception raised when Spinach can't find a class
|
3
3
|
# for a feature.
|
4
|
+
#
|
4
5
|
class FeatureNotFoundException < StandardError
|
6
|
+
# @param [Array] options
|
7
|
+
# An array consisting of the missing class and the feature.
|
8
|
+
#
|
9
|
+
# @api pulic
|
5
10
|
def initialize(options)
|
6
|
-
@
|
7
|
-
@feature = options.last
|
11
|
+
@missing_class, @feature = options
|
8
12
|
end
|
9
13
|
|
14
|
+
# @return [String]
|
15
|
+
# A custom message when a feature class is not found.
|
16
|
+
#
|
17
|
+
# @api public
|
10
18
|
def message
|
11
|
-
"Could not find class for `#{@feature}` feature. Please create a #{@
|
19
|
+
"Could not find class for `#{@feature}` feature. Please create a #{@missing_class}.rb file at #{Spinach.config[:step_definitions_path]}"
|
12
20
|
end
|
13
21
|
end
|
14
22
|
|
15
|
-
# This class represents the
|
16
|
-
# Scenario.
|
23
|
+
# This class represents the exception raised when Spinach can't find a step
|
24
|
+
# for a {Scenario}.
|
17
25
|
#
|
18
26
|
class StepNotDefinedException < StandardError
|
19
|
-
|
20
27
|
attr_reader :feature, :step
|
21
28
|
|
29
|
+
# @param [Feature] feature
|
30
|
+
# The container feature.
|
31
|
+
#
|
32
|
+
# @param [Hash] step
|
33
|
+
# The missing step.
|
34
|
+
#
|
35
|
+
# @api pulic
|
22
36
|
def initialize(feature, step)
|
23
37
|
@feature = feature
|
24
38
|
@step = step
|
25
39
|
end
|
26
40
|
end
|
27
|
-
|
28
41
|
end
|
data/lib/spinach/feature.rb
CHANGED
@@ -2,21 +2,25 @@ require 'minitest/spec'
|
|
2
2
|
MiniTest::Spec.new nil
|
3
3
|
|
4
4
|
module Spinach
|
5
|
-
# The feature class is the class
|
5
|
+
# The feature class is the class which all the features must inherit from.
|
6
6
|
#
|
7
7
|
class Feature
|
8
8
|
include DSL
|
9
9
|
include MiniTest::Assertions
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
# Registers the feature class for later use.
|
12
|
+
#
|
13
|
+
# @param [Class] base
|
14
|
+
# The host class.
|
15
|
+
#
|
16
|
+
# @api public
|
14
17
|
def self.inherited(base)
|
15
18
|
Spinach.features << base
|
16
19
|
end
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
23
|
+
# Syntactic sugar. Define the "Feature do" syntax.
|
20
24
|
Object.send(:define_method, :Feature) do |name, &block|
|
21
25
|
Class.new(Spinach::Feature) do
|
22
26
|
feature name
|
data/lib/spinach/parser.rb
CHANGED
@@ -2,29 +2,35 @@ require 'gherkin'
|
|
2
2
|
require 'gherkin/formatter/json_formatter'
|
3
3
|
|
4
4
|
module Spinach
|
5
|
-
#
|
6
|
-
# needed from the plain feature definition.
|
5
|
+
# Parser leverages Gherkin to parse the feature definition.
|
7
6
|
#
|
8
7
|
class Parser
|
9
|
-
|
10
8
|
# @param [String] filename
|
11
|
-
#
|
9
|
+
# The filename to parse.
|
12
10
|
#
|
11
|
+
# @api public
|
13
12
|
def initialize(filename)
|
14
13
|
@filename = filename
|
15
14
|
@formatter = Gherkin::Formatter::JSONFormatter.new(nil)
|
16
15
|
@parser = Gherkin::Parser::Parser.new(@formatter)
|
17
16
|
end
|
18
17
|
|
19
|
-
# Gets the plain text content of the feature file.
|
18
|
+
# Gets the plain text content out of the feature file.
|
19
|
+
#
|
20
20
|
# @return [String]
|
21
|
-
#
|
21
|
+
# The plain feature content.
|
22
22
|
#
|
23
|
+
# @api public
|
23
24
|
def content
|
24
25
|
File.read(@filename)
|
25
26
|
end
|
26
27
|
|
27
|
-
#
|
28
|
+
# Parses the feature file and returns an AST as a Hash.
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
# The parsed Gherkin output.
|
32
|
+
#
|
33
|
+
# @api public
|
28
34
|
def parse
|
29
35
|
@parser.parse(content, @filename, __LINE__-1)
|
30
36
|
@formatter.gherkin_object
|