cucumber-core 5.0.2 → 6.0.0

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.
@@ -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?
@@ -3,7 +3,7 @@ module Cucumber
3
3
  module Core
4
4
  class Version
5
5
  def self.to_s
6
- "5.0.2"
6
+ "6.0.0"
7
7
  end
8
8
  end
9
9
  end
@@ -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(:parser) { Parser.new(receiver, event_bus) }
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,6 +96,13 @@ 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
90
106
  end
91
107
 
92
108
  context "when scenario is inside a rule" do
@@ -13,11 +13,12 @@ module Cucumber
13
13
  include Core
14
14
  include Core::Gherkin::Writer
15
15
 
16
+ let(:id) { double }
16
17
  let(:name) { double }
17
18
  let(:location) { double }
18
19
  let(:tags) { double }
19
20
  let(:language) { double }
20
- let(:test_case) { Test::Case.new(name, test_steps, location, tags, language) }
21
+ let(:test_case) { Test::Case.new(id, name, test_steps, location, tags, language) }
21
22
  let(:test_steps) { [double, double] }
22
23
 
23
24
  context 'describing itself' do
@@ -45,7 +46,7 @@ module Cucumber
45
46
  expect( first_hook ).to receive(:describe_to).ordered.and_yield
46
47
  expect( second_hook ).to receive(:describe_to).ordered.and_yield
47
48
  around_hooks = [first_hook, second_hook]
48
- Test::Case.new(name, [], location, tags, language, around_hooks).describe_to(visitor, double)
49
+ Test::Case.new(id, name, [], location, tags, language, around_hooks).describe_to(visitor, double)
49
50
  end
50
51
 
51
52
  end
@@ -6,31 +6,29 @@ module Cucumber
6
6
  module Core
7
7
  module Test
8
8
  describe DataTable do
9
- let(:location) { Test::Location.new('foo.feature', 9..12) }
10
-
11
9
  before do
12
10
  @table = DataTable.new([
13
11
  %w{one four seven},
14
12
  %w{4444 55555 666666}
15
- ], location)
13
+ ])
16
14
  end
17
15
 
18
16
  describe "equality" do
19
17
  it "is equal to another table with the same data" do
20
- expect( DataTable.new([[1,2],[3,4]], location) ).to eq DataTable.new([[1,2],[3,4]], location)
18
+ expect( DataTable.new([[1,2],[3,4]]) ).to eq DataTable.new([[1,2],[3,4]])
21
19
  end
22
20
 
23
21
  it "is not equal to another table with different data" do
24
- expect( DataTable.new([[1,2],[3,4]], location) ).not_to eq DataTable.new([[1,2]], location)
22
+ expect( DataTable.new([[1,2],[3,4]]) ).not_to eq DataTable.new([[1,2]])
25
23
  end
26
24
 
27
25
  it "is not equal to a non table" do
28
- expect( DataTable.new([[1,2],[3,4]], location) ).not_to eq Object.new
26
+ expect( DataTable.new([[1,2],[3,4]]) ).not_to eq Object.new
29
27
  end
30
28
  end
31
29
 
32
30
  describe "#data_table?" do
33
- let(:table) { DataTable.new([[1,2],[3,4]], location) }
31
+ let(:table) { DataTable.new([[1,2],[3,4]]) }
34
32
 
35
33
  it "returns true" do
36
34
  expect(table).to be_data_table
@@ -38,7 +36,7 @@ module Cucumber
38
36
  end
39
37
 
40
38
  describe "#doc_string" do
41
- let(:table) { DataTable.new([[1,2],[3,4]], location) }
39
+ let(:table) { DataTable.new([[1,2],[3,4]]) }
42
40
 
43
41
  it "returns false" do
44
42
  expect(table).not_to be_doc_string
@@ -46,7 +44,7 @@ module Cucumber
46
44
  end
47
45
 
48
46
  describe "#map" do
49
- let(:table) { DataTable.new([ %w{foo bar}, %w{1 2} ], location) }
47
+ let(:table) { DataTable.new([ %w{foo bar}, %w{1 2} ]) }
50
48
 
51
49
  it 'yields the contents of each cell to the block' do
52
50
 
@@ -54,7 +52,7 @@ module Cucumber
54
52
  end
55
53
 
56
54
  it 'returns a new table with the cells modified by the block' do
57
- expect( table.map { |cell| "*#{cell}*" } ).to eq DataTable.new([%w{*foo* *bar*}, %w{*1* *2*}], location)
55
+ expect( table.map { |cell| "*#{cell}*" } ).to eq DataTable.new([%w{*foo* *bar*}, %w{*1* *2*}])
58
56
  end
