spinach 0.1.4 → 0.1.5

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 (53) hide show
  1. data/.gitignore +1 -0
  2. data/.yardopts +6 -0
  3. data/Gemfile +1 -0
  4. data/Guardfile +7 -0
  5. data/Rakefile +1 -0
  6. data/Readme.md +147 -10
  7. data/features/{generate_features.feature → automatic_feature_generation.feature} +0 -0
  8. data/features/steps/automatic_feature_generation.rb +5 -2
  9. data/features/steps/exit_status.rb +8 -3
  10. data/features/steps/feature_name_guessing.rb +4 -1
  11. data/features/steps/reporting/display_run_summary.rb +7 -4
  12. data/features/steps/reporting/error_reporting.rb +7 -2
  13. data/features/steps/reporting/show_step_source_location.rb +9 -5
  14. data/features/steps/reporting/undefined_feature_reporting.rb +4 -1
  15. data/features/steps/rspec_compatibility.rb +6 -2
  16. data/features/support/spinach_runner.rb +2 -9
  17. data/lib/spinach/capybara.rb +3 -4
  18. data/lib/spinach/cli.rb +0 -1
  19. data/lib/spinach/config.rb +0 -8
  20. data/lib/spinach/dsl.rb +4 -13
  21. data/lib/spinach/exceptions.rb +1 -1
  22. data/lib/spinach/feature_steps.rb +1 -9
  23. data/lib/spinach/generators/feature_generator.rb +3 -2
  24. data/lib/spinach/generators.rb +1 -1
  25. data/lib/spinach/hookable.rb +81 -0
  26. data/lib/spinach/hooks.rb +132 -0
  27. data/lib/spinach/reporter/stdout/error_reporting.rb +163 -0
  28. data/lib/spinach/reporter/stdout.rb +3 -151
  29. data/lib/spinach/reporter.rb +39 -25
  30. data/lib/spinach/runner/{feature.rb → feature_runner.rb} +5 -15
  31. data/lib/spinach/runner/scenario_runner.rb +65 -0
  32. data/lib/spinach/runner.rb +5 -11
  33. data/lib/spinach/version.rb +1 -1
  34. data/lib/spinach.rb +20 -8
  35. data/spinach.gemspec +2 -3
  36. data/test/spinach/capybara_test.rb +4 -3
  37. data/test/spinach/cli_test.rb +0 -1
  38. data/test/spinach/feature_steps_test.rb +6 -23
  39. data/test/spinach/generators/feature_generator_test.rb +2 -2
  40. data/test/spinach/generators_test.rb +2 -2
  41. data/test/spinach/hookable_test.rb +59 -0
  42. data/test/spinach/hooks_test.rb +28 -0
  43. data/test/spinach/reporter/stdout/error_reporting_test.rb +265 -0
  44. data/test/spinach/reporter/stdout_test.rb +1 -238
  45. data/test/spinach/reporter_test.rb +58 -103
  46. data/test/spinach/runner/{feature_test.rb → feature_runner_test.rb} +21 -23
  47. data/test/spinach/runner/scenario_runner_test.rb +111 -0
  48. data/test/spinach/runner_test.rb +1 -1
  49. data/test/spinach_test.rb +19 -18
  50. data/test/test_helper.rb +1 -1
  51. metadata +60 -61
  52. data/lib/spinach/runner/scenario.rb +0 -77
  53. data/test/spinach/runner/scenario_test.rb +0 -120
@@ -193,7 +193,7 @@ describe Spinach::Reporter::Stdout do
193
193
  end
194
194
 
195
195
  it 'tells the user what to write in the file' do
196
- @out.string.must_include 'Feature \'This feature does not exist\' do'
196
+ @out.string.must_include 'This feature does not exist'
197
197
  end
198
198
  end
199
199
 
@@ -238,219 +238,6 @@ describe Spinach::Reporter::Stdout do
238
238
  end
239
239
  end
240
240
 
