spinach 0.1.5.4 → 0.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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