59
57
  end
60
58
 
@@ -63,14 +61,14 @@ module Cucumber
63
61
  @table = DataTable.new([
64
62
  %w{one 1111},
65
63
  %w{two 22222}
66
- ], location)
64
+ ])
67
65
  end
68
66
 
69
67
  it "should transpose the table" do
70
68
  transposed = DataTable.new([
71
69
  %w{one two},
72
70
  %w{1111 22222}
73
- ], location)
71
+ ])
74
72
  expect( @table.transpose ).to eq( transposed )
75
73
  end
76
74
  end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'cucumber/core/test/location'
3
2
  require 'cucumber/core/test/doc_string'
4
3
  require 'unindent'
5
4
 
@@ -7,11 +6,10 @@ module Cucumber
7
6
  module Core
8
7
  module Test
9
8
  describe DocString do
10
- let(:location) { double }
11
- let(:doc_string) { DocString.new(content, content_type, location) }
9
+ let(:doc_string) { DocString.new(content, content_type) }
12
10
 
13
11
  describe "#data_table?" do
14
- let(:doc_string) { DocString.new("test", "text/plain" , location) }
12
+ let(:doc_string) { DocString.new("test", "text/plain" ) }
15
13
 
16
14
  it "returns false" do
17
15
  expect(doc_string).not_to be_data_table
@@ -19,7 +17,7 @@ module Cucumber
19
17
  end
20
18
 
21
19
  describe "#doc_string" do
22
- let(:doc_string) { DocString.new("test", "text/plain" , location) }
20
+ let(:doc_string) { DocString.new("test", "text/plain" ) }
23
21
 
24
22
  it "returns true" do
25
23
  expect(doc_string).to be_doc_string
@@ -48,15 +46,15 @@ module Cucumber
48
46
  let(:content_type) { 'text/plain' }
49
47
 
50
48
  it 'is equal to another DocString with the same content and content_type' do
51
- expect( doc_string ).to eq DocString.new(content, content_type, location)
49
+ expect( doc_string ).to eq DocString.new(content, content_type)
52
50
  end
53
51
 
54
52
  it 'is not equal to another DocString with different content' do
55
- expect( doc_string ).not_to eq DocString.new('bar', content_type, location)
53
+ expect( doc_string ).not_to eq DocString.new('bar', content_type)
56
54
  end
57
55
 
58
56
  it 'is not equal to another DocString with different content_type' do
59
- expect( doc_string ).not_to eq DocString.new(content, 'text/html', location)
57
+ expect( doc_string ).not_to eq DocString.new(content, 'text/html')
60
58
  end
61
59
 
62
60
  it 'is equal to a string with the same content' do
@@ -96,13 +94,12 @@ module Cucumber
96
94
  end
97
95
 
98
96
  context "inspect" do
99
- let(:location) { Test::Location.new("features/feature.feature", 8) }
100
97
  let(:content_type) { 'text/plain' }
101
98
 
102
99
  it "provides a useful inspect method" do
103
- doc_string = DocString.new("some text", content_type, location)
100
+ doc_string = DocString.new("some text", content_type)
104
101
  expect(doc_string.inspect).to eq <<-END.chomp.unindent
105
- #<Cucumber::Core::Test::DocString (features/feature.feature:8)
102
+ #<Cucumber::Core::Test::DocString
106
103
  """text/plain
107
104
  some text
108
105
  """>
@@ -23,6 +23,11 @@ module Cucumber::Core::Test
23
23
  expect( result.to_s ).to eq "✓"
24
24
  end
25
25
 
26
+ it "converts to a Cucumber::Message::TestResult" do
27
+ message = result.to_message
28
+ expect(message.status).to eq(Cucumber::Messages::TestStepResult::Status::PASSED)
29
+ end
30
+
26
31
  it "has a duration" do
27
32
  expect( result.duration ).to eq duration
28
33
  end
@@ -68,6 +73,11 @@ module Cucumber::Core::Test
68
73
  expect( result.duration ).to eq duration
69
74
  end
70
75
 
76
+ it "converts to a Cucumber::Message::TestResult" do
77
+ message = result.to_message
78
+ expect(message.status).to eq(Cucumber::Messages::TestStepResult::Status::FAILED)
79
+ end
80
+
71
81
  it "requires both constructor arguments" do
72
82
  expect { Result::Failed.new }.to raise_error(ArgumentError)
73
83
  expect { Result::Failed.new(duration) }.to raise_error(ArgumentError)