241
- describe '#error_summary' do
242
- it 'prints a summary with all the errors' do
243
- @reporter.expects(:report_error_steps).once
244
- @reporter.expects(:report_failed_steps).once
245
- @reporter.expects(:report_undefined_steps).once
246
- @reporter.expects(:report_undefined_features).once
247
-
248
- @reporter.error_summary
249
-
250
- @error.string.must_include 'Error summary'
251
- end
252
- end
253
-
254
- describe '#run_summary' do
255
- it 'prints a run summary' do
256
- @reporter.run_summary
257
-
258
- @out.string.must_include 'Steps Summary:'
259
- end
260
- end
261
-
262
- describe '#report_error_steps' do
263
- describe 'when some steps have raised an error' do
264
- it 'outputs the errors' do
265
- steps = [anything]
266
- @reporter.stubs(:error_steps).returns(steps)
267
- @reporter.expects(:report_errors).with('Errors', steps, :light_red)
268
-
269
- @reporter.report_error_steps
270
- end
271
- end
272
-
273
- describe 'when there are no error steps' do
274
- it 'does nothing' do
275
- @reporter.expects(:report_errors).never
276
-
277
- @reporter.report_error_steps
278
- end
279
- end
280
- end
281
-
282
- describe '#report_failed_steps' do
283
- describe 'when some steps have failed' do
284
- it 'outputs the failing steps' do
285
- steps = [anything]
286
- @reporter.stubs(:failed_steps).returns(steps)
287
- @reporter.expects(:report_errors).with('Failures', steps, :light_red)
288
-
289
- @reporter.report_failed_steps
290
- end
291
- end
292
-
293
- describe 'when there are no failed steps' do
294
- it 'does nothing' do
295
- @reporter.expects(:report_errors).never
296
-
297
- @reporter.report_failed_steps
298
- end
299
- end
300
- end
301
-
302
- describe '#report_undefined_steps' do
303
- describe 'when some steps have undefined' do
304
- it 'outputs the failing steps' do
305
- steps = [anything]
306
- @reporter.stubs(:undefined_steps).returns(steps)
307
- @reporter.expects(:report_errors).with('Undefined steps', steps, :yellow)
308
-
309
- @reporter.report_undefined_steps
310
- end
311
- end
312
-
313
- describe 'when there are no undefined steps' do
314
- it 'does nothing' do
315
- @reporter.expects(:report_errors).never
316
-
317
- @reporter.report_undefined_steps
318
- end
319
- end
320
- end
321
-
322
- describe '#report_undefined_features' do
323
- describe 'when some features are undefined' do
324
- it 'outputs the undefined features' do
325
- @reporter.undefined_features << {'name' => 'Undefined feature name'}
326
- @reporter.report_undefined_features
327
-
328
- @error.string.must_include "Undefined features (1)"
329
- @error.string.must_include "Undefined feature name"
330
- end
331
- end
332
-
333
- describe 'when there are no undefined features' do
334
- it 'does nothing' do
335
- error = @error.string.dup
336
- @reporter.report_undefined_steps
337
-
338
- error.must_equal @error.string
339
- end
340
- end
341
- end
342
-
343
- describe '#report_errors' do
344
- describe 'when some steps have raised an error' do
345
- it 'outputs a the banner with the number of steps given' do
346
- @reporter.report_errors('Banner', steps, :blue)
347
-
348
- @error.string.must_include 'Banner (1)'
349
- end
350
-
351
- it 'prints a summarized error' do
352
- @reporter.report_errors('Banner', steps, :blue)
353
-
354
- @error.string.must_include 'My feature :: A scenario :: Keyword step name'
355
- end
356
-
357
- it 'colorizes the output' do
358
- String.any_instance.expects(:colorize).with(:blue).at_least_once
359
-
360
- @reporter.report_errors('Banner', [], :blue)
361
- end
362
- end
363
- end
364
-
365
- describe '#report_error' do
366
- it 'raises when given an unsupported format' do
367
- proc {
368
- @reporter.report_error(error, :nil)
369
- }.must_raise RuntimeError, 'Format not defined'
370
- end
371
-
372
- it 'prints a summarized error by default' do
373
- @reporter.expects(:summarized_error).with(error).returns('summarized error')
374
-
375
- @reporter.report_error(error)
376
-
377
- @error.string.must_include 'summarized error'
378
- end
379
-
380
- it 'prints a summarized error' do
381
- @reporter.expects(:summarized_error).with(error).returns('summarized error')
382
-
383
- @reporter.report_error(error, :summarized)
384
-
385
- @error.string.must_include 'summarized error'
386
- end
387
-
388
- it 'prints a full error' do
389
- @reporter.expects(:full_error).with(error).returns('full error')
390
-
391
- @reporter.report_error(error, :full)
392
-
393
- @error.string.must_include 'full error'
394
- end
395
- end
396
-
397
- describe '#summarized_error' do
398
- it 'prints the error' do
399
- summary = @reporter.summarized_error(error)
400
-
401
- summary.must_include 'My feature :: A scenario :: Keyword step name'
402
- end
403
-
404
- it 'colorizes the print' do
405
- String.any_instance.expects(:red)
406
-
407
- @reporter.summarized_error(error)
408
- end
409
-
410
- describe 'when given an undefined step exception' do
411
- it 'prints the error in yellow' do
412
- undefined_error = error
413
- undefined_error.insert(3, Spinach::StepNotDefinedException.new(anything))
414
-
415
- String.any_instance.expects(:yellow)
416
-
417
- @reporter.summarized_error(error)
418
- end
419
- end
420
- end
421
-
422
- describe '#full_error' do
423
- before do
424
- @reporter.expects(:report_exception).with(exception).returns('Exception backtrace')
425
- end
426
-
427
- it 'returns the exception data' do
428
- exception.expects(:backtrace).returns(['first backtrace line'])
429
- output = @reporter.full_error(error)
430
-
431
- output.must_include 'Exception backtrace'
432
- end
433
-
434
- it 'returns the first backtrace line' do
435
- exception.expects(:backtrace).returns(['first backtrace line'])
436
- output = @reporter.full_error(error)
437
-
438
- output.must_include 'first backtrace line'
439
- end
440
-
441
- describe 'when the user wants to print the full backtrace' do
442
- it 'prints the full backtrace' do
443
- @reporter.stubs(:options).returns({backtrace: true})
444
- exception.expects(:backtrace).returns(['first backtrace line', 'second backtrace line'])
445
-
446
- output = @reporter.full_error(error)
447
-
448
- output.must_include 'first backtrace line'
449
- output.must_include 'second backtrace line'
450
- end
451
- end
452
- end
453
-
454
241
  describe '#full_step' do
