cucumber-core 5.0.2 → 9.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +73 -0
  3. data/CONTRIBUTING.md +3 -3
  4. data/README.md +0 -2
  5. data/lib/cucumber/core.rb +8 -6
  6. data/lib/cucumber/core/compiler.rb +35 -14
  7. data/lib/cucumber/core/event.rb +3 -5
  8. data/lib/cucumber/core/event_bus.rb +1 -1
  9. data/lib/cucumber/core/events.rb +25 -1
  10. data/lib/cucumber/core/gherkin/parser.rb +10 -8
  11. data/lib/cucumber/core/gherkin/writer.rb +15 -5
  12. data/lib/cucumber/core/gherkin/writer/helpers.rb +2 -2
  13. data/lib/cucumber/core/test/action.rb +1 -2
  14. data/lib/cucumber/core/test/case.rb +5 -4
  15. data/lib/cucumber/core/test/data_table.rb +6 -10
  16. data/lib/cucumber/core/test/doc_string.rb +3 -6
  17. data/lib/cucumber/core/test/filters/activate_steps_for_self_test.rb +0 -1
  18. data/lib/cucumber/core/test/result.rb +68 -7
  19. data/lib/cucumber/core/test/step.rb +6 -5
  20. data/lib/cucumber/core/test/timer.rb +2 -2
  21. data/lib/cucumber/core/version.rb +1 -1
  22. data/spec/coverage.rb +1 -0
  23. data/spec/cucumber/core/compiler_spec.rb +66 -3
  24. data/spec/cucumber/core/event_bus_spec.rb +2 -2
  25. data/spec/cucumber/core/event_spec.rb +3 -3
  26. data/spec/cucumber/core/filter_spec.rb +2 -2
  27. data/spec/cucumber/core/gherkin/parser_spec.rb +18 -2
  28. data/spec/cucumber/core/gherkin/writer_spec.rb +0 -1
  29. data/spec/cucumber/core/test/action_spec.rb +1 -2
  30. data/spec/cucumber/core/test/case_spec.rb +3 -2
  31. data/spec/cucumber/core/test/data_table_spec.rb +10 -12
  32. data/spec/cucumber/core/test/doc_string_spec.rb +8 -11
  33. data/spec/cucumber/core/test/location_spec.rb +7 -7
  34. data/spec/cucumber/core/test/result_spec.rb +41 -11
  35. data/spec/cucumber/core/test/runner_spec.rb +23 -21
  36. data/spec/cucumber/core/test/step_spec.rb +10 -9
  37. data/spec/cucumber/core_spec.rb +2 -2
  38. metadata +91 -53
  39. data/spec/capture_warnings.rb +0 -74
@@ -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
@@ -3,6 +3,7 @@ require 'cucumber/core/test/step'
3
3
 
4
4
  module Cucumber::Core::Test
5
5
  describe Step do
6
+ let(:id) { 'some-random-uid' }
6
7
  let(:text) { 'step text' }
7
8
  let(:location) { double }
8
9
 
@@ -10,7 +11,7 @@ module Cucumber::Core::Test
10
11
  it "describes itself to a visitor" do
11
12
  visitor = double
12
13
  args = double
13
- test_step = Step.new(text, location)
14
+ test_step = Step.new(id, text, location)
14
15
  expect( visitor ).to receive(:test_step).with(test_step, args)
15
16
  test_step.describe_to(visitor, args)
16
17
  end
@@ -19,7 +20,7 @@ module Cucumber::Core::Test
19
20
  describe "backtrace line" do
20
21
  let(:text) { 'this step passes' }
21
22
  let(:location) { Location.new('path/file.feature', 10) }
22
- let(:test_step) { Step.new(text, location) }
23
+ let(:test_step) { Step.new(id, text, location) }
23
24
 
24
25
  it "knows how to form the backtrace line" do
25
26
  expect( test_step.backtrace_line ).to eq("path/file.feature:10:in `this step passes'")
@@ -30,7 +31,7 @@ module Cucumber::Core::Test
30
31
  it "passes arbitrary arguments to the action's block" do
31
32
  args_spy = nil
32
33
  expected_args = [double, double]
33
- test_step = Step.new(text, location).with_action do |*actual_args|
34
+ test_step = Step.new(id, text, location).with_action do |*actual_args|
34
35
  args_spy = actual_args
35
36
  end
36
37
  test_step.execute(*expected_args)
@@ -39,7 +40,7 @@ module Cucumber::Core::Test
39
40
 
40
41
  context "when a passing action exists" do
41
42
  it "returns a passing result" do
42
- test_step = Step.new(text, location).with_action {}
43
+ test_step = Step.new(id, text, location).with_action {}
43
44
  expect( test_step.execute ).to be_passed
44
45
  end
45
46
  end
@@ -48,7 +49,7 @@ module Cucumber::Core::Test
48
49
  let(:exception) { StandardError.new('oops') }
49
50
 
50
51
  it "returns a failing result" do
51
- test_step = Step.new(text, location).with_action { raise exception }
52
+ test_step = Step.new(id, text, location).with_action { raise exception }
52
53
  result = test_step.execute
