cucumber 0.3.9 → 0.3.10
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/History.txt +40 -0
- data/Manifest.txt +10 -0
- data/cucumber.yml +1 -1
- data/examples/i18n/pl/Rakefile +6 -0
- data/examples/i18n/pl/features/addition.feature +16 -0
- data/examples/i18n/pl/features/division.feature +9 -0
- data/examples/i18n/pl/features/step_definitons/calculator_steps.rb +24 -0
- data/examples/i18n/pl/features/support/env.rb +6 -0
- data/examples/i18n/pl/lib/calculator.rb +14 -0
- data/examples/self_test/features/sample.feature +2 -0
- data/features/cucumber_cli.feature +24 -6
- data/features/drb_server_integration.feature +92 -0
- data/features/html_formatter/a.html +926 -437
- data/features/junit_formatter.feature +11 -2
- data/features/step_definitions/cucumber_steps.rb +15 -2
- data/features/support/env.rb +35 -1
- data/features/usage.feature +2 -2
- data/lib/cucumber/ast/background.rb +1 -1
- data/lib/cucumber/ast/comment.rb +4 -0
- data/lib/cucumber/ast/feature.rb +2 -1
- data/lib/cucumber/ast/outline_table.rb +2 -2
- data/lib/cucumber/ast/scenario.rb +1 -1
- data/lib/cucumber/ast/scenario_outline.rb +11 -4
- data/lib/cucumber/ast/step_invocation.rb +17 -12
- data/lib/cucumber/ast/visitor.rb +4 -0
- data/lib/cucumber/cli/configuration.rb +32 -8
- data/lib/cucumber/cli/drb_client.rb +21 -0
- data/lib/cucumber/cli/main.rb +9 -0
- data/lib/cucumber/formatter/color_io.rb +2 -2
- data/lib/cucumber/formatter/console.rb +1 -3
- data/lib/cucumber/formatter/html.rb +63 -12
- data/lib/cucumber/formatter/junit.rb +2 -2
- data/lib/cucumber/formatter/pretty.rb +2 -1
- data/lib/cucumber/formatter/rerun.rb +1 -0
- data/lib/cucumber/formatter/tag_cloud.rb +1 -0
- data/lib/cucumber/rails/rspec.rb +5 -3
- data/lib/cucumber/rake/task.rb +1 -1
- data/lib/cucumber/step_match.rb +6 -2
- data/lib/cucumber/step_mother.rb +11 -8
- data/lib/cucumber/version.rb +1 -1
- data/rails_generators/cucumber/cucumber_generator.rb +12 -2
- data/rails_generators/cucumber/templates/cucumber.rake +1 -1
- data/rails_generators/cucumber/templates/cucumber_environment.rb +6 -4
- data/rails_generators/cucumber/templates/env.rb +10 -3
- data/rails_generators/cucumber/templates/spork_env.rb +36 -0
- data/rails_generators/cucumber/templates/webrat_steps.rb +8 -0
- data/spec/cucumber/cli/configuration_spec.rb +56 -1
- data/spec/cucumber/cli/drb_client_spec.rb +42 -0
- data/spec/cucumber/cli/main_spec.rb +64 -19
- metadata +12 -2
@@ -58,5 +58,14 @@ Feature: JUnit output formatter
|
|
58
58
|
"""
|
59
59
|
And "examples/junit/tmp/TEST-One_passing_scenario__one_failing_scenario.xml" should exist
|
60
60
|
And "examples/junit/tmp/TEST-Pending_step.xml" should exist
|
61
|
-
|
62
|
-
|
61
|
+
|
62
|
+
Scenario: show correct error message if no --out is passed
|
63
|
+
When I run cucumber --format junit features
|
64
|
+
Then STDERR should not match
|
65
|
+
"""
|
66
|
+
can't convert .* into String \(TypeError\)
|
67
|
+
"""
|
68
|
+
And STDERR should match
|
69
|
+
"""
|
70
|
+
You \*must\* specify \-\-out DIR for the junit formatter
|
71
|
+
"""
|
@@ -31,6 +31,15 @@ Given /^the following profiles? (?:are|is) defined:$/ do |profiles|
|
|
31
31
|
create_file('cucumber.yml', profiles)
|
32
32
|
end
|
33
33
|
|
34
|
+
Given /^I am running "([^\"]*)" in the background$/ do |command|
|
35
|
+
run_in_background command
|
36
|
+
end
|
37
|
+
|
38
|
+
Given /^I am not running (?:.*) in the background$/ do
|
39
|
+
# no-op
|
40
|
+
end
|
41
|
+
|
42
|
+
|
34
43
|
When /^I run cucumber (.*)$/ do |cucumber_opts|
|
35
44
|
run "#{Cucumber::RUBY_BINARY} #{Cucumber::BINARY} --no-color #{cucumber_opts}"
|
36
45
|
end
|
@@ -88,9 +97,9 @@ end
|
|
88
97
|
|
89
98
|
Then /^"([^\"]*)" should have the same contents as "([^\"]*)"$/ do |actual_file, expected_file|
|
90
99
|
actual = IO.read(actual_file)
|
91
|
-
# Comment out to replace expected file. Use with care! Remember to update duration afterwards.
|
92
|
-
# File.open(expected_file, "w"){|io| io.write(actual)}
|
93
100
|
actual = replace_duration(actual, '0m30.005s')
|
101
|
+
# Comment out to replace expected file. Use with care! Remember to update duration afterwards.
|
102
|
+
# File.open(expected_file, "w") {|io| io.write(actual)}
|
94
103
|
actual.should == IO.read(expected_file)
|
95
104
|
end
|
96
105
|
|
@@ -98,6 +107,10 @@ Then /^STDERR should match$/ do |text|
|
|
98
107
|
last_stderr.should =~ /#{text}/
|
99
108
|
end
|
100
109
|
|
110
|
+
Then /^STDERR should not match$/ do |text|
|
111
|
+
last_stderr.should_not =~ /#{text}/
|
112
|
+
end
|
113
|
+
|
101
114
|
Then /^STDERR should be empty$/ do
|
102
115
|
last_stderr.should == ""
|
103
116
|
end
|
data/features/support/env.rb
CHANGED
@@ -3,6 +3,11 @@ require 'tempfile'
|
|
3
3
|
require 'spec/expectations'
|
4
4
|
require 'fileutils'
|
5
5
|
require 'forwardable'
|
6
|
+
begin
|
7
|
+
require 'spork'
|
8
|
+
rescue Gem::LoadError => ex
|
9
|
+
warn "WARNING: #{ex.message} You need to have the spork gem installed to run the DRb feature properly!"
|
10
|
+
end
|
6
11
|
|
7
12
|
class CucumberWorld
|
8
13
|
extend Forwardable
|
@@ -52,6 +57,10 @@ class CucumberWorld
|
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
60
|
+
def background_jobs
|
61
|
+
@background_jobs ||= []
|
62
|
+
end
|
63
|
+
|
55
64
|
def in_current_dir(&block)
|
56
65
|
Dir.chdir(@current_dir, &block)
|
57
66
|
end
|
@@ -66,6 +75,27 @@ class CucumberWorld
|
|
66
75
|
@last_stderr = IO.read(stderr_file.path)
|
67
76
|
end
|
68
77
|
|
78
|
+
def run_in_background(command)
|
79
|
+
pid = fork
|
80
|
+
in_current_dir do
|
81
|
+
if pid
|
82
|
+
background_jobs << pid
|
83
|
+
else
|
84
|
+
#STDOUT.close
|
85
|
+
#STDERR.close
|
86
|
+
exec command
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def terminate_background_jobs
|
92
|
+
if @background_jobs
|
93
|
+
@background_jobs.each do |pid|
|
94
|
+
Process.kill(Signal.list['TERM'], pid)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
69
99
|
end
|
70
100
|
|
71
101
|
World do
|
@@ -77,7 +107,11 @@ Before do
|
|
77
107
|
FileUtils.mkdir CucumberWorld.working_dir
|
78
108
|
end
|
79
109
|
|
110
|
+
After do
|
111
|
+
terminate_background_jobs
|
112
|
+
end
|
113
|
+
|
80
114
|
Before('@diffxml') do
|
81
115
|
`diffxml --version`
|
82
116
|
raise "Please install diffxml from http://diffxml.sourceforge.net/" if $? != 0
|
83
|
-
end
|
117
|
+
end
|
data/features/usage.feature
CHANGED
@@ -113,11 +113,11 @@ Feature: Cucumber command line
|
|
113
113
|
Then the multiline string should be # features/background/multiline_args_background.feature:17
|
114
114
|
Then the multiline string should be # features/background/multiline_args_background.feature:27
|
115
115
|
/^passing$/ # features/step_definitions/sample_steps.rb:5
|
116
|
-
Given passing # features/sample.feature:
|
116
|
+
Given passing # features/sample.feature:12
|
117
117
|
/^failing expectation$/ # features/step_definitions/sample_steps.rb:62
|
118
118
|
Given failing expectation # features/failing_expectation.feature:4
|
119
119
|
/^failing$/ # features/step_definitions/sample_steps.rb:8
|
120
|
-
Given failing # features/sample.feature:
|
120
|
+
Given failing # features/sample.feature:18
|
121
121
|
(::) UNUSED (::)
|
122
122
|
/^unused$/ # features/step_definitions/sample_steps.rb:66
|
123
123
|
/^another unused$/ # features/step_definitions/sample_steps.rb:69
|
@@ -23,7 +23,7 @@ module Cucumber
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def accept(visitor)
|
26
|
-
visitor.visit_comment(@comment)
|
26
|
+
visitor.visit_comment(@comment) unless @comment.empty?
|
27
27
|
visitor.visit_background_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
|
28
28
|
visitor.step_mother.before(hook_context)
|
29
29
|
visitor.visit_steps(@step_invocations)
|
data/lib/cucumber/ast/comment.rb
CHANGED
data/lib/cucumber/ast/feature.rb
CHANGED
@@ -4,6 +4,7 @@ module Cucumber
|
|
4
4
|
class Feature
|
5
5
|
attr_accessor :file
|
6
6
|
attr_writer :features
|
7
|
+
attr_reader :name
|
7
8
|
|
8
9
|
def initialize(background, comment, tags, name, feature_elements)
|
9
10
|
@background, @comment, @tags, @name, @feature_elements = background, comment, tags, name, feature_elements
|
@@ -15,7 +16,7 @@ module Cucumber
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def accept(visitor)
|
18
|
-
visitor.visit_comment(@comment)
|
19
|
+
visitor.visit_comment(@comment) unless @comment.empty?
|
19
20
|
visitor.visit_tags(@tags)
|
20
21
|
visitor.visit_feature_name(@name)
|
21
22
|
visitor.visit_background(@background) if @background
|
@@ -70,7 +70,7 @@ module Cucumber
|
|
70
70
|
visitor.step_mother.before_and_after(self) do
|
71
71
|
@step_invocations.each do |step_invocation|
|
72
72
|
step_invocation.invoke(visitor.step_mother, visitor.options)
|
73
|
-
@exception ||= step_invocation.
|
73
|
+
@exception ||= step_invocation.reported_exception
|
74
74
|
end
|
75
75
|
|
76
76
|
@cells.each do |cell|
|
@@ -89,7 +89,7 @@ module Cucumber
|
|
89
89
|
@table.visit_scenario_name(visitor, self)
|
90
90
|
@step_invocations.each do |step_invocation|
|
91
91
|
step_invocation.invoke(visitor.step_mother, visitor.options)
|
92
|
-
@exception ||= step_invocation.
|
92
|
+
@exception ||= step_invocation.reported_exception
|
93
93
|
step_invocation.visit_step_result(visitor)
|
94
94
|
end
|
95
95
|
end
|
@@ -21,7 +21,7 @@ module Cucumber
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def accept(visitor)
|
24
|
-
visitor.visit_comment(@comment)
|
24
|
+
visitor.visit_comment(@comment) unless @comment.empty?
|
25
25
|
visitor.visit_tags(@tags)
|
26
26
|
visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
|
27
27
|
|
@@ -3,6 +3,14 @@ module Cucumber
|
|
3
3
|
class ScenarioOutline
|
4
4
|
include FeatureElement
|
5
5
|
|
6
|
+
module ExamplesArray
|
7
|
+
def accept(visitor)
|
8
|
+
each do |examples|
|
9
|
+
visitor.visit_examples(examples)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
6
14
|
# The +example_sections+ argument must be an Array where each element is another array representing
|
7
15
|
# an Examples section. This array has 3 elements:
|
8
16
|
#
|
@@ -23,20 +31,19 @@ module Cucumber
|
|
23
31
|
examples_table = OutlineTable.new(examples_matrix, self)
|
24
32
|
Examples.new(examples_line, examples_keyword, examples_name, examples_table)
|
25
33
|
end
|
34
|
+
@examples_array.extend(ExamplesArray)
|
26
35
|
|
27
36
|
@background.feature_elements << self if @background
|
28
37
|
end
|
29
38
|
|
30
39
|
def accept(visitor)
|
31
|
-
visitor.visit_comment(@comment)
|
40
|
+
visitor.visit_comment(@comment) unless @comment.empty?
|
32
41
|
visitor.visit_tags(@tags)
|
33
42
|
visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
|
34
43
|
visitor.visit_steps(@steps)
|
35
44
|
|
36
45
|
skip_invoke! if @background && @background.failed?
|
37
|
-
@examples_array
|
38
|
-
visitor.visit_examples(examples)
|
39
|
-
end
|
46
|
+
visitor.visit_examples_array(@examples_array) unless @examples_array.empty?
|
40
47
|
end
|
41
48
|
|
42
49
|
def skip_invoke!
|
@@ -2,7 +2,7 @@ module Cucumber
|
|
2
2
|
module Ast
|
3
3
|
class StepInvocation
|
4
4
|
attr_writer :step_collection, :background
|
5
|
-
attr_reader :name, :matched_cells, :status
|
5
|
+
attr_reader :name, :matched_cells, :status, :reported_exception
|
6
6
|
attr_accessor :exception
|
7
7
|
|
8
8
|
def initialize(step, name, multiline_arg, matched_cells)
|
@@ -24,12 +24,12 @@ module Cucumber
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def visit_step_result(visitor)
|
27
|
-
visitor.visit_step_result(keyword, @step_match, @multiline_arg, @status, @
|
27
|
+
visitor.visit_step_result(keyword, @step_match, @multiline_arg, @status, @reported_exception, source_indent, @background)
|
28
28
|
end
|
29
29
|
|
30
30
|
def invoke(step_mother, options)
|
31
31
|
find_step_match!(step_mother)
|
32
|
-
unless @skip_invoke || options[:dry_run] || exception || @step_collection.exception
|
32
|
+
unless @skip_invoke || options[:dry_run] || @exception || @step_collection.exception
|
33
33
|
@skip_invoke = true
|
34
34
|
begin
|
35
35
|
step_mother.current_world.__cucumber_current_step = self if step_mother.current_world # Nil in Pure Java
|
@@ -37,13 +37,13 @@ module Cucumber
|
|
37
37
|
step_mother.after_step
|
38
38
|
status!(:passed)
|
39
39
|
rescue Pending => e
|
40
|
-
failed(e, false)
|
40
|
+
failed(options, e, false)
|
41
41
|
status!(:pending)
|
42
42
|
rescue Undefined => e
|
43
|
-
failed(e, false)
|
43
|
+
failed(options, e, false)
|
44
44
|
status!(:undefined)
|
45
45
|
rescue Exception => e
|
46
|
-
failed(e, false)
|
46
|
+
failed(options, e, false)
|
47
47
|
status!(:failed)
|
48
48
|
end
|
49
49
|
end
|
@@ -54,21 +54,26 @@ module Cucumber
|
|
54
54
|
begin
|
55
55
|
@step_match = step_mother.step_match(@name)
|
56
56
|
rescue Undefined => e
|
57
|
-
failed(e, true)
|
57
|
+
failed(step_mother.options, e, true)
|
58
58
|
status!(:undefined)
|
59
59
|
@step_match = NoStepMatch.new(@step, @name)
|
60
60
|
rescue Ambiguous => e
|
61
|
-
failed(e, false)
|
61
|
+
failed(step_mother.options, e, false)
|
62
62
|
status!(:failed)
|
63
63
|
@step_match = NoStepMatch.new(@step, @name)
|
64
64
|
end
|
65
65
|
step_mother.step_visited(self)
|
66
66
|
end
|
67
67
|
|
68
|
-
def failed(
|
69
|
-
|
70
|
-
@
|
71
|
-
@exception
|
68
|
+
def failed(options, e, clear_backtrace)
|
69
|
+
e.set_backtrace([]) if clear_backtrace
|
70
|
+
e.backtrace << @step.backtrace_line unless @step.backtrace_line.nil?
|
71
|
+
@exception = e
|
72
|
+
if(options[:strict] || !(Undefined === e) || e.nested?)
|
73
|
+
@reported_exception = e
|
74
|
+
else
|
75
|
+
@reported_exception = nil
|
76
|
+
end
|
72
77
|
end
|
73
78
|
|
74
79
|
def status!(status)
|
data/lib/cucumber/ast/visitor.rb
CHANGED
@@ -13,6 +13,9 @@ module Cucumber
|
|
13
13
|
'junit' => 'Cucumber::Formatter::Junit'
|
14
14
|
}
|
15
15
|
DEFAULT_FORMAT = 'pretty'
|
16
|
+
DRB_FLAG = '--drb'
|
17
|
+
PROFILE_SHORT_FLAG = '-p'
|
18
|
+
PROFILE_LONG_FLAG = '--profile'
|
16
19
|
|
17
20
|
attr_reader :paths
|
18
21
|
attr_reader :options
|
@@ -28,8 +31,10 @@ module Cucumber
|
|
28
31
|
end
|
29
32
|
|
30
33
|
def parse!(args)
|
31
|
-
@args = args
|
32
|
-
|
34
|
+
@args = args.empty? ? args_from_profile('default') : args
|
35
|
+
expand_profiles_into_args
|
36
|
+
return if parse_drb
|
37
|
+
|
33
38
|
@args.extend(::OptionParser::Arguable)
|
34
39
|
|
35
40
|
@args.options do |opts|
|
@@ -100,8 +105,8 @@ module Cucumber
|
|
100
105
|
opts.on("-e", "--exclude PATTERN", "Don't run feature files or require ruby files matching PATTERN") do |v|
|
101
106
|
@options[:excludes] << Regexp.new(v)
|
102
107
|
end
|
103
|
-
opts.on(
|
104
|
-
|
108
|
+
opts.on(PROFILE_SHORT_FLAG, "#{PROFILE_LONG_FLAG} PROFILE", "Pull commandline arguments from cucumber.yml.") do |v|
|
109
|
+
# Processing of this is done previsouly so that the DRb flag can be detected within profiles.
|
105
110
|
end
|
106
111
|
opts.on("-c", "--[no-]color",
|
107
112
|
"Whether or not to use ANSI color in the output. Cucumber decides",
|
@@ -158,6 +163,9 @@ module Cucumber
|
|
158
163
|
opts.on("--no-diff", "Disable diff output on failing expectations.") do
|
159
164
|
@options[:diff_enabled] = false
|
160
165
|
end
|
166
|
+
opts.on(DRB_FLAG, "Run features against a DRb server. (i.e. with the spork gem)") do
|
167
|
+
# Processing of this is done previsouly in order to short circuit args from being lost.
|
168
|
+
end
|
161
169
|
opts.on_tail("--version", "Show version.") do
|
162
170
|
@out_stream.puts VERSION::STRING
|
163
171
|
Kernel.exit
|
@@ -176,7 +184,7 @@ module Cucumber
|
|
176
184
|
raise("You can't use both --strict and --wip") if @options[:strict] && @options[:wip]
|
177
185
|
|
178
186
|
# Whatever is left after option parsing is the FILE arguments
|
179
|
-
@paths += args
|
187
|
+
@paths += @args
|
180
188
|
end
|
181
189
|
|
182
190
|
def verbose?
|
@@ -199,6 +207,10 @@ module Cucumber
|
|
199
207
|
@options[:diff_enabled]
|
200
208
|
end
|
201
209
|
|
210
|
+
def drb?
|
211
|
+
@drb
|
212
|
+
end
|
213
|
+
|
202
214
|
def load_language
|
203
215
|
if Cucumber.language_incomplete?(@options[:lang])
|
204
216
|
list_keywords_and_exit(@options[:lang])
|
@@ -313,7 +325,15 @@ module Cucumber
|
|
313
325
|
downcase
|
314
326
|
end
|
315
327
|
|
316
|
-
def
|
328
|
+
def expand_profiles_into_args
|
329
|
+
while (profile_index = @args.index(PROFILE_SHORT_FLAG) || @args.index(PROFILE_LONG_FLAG)) do
|
330
|
+
@args.delete_at(profile_index)
|
331
|
+
@args[profile_index] = args_from_profile(@args[profile_index])
|
332
|
+
@args.flatten!
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def args_from_profile(profile)
|
317
337
|
unless cucumber_yml.has_key?(profile)
|
318
338
|
raise(<<-END_OF_ERROR)
|
319
339
|
Could not find profile: '#{profile}'
|
@@ -334,7 +354,7 @@ Defined profiles in cucumber.yml:
|
|
334
354
|
else
|
335
355
|
raise "The '#{profile}' profile in cucumber.yml was a #{args_from_yml.class}. It must be a String or Array"
|
336
356
|
end
|
337
|
-
|
357
|
+
args_from_yml
|
338
358
|
end
|
339
359
|
|
340
360
|
def cucumber_yml
|
@@ -346,7 +366,7 @@ Defined profiles in cucumber.yml:
|
|
346
366
|
require 'yaml'
|
347
367
|
begin
|
348
368
|
@cucumber_yml = YAML::load(IO.read('cucumber.yml'))
|
349
|
-
rescue
|
369
|
+
rescue StandardError => e
|
350
370
|
raise(YmlLoadError,"cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentation on correct profile usage.\n")
|
351
371
|
end
|
352
372
|
|
@@ -370,6 +390,10 @@ Defined profiles in cucumber.yml:
|
|
370
390
|
Kernel.exit
|
371
391
|
end
|
372
392
|
|
393
|
+
def parse_drb
|
394
|
+
@drb = @args.delete(DRB_FLAG) ? true : false
|
395
|
+
end
|
396
|
+
|
373
397
|
def default_options
|
374
398
|
{
|
375
399
|
:strict => false,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "drb/drb"
|
2
|
+
# This code was taken from the RSpec project and slightly modified.
|
3
|
+
|
4
|
+
module Cucumber
|
5
|
+
module Cli
|
6
|
+
# Runs features on a DRB server, originally created with Spork compatibility in mind.
|
7
|
+
class DRbClient
|
8
|
+
def self.run(args, error_stream, out_stream)
|
9
|
+
begin
|
10
|
+
# See http://redmine.ruby-lang.org/issues/show/496 as to why we specify localhost:0
|
11
|
+
DRb.start_service("druby://localhost:0")
|
12
|
+
feature_server = DRbObject.new_with_uri("druby://127.0.0.1:8990")
|
13
|
+
feature_server.run(args, error_stream, out_stream)
|
14
|
+
true
|
15
|
+
rescue DRb::DRbConnError
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|