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.
Files changed (69) hide show
  1. data/Gemfile +2 -0
  2. data/README.markdown +18 -12
  3. data/features/background.feature +13 -0
  4. data/features/reporting/show_step_source_location.feature +11 -1
  5. data/features/steps/automatic_feature_generation.rb +7 -7
  6. data/features/steps/background.rb +30 -0
  7. data/features/steps/exit_status.rb +12 -13
  8. data/features/steps/feature_name_guessing.rb +7 -7
  9. data/features/steps/reporting/display_run_summary.rb +22 -22
  10. data/features/steps/reporting/error_reporting.rb +7 -7
  11. data/features/steps/reporting/show_step_source_location.rb +63 -14
  12. data/features/steps/reporting/undefined_feature_reporting.rb +7 -7
  13. data/features/steps/rspec_compatibility.rb +14 -14
  14. data/features/support/error_reporting.rb +5 -5
  15. data/features/support/filesystem.rb +71 -0
  16. data/features/support/spinach_runner.rb +5 -6
  17. data/lib/spinach.rb +11 -6
  18. data/lib/spinach/background.rb +11 -0
  19. data/lib/spinach/capybara.rb +7 -1
  20. data/lib/spinach/cli.rb +36 -13
  21. data/lib/spinach/config.rb +40 -6
  22. data/lib/spinach/dsl.rb +14 -11
  23. data/lib/spinach/exceptions.rb +1 -1
  24. data/lib/spinach/feature.rb +16 -0
  25. data/lib/spinach/frameworks.rb +2 -0
  26. data/lib/spinach/{suites → frameworks}/minitest.rb +0 -0
  27. data/lib/spinach/{suites → frameworks}/rspec.rb +0 -0
  28. data/lib/spinach/generators/feature_generator.rb +12 -23
  29. data/lib/spinach/generators/step_generator.rb +5 -5
  30. data/lib/spinach/hookable.rb +6 -4
  31. data/lib/spinach/hooks.rb +12 -4
  32. data/lib/spinach/parser.rb +6 -8
  33. data/lib/spinach/parser/visitor.rb +109 -0
  34. data/lib/spinach/reporter.rb +10 -6
  35. data/lib/spinach/reporter/stdout.rb +41 -16
  36. data/lib/spinach/reporter/stdout/error_reporting.rb +2 -2
  37. data/lib/spinach/runner.rb +9 -6
  38. data/lib/spinach/runner/feature_runner.rb +40 -34
  39. data/lib/spinach/runner/scenario_runner.rb +63 -36
  40. data/lib/spinach/scenario.rb +12 -0
  41. data/lib/spinach/step.rb +10 -0
  42. data/lib/spinach/version.rb +1 -1
  43. data/spinach.gemspec +3 -3
  44. data/test/spinach/background_test.rb +6 -0
  45. data/test/spinach/capybara_test.rb +30 -13
  46. data/test/spinach/cli_test.rb +46 -1
  47. data/test/spinach/config_test.rb +39 -0
  48. data/test/spinach/dsl_test.rb +12 -10
  49. data/test/spinach/feature_steps_test.rb +3 -3
  50. data/test/spinach/feature_test.rb +6 -0
  51. data/test/spinach/{suites → frameworks}/minitest_test.rb +2 -2
  52. data/test/spinach/generators/feature_generator_test.rb +18 -58
  53. data/test/spinach/generators/step_generator_test.rb +3 -3
  54. data/test/spinach/generators_test.rb +12 -10
  55. data/test/spinach/hookable_test.rb +8 -0
  56. data/test/spinach/hooks_test.rb +6 -7
  57. data/test/spinach/parser/visitor_test.rb +173 -0
  58. data/test/spinach/parser_test.rb +14 -27
  59. data/test/spinach/reporter/stdout/error_reporting_test.rb +9 -9
  60. data/test/spinach/reporter/stdout_test.rb +15 -19
  61. data/test/spinach/reporter_test.rb +15 -0
  62. data/test/spinach/runner/feature_runner_test.rb +79 -69
  63. data/test/spinach/runner/scenario_runner_test.rb +118 -92
  64. data/test/spinach/runner_test.rb +10 -6
  65. data/test/spinach/scenario_test.rb +6 -0
  66. data/test/spinach/step_test.rb +6 -0
  67. data/test/spinach_test.rb +7 -7
  68. metadata +60 -39
  69. data/lib/spinach/suites.rb +0 -2