@@ -131,6 +141,11 @@ module Cucumber::Core::Test
131
141
  specify { expect( result ).to be_unknown }
132
142
  specify { expect( result ).not_to be_skipped }
133
143
  specify { expect( result ).not_to be_flaky }
144
+
145
+ it "converts to a Cucumber::Message::TestResult" do
146
+ message = result.to_message
147
+ expect(message.status).to eq(Cucumber::Messages::TestStepResult::Status::UNKNOWN)
148
+ end
134
149
  end
135
150
 
136
151
  describe Result::Raisable do
@@ -190,6 +205,11 @@ module Cucumber::Core::Test
190
205
  result.describe_to(visitor, args)
191
206
  end
192
207
 
208
+ it "converts to a Cucumber::Message::TestResult" do
209
+ message = result.to_message
210
+ expect(message.status).to eq(Cucumber::Messages::TestStepResult::Status::UNDEFINED)
211
+ end
212
+
193
213
  specify { expect( result.to_sym ).to eq :undefined }
194
214
 
195
215
  specify { expect( result ).not_to be_passed }
@@ -214,6 +234,11 @@ module Cucumber::Core::Test
214
234
  result.describe_to(visitor, args)
215
235
  end
216
236
 
237
+ it "converts to a Cucumber::Message::TestResult" do
238
+ message = result.to_message
239
+ expect(message.status).to eq(Cucumber::Messages::TestStepResult::Status::SKIPPED)
240
+ end
241
+
217
242
  specify { expect( result.to_sym ).to eq :skipped }
218
243
 
219
244
  specify { expect( result ).not_to be_passed }
@@ -236,6 +261,11 @@ module Cucumber::Core::Test
236
261
  result.describe_to(visitor, args)
237
262
  end
238
263
 
264
+ it "converts to a Cucumber::Message::TestResult" do
265
+ message = result.to_message
266
+ expect(message.status).to eq(Cucumber::Messages::TestStepResult::Status::PENDING)
267
+ end
268
+
239
269
  specify { expect( result.to_sym ).to eq :pending }
240
270
 
241
271
  specify { expect( result ).not_to be_passed }
@@ -259,7 +289,7 @@ module Cucumber::Core::Test
259
289
 
260
290
  describe Result::StrictConfiguration do
261
291
  subject(:strict_configuration) { Result::StrictConfiguration.new}
262
-
292
+
263
293
  describe '#set_strict' do
264
294
  context 'no type argument' do
265
295
  it 'sets all result types to the setting argument' do
@@ -7,19 +7,21 @@ require 'cucumber/core/test/duration_matcher'
7
7
  module Cucumber::Core::Test
8
8
  describe Runner do
9
9
 
10
+ let(:step_id) { double }
11
+ let(:test_id) { double }
10
12
  let(:name) { double }
11
13
  let(:location) { double }
12
14
  let(:tags) { double }
13
15
  let(:language) { double }
14
- let(:test_case) { Case.new(name, test_steps, location, tags, language) }
16
+ let(:test_case) { Case.new(test_id, name, test_steps, location, tags, language) }
15
17
  let(:text) { double }
16
18
  let(:runner) { Runner.new(event_bus) }
17
19
  let(:event_bus) { double.as_null_object }
18
- let(:passing) { Step.new(text, location, location).with_action {} }
19
- let(:failing) { Step.new(text, location, location).with_action { raise exception } }
20
- let(:pending) { Step.new(text, location, location).with_action { raise Result::Pending.new("TODO") } }
21
- let(:skipping) { Step.new(text, location, location).with_action { raise Result::Skipped.new } }
22
- let(:undefined) { Step.new(text, location, location) }
20
+ let(:passing) { Step.new(step_id, text, location, location).with_action {} }
21
+ let(:failing) { Step.new(step_id, text, location, location).with_action { raise exception } }
22
+ let(:pending) { Step.new(step_id, text, location, location).with_action { raise Result::Pending.new("TODO") } }
23
+ let(:skipping) { Step.new(step_id, text, location, location).with_action { raise Result::Skipped.new } }
24
+ let(:undefined) { Step.new(step_id, text, location, location) }
23
25
  let(:exception) { StandardError.new('test error') }
24
26
 
25
27
  before do
@@ -223,8 +225,8 @@ module Cucumber::Core::Test
223
225
 
224
226
  context 'with multiple test cases' do
225
227
  context 'when the first test case fails' do
