cucumber 2.0.0.beta.2 → 2.0.0.beta.3
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.
- checksums.yaml +4 -4
- data/History.md +25 -7
- data/cucumber.gemspec +1 -1
- data/features/docs/defining_steps/nested_steps.feature +0 -1
- data/features/docs/defining_steps/printing_messages.feature +1 -0
- data/features/docs/defining_steps/table_diffing.feature +9 -4
- data/features/docs/exception_in_after_step_hook.feature +1 -0
- data/features/docs/formatters/json_formatter.feature +51 -4
- data/features/docs/formatters/junit_formatter.feature +1 -0
- data/features/docs/gherkin/outlines.feature +4 -0
- data/features/docs/output_from_hooks.feature +128 -0
- data/features/docs/wire_protocol_table_diffing.feature +6 -2
- data/features/docs/writing_support_code/after_hooks.feature +56 -0
- data/lib/cucumber/cli/configuration.rb +0 -4
- data/lib/cucumber/cli/main.rb +0 -1
- data/lib/cucumber/cli/options.rb +0 -3
- data/lib/cucumber/formatter/console.rb +3 -1
- data/lib/cucumber/formatter/debug.rb +4 -0
- data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +26 -3
- data/lib/cucumber/formatter/html.rb +6 -2
- data/lib/cucumber/formatter/usage.rb +1 -58
- data/lib/cucumber/mappings.rb +25 -7
- data/lib/cucumber/multiline_argument.rb +40 -82
- data/lib/cucumber/multiline_argument/data_table.rb +719 -0
- data/lib/cucumber/multiline_argument/doc_string.rb +10 -0
- data/lib/cucumber/platform.rb +1 -1
- data/lib/cucumber/rb_support/rb_world.rb +2 -4
- data/lib/cucumber/reports/legacy_formatter.rb +69 -22
- data/lib/cucumber/runtime.rb +0 -39
- data/lib/cucumber/runtime/for_programming_languages.rb +12 -10
- data/lib/cucumber/runtime/support_code.rb +11 -4
- data/lib/cucumber/wire_support/wire_protocol/requests.rb +2 -2
- data/spec/cucumber/formatter/pretty_spec.rb +5 -5
- data/spec/cucumber/mappings_spec.rb +137 -8
- data/spec/cucumber/multiline_argument/data_table_spec.rb +508 -0
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +3 -3
- data/spec/cucumber/rb_support/snippet_spec.rb +1 -1
- data/spec/cucumber/runtime/for_programming_languages_spec.rb +16 -12
- metadata +13 -6
- data/lib/cucumber/runtime/features_loader.rb +0 -62
data/lib/cucumber/cli/main.rb
CHANGED
data/lib/cucumber/cli/options.rb
CHANGED
@@ -223,9 +223,6 @@ module Cucumber
|
|
223
223
|
opts.on("-x", "--expand", "Expand Scenario Outline Tables in output.") do
|
224
224
|
@options[:expand] = true
|
225
225
|
end
|
226
|
-
opts.on("--dotcucumber DIR", "Write metadata to DIR") do |dir|
|
227
|
-
@options[:dotcucumber] = dir
|
228
|
-
end
|
229
226
|
opts.on("--order TYPE[:SEED]", "Run examples in the specified order. Available types:",
|
230
227
|
*<<-TEXT.split("\n")) do |order|
|
231
228
|
[defined] Run scenarios in the order they were defined (default).
|
@@ -139,7 +139,9 @@ module Cucumber
|
|
139
139
|
|
140
140
|
unknown_programming_language = runtime.unknown_programming_language?
|
141
141
|
snippets = undefined.map do |step|
|
142
|
-
step_name = Undefined === step.exception ? step.exception.step_name : step.name
|
142
|
+
# step_name = Undefined === step.exception ? step.exception.step_name : step.name
|
143
|
+
# TODO: This probably won't work for nested steps :( See above for old code.
|
144
|
+
step_name = step.name
|
143
145
|
@runtime.snippet_text(step.actual_keyword, step_name, step.multiline_arg)
|
144
146
|
end.compact.uniq
|
145
147
|
|
@@ -10,6 +10,8 @@ module Cucumber
|
|
10
10
|
@gf = gherkin_formatter
|
11
11
|
@print_empty_match = print_empty_match
|
12
12
|
@options = options
|
13
|
+
@delayed_messages = []
|
14
|
+
@delayed_embeddings = []
|
13
15
|
end
|
14
16
|
|
15
17
|
def before_feature(feature)
|
@@ -19,10 +21,12 @@ module Cucumber
|
|
19
21
|
|
20
22
|
def before_background(background)
|
21
23
|
@outline = false
|
24
|
+
@before_steps = true
|
22
25
|
@gf.background(background.gherkin_statement)
|
23
26
|
end
|
24
27
|
|
25
28
|
def before_feature_element(feature_element)
|
29
|
+
@before_steps = true
|
26
30
|
case(feature_element)
|
27
31
|
when Core::Ast::Scenario
|
28
32
|
@outline = false
|
@@ -65,6 +69,8 @@ module Cucumber
|
|
65
69
|
def before_step(step)
|
66
70
|
unless @outline and @options[:expand]
|
67
71
|
@gf.step(step.gherkin_statement)
|
72
|
+
pass_delayed_output
|
73
|
+
@before_steps = false
|
68
74
|
else
|
69
75
|
if @in_instantiated_scenario
|
70
76
|
@current_step_hash = to_hash(step.gherkin_statement)
|
@@ -111,9 +117,11 @@ module Cucumber
|
|
111
117
|
@current_step_hash['comments'],
|
112
118
|
@current_step_hash['keyword'],
|
113
119
|
step_match.format_args(),
|
114
|
-
|
120
|
+
file_colon_line.split(':')[1].to_i,
|
115
121
|
@current_step_hash['rows'],
|
116
122
|
@current_step_hash['doc_string']))
|
123
|
+
pass_delayed_output
|
124
|
+
@before_steps = false
|
117
125
|
@gf.match(@current_match)
|
118
126
|
@gf.result(@current_result)
|
119
127
|
end
|
@@ -159,11 +167,19 @@ module Cucumber
|
|
159
167
|
if defined?(JRUBY_VERSION)
|
160
168
|
data = data.to_java_bytes
|
161
169
|
end
|
162
|
-
@
|
170
|
+
unless @before_steps
|
171
|
+
@gf.embedding(mime_type, data)
|
172
|
+
else
|
173
|
+
@delayed_embeddings.push [mime_type, data]
|
174
|
+
end
|
163
175
|
end
|
164
176
|
|
165
177
|
def puts(message)
|
166
|
-
@
|
178
|
+
unless @before_steps
|
179
|
+
@gf.write(message)
|
180
|
+
else
|
181
|
+
@delayed_messages.push message
|
182
|
+
end
|
167
183
|
end
|
168
184
|
|
169
185
|
private
|
@@ -175,6 +191,13 @@ module Cucumber
|
|
175
191
|
gherkin_statement.to_hash
|
176
192
|
end
|
177
193
|
end
|
194
|
+
|
195
|
+
def pass_delayed_output
|
196
|
+
@delayed_messages.each { |message| @gf.write(message) }
|
197
|
+
@delayed_embeddings.each { |embed_data| @gf.embedding(embed_data[0], embed_data[1]) }
|
198
|
+
@delayed_messages = []
|
199
|
+
@delayed_embeddings = []
|
200
|
+
end
|
178
201
|
end
|
179
202
|
end
|
180
203
|
end
|
@@ -12,7 +12,7 @@ module Cucumber
|
|
12
12
|
Cucumber::Core::Ast::Scenario => 'scenario',
|
13
13
|
Cucumber::Core::Ast::ScenarioOutline => 'scenario outline'
|
14
14
|
}
|
15
|
-
AST_DATA_TABLE = Cucumber::
|
15
|
+
AST_DATA_TABLE = Cucumber::Reports::Legacy::Ast::MultilineArg::DataTable
|
16
16
|
|
17
17
|
include ERB::Util # for the #h method
|
18
18
|
include Duration
|
@@ -618,8 +618,12 @@ module Cucumber
|
|
618
618
|
|
619
619
|
def lines_around(file, line)
|
620
620
|
if File.file?(file)
|
621
|
+
begin
|
621
622
|
lines = File.open(file).read.split("\n")
|
622
|
-
|
623
|
+
rescue ArgumentError
|
624
|
+
return "# Couldn't get snippet for #{file}"
|
625
|
+
end
|
626
|
+
min = [0, line-3].max
|
623
627
|
max = [line+1, lines.length-1].min
|
624
628
|
selected_lines = []
|
625
629
|
selected_lines.join("\n")
|
@@ -21,36 +21,6 @@ module Cucumber
|
|
21
21
|
print_profile_information
|
22
22
|
end
|
23
23
|
|
24
|
-
def before_background(background)
|
25
|
-
@outline = false
|
26
|
-
end
|
27
|
-
|
28
|
-
def before_feature_element(feature_element)
|
29
|
-
case(feature_element)
|
30
|
-
when Core::Ast::Scenario
|
31
|
-
@outline = false
|
32
|
-
when Core::Ast::ScenarioOutline
|
33
|
-
@outline = true
|
34
|
-
if @options[:expand]
|
35
|
-
@in_instantiated_scenario = false
|
36
|
-
end
|
37
|
-
else
|
38
|
-
raise "Bad type: #{feature_element.class}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def scenario_name(keyword, name, file_colon_line, source_indent)
|
43
|
-
if @outline and @in_instantiated_scenario
|
44
|
-
if @new_example_table
|
45
|
-
@example_row = 1
|
46
|
-
@new_example_table = false
|
47
|
-
else
|
48
|
-
@example_row += 1
|
49
|
-
end
|
50
|
-
@example_line = @current_example_rows[@example_row].to_hash['line']
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
24
|
def before_step(step)
|
55
25
|
@step = step
|
56
26
|
@start_time = Time.now
|
@@ -65,30 +35,17 @@ module Cucumber
|
|
65
35
|
unless step_definition.nil? # nil if it's from a scenario outline
|
66
36
|
stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line)
|
67
37
|
|
68
|
-
file_colon_line = @step.file_colon_line
|
69
|
-
if @outline and @in_instantiated_scenario
|
70
|
-
file_colon_line = replace_line_number(@step.file_colon_line, @example_line)
|
71
|
-
end
|
72
|
-
|
73
38
|
@stepdef_to_match[stepdef_key] << {
|
74
39
|
:keyword => keyword,
|
75
40
|
:step_match => step_match,
|
76
41
|
:status => status,
|
77
|
-
:file_colon_line => file_colon_line,
|
42
|
+
:file_colon_line => @step.file_colon_line,
|
78
43
|
:duration => @duration
|
79
44
|
}
|
80
45
|
end
|
81
46
|
super
|
82
47
|
end
|
83
48
|
|
84
|
-
def before_examples(examples)
|
85
|
-
if @options[:expand]
|
86
|
-
@in_instantiated_scenario = true
|
87
|
-
@new_example_table = true
|
88
|
-
@current_example_rows = to_hash(examples.gherkin_statement)['rows']
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
49
|
def print_summary(features)
|
93
50
|
add_unused_stepdefs
|
94
51
|
aggregate_info
|
@@ -176,20 +133,6 @@ module Cucumber
|
|
176
133
|
@stepdef_to_match[stepdef_key] = []
|
177
134
|
end
|
178
135
|
end
|
179
|
-
|
180
|
-
private
|
181
|
-
|
182
|
-
def replace_line_number(file_colon_line, line)
|
183
|
-
file_colon_line.split(':')[0] + ':' + line.to_s
|
184
|
-
end
|
185
|
-
|
186
|
-
def to_hash(gherkin_statement)
|
187
|
-
if defined?(JRUBY_VERSION)
|
188
|
-
gherkin_statement.toMap()
|
189
|
-
else
|
190
|
-
gherkin_statement.to_hash
|
191
|
-
end
|
192
|
-
end
|
193
136
|
end
|
194
137
|
end
|
195
138
|
end
|
data/lib/cucumber/mappings.rb
CHANGED
@@ -68,13 +68,13 @@ module Cucumber
|
|
68
68
|
|
69
69
|
def map_test_case_hooks(mapper)
|
70
70
|
ruby.hooks_for(:before, scenario).each do |hook|
|
71
|
-
mapper.before do
|
72
|
-
hook.invoke('Before', scenario)
|
71
|
+
mapper.before do |result|
|
72
|
+
hook.invoke('Before', scenario.with_result(result))
|
73
73
|
end
|
74
74
|
end
|
75
75
|
ruby.hooks_for(:after, scenario).each do |hook|
|
76
|
-
mapper.after do
|
77
|
-
hook.invoke('After', scenario)
|
76
|
+
mapper.after do |result|
|
77
|
+
hook.invoke('After', scenario.with_result(result))
|
78
78
|
end
|
79
79
|
end
|
80
80
|
ruby.hooks_for(:around, scenario).each do |hook|
|
@@ -86,9 +86,10 @@ module Cucumber
|
|
86
86
|
|
87
87
|
# adapts our test_case to look like the Cucumber Runtime's old Scenario
|
88
88
|
class TestCase
|
89
|
-
def initialize(test_case, feature)
|
89
|
+
def initialize(test_case, feature, result = Core::Test::Result::Unknown.new)
|
90
90
|
@test_case = test_case
|
91
91
|
@feature = feature
|
92
|
+
@result = result
|
92
93
|
end
|
93
94
|
|
94
95
|
def accept_hook?(hook)
|
@@ -96,7 +97,7 @@ module Cucumber
|
|
96
97
|
end
|
97
98
|
|
98
99
|
def failed?
|
99
|
-
|
100
|
+
@result.failed?
|
100
101
|
end
|
101
102
|
|
102
103
|
def language
|
@@ -111,6 +112,11 @@ module Cucumber
|
|
111
112
|
@test_case.name
|
112
113
|
end
|
113
114
|
|
115
|
+
def title
|
116
|
+
warn("deprecated: call #name instead")
|
117
|
+
name
|
118
|
+
end
|
119
|
+
|
114
120
|
def source_tags
|
115
121
|
#warn('deprecated: call #tags instead')
|
116
122
|
tags
|
@@ -123,12 +129,24 @@ module Cucumber
|
|
123
129
|
def tags
|
124
130
|
@test_case.tags
|
125
131
|
end
|
132
|
+
|
133
|
+
def outline?
|
134
|
+
false
|
135
|
+
end
|
136
|
+
|
137
|
+
def with_result(result)
|
138
|
+
self.class.new(@test_case, @feature, result)
|
139
|
+
end
|
126
140
|
end
|
127
141
|
|
128
142
|
class Scenario < TestCase
|
129
143
|
end
|
130
144
|
|
131
145
|
class ScenarioOutlineExample < TestCase
|
146
|
+
def outline?
|
147
|
+
true
|
148
|
+
end
|
149
|
+
|
132
150
|
def scenario_outline
|
133
151
|
self
|
134
152
|
end
|
@@ -204,7 +222,7 @@ module Cucumber
|
|
204
222
|
|
205
223
|
private
|
206
224
|
def map_step(node, step_match)
|
207
|
-
multiline_arg = MultilineArgument.
|
225
|
+
multiline_arg = MultilineArgument.from_core(node.multiline_arg)
|
208
226
|
mapper.map { step_match.invoke(multiline_arg) }
|
209
227
|
end
|
210
228
|
|
@@ -1,104 +1,62 @@
|
|
1
1
|
require 'delegate'
|
2
|
+
require 'cucumber/multiline_argument/data_table'
|
3
|
+
require 'cucumber/multiline_argument/doc_string'
|
4
|
+
require 'gherkin/rubify'
|
5
|
+
|
2
6
|
module Cucumber
|
3
7
|
module MultilineArgument
|
4
|
-
|
5
|
-
Builder.new(core_multiline_arg).result
|
6
|
-
end
|
7
|
-
|
8
|
-
class Builder
|
9
|
-
def initialize(multiline_arg)
|
10
|
-
multiline_arg.describe_to self
|
11
|
-
end
|
8
|
+
extend Gherkin::Rubify
|
12
9
|
|
13
|
-
|
14
|
-
|
10
|
+
class << self
|
11
|
+
def from_core(node)
|
12
|
+
builder.wrap(node)
|
15
13
|
end
|
16
14
|
|
17
|
-
def
|
18
|
-
|
15
|
+
def from(argument, location=nil)
|
16
|
+
location ||= Core::Ast::Location.of_caller
|
17
|
+
argument = rubify(argument)
|
18
|
+
case argument
|
19
|
+
when String
|
20
|
+
doc_string(argument, 'text/plain', location)
|
21
|
+
when Array
|
22
|
+
location = location.on_line(argument.first.line..argument.last.line)
|
23
|
+
data_table(argument.map{ |row| row.cells }, location)
|
24
|
+
when DataTable, DocString, None
|
25
|
+
argument
|
26
|
+
when nil
|
27
|
+
None.new
|
28
|
+
else
|
29
|
+
raise ArgumentError, "Don't know how to convert #{argument.class} #{argument.inspect} into a MultilineArgument"
|
30
|
+
end
|
19
31
|
end
|
20
32
|
|
21
|
-
def
|
22
|
-
|
33
|
+
def doc_string(argument, content_type, location)
|
34
|
+
builder.doc_string(Core::Ast::DocString.new(argument, content_type, location))
|
23
35
|
end
|
24
|
-
end
|
25
36
|
|
26
|
-
|
27
|
-
|
28
|
-
array << self
|
37
|
+
def data_table(data, location)
|
38
|
+
builder.data_table(Core::Ast::DataTable.new(data, location))
|
29
39
|
end
|
30
|
-
end
|
31
40
|
|
32
|
-
|
33
|
-
def append_to(array)
|
34
|
-
array << self
|
35
|
-
end
|
41
|
+
private
|
36
42
|
|
37
|
-
def
|
38
|
-
|
43
|
+
def builder
|
44
|
+
@builder ||= Builder.new
|
39
45
|
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
require_diff_lcs
|
48
|
-
cell_matrix.extend(Diff::LCS)
|
49
|
-
|
50
|
-
changes = cell_matrix.diff(other_table_cell_matrix).flatten
|
51
|
-
|
52
|
-
return if changes.empty?
|
53
|
-
|
54
|
-
inserted = 0
|
55
|
-
missing = 0
|
56
|
-
|
57
|
-
changes.each do |change|
|
58
|
-
if(change.action == '-')
|
59
|
-
missing_row_pos = change.position + inserted
|
60
|
-
cell_matrix[missing_row_pos].each{|cell| cell.status = :undefined}
|
61
|
-
|
62
|
-
missing += 1
|
63
|
-
else # '+'
|
64
|
-
inserted_row = change.element
|
65
|
-
inserted_row.each{|cell| cell.status = :comment}
|
66
|
-
|
67
|
-
insert_row_pos = change.position + missing
|
68
|
-
cell_matrix.insert(insert_row_pos, inserted_row)
|
69
|
-
|
70
|
-
inserted += 1
|
71
|
-
end
|
47
|
+
class Builder
|
48
|
+
def wrap(node)
|
49
|
+
@result = None.new
|
50
|
+
node.describe_to(self)
|
51
|
+
@result
|
72
52
|
end
|
73
53
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
def ensure_green! #:nodoc:
|
78
|
-
each_cell{|cell| cell.status = :passed}
|
79
|
-
end
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def ensure_table(table_or_array) #:nodoc:
|
84
|
-
return table_or_array if DataTable === table_or_array
|
85
|
-
DataTable.new(table_or_array)
|
86
|
-
end
|
87
|
-
|
88
|
-
def require_diff_lcs #:nodoc:
|
89
|
-
begin
|
90
|
-
require 'diff/lcs'
|
91
|
-
rescue LoadError => e
|
92
|
-
e.message << "\n Please gem install diff-lcs\n"
|
93
|
-
raise e
|
54
|
+
def doc_string(node, *args)
|
55
|
+
@result = DocString.new(node)
|
94
56
|
end
|
95
|
-
end
|
96
57
|
|
97
|
-
|
98
|
-
|
99
|
-
def initialize(table)
|
100
|
-
@table = table
|
101
|
-
super("Tables were not identical")
|
58
|
+
def data_table(node, *args)
|
59
|
+
@result = DataTable.new(node)
|
102
60
|
end
|
103
61
|
end
|
104
62
|
end
|