53
54
  expect( result ).to be_failed
54
55
  expect( result.exception ).to eq exception
@@ -57,7 +58,7 @@ module Cucumber::Core::Test
57
58
 
58
59
  context "with no action" do
59
60
  it "returns an Undefined result" do
60
- test_step = Step.new(text, location)
61
+ test_step = Step.new(id, text, location)
61
62
  result = test_step.execute
62
63
  expect( result ).to be_undefined
63
64
  end
@@ -65,7 +66,7 @@ module Cucumber::Core::Test
65
66
  end
66
67
 
67
68
  it "exposes the text and location of as attributes" do
68
- test_step = Step.new(text, location)
69
+ test_step = Step.new(id, text, location)
69
70
  expect( test_step.text ).to eq text
70
71
  expect( test_step.location ).to eq location
71
72
  end
@@ -73,13 +74,13 @@ module Cucumber::Core::Test
73
74
  it "exposes the location of the action as attribute" do
74
75
  location = double
75
76
  action = double(location: location)
76
- test_step = Step.new(text, location, action)
77
+ test_step = Step.new(id, text, location, action)
77
78
  expect( test_step.action_location ).to eq location
78
79
  end
79
80
 
80
81
  it "returns the text when converted to a string" do
81
82
  text = 'a passing step'
82
- test_step = Step.new(text, location)
83
+ test_step = Step.new(id, text, location)
83
84
  expect( test_step.to_s ).to eq 'a passing step'
84
85
  end
85
86
 
@@ -62,7 +62,7 @@ module Cucumber
62
62
  scenario_outline 'foo' do
63
63
  step '<arg>'
64
64
 
65
- examples tags: '@a'do
65
+ examples tags: '@a' do
66
66
  row 'arg'
67
67
  row 'x'
68
68
  end
@@ -170,7 +170,7 @@ module Cucumber
170
170
  context "with around hooks" do
171
171
  class WithAroundHooks < Core::Filter.new(:logger)
172
172
  def test_case(test_case)
173
- base_step = Core::Test::Step.new('text', nil, nil, nil)
173
+ base_step = Core::Test::Step.new('some-random-uid', 'text', nil, nil, nil)
174
174
  test_steps = [
175
175
  base_step.with_action { logger << :step },
176
176
  ]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.2
4
+ version: 9.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aslak Hellesøy
@@ -12,68 +12,68 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2019-10-31 00:00:00.000000000 Z
15
+ date: 2021-04-07 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
- name: gherkin
18
+ name: cucumber-gherkin
19
19
  requirement: !ruby/object:Gem::Requirement
20
20
  requirements:
21
21
  - - "~>"
22
22
  - !ruby/object:Gem::Version
23
- version: '8.1'
23
+ version: '18.1'
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 8.1.1
26
+ version: 18.1.0
27
27
  type: :runtime
28
28
  prerelease: false
29
29
  version_requirements: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '8.1'
33
+ version: '18.1'
34
34
  - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: 8.1.1
36
+ version: 18.1.0
37
37
  - !ruby/object:Gem::Dependency
38
- name: cucumber-tag_expressions
38
+ name: cucumber-messages
39
39
  requirement: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - "~>"
42
42
  - !ruby/object:Gem::Version
43
- version: '2.0'
43
+ version: '15.0'
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 2.0.2
46
+ version: 15.0.0
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '2.0'
53
+ version: '15.0'
54
54
  - - ">="
55
55
  - !ruby/object:Gem::Version
56
- version: 2.0.2
56
+ version: 15.0.0
57
57
  - !ruby/object:Gem::Dependency
58
- name: backports
58
+ name: cucumber-tag-expressions
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: 3.15.0
64
61
  - - "~>"
65
62
  - !ruby/object:Gem::Version
66
- version: '3.15'
63
+ version: '3.0'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 3.0.1
67
67
  type: :runtime
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 3.15.0
74
71
  - - "~>"
75
72
  - !ruby/object:Gem::Version
76
- version: '3.15'
73
+ version: '3.0'
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 3.0.1
77
77
  - !ruby/object:Gem::Dependency
78
78
  name: coveralls
79
79
  requirement: !ruby/object:Gem::Requirement
@@ -100,58 +100,98 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '12.3'
103
+ version: '13.0'
104
104
  - - ">="
105
105
  - !ruby/object:Gem::Version
106
- version: 12.3.3
106
+ version: 13.0.3
107
107
  type: :development
108
108
  prerelease: false
109
109
  version_requirements: !ruby/object:Gem::Requirement
110
110
  requirements:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
- version: '12.3'
113
+ version: '13.0'
114
114
  - - ">="
115
115
  - !ruby/object:Gem::Version
116
- version: 12.3.3
116
+ version: 13.0.3
117
117
  - !ruby/object:Gem::Dependency
118
118
  name: rspec
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.10'
121
124
  - - ">="
122
125
  - !ruby/object:Gem::Version
123
- version: 3.8.0
126
+ version: 3.10.0
127
+ type: :development
128
+ prerelease: false
129
+ version_requirements: !ruby/object:Gem::Requirement
130
+ requirements:
124
131
  - - "~>"
