spinach 0.1.1 → 0.1.2

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