455
242
  it 'returns the step with keyword and name' do
456
243
  @reporter.full_step({'keyword' => 'Keyword', 'name' => 'step name'}).must_equal 'Keyword step name'
@@ -460,28 +247,4 @@ describe Spinach::Reporter::Stdout do
460
247
  @reporter.full_step({'keyword' => ' Keyword ', 'name' => ' step name '}).must_equal 'Keyword step name'
461
248
  end
462
249
  end
463
-
464
- describe '#report_exception' do
465
- it 'returns the exception data' do
466
- output = @reporter.report_exception(exception)
467
-
468
- output.must_include 'Something went wrong'
469
- end
470
-
471
- it 'colorizes the print' do
472
- String.any_instance.expects(:red)
473
-
474
- @reporter.report_exception(exception)
475
- end
476
-
477
- describe 'when given an undefined step exception' do
478
- it 'prints the error in yellow' do
479
- undefined_exception = Spinach::StepNotDefinedException.new(anything)
480
-
481
- String.any_instance.expects(:yellow)
482
-
483
- @reporter.report_exception(undefined_exception)
484
- end
485
- end
486
- end
487
250
  end
@@ -10,11 +10,6 @@ module Spinach
10
10
  @reporter = Reporter.new(@options)
11
11
  end
12
12
 
13
- describe "#initialize" do
14
- it "initializes the option hash" do
15
- end
16
- end
17
-
18
13
  describe "#options" do
19
14
  it "returns the options passed to the reporter" do