125
132
  - !ruby/object:Gem::Version
126
- version: '3.8'
133
+ version: '3.10'
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 3.10.0
137
+ - !ruby/object:Gem::Dependency
138
+ name: rubocop
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '1.12'
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: 1.12.1
127
147
  type: :development
128
148
  prerelease: false
129
149
  version_requirements: !ruby/object:Gem::Requirement
130
150
  requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '1.12'
131
154
  - - ">="
132
155
  - !ruby/object:Gem::Version
133
- version: 3.8.0
156
+ version: 1.12.1
157
+ - !ruby/object:Gem::Dependency
158
+ name: rubocop-packaging
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
134
161
  - - "~>"
135
162
  - !ruby/object:Gem::Version
136
- version: '3.8'
163
+ version: '0.5'
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: 0.5.1
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.5'
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: 0.5.1
137
177
  - !ruby/object:Gem::Dependency
138
178
  name: unindent
139
179
  requirement: !ruby/object:Gem::Requirement
140
180
  requirements:
141
- - - ">="
181
+ - - "~>"
142
182
  - !ruby/object:Gem::Version
143
183
  version: '1.0'
144
- - - "~>"
184
+ - - ">="
145
185
  - !ruby/object:Gem::Version
146
186
  version: '1.0'
147
187
  type: :development
148
188
  prerelease: false
149
189
  version_requirements: !ruby/object:Gem::Requirement
150
190
  requirements:
151
- - - ">="
191
+ - - "~>"
152
192
  - !ruby/object:Gem::Version
153
193
  version: '1.0'
154
- - - "~>"
194
+ - - ">="
155
195
  - !ruby/object:Gem::Version
156
196
  version: '1.0'
157
197
  description: Core library for the Cucumber BDD app
@@ -194,7 +234,6 @@ files:
194
234
  - lib/cucumber/core/test/tag.rb
195
235
  - lib/cucumber/core/test/timer.rb
196
236
  - lib/cucumber/core/version.rb
197
- - spec/capture_warnings.rb
198
237
  - spec/coverage.rb
199
238
  - spec/cucumber/core/compiler_spec.rb
200
239
  - spec/cucumber/core/event_bus_spec.rb
@@ -242,31 +281,30 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
281
  - !ruby/object:Gem::Version
243
282
  version: '0'
244
283
  requirements: []
245
- rubygems_version: 3.0.3
284
+ rubygems_version: 3.1.2
246
285
  signing_key:
247
286
  specification_version: 4
248
- summary: cucumber-core-5.0.2
287
+ summary: cucumber-core-9.0.0
249
288
  test_files:
250
- - spec/cucumber/core/test/runner_spec.rb
289
+ - spec/coverage.rb
290
+ - spec/cucumber/core/compiler_spec.rb
291
+ - spec/cucumber/core/event_bus_spec.rb
292
+ - spec/cucumber/core/event_spec.rb
293
+ - spec/cucumber/core/filter_spec.rb
294
+ - spec/cucumber/core/gherkin/parser_spec.rb
295
+ - spec/cucumber/core/gherkin/writer_spec.rb
296
+ - spec/cucumber/core/report/summary_spec.rb
297
+ - spec/cucumber/core/test/action_spec.rb
298
+ - spec/cucumber/core/test/case_spec.rb
299
+ - spec/cucumber/core/test/data_table_spec.rb
251
300
  - spec/cucumber/core/test/doc_string_spec.rb
252
- - spec/cucumber/core/test/filters/locations_filter_spec.rb
253
- - spec/cucumber/core/test/step_spec.rb
254
301
  - spec/cucumber/core/test/duration_matcher.rb
255
- - spec/cucumber/core/test/case_spec.rb
256
- - spec/cucumber/core/test/result_spec.rb
302
+ - spec/cucumber/core/test/empty_multiline_argument_spec.rb
303
+ - spec/cucumber/core/test/filters/locations_filter_spec.rb
257
304
  - spec/cucumber/core/test/location_spec.rb
258
- - spec/cucumber/core/test/action_spec.rb
305
+ - spec/cucumber/core/test/result_spec.rb
306
+ - spec/cucumber/core/test/runner_spec.rb
307
+ - spec/cucumber/core/test/step_spec.rb
259
308
  - spec/cucumber/core/test/timer_spec.rb
260
- - spec/cucumber/core/test/data_table_spec.rb
261
- - spec/cucumber/core/test/empty_multiline_argument_spec.rb
262
- - spec/cucumber/core/gherkin/parser_spec.rb
263
- - spec/cucumber/core/gherkin/writer_spec.rb
264
- - spec/cucumber/core/event_spec.rb
265
- - spec/cucumber/core/report/summary_spec.rb
266
- - spec/cucumber/core/compiler_spec.rb
267
- - spec/cucumber/core/event_bus_spec.rb
268
- - spec/cucumber/core/filter_spec.rb
269
309
  - spec/cucumber/core_spec.rb
270
- - spec/capture_warnings.rb
271
- - spec/coverage.rb
272
310
  - spec/report_api_spy.rb