226
- let(:first_test_case) { Case.new(name, [failing], location, tags, language) }
227
- let(:last_test_case) { Case.new(name, [passing], location, tags, language) }
228
+ let(:first_test_case) { Case.new(test_id, name, [failing], location, tags, language) }
229
+ let(:last_test_case) { Case.new(test_id, name, [passing], location, tags, language) }
228
230
  let(:test_cases) { [first_test_case, last_test_case] }
229
231
 
230
232
  it 'reports the results correctly for the following test case' do
@@ -244,9 +246,9 @@ module Cucumber::Core::Test
244
246
  hook_mapping = UnskippableAction.new do |last_result|
245
247
  result_spy = last_result
246
248
  end
247
- after_hook = HookStep.new(text, location, hook_mapping)
248
- failing_step = Step.new(text, location).with_action { fail }
249
- test_case = Case.new(name, [failing_step, after_hook], location, tags, language)
249
+ after_hook = HookStep.new(step_id, text, location, hook_mapping)
250
+ failing_step = Step.new(step_id, text, location).with_action { fail }
251
+ test_case = Case.new(test_id, name, [failing_step, after_hook], location, tags, language)
250
252
  test_case.describe_to runner
251
253
  expect(result_spy).to be_failed
252
254
  end
@@ -256,8 +258,8 @@ module Cucumber::Core::Test
256
258
  context "with around hooks" do
257
259
  it "passes normally when around hooks don't fail" do
258
260
  around_hook = AroundHook.new { |block| block.call }
259
- passing_step = Step.new(text, location, location).with_action {}
260
- test_case = Case.new(name, [passing_step], location, tags, language, [around_hook])
261
+ passing_step = Step.new(step_id, text, location, location).with_action {}
262
+ test_case = Case.new(test_id, name, [passing_step], location, tags, language, [around_hook])
261
263
  expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
262
264
  expect(result).to be_passed
263
265
  end
@@ -266,8 +268,8 @@ module Cucumber::Core::Test
266
268
 
267
269
  it "gets a failed result if the Around hook fails before the test case is run" do
268
270
  around_hook = AroundHook.new { |block| raise exception }
269
- passing_step = Step.new(text, location, location).with_action {}
270
- test_case = Case.new(name, [passing_step], location, tags, language, [around_hook])
271
+ passing_step = Step.new(step_id, text, location, location).with_action {}
272
+ test_case = Case.new(test_id, name, [passing_step], location, tags, language, [around_hook])
271
273
  expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
272
274
  expect(result).to be_failed
273
275
  expect(result.exception).to eq exception
@@ -277,8 +279,8 @@ module Cucumber::Core::Test
277
279
 
278
280
  it "gets a failed result if the Around hook fails after the test case is run" do
279
281
  around_hook = AroundHook.new { |block| block.call; raise exception }
280
- passing_step = Step.new(text, location, location).with_action {}
281
- test_case = Case.new(name, [passing_step], location, tags, language, [around_hook])
282
+ passing_step = Step.new(step_id, text, location, location).with_action {}
283
+ test_case = Case.new(test_id, name, [passing_step], location, tags, language, [around_hook])
282
284
  expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
283
285
  expect(result).to be_failed
284
286
  expect(result.exception).to eq exception
@@ -288,8 +290,8 @@ module Cucumber::Core::Test
288
290
 
289
291
  it "fails when a step fails if the around hook works" do
290
292
  around_hook = AroundHook.new { |block| block.call }
291
- failing_step = Step.new(text, location, location).with_action { raise exception }
292
- test_case = Case.new(name, [failing_step], location, tags, language, [around_hook])
293
+ failing_step = Step.new(step_id, text, location, location).with_action { raise exception }
294
+ test_case = Case.new(test_id, name, [failing_step], location, tags, language, [around_hook])
293
295
  expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
294
296
  expect(result).to be_failed
295
297
  expect(result.exception).to eq exception
@@ -299,8 +301,8 @@ module Cucumber::Core::Test
299
301
 
300
302
  it "sends after_test_step for a step interrupted by (a timeout in) the around hook" do
301
303
  around_hook = AroundHook.new { |block| block.call; raise exception }
302
- passing_step = Step.new(text, location, location).with_action {}
303
- test_case = Case.new(name, [], location, tags, language, [around_hook])
304
+ passing_step = Step.new(step_id, text, location, location).with_action {}
305
+ test_case = Case.new(test_id, name, [], location, tags, language, [around_hook])
304
306
  allow(runner).to receive(:running_test_step).and_return(passing_step)
305
307
  expect(event_bus).to receive(:test_step_finished).with(passing_step, anything) do |reported_test_case, result|
306
308
  expect(result).to be_failed