20
15
  @reporter.options[:backtrace].must_equal true
@@ -52,124 +47,84 @@ module Spinach
52
47
  @reporter.stubs(:method)
53
48
  end
54
49
 
55
- it "binds a callback after running all the suite" do
56
- @reporter.expects(:method).with(:after_run).returns(@callback)
57
- @reporter.runner.expects(:after_run).with(@callback)
58
- @reporter.bind
59
- end
60
-
61
- it "binds a callback before running every feature" do
62
- @reporter.expects(:method).with(:before_feature_run).returns(@callback)
63
- @reporter.feature_runner.expects(:before_run).with(@callback)
64
- @reporter.bind
65
- end
66
-
67
- it "binds a callback after running every feature" do
68
- @reporter.expects(:method).with(:after_feature_run).returns(@callback)
69
- @reporter.feature_runner.expects(:after_run).with(@callback)
70
- @reporter.bind
71
- end
72
-
73
- it "binds a callback for not defined features" do
74
- @reporter.expects(:method).with(:on_feature_not_found).returns(@callback)
75
- @reporter.feature_runner.expects(:when_not_found).with(@callback)
76
- @reporter.bind
77
- end
78
-
79
- it "binds a callback before running every scenario" do
80
- @reporter.expects(:method).with(:before_scenario_run).returns(@callback)
81
- @reporter.scenario_runner.expects(:before_run).with(@callback)
82
- @reporter.bind
83
- end
50
+ describe "bindings" do
51
+ before do
52
+ @reporter.bind
53
+ end
84
54
 
85
- it "binds a callback after running every feature" do
86
- @reporter.expects(:method).with(:after_scenario_run).returns(@callback)
87
- @reporter.scenario_runner.expects(:after_run).with(@callback)
88
- @reporter.bind
89
- end
55
+ after do
56
+ Spinach.hooks.reset
57
+ end
90
58
 
91
- describe "when running steps" do
92
- %w{successful failed error undefined skipped}.each do |type|
93
- it "binds a callback after running a #{type} step" do
94
- @reporter.expects(:method).with(:"on_#{type}_step").returns(@callback)
95
- @reporter.scenario_runner.expects(:"on_#{type}_step").with(@callback)
96
- @reporter.bind
97
- end
59
+ it "binds a callback after running" do
60
+ @reporter.expects(:after_run)
61
+ Spinach.hooks.run_after_run
98
62
  end
99
- end
100
63
 
101
- describe "binds the context methods" do
102
- it "binds the current feature setter" do
103
- @reporter.expects(:method).with(:current_feature=).returns(@callback)
104
- @reporter.feature_runner.expects(:before_run).with(@callback)
105
- @reporter.bind
64
+ it "binds a callback before running every feature" do
65
+ @reporter.expects(:before_feature_run)
66
+ Spinach.hooks.run_before_feature(anything)
106
67
  end
107
68
 
108
- it "binds the current feature clearer" do
109
- @reporter.expects(:method).with(:clear_current_feature).returns(@callback)
110
- @reporter.feature_runner.expects(:after_run).with(@callback)
111
- @reporter.bind
69
+ it "binds a callback after running every feature" do
70
+ @reporter.expects(:after_feature_run)
71
+ Spinach.hooks.run_after_feature
112
72
  end
113
73
 
114
- it "binds the current scenario setter" do
115
- @reporter.expects(:method).with(:current_scenario=).returns(@callback)
116
- @reporter.scenario_runner.expects(:before_run).with(@callback)
117
- @reporter.bind
74
+ it "binds a callback when a feature is not found" do
75
+ @reporter.expects(:on_feature_not_found)
76
+ Spinach.hooks.run_on_undefined_feature
118
77
  end
119
78
 
120
- it "binds the current feature clearer" do
121
- @reporter.expects(:method).with(:clear_current_scenario).returns(@callback)
122
- @reporter.scenario_runner.expects(:after_run).with(@callback)
123
- @reporter.bind
79
+ it "binds a callback before every scenario" do
80
+ @reporter.expects(:before_scenario_run)
81
+ Spinach.hooks.run_before_scenario(anything)
124
82
  end
