spinach 0.1.1 → 0.1.2

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 CHANGED
@@ -6,7 +6,6 @@ gemspec
6
6
  group :test do
7
7
  gem 'guard'
8
8
  gem 'guard-minitest'
9
- gem 'pry', git: 'git://github.com/pry/pry.git'
10
9
  end
11
10
 
12
11
  group :darwin do
@@ -0,0 +1,14 @@
1
+ Feature: Show step source location
2
+ As a developer
3
+ I want spinach to give me every step source location in output
4
+ So I can easyly know where I defined a step
5
+
6
+ Scenario: Show class steps source location in output
7
+ Given I have a feature that has no error or failure
8
+ When I run it
9
+ Then I should see the source location of each step of every scenario
10
+
11
+ Scenario: Show in output the source location of external modules steps
12
+ Given I have a feature that has no error or failure and use external steps
13
+ When I run it
14
+ Then I should see the source location of each step, even external ones
@@ -0,0 +1,9 @@
1
+ Feature: Undefined feature reporting
2
+ In order to be aware of what features I've still not defined
3
+ As a developer
4
+ I want spinach to tell me which of them I'm missing
5
+
6
+ Scenario: Undefined feature
7
+ Given I've written a feature but not its steps
8
+ When I run spinach
9
+ Then I should see a message telling me that there's an undefined feature
@@ -0,0 +1,57 @@
1
+ require 'aruba/api'
2
+
3
+ Feature "Show step source location" do
4
+ include Integration::SpinachRunner
5
+
6
+ Given "I have a feature that has no error or failure" do
7
+ write_file('features/success_feature.feature',
8
+ 'Feature: A success feature
9
+
10
+ Scenario: This is scenario will succeed
11
+ Then I succeed
12
+ ')
13
+ write_file('features/steps/success_feature.rb',
14
+ 'Feature "A success feature" do
15
+ Then "I succeed" do
16
+ end
17
+ end')
18
+ @feature = "features/success_feature.feature"
19
+ end
20
+
21
+ When "I run it" do
22
+ run_feature @feature
23
+ end
24
+
25
+ Then "I should see the source location of each step of every scenario" do
26
+ all_stdout.must_match(
27
+ /I succeed.*features\/steps\/success_feature\.rb.*2/
28
+ )
29
+ end
30
+
31
+ Given "I have a feature that has no error or failure and use external steps" do
32
+ write_file('features/success_feature.feature',
33
+ 'Feature: A feature that uses external steps
34
+
35
+ Scenario: This is scenario will succeed
36
+ Given this is a external step
37
+ ')
38
+ write_file('features/steps/success_feature.rb',
39
+ 'Feature "A feature that uses external steps" do
40
+ include ExternalSteps
41
+ end')
42
+ write_file('features/support/external_steps.rb',
43
+ 'module ExternalSteps
44
+ include Spinach::DSL
45
+ Given "this is a external step" do
46
+ end
47
+ end')
48
+ @feature = "features/success_feature.feature"
49
+ end
50
+
51
+ Then "I should see the source location of each step, even external ones" do
52
+ all_stdout.must_match(
53
+ /this is a external step.*features\/support\/external_steps\.rb.*3/
54
+ )
55
+ end
56
+ end
57
+
@@ -0,0 +1,21 @@
1
+ Feature "Undefined feature reporting" do
2
+ include Integration::SpinachRunner
3
+
4
+ Given "I've written a feature but not its steps" do
5
+ write_file('features/feature_without_steps.feature',
6
+ 'Feature: Feature without steps
7
+
8
+ Scenario: A scenario without steps
9
+ Given I have no steps
10
+ Then I should do nothing
11
+ ')
12
+ end
13
+
14
+ When "I run spinach" do
15
+ run_feature 'features/feature_without_steps.feature'
16
+ end
17
+
18
+ Then "I should see a message telling me that there's an undefined feature" do
19
+ all_stderr.must_match /Undefined features.*1/
20
+ end
21
+ end
@@ -6,11 +6,14 @@ module Integration
6
6
 
7
7
  def self.included(base)
8
8
  base.class_eval do
9
- before do
9
+ before_scenario do
10
10
  in_current_dir do
11
11
  FileUtils.rmdir('features')
12
12
  end
13
13
  end
14
+ before do
15
+ @aruba_timeout_seconds = 6
16
+ end
14
17
  end
15
18
  end
16
19
 
data/lib/spinach/dsl.rb CHANGED
@@ -47,7 +47,7 @@ module Spinach
47
47
  #
48
48
  # @api public
49
49
  def Given(step, &block)
50
- define_method(step, &block)
50
+ define_method(Spinach::Support.underscore(step), &block)
51
51
  end
52
52
 
53
53
  alias_method :When, :Given
@@ -84,11 +84,15 @@ module Spinach
84
84
  #
85
85
  # @api public
86
86
  def execute_step(step)
87
+ step = Spinach::Support.underscore(step)
88
+ location = nil
87
89
  if self.respond_to?(step)
90
+ location = method(step).source_location
88
91
  self.send(step)
89
92
  else
90
93
  raise Spinach::StepNotDefinedException.new(self, step)
91
94
  end
95
+ location
92
96
  end
93
97
 
94
98
  # @return [String]
@@ -16,15 +16,10 @@ module Spinach
16
16
  #
17
17
  # @api public
18
18
  def message
19
- [%Q{Could not find steps for `#{@feature}` feature.
20
- Please create the file #{Spinach::Support.underscore(@missing_class)}.rb
21
- at #{Spinach.config[:step_definitions_path]}, with:}.gsub(/^\s{6,7}/, ''),
22
- %Q{class #{@missing_class} << Spinach::FeatureSteps
23
- #
24
- # define your steps here
25
- #
26
- end}.gsub(/^\s{6,7}/, '')].join("\n\n").red
19
+ "Could not find steps for `#{@feature}` feature"
27
20
  end
21
+
22
+ attr_reader :missing_class
28
23
  end
29
24
 
30
25
  # This class represents the exception raised when Spinach can't find a step
@@ -22,6 +22,7 @@ module Spinach
22
22
  super(*args)
23
23
  @out = options[:output] || $stdout
24
24
  @error = options[:error] || $stderr
25
+ @max_step_name_length = 0
25
26
  end
26
27
 
27
28
  # Prints the feature name to the standard output
@@ -40,9 +41,9 @@ module Spinach
40
41
  # The feature in a JSON Gherkin format
41
42
  #
42
43
  def before_scenario_run(data)
44
+ @max_step_name_length = data['steps'].map{|step| step['name'].length}.max if data['steps']
43
45
  name = data['name']
44
46
  out.puts "\n #{'Scenario:'.green} #{name.light_green}"
45
- out.puts
46
47
  end
47
48
 
48
49
  # Adds an error report and re
@@ -62,8 +63,8 @@ module Spinach
62
63
  # @param [Hash] step
63
64
  # The step in a JSON Gherkin format
64
65
  #
65
- def on_successful_step(step)
66
- output_step('✔', step, :green)
66
+ def on_successful_step(step, step_location)
67
+ output_step('✔', step, :green, step_location)
67
68
  end
68
69
 
69
70
  # Adds a failing step to the output buffer.
@@ -74,8 +75,8 @@ module Spinach
74
75
  # @param [Exception] failure
75
76
  # The exception that caused the failure
76
77
  #
77
- def on_failed_step(step, failure)
78
- output_step('✘', step, :red)
78
+ def on_failed_step(step, failure, step_location)
79
+ output_step('✘', step, :red, step_location)
79
80
  self.scenario_error = [current_feature, current_scenario, step, failure]
80
81
  failed_steps << scenario_error
81
82
  end
@@ -88,8 +89,8 @@ module Spinach
88
89
  # @param [Exception] failure
89
90
  # The exception that caused the failure
90
91
  #
91
- def on_error_step(step, failure)
92
- output_step('!', step, :red)
92
+ def on_error_step(step, failure, step_location)
93
+ output_step('!', step, :red, step_location)
93
94
  self.scenario_error = [current_feature, current_scenario, step, failure]
94
95
  error_steps << scenario_error
95
96
  end
@@ -99,12 +100,41 @@ module Spinach
99
100
  # @param [Hash] step
100
101
  # The step in a JSON Gherkin format
101
102
  #
102
- def on_undefined_step(step)
103
+ def on_undefined_step(step, failure)
103
104
  output_step('?', step, :yellow)
104
105
  self.scenario_error = [current_feature, current_scenario, step]
105
106
  undefined_steps << scenario_error
106
107
  end
107
108
 
109
+ # Adds a feature not found message to the output buffer.
110
+ #
111
+ # @param [Hash] feature
112
+ # the feature in a json gherkin format
113
+ #
114
+ # @param [Spinach::FeatureNotFoundException] exception
115
+ # the related exception
116
+ #
117
+ def on_feature_not_found(feature, exception)
118
+ lines = "#{exception.message}\n"
119
+
120
+ lines << "\nPlease create the file #{Spinach::Support.underscore(exception.missing_class)}.rb at #{Spinach.config[:step_definitions_path]}, with:\n\n"
121
+
122
+ lines << "Feature '#{feature['name']}' do\n"
123
+
124
+ # TODO: Write the actual steps. We can do this since we have the entire
125
+ # feature just here. We should iterate over all the scenarios and return
126
+ # the different steps
127
+ #
128
+ lines << " # Write your steps here"
129
+ lines << "end\n\n"
130
+
131
+ lines.split("\n").each do |line|
132
+ out.puts " #{line}".yellow
133
+ end
134
+
135
+ undefined_features << feature
136
+ end
137
+
108
138
  # Adds a step that has been skipped to the output buffer.
109
139
  #
110
140
  # @param [Hash] step
@@ -126,8 +156,14 @@ module Spinach
126
156
  # @param [Symbol] color
127
157
  # The color code to use with Colorize to colorize the output.
128
158
  #
129
- def output_step(symbol, step, color)
130
- out.puts " #{symbol.colorize(:"light_#{color}")} #{step['keyword'].strip.colorize(:"light_#{color}")} #{step['name'].strip.colorize(color)}"
159
+ # @param [Array] step_location
160
+ # step source location and file line
161
+ #
162
+ def output_step(symbol, step, color, step_location = nil)
163
+ step_location = step_location.first.gsub("#{File.expand_path('.')}/", '# ')+":#{step_location.last.to_s}" if step_location
164
+ max_length = @max_step_name_length + 60 # Colorize and output format correction
165
+ # REMEMBER TO CORRECT PREVIOUS MAX LENGTH IF OUTPUT FORMAT IS MODIFIED
166
+ out.puts " #{symbol.colorize(:"light_#{color}")} #{step['keyword'].strip.colorize(:"light_#{color}")} #{step['name'].strip.colorize(color)} ".ljust(max_length) + step_location.to_s.colorize(:grey)
131
167
  end
132
168
 
133
169
  # It prints the error summary if the run has failed
@@ -145,6 +181,7 @@ module Spinach
145
181
  error.puts "\nError summary:\n"
146
182
  report_error_steps
147
183
  report_failed_steps
184
+ report_undefined_features
148
185
  report_undefined_steps
149
186
  end
150
187
 
@@ -166,6 +203,15 @@ module Spinach
166
203
  report_errors('Undefined steps', undefined_steps, :yellow) if undefined_steps.any?
167
204
  end
168
205
 
206
+ def report_undefined_features
207
+ if undefined_features.any?
208
+ error.puts " Undefined features (#{undefined_features.length})".light_yellow
209
+ undefined_features.each do |feature|
210
+ error.puts " #{feature['name']}".yellow
211
+ end
212
+ end
213
+ end
214
+
169
215
  # Prints the error for a given set of steps
170
216
  #
171
217
  # @param [String] banner
@@ -178,7 +224,7 @@ module Spinach
178
224
  # The color code to use with Colorize to colorize the output.
179
225
  #
180
226
  def report_errors(banner, steps, color)
181
- error.puts "#{banner} (#{steps.length})".colorize(color)
227
+ error.puts " #{banner} (#{steps.length})".colorize(color)
182
228
  steps.each do |error|
183
229
  report_error error
184
230
  end
@@ -218,7 +264,7 @@ module Spinach
218
264
  #
219
265
  def summarized_error(error)
220
266
  feature, scenario, step, exception = error
221
- summary = " #{feature['name']} :: #{scenario['name']} :: #{full_step step}"
267
+ summary = " #{feature['name']} :: #{scenario['name']} :: #{full_step step}"
222
268
  if exception.kind_of?(Spinach::StepNotDefinedException)
223
269
  summary.yellow
224
270
  else
@@ -10,6 +10,7 @@ module Spinach
10
10
  def initialize(options = {})
11
11
  @errors = []
12
12
  @options = options
13
+ @undefined_features = []
13
14
  @undefined_steps = []
14
15
  @failed_steps = []
15
16
  @error_steps = []
@@ -21,15 +22,17 @@ module Spinach
21
22
 
22
23
  attr_accessor :current_feature, :current_scenario
23
24
 
24
- attr_reader :undefined_steps, :failed_steps, :error_steps
25
+ attr_reader :undefined_steps, :failed_steps, :error_steps, :undefined_features
25
26
 
26
27
  def bind
27
28
  runner.after_run method(:after_run)
28
29
  feature_runner.before_run method(:before_feature_run)
29
30
  feature_runner.after_run method(:after_feature_run)
31
+ feature_runner.when_not_found method(:on_feature_not_found)
30
32
  scenario_runner.before_run method(:before_scenario_run)
31
33
  scenario_runner.after_run method(:after_scenario_run)
32
34
  scenario_runner.on_successful_step method(:on_successful_step)
35
+ scenario_runner.on_undefined_step method(:on_undefined_step)
33
36
  scenario_runner.on_failed_step method(:on_failed_step)
34
37
  scenario_runner.on_error_step method(:on_error_step)
35
38
  scenario_runner.on_skipped_step method(:on_skipped_step)
@@ -47,6 +50,7 @@ module Spinach
47
50
  def after_run(*args); end;
48
51
  def before_feature_run(*args); end
49
52
  def after_feature_run(*args); end
53
+ def on_feature_not_found(*args); end
50
54
  def before_scenario_run(*args); end
51
55
  def after_scenario_run(*args); end
52
56
  def on_successful_step(*args); end;
@@ -15,6 +15,7 @@ module Spinach
15
15
 
16
16
  define_hook :before_run
17
17
  define_hook :after_run
18
+ define_hook :when_not_found
18
19
 
19
20
  # @param [String] filename
20
21
  # path to the feature file. Scenario line could be passed to run just
@@ -81,6 +82,9 @@ module Spinach
81
82
  feature.run_hook :after, data
82
83
  run_hook :after_run, data
83
84
 
85
+ rescue Spinach::FeatureStepsNotFoundException => e
86
+ run_hook :when_not_found, data, e
87
+ ensure
84
88
  return !!@success
85
89
  end
86
90
  end
@@ -44,17 +44,17 @@ module Spinach
44
44
  feature.run_hook :before_step, step
45
45
  unless @exception
46
46
  begin
47
- feature.execute_step(step['name'])
48
- run_hook :on_successful_step, step
47
+ step_location = feature.execute_step(step['name'])
48
+ run_hook :on_successful_step, step, step_location
49
49
  rescue *Spinach.config[:failure_exceptions] => e
50
50
  @exception = e
51
- run_hook :on_failed_step, step, @exception
51
+ run_hook :on_failed_step, step, @exception, step_location
52
52
  rescue Spinach::StepNotDefinedException => e
53
53
  @exception = e
54
54
  run_hook :on_undefined_step, step, @exception
55
- rescue StandardError => e
55
+ rescue Exception => e
56
56
  @exception = e
57
- run_hook :on_error_step, step, @exception
57
+ run_hook :on_error_step, step, @exception, step_location
58
58
  end
59
59
  else
60
60
  run_hook :on_skipped_step, step
@@ -1,4 +1,4 @@
1
1
  module Spinach
2
- # Spianch version.
3
- VERSION = "0.1.1"
2
+ # Spinach version.
3
+ VERSION = "0.1.2"
4
4
  end
@@ -7,20 +7,7 @@ describe Spinach::FeatureStepsNotFoundException do
7
7
 
8
8
  describe 'message' do
9
9
  it 'tells the user that the steps could not be found' do
10
- subject.message.must_include 'Could not find steps for `This feature does not exist` feature.'
11
- end
12
-
13
- it 'tells the user to create the file' do
14
- subject.message.must_include 'Please create the file this_feature_does_not_exist.rb'
15
- end
16
-
17
- it 'tells the user where to create the file respecting the step definitions path' do
18
- Spinach.config.stubs(:step_definitions_path).returns('my/path')
19
- subject.message.must_include 'at my/path, with:'
20
- end
21
-
22
- it 'tells the user what to write in the file' do
23
- subject.message.must_include 'class ThisFeatureDoesNotExist << Spinach::FeatureSteps'
10
+ subject.message.must_include 'Could not find steps for `This feature does not exist` feature'
24
11
  end
25
12
  end
26
13
  end
@@ -1,45 +1,45 @@
1
1
  require_relative '../test_helper'
2
2
 
3
3
  describe Spinach::Config do
4
- before do
5
- @config = Spinach::Config.new
4
+ subject do
5
+ Spinach::Config.new
6
6
  end
7
7
 
8
8
  describe '#step_definitions_path' do
9
9
  it 'returns a default' do
10
- @config[:step_definitions_path].must_be_kind_of String
10
+ subject[:step_definitions_path].must_be_kind_of String
11
11
  end
12
12
 
13
13
  it 'can be overwritten' do
14
- @config[:step_definitions_path] = 'steps'
15
- @config[:step_definitions_path].must_equal 'steps'
14
+ subject[:step_definitions_path] = 'steps'
15
+ subject[:step_definitions_path].must_equal 'steps'
16
16
  end
17
17
  end
18
18
 
19
19
  describe '#support_path' do
20
20
  it 'returns a default' do
21
- @config[:support_path].must_be_kind_of String
21
+ subject[:support_path].must_be_kind_of String
22
22
  end
23
23
 
24
24
  it 'can be overwritten' do
25
- @config[:support_path] = 'support'
26
- @config[:support_path].must_equal 'support'
25
+ subject[:support_path] = 'support'
26
+ subject[:support_path].must_equal 'support'
27
27
  end
28
28
  end
29
29
 
30
30
  describe '#failure_exceptions' do
31
31
  it 'returns a default' do
32
- @config[:failure_exceptions].must_be_kind_of Array
32
+ subject[:failure_exceptions].must_be_kind_of Array
33
33
  end
34
34
 
35
35
  it 'can be overwritten' do
36
- @config[:failure_exceptions] = [1, 2, 3]
37
- @config[:failure_exceptions].must_equal [1,2,3]
36
+ subject[:failure_exceptions] = [1, 2, 3]
37
+ subject[:failure_exceptions].must_equal [1,2,3]
38
38
  end
39
39
 
40
40
  it 'allows adding elements' do
41
- @config[:failure_exceptions] << RuntimeError
42
- @config[:failure_exceptions].must_include RuntimeError
41
+ subject[:failure_exceptions] << RuntimeError
42
+ subject[:failure_exceptions].must_include RuntimeError
43
43
  end
44
44
  end
45
45
  end
@@ -10,11 +10,22 @@ describe Spinach::DSL do
10
10
  describe 'class methods' do
11
11
  describe '#When' do
12
12
  it 'defines a method with the step name' do
13
+ step_executed = false
14
+ @feature.When('I say goodbye') do
15
+ step_executed = true
16
+ end
17
+
18
+ @feature.new.execute_step('I say goodbye')
19
+ step_executed.must_equal true
20
+ end
21
+
22
+ it 'returns step source location' do
13
23
  @feature.When('I say goodbye') do
14
24
  'You say hello'
15
25
  end
16
26
 
17
- @feature.new.send('I say goodbye').must_equal 'You say hello'
27
+ @feature.new.execute_step('I say goodbye').first.must_include '/dsl_test.rb'
28
+ @feature.new.execute_step('I say goodbye').last.must_be_kind_of Fixnum
18
29
  end
19
30
  end
20
31
 
@@ -68,8 +68,9 @@ describe Spinach::Reporter::Stdout do
68
68
  end
69
69
 
70
70
  describe '#on_successful_step' do
71
+ let(:step_location){['error_step_location', 1]}
71
72
  it 'adds the step to the output buffer' do
72
- @reporter.on_successful_step({'keyword' => 'Given', 'name' => 'I am too cool'})
73
+ @reporter.on_successful_step({'keyword' => 'Given', 'name' => 'I am too cool'}, step_location)
73
74
 
74
75
  @out.string.must_include '✔'
75
76
  @out.string.must_include 'Given'
@@ -79,9 +80,10 @@ describe Spinach::Reporter::Stdout do
79
80
 
80
81
  describe '#on_failed_step' do
81
82
  let(:step) { {'keyword' => 'Then', 'name' => 'I write failing steps'} }
83
+ let(:step_location){['error_step_location', 1]}
82
84
 
83
85
  it 'adds the step to the output buffer' do
84
- @reporter.on_failed_step(step, anything)
86
+ @reporter.on_failed_step(step, anything, step_location)
85
87
 
86
88
  @out.string.must_include '✘'
87
89
  @out.string.must_include 'Then'
@@ -89,13 +91,13 @@ describe Spinach::Reporter::Stdout do
89
91
  end
90
92
 
91
93
  it 'sets the current scenario error' do
92
- @reporter.on_failed_step(step, anything)
94
+ @reporter.on_failed_step(step, anything, step_location)
93
95
 
94
96
  @reporter.scenario_error.must_include step
95
97
  end
96
98
 
97
99
  it 'adds the step to the failing steps' do
98
- @reporter.on_failed_step(step, anything)
100
+ @reporter.on_failed_step(step, anything, step_location)
99
101
 
100
102
  @reporter.failed_steps.last.must_include step
101
103
  end
@@ -103,9 +105,10 @@ describe Spinach::Reporter::Stdout do
103
105
 
104
106
  describe '#on_error_step' do
105
107
  let(:step) { {'keyword' => 'And', 'name' => 'I even make syntax errors'} }
108
+ let(:step_location){['error_step_location', 1]}
106
109
 
107
110
  it 'adds the step to the output buffer' do
108
- @reporter.on_error_step(step, anything)
111
+ @reporter.on_error_step(step, anything, step_location)
109
112
 
110
113
  @out.string.must_include '!'
111
114
  @out.string.must_include 'And'
@@ -113,13 +116,13 @@ describe Spinach::Reporter::Stdout do
113
116
  end
114
117
 
115
118
  it 'sets the current scenario error' do
116
- @reporter.on_error_step(step, anything)
119
+ @reporter.on_error_step(step, anything, step_location)
117
120
 
118
121
  @reporter.scenario_error.must_include step
119
122
  end
120
123
 
121
124
  it 'adds the step to the error steps' do
122
- @reporter.on_error_step(step, anything)
125
+ @reporter.on_error_step(step, anything, step_location)
123
126
 
124
127
  @reporter.error_steps.last.must_include step
125
128
  end
@@ -129,7 +132,7 @@ describe Spinach::Reporter::Stdout do
129
132
  let(:step) { {'keyword' => 'When', 'name' => 'I forgot to write steps'} }
130
133
 
131
134
  it 'adds the step to the output buffer' do
132
- @reporter.on_undefined_step(step)
135
+ @reporter.on_undefined_step(step, anything)
133
136
 
134
137
  @out.string.must_include '?'
135
138
  @out.string.must_include 'When'
@@ -137,18 +140,50 @@ describe Spinach::Reporter::Stdout do
137
140
  end
138
141
 
139
142
  it 'sets the current scenario error' do
140
- @reporter.on_undefined_step(step)
143
+ @reporter.on_undefined_step(step, anything)
141
144
 
142
145
  @reporter.scenario_error.must_include step
143
146
  end
144
147
 
145
148
  it 'adds the step to the undefined steps' do
146
- @reporter.on_undefined_step(step)
149
+ @reporter.on_undefined_step(step, anything)
147
150
 
148
151
  @reporter.undefined_steps.last.must_include step
149
152
  end
150
153
  end
151
154
 
155
+ describe "#on_feature_not_found" do
156
+ before do
157
+ @feature = {
158
+ 'name' => 'This feature does not exist'
159
+ }
160
+ Spinach.config.stubs(:step_definitions_path).returns('my/path')
161
+ exception = stub(
162
+ message: "This is a \nmultiple line error message",
163
+ missing_class: "ThisFeatureDoesNotExist"
164
+ )
165
+ @reporter.on_feature_not_found(@feature, exception)
166
+ end
167
+ it "outputs a message" do
168
+ @out.string.must_include "this_feature_does_not_exist.rb"
169
+ @out.string.must_include "This is a"
170
+ @out.string.must_include "multiple line error message"
171
+ @reporter.undefined_features.must_include @feature
172
+ end
173
+
174
+ it 'tells the user to create the file' do
175
+ @out.string.must_include 'Please create the file this_feature_does_not_exist.rb'
176
+ end
177
+
178
+ it 'tells the user where to create the file respecting the step definitions path' do
179
+ @out.string.must_include 'at my/path, with:'
180
+ end
181
+
182
+ it 'tells the user what to write in the file' do
183
+ @out.string.must_include 'Feature \'This feature does not exist\' do'
184
+ end
185
+ end
186
+
152
187
  describe '#on_skipped_step' do
153
188
  it 'adds the step to the output buffer' do
154
189
  @reporter.on_skipped_step({'keyword' => 'Then', 'name' => 'some steps are not even called'})
@@ -191,6 +226,7 @@ describe Spinach::Reporter::Stdout do
191
226
  @reporter.expects(:report_error_steps).once
192
227
  @reporter.expects(:report_failed_steps).once
193
228
  @reporter.expects(:report_undefined_steps).once
229
+ @reporter.expects(:report_undefined_features).once
194
230
 
195
231
  @reporter.error_summary
196
232
 
@@ -258,6 +294,27 @@ describe Spinach::Reporter::Stdout do
258
294
  end
259
295
  end
260
296
 
297
+ describe '#report_undefined_features' do
298
+ describe 'when some features are undefined' do
299
+ it 'outputs the undefined features' do
300
+ @reporter.undefined_features << {'name' => 'Undefined feature name'}
301
+ @reporter.report_undefined_features
302
+
303
+ @error.string.must_include "Undefined features (1)"
304
+ @error.string.must_include "Undefined feature name"
305
+ end
306
+ end
307
+
308
+ describe 'when there are no undefined features' do
309
+ it 'does nothing' do
310
+ error = @error.string.dup
311
+ @reporter.report_undefined_steps
312
+
313
+ error.must_equal @error.string
314
+ end
315
+ end
316
+ end
317
+
261
318
  describe '#report_errors' do
262
319
  describe 'when some steps have raised an error' do
263
320
  it 'outputs a the banner with the number of steps given' do
@@ -51,33 +51,45 @@ module Spinach
51
51
  @callback = mock
52
52
  @reporter.stubs(:method)
53
53
  end
54
+
54
55
  it "binds a callback after running all the suite" do
55
56
  @reporter.expects(:method).with(:after_run).returns(@callback)
56
57
  @reporter.runner.expects(:after_run).with(@callback)
57
58
  @reporter.bind
58
59
  end
60
+
59
61
  it "binds a callback before running every feature" do
60
62
  @reporter.expects(:method).with(:before_feature_run).returns(@callback)
61
63
  @reporter.feature_runner.expects(:before_run).with(@callback)
62
64
  @reporter.bind
63
65
  end
66
+
64
67
  it "binds a callback after running every feature" do
65
68
  @reporter.expects(:method).with(:after_feature_run).returns(@callback)
66
69
  @reporter.feature_runner.expects(:after_run).with(@callback)
67
70
  @reporter.bind
68
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
+
69
79
  it "binds a callback before running every scenario" do
70
80
  @reporter.expects(:method).with(:before_scenario_run).returns(@callback)
71
81
  @reporter.scenario_runner.expects(:before_run).with(@callback)
72
82
  @reporter.bind
73
83
  end
84
+
74
85
  it "binds a callback after running every feature" do
75
86
  @reporter.expects(:method).with(:after_scenario_run).returns(@callback)
76
87
  @reporter.scenario_runner.expects(:after_run).with(@callback)
77
88
  @reporter.bind
78
89
  end
90
+
79
91
  describe "when running steps" do
80
- %w{successful failed error skipped}.each do |type|
92
+ %w{successful failed error undefined skipped}.each do |type|
81
93
  it "binds a callback after running a #{type} step" do
82
94
  @reporter.expects(:method).with(:"on_#{type}_step").returns(@callback)
83
95
  @reporter.scenario_runner.expects(:"on_#{type}_step").with(@callback)
@@ -85,22 +97,26 @@ module Spinach
85
97
  end
86
98
  end
87
99
  end
100
+
88
101
  describe "binds the context methods" do
89
102
  it "binds the current feature setter" do
90
103
  @reporter.expects(:method).with(:current_feature=).returns(@callback)
91
104
  @reporter.feature_runner.expects(:before_run).with(@callback)
92
105
  @reporter.bind
93
106
  end
107
+
94
108
  it "binds the current feature clearer" do
95
109
  @reporter.expects(:method).with(:clear_current_feature).returns(@callback)
96
110
  @reporter.feature_runner.expects(:after_run).with(@callback)
97
111
  @reporter.bind
98
112
  end
113
+
99
114
  it "binds the current scenario setter" do
100
115
  @reporter.expects(:method).with(:current_scenario=).returns(@callback)
101
116
  @reporter.scenario_runner.expects(:before_run).with(@callback)
102
117
  @reporter.bind
103
118
  end
119
+
104
120
  it "binds the current feature clearer" do
105
121
  @reporter.expects(:method).with(:clear_current_scenario).returns(@callback)
106
122
  @reporter.scenario_runner.expects(:after_run).with(@callback)
@@ -131,11 +147,13 @@ module Spinach
131
147
  @reporter.feature_runner.must_be_kind_of Class
132
148
  end
133
149
  end
150
+
134
151
  describe "#scenario_runner" do
135
152
  it "returns a runner class" do
136
153
  @reporter.scenario_runner.must_be_kind_of Class
137
154
  end
138
155
  end
156
+
139
157
  describe "#runner" do
140
158
  it "returns a runner class" do
141
159
  @reporter.runner.must_be_kind_of Class
@@ -156,6 +174,5 @@ module Spinach
156
174
  end
157
175
  end
158
176
  end
159
-
160
177
  end
161
178
  end
@@ -93,5 +93,19 @@ describe Spinach::Runner::Feature do
93
93
  Spinach::Runner::Scenario.expects(:new).with(anything, anything, @feature.scenarios[1], anything).once.returns(stub_everything)
94
94
  @feature.run
95
95
  end
96
+
97
+ it "fires a hook if the feature is not defined" do
98
+ feature = Spinach::Runner::Feature.new(filename)
99
+ data = mock
100
+ exception = Spinach::FeatureStepsNotFoundException.new([anything, anything])
101
+ feature.stubs(:feature).raises(exception)
102
+ feature.stubs(:data).returns(data)
103
+ not_found_called = false
104
+ feature.class.when_not_found do |data, exception|
105
+ not_found_called = [data, exception]
106
+ end
107
+ feature.run
108
+ not_found_called.must_equal [data, exception]
109
+ end
96
110
  end
97
111
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spinach
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,11 +12,11 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2011-10-09 00:00:00.000000000Z
15
+ date: 2011-10-10 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: gherkin
19
- requirement: &70133830838360 !ruby/object:Gem::Requirement
19
+ requirement: &2164332760 !ruby/object:Gem::Requirement
20
20
  none: false
21
21
  requirements:
22
22
  - - ! '>='
@@ -24,10 +24,10 @@ dependencies:
24
24
  version: '0'
25
25
  type: :runtime
26
26
  prerelease: false
27
- version_requirements: *70133830838360
27
+ version_requirements: *2164332760
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: minitest
30
- requirement: &70133830837940 !ruby/object:Gem::Requirement
30
+ requirement: &2164330700 !ruby/object:Gem::Requirement
31
31
  none: false
32
32
  requirements:
33
33
  - - ! '>='
@@ -35,10 +35,10 @@ dependencies:
35
35
  version: '0'
36
36
  type: :runtime
37
37
  prerelease: false
38
- version_requirements: *70133830837940
38
+ version_requirements: *2164330700
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: colorize
41
- requirement: &70133830837520 !ruby/object:Gem::Requirement
41
+ requirement: &2164330180 !ruby/object:Gem::Requirement
42
42
  none: false
43
43
  requirements:
44
44
  - - ! '>='
@@ -46,10 +46,10 @@ dependencies:
46
46
  version: '0'
47
47
  type: :runtime
48
48
  prerelease: false
49
- version_requirements: *70133830837520
49
+ version_requirements: *2164330180
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: hooks
52
- requirement: &70133830837100 !ruby/object:Gem::Requirement
52
+ requirement: &2164329420 !ruby/object:Gem::Requirement
53
53
  none: false
54
54
  requirements:
55
55
  - - ! '>='
@@ -57,10 +57,10 @@ dependencies:
57
57
  version: '0'
58
58
  type: :runtime
59
59
  prerelease: false
60
- version_requirements: *70133830837100
60
+ version_requirements: *2164329420
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: purdytest
63
- requirement: &70133830836680 !ruby/object:Gem::Requirement
63
+ requirement: &2164328540 !ruby/object:Gem::Requirement
64
64
  none: false
65
65
  requirements:
66
66
  - - ! '>='
@@ -68,10 +68,10 @@ dependencies:
68
68
  version: '0'
69
69
  type: :development
70
70
  prerelease: false
71
- version_requirements: *70133830836680
71
+ version_requirements: *2164328540
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: rake
74
- requirement: &70133830836260 !ruby/object:Gem::Requirement
74
+ requirement: &2164328020 !ruby/object:Gem::Requirement
75
75
  none: false
76
76
  requirements:
77
77
  - - ! '>='
@@ -79,10 +79,10 @@ dependencies:
79
79
  version: '0'
80
80
  type: :development
81
81
  prerelease: false
82
- version_requirements: *70133830836260
82
+ version_requirements: *2164328020
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: mocha
85
- requirement: &70133830835840 !ruby/object:Gem::Requirement
85
+ requirement: &2164373480 !ruby/object:Gem::Requirement
86
86
  none: false
87
87
  requirements:
88
88
  - - ! '>='
@@ -90,10 +90,10 @@ dependencies:
90
90
  version: '0'
91
91
  type: :development
92
92
  prerelease: false
93
- version_requirements: *70133830835840
93
+ version_requirements: *2164373480
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: sinatra
96
- requirement: &70133830835420 !ruby/object:Gem::Requirement
96
+ requirement: &2164372820 !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
99
99
  - - ! '>='
@@ -101,10 +101,10 @@ dependencies:
101
101
  version: '0'
102
102
  type: :development
103
103
  prerelease: false
104
- version_requirements: *70133830835420
104
+ version_requirements: *2164372820
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: capybara
107
- requirement: &70133830835000 !ruby/object:Gem::Requirement
107
+ requirement: &2164372260 !ruby/object:Gem::Requirement
108
108
  none: false
109
109
  requirements:
110
110
  - - ! '>='
@@ -112,10 +112,10 @@ dependencies:
112
112
  version: '0'
113
113
  type: :development
114
114
  prerelease: false
115
- version_requirements: *70133830835000
115
+ version_requirements: *2164372260
116
116
  - !ruby/object:Gem::Dependency
117
117
  name: aruba
118
- requirement: &70133830834580 !ruby/object:Gem::Requirement
118
+ requirement: &2164371820 !ruby/object:Gem::Requirement
119
119
  none: false
120
120
  requirements:
121
121
  - - ! '>='
@@ -123,10 +123,10 @@ dependencies:
123
123
  version: '0'
124
124
  type: :development
125
125
  prerelease: false
126
- version_requirements: *70133830834580
126
+ version_requirements: *2164371820
127
127
  - !ruby/object:Gem::Dependency
128
128
  name: pry
129
- requirement: &70133830834160 !ruby/object:Gem::Requirement
129
+ requirement: &2164371000 !ruby/object:Gem::Requirement
130
130
  none: false
131
131
  requirements:
132
132
  - - ! '>='
@@ -134,10 +134,10 @@ dependencies:
134
134
  version: '0'
135
135
  type: :development
136
136
  prerelease: false
137
- version_requirements: *70133830834160
137
+ version_requirements: *2164371000
138
138
  - !ruby/object:Gem::Dependency
139
139
  name: simplecov
140
- requirement: &70133830833740 !ruby/object:Gem::Requirement
140
+ requirement: &2164370500 !ruby/object:Gem::Requirement
141
141
  none: false
142
142
  requirements:
143
143
  - - ! '>='
@@ -145,10 +145,10 @@ dependencies:
145
145
  version: '0'
146
146
  type: :development
147
147
  prerelease: false
148
- version_requirements: *70133830833740
148
+ version_requirements: *2164370500
149
149
  - !ruby/object:Gem::Dependency
150
150
  name: rspec
151
- requirement: &70133830833320 !ruby/object:Gem::Requirement
151
+ requirement: &2164369940 !ruby/object:Gem::Requirement
152
152
  none: false
153
153
  requirements:
154
154
  - - ! '>='
@@ -156,7 +156,7 @@ dependencies:
156
156
  version: '0'
157
157
  type: :development
158
158
  prerelease: false
159
- version_requirements: *70133830833320
159
+ version_requirements: *2164369940
160
160
  description: Spinach is a BDD framework on top of gherkin
161
161
  email:
162
162
  - info@codegram.com
@@ -177,13 +177,17 @@ files:
177
177
  - Rakefile
178
178
  - Readme.md
179
179
  - bin/spinach
180
- - features/error_reporting.feature
181
180
  - features/exit_status.feature
182
181
  - features/feature_name_guessing.feature
182
+ - features/reporting/error_reporting.feature
183
+ - features/reporting/show_step_source_location.feature
184
+ - features/reporting/undefined_feature_reporting.feature
183
185
  - features/rspec_compatibility.feature
184
- - features/steps/error_reporting.rb
185
186
  - features/steps/exit_status.rb
186
187
  - features/steps/feature_name_guessing.rb
188
+ - features/steps/reporting/error_reporting.rb
189
+ - features/steps/reporting/show_step_source_location.rb
190
+ - features/steps/reporting/undefined_feature_reporting.rb
187
191
  - features/steps/rspec_compatibility.rb
188
192
  - features/support/env.rb
189
193
  - features/support/error_reporting.rb
@@ -235,26 +239,36 @@ required_ruby_version: !ruby/object:Gem::Requirement
235
239
  - - ! '>='
236
240
  - !ruby/object:Gem::Version
237
241
  version: '0'
242
+ segments:
243
+ - 0
244
+ hash: 1257566033182471881
238
245
  required_rubygems_version: !ruby/object:Gem::Requirement
239
246
  none: false
240
247
  requirements:
241
248
  - - ! '>='
242
249
  - !ruby/object:Gem::Version
243
250
  version: '0'
251
+ segments:
252
+ - 0
253
+ hash: 1257566033182471881
244
254
  requirements: []
245
255
  rubyforge_project:
246
- rubygems_version: 1.8.6
256
+ rubygems_version: 1.8.5
247
257
  signing_key:
248
258
  specification_version: 3
249
259
  summary: Spinach is a BDD framework on top of gherkin
250
260
  test_files:
251
- - features/error_reporting.feature
252
261
  - features/exit_status.feature
253
262
  - features/feature_name_guessing.feature
263
+ - features/reporting/error_reporting.feature
264
+ - features/reporting/show_step_source_location.feature
265
+ - features/reporting/undefined_feature_reporting.feature
254
266
  - features/rspec_compatibility.feature
255
- - features/steps/error_reporting.rb
256
267
  - features/steps/exit_status.rb
257
268
  - features/steps/feature_name_guessing.rb
269
+ - features/steps/reporting/error_reporting.rb
270
+ - features/steps/reporting/show_step_source_location.rb
271
+ - features/steps/reporting/undefined_feature_reporting.rb
258
272
  - features/steps/rspec_compatibility.rb
259
273
  - features/support/env.rb
260
274
  - features/support/error_reporting.rb