cucumber-core 5.0.1 → 8.0.1
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/CHANGELOG.md +63 -9
- data/CONTRIBUTING.md +3 -1
- data/README.md +1 -0
- data/lib/cucumber/core.rb +8 -6
- data/lib/cucumber/core/compiler.rb +34 -13
- data/lib/cucumber/core/event.rb +0 -2
- data/lib/cucumber/core/events.rb +25 -0
- data/lib/cucumber/core/gherkin/parser.rb +21 -10
- data/lib/cucumber/core/gherkin/writer.rb +30 -2
- data/lib/cucumber/core/test/case.rb +5 -4
- data/lib/cucumber/core/test/data_table.rb +5 -9
- data/lib/cucumber/core/test/doc_string.rb +3 -6
- data/lib/cucumber/core/test/result.rb +64 -3
- data/lib/cucumber/core/test/step.rb +6 -5
- data/lib/cucumber/core/version.rb +1 -1
- data/spec/coverage.rb +2 -0
- data/spec/cucumber/core/compiler_spec.rb +66 -3
- data/spec/cucumber/core/gherkin/parser_spec.rb +68 -1
- data/spec/cucumber/core/test/case_spec.rb +3 -2
- data/spec/cucumber/core/test/data_table_spec.rb +10 -12
- data/spec/cucumber/core/test/doc_string_spec.rb +8 -11
- data/spec/cucumber/core/test/location_spec.rb +5 -2
- data/spec/cucumber/core/test/result_spec.rb +31 -1
- data/spec/cucumber/core/test/runner_spec.rb +23 -21
- data/spec/cucumber/core/test/step_spec.rb +10 -9
- data/spec/cucumber/core_spec.rb +1 -1
- metadata +58 -40
- data/spec/capture_warnings.rb +0 -74
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'cucumber/core/test/location'
|
3
2
|
|
4
3
|
module Cucumber
|
5
4
|
module Core
|
@@ -24,18 +23,15 @@ module Cucumber
|
|
24
23
|
# This will store <tt>[['a', 'b'], ['c', 'd']]</tt> in the <tt>data</tt> variable.
|
25
24
|
#
|
26
25
|
class DataTable
|
27
|
-
include HasLocation
|
28
|
-
|
29
26
|
# Creates a new instance. +raw+ should be an Array of Array of String
|
30
27
|
# or an Array of Hash
|
31
28
|
# You don't typically create your own DataTable objects - Cucumber will do
|
32
29
|
# it internally and pass them to your Step Definitions.
|
33
30
|
#
|
34
|
-
def initialize(rows
|
31
|
+
def initialize(rows)
|
35
32
|
raw = ensure_array_of_array(rows)
|
36
33
|
verify_rows_are_same_length(raw)
|
37
34
|
@raw = raw.freeze
|
38
|
-
@location = location
|
39
35
|
end
|
40
36
|
attr_reader :raw
|
41
37
|
|
@@ -58,7 +54,7 @@ module Cucumber
|
|
58
54
|
# Creates a copy of this table
|
59
55
|
#
|
60
56
|
def dup
|
61
|
-
self.class.new(raw.dup
|
57
|
+
self.class.new(raw.dup)
|
62
58
|
end
|
63
59
|
|
64
60
|
# Returns a new, transposed table. Example:
|
@@ -73,7 +69,7 @@ module Cucumber
|
|
73
69
|
# | 4 | 2 |
|
74
70
|
#
|
75
71
|
def transpose
|
76
|
-
self.class.new(raw.transpose
|
72
|
+
self.class.new(raw.transpose)
|
77
73
|
end
|
78
74
|
|
79
75
|
def map(&block)
|
@@ -81,7 +77,7 @@ module Cucumber
|
|
81
77
|
row.map(&block)
|
82
78
|
end
|
83
79
|
|
84
|
-
self.class.new(new_raw
|
80
|
+
self.class.new(new_raw)
|
85
81
|
end
|
86
82
|
|
87
83
|
def ==(other)
|
@@ -89,7 +85,7 @@ module Cucumber
|
|
89
85
|
end
|
90
86
|
|
91
87
|
def inspect
|
92
|
-
%{#<#{self.class} #{raw.inspect}
|
88
|
+
%{#<#{self.class} #{raw.inspect})>}
|
93
89
|
end
|
94
90
|
|
95
91
|
private
|
@@ -20,14 +20,11 @@ module Cucumber
|
|
20
20
|
# Note how the indentation from the source is stripped away.
|
21
21
|
#
|
22
22
|
class DocString < SimpleDelegator
|
23
|
-
include HasLocation
|
24
|
-
|
25
23
|
attr_reader :content_type, :content
|
26
24
|
|
27
|
-
def initialize(content, content_type
|
25
|
+
def initialize(content, content_type)
|
28
26
|
@content = content
|
29
27
|
@content_type = content_type
|
30
|
-
@location = location
|
31
28
|
super @content
|
32
29
|
end
|
33
30
|
|
@@ -46,7 +43,7 @@ module Cucumber
|
|
46
43
|
def map
|
47
44
|
raise ArgumentError, "No block given" unless block_given?
|
48
45
|
new_content = yield content
|
49
|
-
self.class.new(new_content, content_type
|
46
|
+
self.class.new(new_content, content_type)
|
50
47
|
end
|
51
48
|
|
52
49
|
def to_step_definition_arg
|
@@ -65,7 +62,7 @@ module Cucumber
|
|
65
62
|
|
66
63
|
def inspect
|
67
64
|
[
|
68
|
-
%{#<#{self.class}
|
65
|
+
%{#<#{self.class}},
|
69
66
|
%{ """#{content_type}},
|
70
67
|
%{ #{@content}},
|
71
68
|
%{ """>}
|
@@ -9,7 +9,6 @@ module Cucumber
|
|
9
9
|
STRICT_AFFECTED_TYPES = [:flaky, :undefined, :pending].freeze
|
10
10
|
|
11
11
|
def self.ok?(type, be_strict = StrictConfiguration.new)
|
12
|
-
private
|
13
12
|
class_name = type.to_s.slice(0, 1).capitalize + type.to_s.slice(1..-1)
|
14
13
|
const_get(class_name).ok?(be_strict.strict?(type))
|
15
14
|
end
|
@@ -43,6 +42,13 @@ module Cucumber
|
|
43
42
|
def with_filtered_backtrace(filter)
|
44
43
|
self
|
45
44
|
end
|
45
|
+
|
46
|
+
def to_message
|
47
|
+
Cucumber::Messages::TestStepFinished::TestStepResult.new(
|
48
|
+
status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::UNKNOWN,
|
49
|
+
duration: UnknownDuration.new.to_message_duration
|
50
|
+
)
|
51
|
+
end
|
46
52
|
end
|
47
53
|
|
48
54
|
class Passed
|
@@ -68,6 +74,13 @@ module Cucumber
|
|
68
74
|
"✓"
|
69
75
|
end
|
70
76
|
|
77
|
+
def to_message
|
78
|
+
Cucumber::Messages::TestStepFinished::TestStepResult.new(
|
79
|
+
status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::PASSED,
|
80
|
+
duration: duration.to_message_duration
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
71
84
|
def ok?(be_strict = nil)
|
72
85
|
self.class.ok?
|
73
86
|
end
|
@@ -83,6 +96,7 @@ module Cucumber
|
|
83
96
|
|
84
97
|
class Failed
|
85
98
|
include Result.query_methods :failed
|
99
|
+
|
86
100
|
attr_reader :duration, :exception
|
87
101
|
|
88
102
|
def self.ok?(be_strict = false)
|
@@ -107,6 +121,20 @@ module Cucumber
|
|
107
121
|
"✗"
|
108
122
|
end
|
109
123
|
|
124
|
+
def to_message
|
125
|
+
begin
|
126
|
+
message = exception.backtrace.join("\n")
|
127
|
+
rescue NoMethodError
|
128
|
+
message = ""
|
129
|
+
end
|
130
|
+
|
131
|
+
Cucumber::Messages::TestStepFinished::TestStepResult.new(
|
132
|
+
status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::FAILED,
|
133
|
+
duration: duration.to_message_duration,
|
134
|
+
message: message
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
110
138
|
def ok?(be_strict = nil)
|
111
139
|
self.class.ok?
|
112
140
|
end
|
@@ -186,6 +214,13 @@ module Cucumber
|
|
186
214
|
def to_s
|
187
215
|
"?"
|
188
216
|
end
|
217
|
+
|
218
|
+
def to_message
|
219
|
+
Cucumber::Messages::TestStepFinished::TestStepResult.new(
|
220
|
+
status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::UNDEFINED,
|
221
|
+
duration: duration.to_message_duration
|
222
|
+
)
|
223
|
+
end
|
189
224
|
end
|
190
225
|
|
191
226
|
class Skipped < Raisable
|
@@ -204,6 +239,13 @@ module Cucumber
|
|
204
239
|
def to_s
|
205
240
|
"-"
|
206
241
|
end
|
242
|
+
|
243
|
+
def to_message
|
244
|
+
Cucumber::Messages::TestStepFinished::TestStepResult.new(
|
245
|
+
status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::SKIPPED,
|
246
|
+
duration: duration.to_message_duration
|
247
|
+
)
|
248
|
+
end
|
207
249
|
end
|
208
250
|
|
209
251
|
class Pending < Raisable
|
@@ -222,6 +264,13 @@ module Cucumber
|
|
222
264
|
def to_s
|
223
265
|
"P"
|
224
266
|
end
|
267
|
+
|
268
|
+
def to_message
|
269
|
+
Cucumber::Messages::TestStepFinished::TestStepResult.new(
|
270
|
+
status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::PENDING,
|
271
|
+
duration: duration.to_message_duration
|
272
|
+
)
|
273
|
+
end
|
225
274
|
end
|
226
275
|
|
227
276
|
# Handles the strict settings for the result types that are
|
@@ -229,7 +278,7 @@ module Cucumber
|
|
229
278
|
class StrictConfiguration
|
230
279
|
attr_accessor :settings
|
231
280
|
private :settings
|
232
|
-
|
281
|
+
|
233
282
|
def initialize(strict_types = [])
|
234
283
|
@settings = Hash[STRICT_AFFECTED_TYPES.map { |t| [t, :default] }]
|
235
284
|
strict_types.each do |type|
|
@@ -329,7 +378,7 @@ module Cucumber
|
|
329
378
|
def decrement_failed
|
330
379
|
@totals[:failed] -= 1
|
331
380
|
end
|
332
|
-
|
381
|
+
|
333
382
|
private
|
334
383
|
|
335
384
|
def get_total(method_name)
|
@@ -344,14 +393,22 @@ module Cucumber
|
|
344
393
|
end
|
345
394
|
|
346
395
|
class Duration
|
396
|
+
include Cucumber::Messages::TimeConversion
|
397
|
+
|
347
398
|
attr_reader :nanoseconds
|
348
399
|
|
349
400
|
def initialize(nanoseconds)
|
350
401
|
@nanoseconds = nanoseconds
|
351
402
|
end
|
403
|
+
|
404
|
+
def to_message_duration
|
405
|
+
seconds_to_duration(nanoseconds.to_f / NANOSECONDS_PER_SECOND)
|
406
|
+
end
|
352
407
|
end
|
353
408
|
|
354
409
|
class UnknownDuration
|
410
|
+
include Cucumber::Messages::TimeConversion
|
411
|
+
|
355
412
|
def tap(&block)
|
356
413
|
self
|
357
414
|
end
|
@@ -359,6 +416,10 @@ module Cucumber
|
|
359
416
|
def nanoseconds
|
360
417
|
raise "#nanoseconds only allowed to be used in #tap block"
|
361
418
|
end
|
419
|
+
|
420
|
+
def to_message_duration
|
421
|
+
seconds_to_duration(0)
|
422
|
+
end
|
362
423
|
end
|
363
424
|
end
|
364
425
|
end
|
@@ -8,10 +8,11 @@ module Cucumber
|
|
8
8
|
module Core
|
9
9
|
module Test
|
10
10
|
class Step
|
11
|
-
attr_reader :text, :location, :multiline_arg
|
11
|
+
attr_reader :id, :text, :location, :multiline_arg
|
12
12
|
|
13
|
-
def initialize(text, location, multiline_arg = Test::EmptyMultilineArgument.new, action = Test::UndefinedAction.new(location))
|
13
|
+
def initialize(id, text, location, multiline_arg = Test::EmptyMultilineArgument.new, action = Test::UndefinedAction.new(location))
|
14
14
|
raise ArgumentError if text.nil? || text.empty?
|
15
|
+
@id = id
|
15
16
|
@text = text
|
16
17
|
@location = location
|
17
18
|
@multiline_arg = multiline_arg
|
@@ -35,7 +36,7 @@ module Cucumber
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def with_action(action_location = nil, &block)
|
38
|
-
self.class.new(text, location, multiline_arg, Test::Action.new(action_location, &block))
|
39
|
+
self.class.new(id, text, location, multiline_arg, Test::Action.new(action_location, &block))
|
39
40
|
end
|
40
41
|
|
41
42
|
def backtrace_line
|
@@ -56,8 +57,8 @@ module Cucumber
|
|
56
57
|
end
|
57
58
|
|
58
59
|
class HookStep < Step
|
59
|
-
def initialize(text, location, action)
|
60
|
-
super(text, location, Test::EmptyMultilineArgument.new, action)
|
60
|
+
def initialize(id, text, location, action)
|
61
|
+
super(id, text, location, Test::EmptyMultilineArgument.new, action)
|
61
62
|
end
|
62
63
|
|
63
64
|
def hook?
|
data/spec/coverage.rb
CHANGED
@@ -31,6 +31,60 @@ module Cucumber::Core
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
context "when the event_bus is provided" do
|
35
|
+
let(:event_bus) { double }
|
36
|
+
|
37
|
+
before do
|
38
|
+
allow( event_bus ).to receive(:envelope)
|
39
|
+
allow( event_bus ).to receive(:gherkin_source_parsed).and_return(nil)
|
40
|
+
allow( event_bus ).to receive(:test_case_created).and_return(nil)
|
41
|
+
allow( event_bus ).to receive(:test_step_created).and_return(nil)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "emits a TestCaseCreated event with the created Test::Case and Pickle" do
|
45
|
+
gherkin_documents = [
|
46
|
+
gherkin do
|
47
|
+
feature do
|
48
|
+
scenario do
|
49
|
+
step 'passing'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
]
|
54
|
+
|
55
|
+
compile(gherkin_documents, event_bus) do | visitor |
|
56
|
+
allow( visitor ).to receive(:test_case)
|
57
|
+
allow( visitor ).to receive(:test_step)
|
58
|
+
allow( visitor ).to receive(:done)
|
59
|
+
allow( event_bus ).to receive(:envelope)
|
60
|
+
|
61
|
+
expect( event_bus ).to receive(:test_case_created).once
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "emits a TestStepCreated event with the created Test::Step and PickleStep" do
|
66
|
+
gherkin_documents = [
|
67
|
+
gherkin do
|
68
|
+
feature do
|
69
|
+
scenario do
|
70
|
+
step 'passing'
|
71
|
+
step 'passing'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
]
|
76
|
+
|
77
|
+
compile(gherkin_documents, event_bus) do |visitor|
|
78
|
+
allow( visitor ).to receive(:test_case)
|
79
|
+
allow( visitor ).to receive(:test_step)
|
80
|
+
allow( visitor ).to receive(:done)
|
81
|
+
allow( event_bus ).to receive(:envelope)
|
82
|
+
|
83
|
+
expect( event_bus ).to receive(:test_step_created).twice
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
34
88
|
it "compiles a feature with a background" do
|
35
89
|
gherkin_documents = [
|
36
90
|
gherkin do
|
@@ -166,13 +220,22 @@ module Cucumber::Core
|
|
166
220
|
end
|
167
221
|
end
|
168
222
|
|
169
|
-
def compile(gherkin_documents)
|
223
|
+
def compile(gherkin_documents, event_bus = nil)
|
170
224
|
visitor = double
|
171
225
|
allow( visitor ).to receive(:test_suite).and_yield(visitor)
|
172
226
|
allow( visitor ).to receive(:test_case).and_yield(visitor)
|
227
|
+
|
228
|
+
if event_bus.nil?
|
229
|
+
event_bus = double
|
230
|
+
allow( event_bus ).to receive(:envelope).and_return(nil)
|
231
|
+
allow( event_bus ).to receive(:gherkin_source_parsed).and_return(nil)
|
232
|
+
allow( event_bus ).to receive(:test_case_created).and_return(nil)
|
233
|
+
allow( event_bus ).to receive(:test_step_created).and_return(nil)
|
234
|
+
allow( event_bus ).to receive(:envelope).and_return(nil)
|
235
|
+
end
|
236
|
+
|
173
237
|
yield visitor
|
174
|
-
super(gherkin_documents, visitor)
|
238
|
+
super(gherkin_documents, visitor, [], event_bus)
|
175
239
|
end
|
176
|
-
|
177
240
|
end
|
178
241
|
end
|
@@ -9,11 +9,14 @@ module Cucumber
|
|
9
9
|
describe Parser do
|
10
10
|
let(:receiver) { double }
|
11
11
|
let(:event_bus) { double }
|
12
|
-
let(:
|
12
|
+
let(:gherkin_query) { double }
|
13
|
+
let(:parser) { Parser.new(receiver, event_bus, gherkin_query) }
|
13
14
|
let(:visitor) { double }
|
14
15
|
|
15
16
|
before do
|
16
17
|
allow( event_bus ).to receive(:gherkin_source_parsed)
|
18
|
+
allow( event_bus).to receive(:envelope)
|
19
|
+
allow( gherkin_query ).to receive(:update)
|
17
20
|
end
|
18
21
|
|
19
22
|
def parse
|
@@ -40,6 +43,12 @@ module Cucumber
|
|
40
43
|
expect( event_bus ).to receive(:gherkin_source_parsed)
|
41
44
|
parse
|
42
45
|
end
|
46
|
+
|
47
|
+
it "emits an 'envelope' event for every message produced by Gherkin" do
|
48
|
+
# Only one message emited, there's no pickles generated
|
49
|
+
expect( event_bus ).to receive(:envelope).once
|
50
|
+
parse
|
51
|
+
end
|
43
52
|
end
|
44
53
|
|
45
54
|
context "for empty files" do
|
@@ -87,8 +96,66 @@ module Cucumber
|
|
87
96
|
expect( receiver ).to receive(:pickle)
|
88
97
|
parse
|
89
98
|
end
|
99
|
+
|
100
|
+
it "emits an 'envelope' event containing the pickle" do
|
101
|
+
allow( receiver ).to receive(:pickle)
|
102
|
+
# Once for the gherkin document, once with the pickle
|
103
|
+
expect( event_bus ).to receive(:envelope).twice
|
104
|
+
parse
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when scenario is inside a rule" do
|
109
|
+
source do
|
110
|
+
feature do
|
111
|
+
rule do
|
112
|
+
scenario name: "My scenario"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it "passes on the pickle" do
|
118
|
+
expect( receiver ).to receive(:pickle)
|
119
|
+
parse
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when example is inside a rule" do
|
124
|
+
source do
|
125
|
+
feature do
|
126
|
+
rule do
|
127
|
+
example name: "My example"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it "passes on the pickle" do
|
133
|
+
expect( receiver ).to receive(:pickle)
|
134
|
+
parse
|
135
|
+
end
|
90
136
|
end
|
91
137
|
|
138
|
+
context "when there are multiple rules and scenarios or examples" do
|
139
|
+
source do
|
140
|
+
feature do
|
141
|
+
rule description: "First rule" do
|
142
|
+
scenario name: "Do not talk about the fight club" do
|
143
|
+
step 'text'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
rule description: "Second rule"do
|
147
|
+
example name: "Do not talk about the fight club" do
|
148
|
+
step 'text'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it "passes on the pickles" do
|
155
|
+
expect( receiver ).to receive(:pickle).twice
|
156
|
+
parse
|
157
|
+
end
|
158
|
+
end
|
92
159
|
end
|
93
160
|
end
|
94
161
|
end
|