125
- end
126
- end
127
83
 
128
- describe "#clear_current_feature" do
129
- it "clears the current feature" do
130
- @reporter.current_feature = mock
131
- @reporter.clear_current_feature
132
- @reporter.current_feature.must_equal nil
133
- end
134
- end
84
+ it "binds a callback after every scenario" do
85
+ @reporter.expects(:after_scenario_run)
86
+ Spinach.hooks.run_after_scenario
87
+ end
135
88
 
136
- describe "#clear_current_scenario" do
137
- it "clears the current scenario" do
138
- @reporter.current_scenario = mock
139
- @reporter.clear_current_scenario
140
- @reporter.current_scenario.must_equal nil
141
- end
142
- end
89
+ it "binds a callback after every successful step" do
90
+ @reporter.expects(:on_successful_step)
91
+ Spinach.hooks.run_on_successful_step
92
+ end
143
93
 
144
- describe "runner classes" do
145
- describe "#feature_runner" do
146
- it "returns a runner class" do
147
- @reporter.feature_runner.must_be_kind_of Class
94
+ it "binds a callback after every failed step" do
95
+ @reporter.expects(:on_failed_step)
96
+ Spinach.hooks.run_on_failed_step
148
97
  end
149
- end
150
98
 
151
- describe "#scenario_runner" do
152
- it "returns a runner class" do
153
- @reporter.scenario_runner.must_be_kind_of Class
99
+ it "binds a callback after every error step" do
100
+ @reporter.expects(:on_error_step)
101
+ Spinach.hooks.run_on_error_step
154
102
  end
155
- end
156
103
 
157
- describe "#runner" do
158
- it "returns a runner class" do
159
- @reporter.runner.must_be_kind_of Class
104
+ it "binds a callback after every skipped step" do
105
+ @reporter.expects(:on_skipped_step)
106
+ Spinach.hooks.run_on_skipped_step
160
107
  end
161
- end
162
- end
163
108
 
164
- describe "callback methods" do
165
- %w{
166
- after_run before_feature_run after_feature_run before_scenario_run
167
- after_scenario_run on_successful_step on_failed_step on_error_step
168
- on_undefined_step on_skipped_step
169
- }.each do |callback|
170
- describe "##{callback}" do
171
- it "does nothing" do
172
- @reporter.send(callback)
109
+ describe "internals" do
110
+ it "binds a callback before running" do
111
+ @reporter.expects(:set_current_feature)
112
+ Spinach.hooks.run_before_feature({})
113
+ end
114
+
115
+ it "binds a callback after running" do
116
+ @reporter.expects(:clear_current_feature)
117
+ Spinach.hooks.run_after_feature
118
+ end
119
+
120
+ it "binds a callback before every scenario" do
121
+ @reporter.expects(:set_current_scenario)
122
+ Spinach.hooks.run_before_scenario
123
+ end
124
+
125
+ it "binds a callback after every scenario" do
126
+ @reporter.expects(:clear_current_scenario)
127
+ Spinach.hooks.run_after_scenario
173
128
  end
174
129
  end
175
130
  end
@@ -1,17 +1,17 @@
1
1
  require_relative '../../test_helper'
2
2
 
3
- describe Spinach::Runner::Feature do
3
+ describe Spinach::Runner::FeatureRunner do
4
4
  let(:filename) { 'feature/a_cool_feature.feature' }
5
- let(:feature) { Spinach::Runner::Feature.new(filename) }
5
+ subject{ Spinach::Runner::FeatureRunner.new(filename) }
6
6
 
7
7
  describe '#initialize' do
8
8
  it 'initializes the given filename' do
9
- feature.filename.must_equal filename
9
+ subject.filename.must_equal filename
10
10
  end
11
11
 
12
12
  it 'initalizes the given scenario line' do
13
13
  @filename = 'feature/a_cool_feature.feature:12'
14
- @feature = Spinach::Runner::Feature.new(@filename)
14
+ @feature = Spinach::Runner::FeatureRunner.new(@filename)
15
15
 
