spinach 0.1.5.4 → 0.2.0.1
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 +2 -0
- data/README.markdown +18 -12
- data/features/background.feature +13 -0
- data/features/reporting/show_step_source_location.feature +11 -1
- data/features/steps/automatic_feature_generation.rb +7 -7
- data/features/steps/background.rb +30 -0
- data/features/steps/exit_status.rb +12 -13
- data/features/steps/feature_name_guessing.rb +7 -7
- data/features/steps/reporting/display_run_summary.rb +22 -22
- data/features/steps/reporting/error_reporting.rb +7 -7
- data/features/steps/reporting/show_step_source_location.rb +63 -14
- data/features/steps/reporting/undefined_feature_reporting.rb +7 -7
- data/features/steps/rspec_compatibility.rb +14 -14
- data/features/support/error_reporting.rb +5 -5
- data/features/support/filesystem.rb +71 -0
- data/features/support/spinach_runner.rb +5 -6
- data/lib/spinach.rb +11 -6
- data/lib/spinach/background.rb +11 -0
- data/lib/spinach/capybara.rb +7 -1
- data/lib/spinach/cli.rb +36 -13
- data/lib/spinach/config.rb +40 -6
- data/lib/spinach/dsl.rb +14 -11
- data/lib/spinach/exceptions.rb +1 -1
- data/lib/spinach/feature.rb +16 -0
- data/lib/spinach/frameworks.rb +2 -0
- data/lib/spinach/{suites → frameworks}/minitest.rb +0 -0
- data/lib/spinach/{suites → frameworks}/rspec.rb +0 -0
- data/lib/spinach/generators/feature_generator.rb +12 -23
- data/lib/spinach/generators/step_generator.rb +5 -5
- data/lib/spinach/hookable.rb +6 -4
- data/lib/spinach/hooks.rb +12 -4
- data/lib/spinach/parser.rb +6 -8
- data/lib/spinach/parser/visitor.rb +109 -0
- data/lib/spinach/reporter.rb +10 -6
- data/lib/spinach/reporter/stdout.rb +41 -16
- data/lib/spinach/reporter/stdout/error_reporting.rb +2 -2
- data/lib/spinach/runner.rb +9 -6
- data/lib/spinach/runner/feature_runner.rb +40 -34
- data/lib/spinach/runner/scenario_runner.rb +63 -36
- data/lib/spinach/scenario.rb +12 -0
- data/lib/spinach/step.rb +10 -0
- data/lib/spinach/version.rb +1 -1
- data/spinach.gemspec +3 -3
- data/test/spinach/background_test.rb +6 -0
- data/test/spinach/capybara_test.rb +30 -13
- data/test/spinach/cli_test.rb +46 -1
- data/test/spinach/config_test.rb +39 -0
- data/test/spinach/dsl_test.rb +12 -10
- data/test/spinach/feature_steps_test.rb +3 -3
- data/test/spinach/feature_test.rb +6 -0
- data/test/spinach/{suites → frameworks}/minitest_test.rb +2 -2
- data/test/spinach/generators/feature_generator_test.rb +18 -58
- data/test/spinach/generators/step_generator_test.rb +3 -3
- data/test/spinach/generators_test.rb +12 -10
- data/test/spinach/hookable_test.rb +8 -0
- data/test/spinach/hooks_test.rb +6 -7
- data/test/spinach/parser/visitor_test.rb +173 -0
- data/test/spinach/parser_test.rb +14 -27
- data/test/spinach/reporter/stdout/error_reporting_test.rb +9 -9
- data/test/spinach/reporter/stdout_test.rb +15 -19
- data/test/spinach/reporter_test.rb +15 -0
- data/test/spinach/runner/feature_runner_test.rb +79 -69
- data/test/spinach/runner/scenario_runner_test.rb +118 -92
- data/test/spinach/runner_test.rb +10 -6
- data/test/spinach/scenario_test.rb +6 -0
- data/test/spinach/step_test.rb +6 -0
- data/test/spinach_test.rb +7 -7
- metadata +60 -39
- data/lib/spinach/suites.rb +0 -2
@@ -36,7 +36,7 @@ module Spinach
|
|
36
36
|
if undefined_features.any?
|
37
37
|
error.puts " Undefined features (#{undefined_features.length})".light_yellow
|
38
38
|
undefined_features.each do |feature|
|
39
|
-
error.puts " #{feature
|
39
|
+
error.puts " #{feature.name}".yellow
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -93,7 +93,7 @@ module Spinach
|
|
93
93
|
#
|
94
94
|
def summarized_error(error)
|
95
95
|
feature, scenario, step, exception = error
|
96
|
-
summary = " #{feature
|
96
|
+
summary = " #{feature.name} :: #{scenario.name} :: #{full_step step}"
|
97
97
|
if exception.kind_of?(Spinach::StepNotDefinedException)
|
98
98
|
summary.yellow
|
99
99
|
else
|
data/lib/spinach/runner.rb
CHANGED
@@ -54,14 +54,17 @@ module Spinach
|
|
54
54
|
# @api public
|
55
55
|
def run
|
56
56
|
require_dependencies
|
57
|
-
|
57
|
+
require_frameworks
|
58
58
|
|
59
59
|
Spinach.hooks.run_before_run
|
60
60
|
|
61
61
|
successful = true
|
62
62
|
|
63
|
-
filenames.
|
64
|
-
|
63
|
+
filenames.map do |filename|
|
64
|
+
filename.split(':')
|
65
|
+
end.each do |filename, line|
|
66
|
+
feature = Parser.open_file(filename).parse
|
67
|
+
success = FeatureRunner.new(feature, line).run
|
65
68
|
successful = false unless success
|
66
69
|
end
|
67
70
|
|
@@ -80,10 +83,10 @@ module Spinach
|
|
80
83
|
end
|
81
84
|
end
|
82
85
|
|
83
|
-
# Requires the test
|
86
|
+
# Requires the test framework support
|
84
87
|
#
|
85
|
-
def
|
86
|
-
require_relative '
|
88
|
+
def require_frameworks
|
89
|
+
require_relative 'frameworks'
|
87
90
|
end
|
88
91
|
|
89
92
|
# @return [Array<String>] files
|
@@ -3,30 +3,19 @@ module Spinach
|
|
3
3
|
# A feature runner handles a particular feature run.
|
4
4
|
#
|
5
5
|
class FeatureRunner
|
6
|
+
attr_reader :feature
|
6
7
|
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
# @param [String] filename
|
11
|
-
# path to the feature file. Scenario line could be passed to run just
|
12
|
-
# that scenario.
|
13
|
-
# @example feature/a_cool_feature.feature:12
|
14
|
-
#
|
15
|
-
# @api public
|
16
|
-
def initialize(filename)
|
17
|
-
@filename, @scenario_line = filename.split(':')
|
18
|
-
end
|
19
|
-
|
20
|
-
# The file taht describes the feature.
|
8
|
+
# @param [Gherkin::AST::Feature] feature
|
9
|
+
# The feature to run.
|
21
10
|
#
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
# The parsed data for this feature.
|
11
|
+
# @param [#to_i] line
|
12
|
+
# If a scenario line is passed, then only the scenario defined on that
|
13
|
+
# line will be run.
|
26
14
|
#
|
27
15
|
# @api public
|
28
|
-
def
|
29
|
-
@
|
16
|
+
def initialize(feature, line=nil)
|
17
|
+
@feature = feature
|
18
|
+
@line = line.to_i if line
|
30
19
|
end
|
31
20
|
|
32
21
|
# @return [String]
|
@@ -34,15 +23,15 @@ module Spinach
|
|
34
23
|
#
|
35
24
|
# @api public
|
36
25
|
def feature_name
|
37
|
-
@
|
26
|
+
@feature.name
|
38
27
|
end
|
39
28
|
|
40
|
-
# @return [
|
29
|
+
# @return [Array<Gherkin::AST::Scenario>]
|
41
30
|
# The parsed scenarios for this runner's feature.
|
42
31
|
#
|
43
32
|
# @api public
|
44
33
|
def scenarios
|
45
|
-
@scenarios
|
34
|
+
@feature.scenarios
|
46
35
|
end
|
47
36
|
|
48
37
|
# Runs this feature.
|
@@ -52,21 +41,38 @@ module Spinach
|
|
52
41
|
#
|
53
42
|
# @api public
|
54
43
|
def run
|
55
|
-
Spinach.hooks.run_before_feature
|
56
|
-
if Spinach.
|
57
|
-
|
58
|
-
if !@scenario_line || scenario['line'].to_s == @scenario_line
|
59
|
-
success = ScenarioRunner.new(feature_name, scenario).run
|
60
|
-
@failed = true unless success
|
61
|
-
end
|
62
|
-
end
|
44
|
+
Spinach.hooks.run_before_feature @feature
|
45
|
+
if Spinach.find_step_definitions(feature_name)
|
46
|
+
run_scenarios!
|
63
47
|
else
|
64
|
-
|
65
|
-
@failed = true
|
48
|
+
undefined_steps!
|
66
49
|
end
|
67
|
-
Spinach.hooks.run_after_feature
|
50
|
+
Spinach.hooks.run_after_feature @feature
|
68
51
|
!@failed
|
69
52
|
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def run_scenarios!
|
57
|
+
scenarios.each_with_index do |scenario, current_scenario_index|
|
58
|
+
if match(current_scenario_index)
|
59
|
+
success = ScenarioRunner.new(scenario).run
|
60
|
+
@failed = true unless success
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def match(current_scenario_index)
|
66
|
+
return true unless @line
|
67
|
+
return false if @line<scenarios[current_scenario_index].line
|
68
|
+
next_scenario = scenarios[current_scenario_index+1]
|
69
|
+
!next_scenario || @line<next_scenario.line
|
70
|
+
end
|
71
|
+
|
72
|
+
def undefined_steps!
|
73
|
+
Spinach.hooks.run_on_undefined_feature @feature
|
74
|
+
@failed = true
|
75
|
+
end
|
70
76
|
end
|
71
77
|
end
|
72
78
|
end
|
@@ -3,61 +3,88 @@ module Spinach
|
|
3
3
|
# A Scenario Runner handles a particular scenario run.
|
4
4
|
#
|
5
5
|
class ScenarioRunner
|
6
|
-
|
7
|
-
|
8
|
-
# @param [String] feature_name
|
9
|
-
# The feature name
|
6
|
+
# @param [Gherkin::AST::Scenario] scenario
|
7
|
+
# The scenario.
|
10
8
|
#
|
11
|
-
# @
|
12
|
-
|
9
|
+
# @api public
|
10
|
+
def initialize(scenario)
|
11
|
+
@scenario = scenario
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Gherkin::AST::Feature>]
|
15
|
+
# The feature containing the scenario.
|
13
16
|
#
|
14
17
|
# @api public
|
15
|
-
def
|
16
|
-
@
|
17
|
-
@data = data
|
18
|
+
def feature
|
19
|
+
@scenario.feature
|
18
20
|
end
|
19
21
|
|
22
|
+
# @return [Array<Gherkin::AST::Step>]
|
23
|
+
# An array of steps.
|
24
|
+
#
|
25
|
+
# @api public
|
20
26
|
def steps
|
21
|
-
|
27
|
+
feature.background_steps + @scenario.steps
|
22
28
|
end
|
23
29
|
|
24
30
|
# @return [FeatureSteps]
|
25
|
-
# The
|
31
|
+
# The step definitions for the current feature.
|
26
32
|
#
|
27
33
|
# @api public
|
28
|
-
def
|
29
|
-
@
|
34
|
+
def step_definitions
|
35
|
+
@step_definitions ||= Spinach.find_step_definitions(feature.name).new
|
30
36
|
end
|
31
37
|
|
32
|
-
# Runs
|
33
|
-
#
|
34
|
-
#
|
38
|
+
# Runs the scenario, capturing any exception, and running the
|
39
|
+
# corresponding hooks.
|
40
|
+
#
|
41
|
+
# @return [true, false]
|
42
|
+
# Whether the scenario succeeded or not.
|
43
|
+
#
|
44
|
+
# @api public
|
35
45
|
def run
|
36
|
-
Spinach.hooks.run_before_scenario
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@exception = e
|
48
|
-
Spinach.hooks.run_on_undefined_step step, @exception
|
49
|
-
rescue Exception => e
|
50
|
-
@exception = e
|
51
|
-
Spinach.hooks.run_on_error_step step, @exception, step_location
|
46
|
+
Spinach.hooks.run_before_scenario @scenario
|
47
|
+
scenario_run = false
|
48
|
+
Spinach.hooks.run_around_scenario @scenario do
|
49
|
+
scenario_run = true
|
50
|
+
steps.each do |step|
|
51
|
+
Spinach.hooks.run_before_step step
|
52
|
+
|
53
|
+
if @exception
|
54
|
+
Spinach.hooks.run_on_skipped_step step
|
55
|
+
else
|
56
|
+
run_step(step)
|
52
57
|
end
|
53
|
-
|
54
|
-
Spinach.hooks.
|
58
|
+
|
59
|
+
Spinach.hooks.run_after_step step
|
55
60
|
end
|
56
|
-
Spinach.hooks.run_after_step step
|
57
61
|
end
|
58
|
-
|
62
|
+
raise "around_scenario hooks *must* yield" if !scenario_run && !@exception
|
63
|
+
Spinach.hooks.run_after_scenario @scenario
|
59
64
|
!@exception
|
60
65
|
end
|
66
|
+
|
67
|
+
# Runs a particular step.
|
68
|
+
#
|
69
|
+
# @param [Gherkin::AST::Step] step
|
70
|
+
# The step to be run.
|
71
|
+
#
|
72
|
+
# @api semipublic
|
73
|
+
def run_step(step)
|
74
|
+
step_location = step_definitions.step_location_for(step.name)
|
75
|
+
step_definitions.execute(step)
|
76
|
+
Spinach.hooks.run_on_successful_step step, step_location
|
77
|
+
rescue *Spinach.config[:failure_exceptions] => e
|
78
|
+
@exception = e
|
79
|
+
Spinach.hooks.run_on_failed_step step, @exception, step_location
|
80
|
+
rescue Spinach::StepNotDefinedException => e
|
81
|
+
@exception = e
|
82
|
+
Spinach.hooks.run_on_undefined_step step, @exception
|
83
|
+
rescue Exception => e
|
84
|
+
@exception = e
|
85
|
+
Spinach.hooks.run_on_error_step step, @exception, step_location
|
86
|
+
end
|
87
|
+
|
61
88
|
end
|
62
89
|
end
|
63
90
|
end
|
data/lib/spinach/step.rb
ADDED
data/lib/spinach/version.rb
CHANGED
data/spinach.gemspec
CHANGED
@@ -9,18 +9,18 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.summary = %q{Spinach is a BDD framework on top of gherkin}
|
10
10
|
gem.homepage = "http://github.com/codegram/spinach"
|
11
11
|
|
12
|
-
gem.add_runtime_dependency 'gherkin', '
|
12
|
+
gem.add_runtime_dependency 'gherkin-ruby', '~> 0.0.2'
|
13
13
|
gem.add_runtime_dependency 'colorize'
|
14
14
|
gem.add_development_dependency 'rake'
|
15
15
|
gem.add_development_dependency 'mocha'
|
16
16
|
gem.add_development_dependency 'sinatra'
|
17
17
|
gem.add_development_dependency 'capybara'
|
18
|
-
gem.add_development_dependency '
|
18
|
+
gem.add_development_dependency 'open4'
|
19
19
|
gem.add_development_dependency 'pry'
|
20
20
|
gem.add_development_dependency 'simplecov'
|
21
21
|
gem.add_development_dependency 'rspec'
|
22
22
|
gem.add_development_dependency 'fakefs'
|
23
|
-
gem.add_development_dependency 'minitest'
|
23
|
+
gem.add_development_dependency 'minitest', '~> 2.8.0'
|
24
24
|
gem.add_development_dependency 'turn'
|
25
25
|
|
26
26
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
@@ -27,6 +27,19 @@ describe Spinach::FeatureSteps::Capybara do
|
|
27
27
|
end.new
|
28
28
|
end
|
29
29
|
|
30
|
+
let(:parsed_feature) { Spinach::Parser.new("""
|
31
|
+
Feature: A test feature
|
32
|
+
Scenario: A test scenario
|
33
|
+
Given Hello
|
34
|
+
Then Goodbye
|
35
|
+
|
36
|
+
@javascript
|
37
|
+
Scenario: Another test scenario
|
38
|
+
Given Hello
|
39
|
+
Then Goodbye
|
40
|
+
""").parse
|
41
|
+
}
|
42
|
+
|
30
43
|
it 'includes capybara into all features' do
|
31
44
|
@feature.kind_of? Capybara
|
32
45
|
end
|
@@ -37,22 +50,26 @@ describe Spinach::FeatureSteps::Capybara do
|
|
37
50
|
end
|
38
51
|
|
39
52
|
it 'resets the capybara session after each scenario' do
|
40
|
-
@feature_runner = Spinach::Runner::FeatureRunner.new(
|
41
|
-
'a_feature.feature')
|
53
|
+
@feature_runner = Spinach::Runner::FeatureRunner.new(parsed_feature)
|
42
54
|
|
43
|
-
|
44
|
-
Feature: A test feature
|
45
|
-
Scenario: A test scenario
|
46
|
-
Given Hello
|
47
|
-
Then Goodbye
|
48
|
-
Scenario: Another test scenario
|
49
|
-
Given Hello
|
50
|
-
Then Goodbye
|
51
|
-
').parse).at_least_once
|
55
|
+
Capybara.current_session.expects(:reset!).at_least_once
|
52
56
|
|
53
|
-
|
57
|
+
@feature_runner.run
|
58
|
+
end
|
54
59
|
|
55
|
-
|
60
|
+
it 'resets the javascript driver after each scenario' do
|
61
|
+
@feature_runner = Spinach::Runner::FeatureRunner.new(parsed_feature)
|
62
|
+
|
63
|
+
Capybara.expects(:use_default_driver).at_least(2)
|
64
|
+
|
65
|
+
@feature_runner.run
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'changes the javascript driver when an scenario has the @javascript tag' do
|
69
|
+
@feature_runner = Spinach::Runner::FeatureRunner.new(parsed_feature)
|
70
|
+
|
71
|
+
Capybara.expects(:javascript_driver).at_least(1)
|
72
|
+
Capybara.expects(:current_driver=).at_least(1)
|
56
73
|
|
57
74
|
@feature_runner.run
|
58
75
|
end
|
data/test/spinach/cli_test.rb
CHANGED
@@ -18,7 +18,19 @@ describe Spinach::Cli do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
describe '
|
21
|
+
describe 'features_path' do
|
22
|
+
%w{-f --features_path}.each do |opt|
|
23
|
+
it 'sets the given features_path' do
|
24
|
+
config = Spinach::Config.new
|
25
|
+
Spinach.stubs(:config).returns(config)
|
26
|
+
cli = Spinach::Cli.new([opt,"custom_path"])
|
27
|
+
cli.options
|
28
|
+
config.features_path.must_equal 'custom_path'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'generate' do
|
22
34
|
%w{-g --generate}.each do |opt|
|
23
35
|
it 'inits the generator if #{opt}' do
|
24
36
|
Spinach::Generators.expects(:bind)
|
@@ -40,6 +52,39 @@ describe Spinach::Cli do
|
|
40
52
|
end
|
41
53
|
end
|
42
54
|
end
|
55
|
+
|
56
|
+
describe 'config_path' do
|
57
|
+
%w{-c --config_path}.each do |opt|
|
58
|
+
it "sets the config path" do
|
59
|
+
config = Spinach::Config.new
|
60
|
+
Spinach.stubs(:config).returns(config)
|
61
|
+
cli = Spinach::Cli.new([opt, 'config_file'])
|
62
|
+
config.expects(:parse_from_file)
|
63
|
+
cli.options
|
64
|
+
config.config_path.must_equal 'config_file'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "gets overriden by the other cli options" do
|
68
|
+
config = Spinach::Config.new
|
69
|
+
Spinach.stubs(:config).returns(config)
|
70
|
+
YAML.stubs(:load_file).returns({features_path: 'my_path'})
|
71
|
+
cli = Spinach::Cli.new(['-f', 'another_path', opt, 'config_file'])
|
72
|
+
cli.options
|
73
|
+
config.features_path.must_equal 'another_path'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'undefined option' do
|
79
|
+
%w{-lorem --ipsum}.each do |opt|
|
80
|
+
it 'exits and outputs error message with #{opt}' do
|
81
|
+
cli = Spinach::Cli.new([opt])
|
82
|
+
cli.expects(:exit)
|
83
|
+
cli.expects(:puts).with("Invalid option: #{opt}")
|
84
|
+
options = cli.options
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
43
88
|
end
|
44
89
|
|
45
90
|
describe '#init_reporter' do
|