@@ -2,38 +2,25 @@ require_relative '../test_helper'
2
2
 
3
3
  describe Spinach::Parser do
4
4
  before do
5
- @parser = Spinach::Parser.new(
6
- "Feature: User authentication
7
- Scenario: User logs in
8
- Given I am on the front page
9
- When I fill in the login form and press 'login'
10
- Then I should be on my dashboard
11
- ")
5
+ @contents = """
6
+ Feature: User authentication
7
+
8
+ Scenario: User logs in
9
+ Given I am on the front page
10
+ When I fill in the login form and press 'login'
11
+ Then I should be on my dashboard
12
+ """
13
+ @parser = Spinach::Parser.new(@contents)
12
14
  end
13
15
 
14
16
  let(:parsed) { @parser.parse }
15
17
 
16
18
  describe '#parse' do
17
- it 'parses the feature name' do
18
- parsed['name'].must_equal 'User authentication'
19
- end
20
-
21
- describe 'scenario' do
22
- before do
23
- @scenario = parsed['elements'][0]
24
- end
25
-
26
- it 'parses the scenario name' do
27
- @scenario['name'].must_equal 'User logs in'
28
- end
29
-
30
- it 'parses the scenario steps' do
31
- @scenario['steps'][0]['name'].must_equal 'I am on the front page'
32
- @scenario['steps'][1]['name'].must_equal(
33
- 'I fill in the login form and press \'login\''
34
- )
35
- @scenario['steps'][2]['name'].must_equal 'I should be on my dashboard'
36
- end
19
+ it 'parses the file' do
20
+ Gherkin.expects(:parse).with(@contents.strip).returns ast = stub
21
+ Spinach::Parser::Visitor.stubs(:new).returns visitor = stub
22
+ visitor.expects(:visit).with ast
23
+ @parser.parse
37
24
  end
38
25
  end
39
26
 
@@ -6,9 +6,9 @@ describe Spinach::Reporter::Stdout do
6
6
  let(:exception) { StandardError.new('Something went wrong') }
7
7
 
8
8
  let(:error) do
9
- [{'name' => 'My feature'},
10
- {'name' => 'A scenario'},
11
- {'keyword' => 'Keyword', 'name' => 'step name'},
9
+ [stub(name: 'My feature'),
10
+ stub(name: 'A scenario'),
11
+ stub(keyword: 'Keyword', name: 'step name'),
12
12
  exception]
13
13
  end
14
14
 
@@ -110,7 +110,7 @@ describe Spinach::Reporter::Stdout do
110
110
  describe '#report_undefined_features' do
111
111
  describe 'when some features are undefined' do
112
112
  it 'outputs the undefined features' do
113
- @reporter.undefined_features << {'name' => 'Undefined feature name'}
113
+ @reporter.undefined_features << stub(name: 'Undefined feature name')
114
114
  @reporter.report_undefined_features
115
115
 
116
116
  @error.string.must_include "Undefined features (1)"
@@ -242,10 +242,10 @@ describe Spinach::Reporter::Stdout do
242
242
 
243
243
  describe "when it's a step not defined exception" do
244
244
  it "returns a suggestion" do
245
- @exception = Spinach::StepNotDefinedException.new("foo")
246
- @error = [{'name' => 'My feature'},
247
- {'name' => 'A scenario'},
248
- {'keyword' => 'Given', 'name' => 'foo'},
245
+ @exception = Spinach::StepNotDefinedException.new(stub(name: "foo"))
246
+ @error = [stub(name: 'My feature'),
247
+ stub(name: 'A scenario'),
248
+ stub(keyword: 'Given', name: 'foo'),
249
249
  @exception]
250
250
  output = @reporter.full_error(@error)
251
251
  output.must_include "Given"
@@ -269,7 +269,7 @@ describe Spinach::Reporter::Stdout do
269
269
 
270
270
  describe 'when given an undefined step exception' do
271
271
  it 'prints the error in yellow' do
272
- undefined_exception = Spinach::StepNotDefinedException.new(anything)
272
+ undefined_exception = Spinach::StepNotDefinedException.new(stub(name: 'some step'))
273
273
 
274
274
  String.any_instance.expects(:yellow)
275
275
 
@@ -6,9 +6,9 @@ describe Spinach::Reporter::Stdout do
6
6
  let(:exception) { StandardError.new('Something went wrong') }
7
7
 
8
8
  let(:error) do
9
- [{'name' => 'My feature'},
10
- {'name' => 'A scenario'},
11
- {'keyword' => 'Keyword', 'name' => 'step name'},
9
+ [stub(name: 'My feature'),
10
+ stub(name: 'A scenario'),
11
+ stub(keyword: 'Keyword', name: 'step name'),
12
12
  exception]
13
13
  end
14
14
 
@@ -28,7 +28,8 @@ describe Spinach::Reporter::Stdout do
28
28
 
29
29
  describe '#before_feature_run' do
30
30
  it 'outputs the feature' do
31
- @reporter.before_feature_run('name' => 'A cool feature')
31
+ feature = stub_everything(name: 'A cool feature')
32
+ @reporter.before_feature_run(feature)
32
33
 
33
34
  @out.string.must_include 'Feature'
34
35
  @out.string.must_include 'A cool feature'
@@ -37,7 +38,8 @@ describe Spinach::Reporter::Stdout do
37
38
 
38
39
  describe '#before_scenario_run' do
39
40
  it 'outputs the scenario' do
40
- @reporter.before_scenario_run('name' => 'Arbitrary scenario')
41
+ scenario = stub_everything(name: 'Arbitrary scenario', steps: [])
42
+ @reporter.before_scenario_run(scenario)
41
43
 
42
44
  @out.string.must_include 'Scenario'
43
45
  @out.string.must_include 'Arbitrary scenario'
@@ -68,7 +70,7 @@ describe Spinach::Reporter::Stdout do
68
70
  end
69
71
 
70
72
  describe '#on_successful_step' do
71
- let(:step) { {'keyword' => 'Given', 'name' => 'I am too cool'} }
73
+ let(:step) { stub(keyword: 'Given', name: 'I am too cool') }
72
74
  let(:step_location){['error_step_location', 1]}
73
75
  it 'adds the step to the output buffer' do
74
76
  @reporter.on_successful_step(step, step_location)
@@ -92,7 +94,7 @@ describe Spinach::Reporter::Stdout do
92
94
  end
93
95
 
94
96
  describe '#on_failed_step' do
95
- let(:step) { {'keyword' => 'Then', 'name' => 'I write failing steps'} }
97
+ let(:step) { stub(keyword: 'Then', name: 'I write failing steps') }
96
98
  let(:step_location){['error_step_location', 1]}
97
99
 
98
100
  it 'adds the step to the output buffer' do
@@ -117,7 +119,7 @@ describe Spinach::Reporter::Stdout do
117
119
  end
118
120
 
119
121
  describe '#on_error_step' do
120
- let(:step) { {'keyword' => 'And', 'name' => 'I even make syntax errors'} }
122
+ let(:step) { stub(keyword: 'And', name: 'I even make syntax errors') }
121
123
  let(:step_location){['error_step_location', 1]}
122
124
 
123
125
  it 'adds the step to the output buffer' do
@@ -142,7 +144,7 @@ describe Spinach::Reporter::Stdout do
142
144
  end
143
145
 
144
146
  describe '#on_undefined_step' do
145
- let(:step) { {'keyword' => 'When', 'name' => 'I forgot to write steps'} }
147
+ let(:step) { stub(keyword: 'When', name: 'I forgot to write steps') }
146
148
 
147
149
  it 'adds the step to the output buffer' do
148
150
  @reporter.on_undefined_step(step, anything)
@@ -167,9 +169,7 @@ describe Spinach::Reporter::Stdout do
167
169
 
168
170
  describe "#on_feature_not_found" do
169
171
  before do
170
- @feature = {
171
- 'name' => 'This feature does not exist'
172
- }
172
+ @feature = stub(name: 'This feature does not exist', scenarios: [], background_steps: [])
173
173
  Spinach.config.stubs(:step_definitions_path).returns('my/path')
174
174
  @reporter.on_feature_not_found(@feature)
175
175
  end
@@ -195,7 +195,7 @@ describe Spinach::Reporter::Stdout do
195
195
 
196
196
  describe '#on_skipped_step' do
197
197
  it 'adds the step to the output buffer' do
198
- @reporter.on_skipped_step({'keyword' => 'Then', 'name' => 'some steps are not even called'})
198
+ @reporter.on_skipped_step(stub(keyword: 'Then', name: 'some steps are not even called'))
199
199
 
200
200
  @out.string.must_include '~'
201
201
  @out.string.must_include 'Then'
@@ -205,7 +205,7 @@ describe Spinach::Reporter::Stdout do
205
205
 
206
206
  describe '#output_step' do
207
207
  it 'adds a step to the output buffer with nice colors' do
208
- step = {'keyword' => 'Keyword', 'name' => 'step name'}
208
+ step = stub(keyword: 'Keyword', name: 'step name')
209
209
  @reporter.output_step('symbol', step, :blue)
210
210
 
211
211
  @out.string.must_include 'symbol'
@@ -236,11 +236,7 @@ describe Spinach::Reporter::Stdout do
236
236
 
237
237
  describe '#full_step' do
238
238
  it 'returns the step with keyword and name' do
239
- @reporter.full_step({'keyword' => 'Keyword', 'name' => 'step name'}).must_equal 'Keyword step name'
240
- end
241
-
242
- it 'strips the arguments' do
243
- @reporter.full_step({'keyword' => ' Keyword ', 'name' => ' step name '}).must_equal 'Keyword step name'
239
+ @reporter.full_step(stub(keyword: 'Keyword', name: 'step name')).must_equal 'Keyword step name'
244
240
  end
245
241
  end
246
242
  end
@@ -81,6 +81,21 @@ module Spinach
81
81
  Spinach.hooks.run_before_scenario(anything)
82
82
  end
83
83
 
84
+ it "binds a callback around every scenario" do
85
+ @reporter.expects(:around_scenario_run)
86
+ Spinach.hooks.run_around_scenario(anything) do
87
+ yield
88
+ end
89
+ end
90
+
91
+ it "yields to around scenario callback" do
92
+ called = false
93
+ @reporter.around_scenario_run do
94
+ called = true
95
+ end
96
+ called.must_equal true
97
+ end
98
+
84
99
  it "binds a callback after every scenario" do
85
100
  @reporter.expects(:after_scenario_run)
86
101
  Spinach.hooks.run_after_scenario
@@ -1,100 +1,110 @@
1
1
  require_relative '../../test_helper'
2
2
 
3
3
  describe Spinach::Runner::FeatureRunner do
4
- let(:filename) { 'feature/a_cool_feature.feature' }
5
- subject{ Spinach::Runner::FeatureRunner.new(filename) }
4
+ let(:feature) { stub('feature', name: 'Feature') }
5
+ subject{ Spinach::Runner::FeatureRunner.new(feature) }
6
6
 
7
7
  describe '#initialize' do
8
8
  it 'initializes the given filename' do
9
- subject.filename.must_equal filename
9
+ subject.feature.must_equal feature
10
10
  end
11
11
 
12
12
  it 'initalizes the given scenario line' do
13
- @filename = 'feature/a_cool_feature.feature:12'
14
- @feature = Spinach::Runner::FeatureRunner.new(@filename)
15
-
16
- @feature.instance_variable_get(:@scenario_line).must_equal '12'
17
- end
18
- end
19
-
20
- describe '#data' do
21
- it 'returns the parsed data' do
22
- parsed_data = {name: 'A cool feature'}
23
- parser = stub(parse: parsed_data)
24
- Spinach::Parser.expects(:open_file).returns(parser)
25
- subject.data.must_equal parsed_data
13
+ @runner = Spinach::Runner::FeatureRunner.new(feature, '34')
14
+ @runner.instance_variable_get(:@line).must_equal 34
26
15
  end
27
16
  end
28
17
 
29
18
  describe '#scenarios' do
30
- it 'returns the parsed scenarios' do
31
- subject.stubs(data: {'elements' => [1, 2, 3]})
19
+ it 'delegates to the feature' do
20
+ subject.feature.stubs(scenarios: [1,2,3])
32
21
  subject.scenarios.must_equal [1,2,3]
33
22
  end
34
23
  end
35
24
 
36
25
  describe '#run' do
37
- before do
38
- subject.stubs(data: {
39
- 'name' => 'A cool feature',
40
- 'elements' => [{'keyword'=>'Scenario', 'name'=>'Basic guess', 'line'=>6, 'description'=>'', 'type'=>'scenario'},
41
- {'keyword'=>'Scenario', 'name'=>'Basic guess II', 'line'=>12, 'description'=>'', 'type'=>'scenario'},
42
- {'keyword'=>'Scenario', 'name'=>'Basic guess III', 'line'=>18, 'description'=>'', 'type'=>'scenario'}]
43
- })
44
- subject.stubs(feature: stub_everything)
45
- end
26
+ it 'runs the hooks in order' do
27
+ hooks = sequence('hooks')
28
+ Spinach.hooks.expects(:run_before_feature).with(feature).in_sequence(hooks)
29
+ Spinach.expects(:find_step_definitions).returns(false).in_sequence(hooks)
30
+ Spinach.hooks.expects(:run_after_feature).with(feature).in_sequence(hooks)
46
31
 
47
- it 'calls the steps as expected' do
48
- Spinach.expects(:find_feature_steps).returns(true)
49
- seq = sequence('feature')
50
- 3.times do
51
- Spinach::Runner::ScenarioRunner.
52
- expects(:new).
53
- returns(stub_everything).
54
- in_sequence(seq)
55
- end
56
32
  subject.run
57
33
  end
58
34
 
59
- it 'returns true if the execution succeeds' do
60
- Spinach.expects(:find_feature_steps).returns(true)
61
- Spinach::Runner::ScenarioRunner.any_instance.
62
- expects(run: true).times(3)
63
- subject.run.must_equal true
64
- end
35
+ describe 'when the steps exist' do
36
+ before do
37
+ @feature = stub('feature', name: 'Feature')
38
+ Spinach.stubs(:find_step_definitions).returns(true)
39
+ @scenarios = [
40
+ scenario = stub,
41
+ another_scenario = stub
42
+ ]
43
+ @feature.stubs(:scenarios).returns @scenarios
44
+ @runner = Spinach::Runner::FeatureRunner.new(@feature)
45
+ end
65
46
 
66
- it 'returns false if the execution fails' do
67
- Spinach.expects(:find_feature_steps).returns(true)
68
- Spinach::Runner::ScenarioRunner.any_instance.
69
- expects(run: false).times(3)
70
- subject.run.must_equal false
71
- end
47
+ describe 'and the scenarios pass' do
48
+ it 'runs the scenarios and returns true' do
49
+ @scenarios.each do |scenario|
50
+ runner = stub(run: true)
51
+ Spinach::Runner::ScenarioRunner.expects(:new).with(scenario).returns runner
52
+ end
53
+
54
+ @runner.run.must_equal true
55
+ end
56
+ end
72
57
 
73
- it 'calls only the given scenario' do
74
- Spinach.expects(:find_feature_steps).returns(true)
75
- @filename = 'feature/a_cool_feature.feature:12'
76
- @feature = Spinach::Runner::FeatureRunner.new(@filename)
77
- @feature.stubs(data: {
78
- 'name' => 'A cool feature',
79
- 'elements' => [{'keyword'=>'Scenario', 'name'=>'Basic guess', 'line'=>6, 'description'=>'', 'type'=>'scenario'},
80
- {'keyword'=>'Scenario', 'name'=>'Basic guess II', 'line'=>12, 'description'=>'', 'type'=>'scenario'},
81
- {'keyword'=>'Scenario', 'name'=>'Basic guess III', 'line'=>18, 'description'=>'', 'type'=>'scenario'}]
82
- })
58
+ describe 'and the scenarios fail' do
59
+ it 'runs the scenarios and returns false' do
60
+ @scenarios.each do |scenario|
61
+ runner = stub(run: false)
62
+ Spinach::Runner::ScenarioRunner.expects(:new).with(scenario).returns runner
63
+ end
83
64
 
84
- Spinach::Runner::ScenarioRunner.expects(:new).with(anything, @feature.scenarios[1], anything).once.returns(stub_everything)
85
- @feature.run
65
+ @runner.run.must_equal false
66
+ end
67
+ end
86
68
  end
87
69
 
88
- it "fires a hook if the feature is not defined" do
89
- data = stub_everything
90
- Spinach.expects(:find_feature_steps).returns(false)
91
- subject.stubs(:data).returns(data)
92
- not_found_called = false
93
- Spinach.hooks.on_undefined_feature do |data|
94
- not_found_called = data
70
+ describe "when the steps don't exist" do
71
+ it 'runs the corresponding hooks and returns false' do
72
+ Spinach.stubs(:find_step_definitions).returns(false)
73
+ Spinach.hooks.expects(:run_on_undefined_feature).with(feature)
74
+ subject.run.must_equal false
75
+ end
76
+ end
77
+
78
+ describe "when a line is given" do
79
+ before do
80
+ @feature = stub('feature', name: 'Feature')
81
+ Spinach.stubs(:find_step_definitions).returns(true)
82
+ @scenarios = [
83
+ scenario = stub(line: 4),
84
+ another_scenario = stub(line: 12)
85
+ ]
86
+ @feature.stubs(:scenarios).returns @scenarios
87
+ end
88
+ it "runs exactly matching scenario" do
89
+ Spinach::Runner::ScenarioRunner.expects(:new).with(@scenarios[1]).returns stub(run: true)
90
+ @runner = Spinach::Runner::FeatureRunner.new(@feature, "12")
91
+ @runner.run
92
+ end
93
+ it "runs no scenario and returns false" do
94
+ Spinach::Runner::ScenarioRunner.expects(:new).never
95
+ @runner = Spinach::Runner::FeatureRunner.new(@feature, "3")
96
+ @runner.run
97
+ end
98
+ it "runs matching scenario" do
99
+ Spinach::Runner::ScenarioRunner.expects(:new).with(@scenarios[0]).returns stub(run: true)
100
+ @runner = Spinach::Runner::FeatureRunner.new(@feature, "8")
101
+ @runner.run
102
+ end
103
+ it "runs last scenario" do
104
+ Spinach::Runner::ScenarioRunner.expects(:new).with(@scenarios[1]).returns stub(run: true)
105
+ @runner = Spinach::Runner::FeatureRunner.new(@feature, "15")
106
+ @runner.run
95
107
  end
96
- subject.run
97
- not_found_called.must_equal data
98
108
  end
99
109
  end
100
110
  end
@@ -1,111 +1,137 @@
1
1
  require_relative '../../test_helper'
2
2
 
3
- describe Spinach::Runner::ScenarioRunner do
4
- let(:data) do
5
- {
6
- 'name' => 'A cool scenario',
7
- 'steps' => [
8
- {'keyword' => 'Given', 'name' => 'I herd you like steps'},
9
- {'keyword' => 'When', 'name' => 'I test steps'},
10
- {'keyword' => 'Then', 'name' => 'I go step by step'}
11
- ]
12
- }
13
- end
14
-
15
- let(:feature_steps) { stub_everything }
16
- let(:feature_name) { 'My feature' }
17
- subject{
18
- scenario = Spinach::Runner::ScenarioRunner.new(feature_name, data)
19
- scenario.stubs(feature_steps: feature_steps)
20
- scenario
21
- }
22
-
23
- describe '#initialize' do
24
- it 'lists all the steps' do
25
- subject.steps.count.must_equal 3
26
- end
27
-
28
- it 'sets the feature' do
29
- subject.feature_steps.must_equal feature_steps
30
- end
31
- end
3
+ module Spinach
4
+ class Runner
5
+ describe ScenarioRunner do
6
+ let(:feature) { stub(name: 'Feature', background_steps: []) }
7
+ let(:steps) { [stub(name: 'go shopping'), stub(name: 'do something')] }
8
+ let(:scenario) do
9
+ stub(
10
+ feature: feature,
11
+ steps: steps
12
+ )
13
+ end
32
14
 
33
- describe '#feature' do
34
- it 'finds the feature given a feature name' do
35
- subject.unstub(:feature_steps)
36
- @feature = stub_everything
37
- subject.stubs(feature_name: 'A cool feature')
38
- Spinach.expects(:find_feature_steps).with('A cool feature').returns(@feature)
39
- subject.feature_steps
40
- end
41
- end
15
+ subject { ScenarioRunner.new(scenario) }
42
16
 
43
- describe '#run' do
44
- it 'calls the appropiate feature steps' do
45
- feature_steps.expects(:execute_step).with('I herd you like steps')
46
- feature_steps.expects(:execute_step).with('I test steps')
47
- feature_steps.expects(:execute_step).with('I go step by step')
48
- subject.run
49
- end
17
+ describe 'delegations' do
18
+ it 'delegates #feature to the scenario' do
19
+ subject.feature.must_equal feature
20
+ end
50
21
 
51
- describe 'when throwing exceptions' do
52
- it 'rescues a MiniTest::Assertion' do
53
- Spinach.config[:failure_exceptions] << MiniTest::Assertion
54
- feature_steps.expects(:execute_step).raises(MiniTest::Assertion)
55
- Spinach.hooks.expects("run_before_scenario").with(has_value("A cool scenario"))
56
- Spinach.hooks.expects("run_after_scenario").with(has_value("A cool scenario"))
57
- Spinach.hooks.expects('run_on_failed_step').with(anything, anything, anything)
58
- Spinach.hooks.expects('run_on_skipped_step').with(anything, anything).twice
59
- subject.run
22
+ it 'delegates #steps to the scenario' do
23
+ subject.steps.must_equal steps
24
+ end
60
25
  end
61
26
 
62
- it 'rescues a Spinach::StepNotDefinedException' do
63
- feature_steps.expects(:execute_step).raises(
64
- Spinach::StepNotDefinedException.new('bar'))
65
- Spinach.hooks.expects("run_before_scenario").with(has_value("A cool scenario"))
66
- Spinach.hooks.expects("run_after_scenario").with(has_value("A cool scenario"))
67
- Spinach.hooks.expects("run_on_undefined_step").with(
68
- anything, anything, anything)
69
- Spinach.hooks.expects("run_on_skipped_step").with(
70
- anything, anything).twice
71
- subject.run
27
+ describe '#step_definitions' do
28
+ it 'looks up the step definitions' do
29
+ klass = Class.new
30
+ Spinach.expects(:find_step_definitions).with('Feature').returns klass
31
+ subject.step_definitions
32
+ end
72
33
  end
73
34
 
74
- it 'rescues any other error' do
75
- feature_steps.expects(:execute_step).raises
76
- Spinach.hooks.expects("run_after_scenario").with(has_value("A cool scenario"))
77
- Spinach.hooks.expects("run_before_scenario").with(has_value("A cool scenario"))
78
- Spinach.hooks.expects("run_on_error_step").with(anything, anything, anything)
79
- Spinach.hooks.expects("run_on_skipped_step").with(anything, anything).twice
80
- subject.run
81
- end
35
+ describe '#run' do
36
+ describe 'hooks' do
37
+ it 'runs hooks in order' do
38
+ hooks = sequence('hooks')
39
+ subject.stubs(:step_definitions).returns step_definitions = stub
82
40
 
83
- it 'returns an failure' do
84
- feature_steps.expects(:execute_step).raises(MiniTest::Assertion)
85
- subject.run.wont_equal nil
86
- end
87
- end
41
+ Spinach.hooks.expects(:run_before_scenario).with(scenario).in_sequence(hooks)
42
+ Spinach.hooks.expects(:run_around_scenario).with(scenario).in_sequence(hooks).yields
88
43
 
89
- it 'runs a step' do
90
- feature_steps.expects(:execute_step).with(anything).times(3)
91
- subject.run.must_equal true
92
- end
44
+ Spinach.hooks.expects(:run_before_step).with(steps.first).in_sequence(hooks)
45
+ subject.expects(:run_step).with(steps.first)
46
+ Spinach.hooks.expects(:run_after_step).with(steps.first).in_sequence(hooks)
47
+
48
+ Spinach.hooks.expects(:run_before_step).with(steps.last).in_sequence(hooks)
49
+ subject.expects(:run_step).with(steps.last)
50
+ Spinach.hooks.expects(:run_after_step).with(steps.last).in_sequence(hooks)
51
+
52
+ Spinach.hooks.expects(:run_after_scenario).with(scenario).in_sequence(hooks)
93
53
 
94
- describe 'hooks' do
95
- it 'fires up the scenario hooks' do
96
- feature_steps.expects(:execute_step).raises(Spinach::StepNotDefinedException.new('bar'))
97
- Spinach.hooks.expects(:run_before_scenario).with(has_value("A cool scenario"))
98
- Spinach.hooks.expects(:run_after_scenario).with(has_value("A cool scenario"))
99
- subject.run
54
+ subject.run
55
+ end
56
+
57
+ it 'raises if around hook does not yield' do
58
+ subject.stubs(:step_definitions).returns stub
59
+
60
+ Spinach.hooks.stubs(:run_around_scenario).with(scenario)
61
+
62
+ proc do
63
+ subject.run
64
+ end.must_raise RuntimeError
65
+ end
66
+ end
100
67
  end
101
68
 
102
- it 'fires up the step hooks' do
103
- feature_steps.expects(:execute_step).raises(Spinach::StepNotDefinedException.new('bar'))
104
- %w{before_step after_step}.each do |hook|
105
- Spinach.hooks.expects("run_#{hook}").with(kind_of(Hash)).times(3)
69
+ describe '#run_step' do
70
+ before do
71
+ @step = stub(name: 'Go shopping')
72
+ @step_definitions = stub
73
+ @step_definitions.stubs(:step_location_for).with('Go shopping').returns @location = stub
74
+ subject.stubs(:step_definitions).returns @step_definitions
75
+ end
76
+
77
+ describe 'when the step is successful' do
78
+ it 'runs the successful hooks' do
79
+ @step_definitions.stubs(:execute).with(@step).returns true
80
+ Spinach.hooks.expects(:run_on_successful_step).with(@step, @location)
81
+
82
+ subject.run_step(@step)
83
+ end
84
+ end
85
+
86
+ describe 'when the step fails' do
87
+ before do
88
+ @failure_exception = Class.new(StandardError)
89
+ Spinach.stubs(:config).returns({ failure_exceptions: [@failure_exception] })
90
+ @step_definitions.stubs(:execute).with(@step).raises @failure_exception
91
+ end
92
+
93
+ it 'sets the exception' do
94
+ subject.run_step(@step)
95
+ subject.instance_variable_get(:@exception).must_be_kind_of(@failure_exception)
96
+ end
97
+
98
+ it 'runs the failed hooks' do
99
+ Spinach.hooks.expects(:run_on_failed_step).with(@step, kind_of(@failure_exception), @location)
100
+ subject.run_step(@step)
101
+ end
106
102
  end
107
103
 
108
- subject.run
104
+ describe 'when the step is undefined' do
105
+ before do
106
+ @step_definitions.stubs(:execute).with(@step).raises Spinach::StepNotDefinedException, @step
107
+ end
108
+
109
+ it 'sets the exception' do
110
+ subject.run_step(@step)
111
+ subject.instance_variable_get(:@exception).must_be_kind_of(Spinach::StepNotDefinedException)
112
+ end
113
+
114
+ it 'runs the undefined hooks' do
115
+ Spinach.hooks.expects(:run_on_undefined_step).with(@step, kind_of(Spinach::StepNotDefinedException))
116
+ subject.run_step(@step)
117
+ end
118
+ end
119
+
120
+ describe 'when the step raises an error' do
121
+ before do
122
+ @step_definitions.stubs(:execute).with(@step).raises StandardError
123
+ end
124
+
125
+ it 'sets the exception' do
126
+ subject.run_step(@step)
127
+ subject.instance_variable_get(:@exception).must_be_kind_of(StandardError)
128
+ end
129
+
130
+ it 'runs the error hooks' do
131
+ Spinach.hooks.expects(:run_on_error_step).with(@step, kind_of(StandardError), @location)
132
+ subject.run_step(@step)
133
+ end
134
+ end
109
135
  end
110
136
  end
111
137
  end