16
16
  @feature.instance_variable_get(:@scenario_line).must_equal '12'
17
17
  end
@@ -22,77 +22,75 @@ describe Spinach::Runner::Feature do
22
22
  parsed_data = {name: 'A cool feature'}
23
23
  parser = stub(parse: parsed_data)
24
24
  Spinach::Parser.expects(:open_file).returns(parser)
25
- feature.data.must_equal parsed_data
25
+ subject.data.must_equal parsed_data
26
26
  end
27
27
  end
28
28
 
29
29
  describe '#scenarios' do
30
30
  it 'returns the parsed scenarios' do
31
- feature.stubs(data: {'elements' => [1, 2, 3]})
32
- feature.scenarios.must_equal [1,2,3]
31
+ subject.stubs(data: {'elements' => [1, 2, 3]})
32
+ subject.scenarios.must_equal [1,2,3]
33
33
  end
34
34
  end
35
35
 
36
36
  describe '#run' do
37
37
  before do
38
- feature.stubs(data: {
38
+ subject.stubs(data: {
39
39
  'name' => 'A cool feature',
40
40
  'elements' => [{'keyword'=>'Scenario', 'name'=>'Basic guess', 'line'=>6, 'description'=>'', 'type'=>'scenario'},
41
41
  {'keyword'=>'Scenario', 'name'=>'Basic guess II', 'line'=>12, 'description'=>'', 'type'=>'scenario'},
42
42
  {'keyword'=>'Scenario', 'name'=>'Basic guess III', 'line'=>18, 'description'=>'', 'type'=>'scenario'}]
43
43
  })
44
- feature.stubs(feature: stub_everything)
44
+ subject.stubs(feature: stub_everything)
45
45
  end
46
46
 
47
47
  it 'calls the steps as expected' do
48
48
  seq = sequence('feature')
49
49
  3.times do
50
- Spinach::Runner::Scenario.
50
+ Spinach::Runner::ScenarioRunner.
51
51
  expects(:new).
52
52
  returns(stub_everything).
53
53
  in_sequence(seq)
54
54
  end
55
- feature.run
55
+ subject.run
56
56
  end
57
57
 
58
58
  it 'returns true if the execution succeeds' do
59
- Spinach::Runner::Scenario.any_instance.
59
+ Spinach::Runner::ScenarioRunner.any_instance.
60
60
  expects(run: true).times(3)
61
- feature.run.must_equal true
61
+ subject.run.must_equal true
62
62
  end
63
63
 
64
64
  it 'returns false if the execution fails' do
65
- Spinach::Runner::Scenario.any_instance.
65
+ Spinach::Runner::ScenarioRunner.any_instance.
66
66
  expects(run: false).times(3)
67
- feature.run.must_equal false
67
+ subject.run.must_equal false
68
68
  end
69
69
 
70
70
  it 'calls only the given scenario' do
71
71
  @filename = 'feature/a_cool_feature.feature:12'
72
- @feature = Spinach::Runner::Feature.new(@filename)
72
+ @feature = Spinach::Runner::FeatureRunner.new(@filename)
73
73
  @feature.stubs(data: {
74
74
  'name' => 'A cool feature',
75
75
  'elements' => [{'keyword'=>'Scenario', 'name'=>'Basic guess', 'line'=>6, 'description'=>'', 'type'=>'scenario'},
76
76
  {'keyword'=>'Scenario', 'name'=>'Basic guess II', 'line'=>12, 'description'=>'', 'type'=>'scenario'},
77
77
  {'keyword'=>'Scenario', 'name'=>'Basic guess III', 'line'=>18, 'description'=>'', 'type'=>'scenario'}]
78
78
  })
79
- @feature.stubs(feature: stub_everything)
80
79
 
81
- Spinach::Runner::Scenario.expects(:new).with(anything, @feature.scenarios[1], anything).once.returns(stub_everything)
80
+ Spinach::Runner::ScenarioRunner.expects(:new).with(anything, @feature.scenarios[1], anything).once.returns(stub_everything)
82
81
  @feature.run
83
82
  end
84
83
 
85
84
  it "fires a hook if the feature is not defined" do
86
- feature = Spinach::Runner::Feature.new(filename)
87
85
  data = mock
88
86
  exception = Spinach::FeatureStepsNotFoundException.new([anything, anything])
89
- feature.stubs(:scenarios).raises(exception)
90
- feature.stubs(:data).returns(data)
87
+ subject.stubs(:scenarios).raises(exception)
88
+ subject.stubs(:data).returns(data)
91
89
  not_found_called = false
92
- feature.class.when_not_found do |data, exception|
90
+ Spinach.hooks.on_undefined_feature do |data, exception|
93
91
  not_found_called = [data, exception]
94
92
  end
95
- feature.run
93
+ subject.run
96
94
  not_found_called.must_equal [data, exception]
97
95
  end
98
96
  end
@@ -0,0 +1,111 @@
1
+ require_relative '../../test_helper'
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
32
+
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
42
+
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
50
+
51
+ describe 'when throwing exceptions' do
52
+ it 'rescues a MiniTest::Assertion' do
53
+ feature_steps.expects(:execute_step).raises(MiniTest::Assertion)
54
+ Spinach.hooks.expects("run_before_scenario").with(has_value("A cool scenario"))
55
+ Spinach.hooks.expects("run_after_scenario").with(has_value("A cool scenario"))
56
+ Spinach.hooks.expects('run_on_failed_step').with(anything, anything, anything)
57
+ Spinach.hooks.expects('run_on_skipped_step').with(anything, anything).twice
58
+ subject.run
59
+ end
60
+
61
+ it 'rescues a Spinach::StepNotDefinedException' do
62
+ feature_steps.expects(:execute_step).raises(
63
+ Spinach::StepNotDefinedException.new('bar'))
64
+ Spinach.hooks.expects("run_before_scenario").with(has_value("A cool scenario"))
65
+ Spinach.hooks.expects("run_after_scenario").with(has_value("A cool scenario"))
66
+ Spinach.hooks.expects("run_on_undefined_step").with(
67
+ anything, anything, anything)
68
+ Spinach.hooks.expects("run_on_skipped_step").with(
69
+ anything, anything).twice
70
+ subject.run
71
+ end
72
+
73
+ it 'rescues any other error' do
74
+ feature_steps.expects(:execute_step).raises
75
+ Spinach.hooks.expects("run_after_scenario").with(has_value("A cool scenario"))
76
+ Spinach.hooks.expects("run_before_scenario").with(has_value("A cool scenario"))
77
+ Spinach.hooks.expects("run_on_error_step").with(anything, anything, anything)
78
+ Spinach.hooks.expects("run_on_skipped_step").with(anything, anything).twice
79
+ subject.run
80
+ end
81
+
82
+ it 'returns an failure' do
83
+ feature_steps.expects(:execute_step).raises(MiniTest::Assertion)
84
+ subject.run.wont_equal nil
85
+ end
86
+ end
87
+
88
+ it 'runs a step' do
89
+ feature_steps.expects(:execute_step).with(anything).times(3)
90
+ subject.run.must_equal true
91
+ end
92
+
93
+ describe 'hooks' do
94
+ it 'fires up the scenario hooks' do
95
+ feature_steps.expects(:execute_step).raises(Spinach::StepNotDefinedException.new('bar'))
96
+ Spinach.hooks.expects(:run_before_scenario).with(has_value("A cool scenario"))
97
+ Spinach.hooks.expects(:run_after_scenario).with(has_value("A cool scenario"))
98
+ subject.run
99
+ end
100
+
101
+ it 'fires up the step hooks' do
102
+ feature_steps.expects(:execute_step).raises(Spinach::StepNotDefinedException.new('bar'))
103
+ %w{before_step after_step}.each do |hook|
104
+ Spinach.hooks.expects("run_#{hook}").with(kind_of(Hash)).times(3)
105
+ end
106
+
107
+ subject.run
108
+ end
109
+ end
110
+ end
111
+ end