rspec-tracer 0.8.0 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 675be2bd6603501deb282508ea234808f0bbdf60c2b626611919f84c32bb4ba9
4
- data.tar.gz: 591be21b4e97c50f33385111ac758665a97e83ca82e154cd3b86d32133f7ef52
3
+ metadata.gz: 1df1d0c90323ae123f24629f74f654bce0fff93bba8e8b052388d582dfb64d8f
4
+ data.tar.gz: 5caabede1fb71ffcbbd70f0e9bfe8ca355303e843dbb99cacf14f146149afe5a
5
5
  SHA512:
6
- metadata.gz: 1ab8ca453da65dd7185fa4869633d9b9ab85fb5c73cfb45929928a492d58d0e16d24e3bcef2466ceae4408c7e1ad2e5ab3f10137061ab684b1decf885809607d
7
- data.tar.gz: 8dc1d3078f2c16c8ee5142c03d05222dd0bd458c979bca0a35ee1b1e44fead38ed2c1a6d84795a93f2a4d7a15c58da40562f4dae360f22e65f1518fc0ddecf75
6
+ metadata.gz: 5ad9ec360d867ed745039fc2cf2a4aef314912a5b6a596c8c79e9d6615b00f2b578f5d3a164c2725ed710d9b0aa055855c607eebe52f7b032d1b959d483cb079
7
+ data.tar.gz: 347236ad3e59372ff1cf33aa3c812ae5a22911ff6b46bfdfced44b96ef80161c4da0798a9afecf96846bc44963713bac4aa625c714266431b975c3152ebd92b1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.9.0] - 2021-09-15
2
+
3
+ ### Added
4
+
5
+ - Handling all examples filtered by RSpec (#34)
6
+ - Warn on incorrect analysis to stop using RSpec Tracer (#35)
7
+ - Run `SimpleCov.at_exit` hook (#36)
8
+
1
9
  ## [0.8.0] - 2021-09-13
2
10
 
3
11
  ### Fixed
data/README.md CHANGED
@@ -40,6 +40,7 @@ describing the **intention** and implementation details of **managing dependency
40
40
  * [Advanced Configuration](#advanced-configuration)
41
41
  * [Filters](#filters)
42
42
  * [Environment Variables](#environment-variables)
43
+ * [When Should You Not Use RSpec Tracer](#when-should-you-not-use-rspec-tracer)
43
44
 
44
45
  ## Demo
45
46
 
@@ -93,7 +94,7 @@ These reports provide information on the total number of tests that will run aft
93
94
 
94
95
  1. Add this line to your `Gemfile` and `bundle install`:
95
96
  ```ruby
96
- gem 'rspec-tracer', '~> 0.7', group: :test, require: false
97
+ gem 'rspec-tracer', '~> 0.9', group: :test, require: false
97
98
  ```
98
99
 
99
100
  And, add the followings to your `.gitignore`:
@@ -124,10 +125,8 @@ any of the application code.**
124
125
  RSpecTracer.start
125
126
  ```
126
127
 
127
- Currently using RSpec Tracer with SimpleCov has the following two limitations:
128
-
129
- - SimpleCov **won't be able to provide branch coverage report** even when enabled.
130
- - RSpec Tracer **nullifies the `SimpleCov.at_exit`** callback.
128
+ If you use RSpec Tracer with SimpleCov, then **SimpleCov would not report branch
129
+ coverage results even when enabled**.
131
130
 
132
131
  3. After running your tests, open `rspec_tracer_report/index.html` in the browser
133
132
  of your choice.
@@ -257,52 +256,48 @@ end
257
256
  ### Defining Custom Filteres
258
257
 
259
258
  You can currently define a filter using either a String or Regexp (that will then
260
- be Regexp-matched against each source file's path), a block or by passing in your
261
- own Filter class.
262
-
263
- #### String Filter
264
-
265
- ```ruby
266
- RSpecTracer.start do
267
- add_filter '/helpers/'
268
- end
269
- ```
270
-
271
- This simple string filter will remove all files that match "/helpers/" in their path.
259
+ be Regexp-matched against each source file's name relative to the project root),
260
+ a block or by passing in your own Filter class.
272
261
 
273
- #### Regex Filter
274
-
275
- ```ruby
276
- RSpecTracer.start do
277
- add_filter %r{^/helpers/}
278
- end
279
- ```
280
-
281
- This simple regex filter will remove all files that start with /helper/ in their path.
282
-
283
- #### Block Filter
262
+ - **String Filter**: The string filter matches files that have the given string
263
+ in their name. For example, the following string filter will remove all files that
264
+ have `"/helpers/"` in their name.
265
+ ```ruby
266
+ RSpecTracer.start do
267
+ add_filter '/helpers/'
268
+ end
269
+ ```
284
270
 
285
- ```ruby
286
- RSpecTracer.start do
287
- add_filter do |source_file|
288
- source_file[:file_path].include?('/helpers/')
271
+ - **Regex Filter**: The regex filter removes all files that have a successful name
272
+ match against the given regex expression. This simple regex filter will remove
273
+ all files that start with `%r{^/helper/}` in their name:
274
+ ```ruby
275
+ RSpecTracer.start do
276
+ add_filter %r{^/helpers/}
289
277
  end
290
- end
291
- ```
278
+ ```
292
279
 
293
- Block filters receive a `Hash` object and expect your block to return either true
294
- (if the file is to be removed from the result) or false (if the result should be kept).
295
- In the above example, the filter will remove all files that match "/helpers/" in their path.
280
+ - **Block Filter**: Block filters receive a `Hash` object and expect your block
281
+ to return either **true** (if the file is to be removed from the result) or **false**
282
+ (if the result should be kept). In the below example, the filter will remove all
283
+ files that match `"/helpers/"` in their path.
284
+ ```ruby
285
+ RSpecTracer.start do
286
+ add_filter do |source_file|
287
+ source_file[:file_path].include?('/helpers/')
288
+ end
289
+ end
290
+ ```
296
291
 
297
- #### Array Filter
292
+ You can also use `source_file[:name]` to define the return value of the block
293
+ filter for the given source file.
298
294
 
299
- ```ruby
300
- RSpecTracer.start do
301
- add_filter ['/helpers/', %r{^/utils/}]
302
- end
303
- ```
304
-
305
- You can pass in an array containing any of the other filter types.
295
+ - **Array Filter**: You can pass in an array containing any of the other filter types:
296
+ ```ruby
297
+ RSpecTracer.start do
298
+ add_filter ['/helpers/', %r{^/utils/}]
299
+ end
300
+ ```
306
301
 
307
302
  ## Environment Variables
308
303
 
@@ -340,6 +335,122 @@ specific test suites and not merge them.
340
335
  TEST_SUITE_ID=2 bundle exec rspec spec/helpers
341
336
  ```
342
337
 
338
+ ## When Should You Not Use RSpec Tracer
339
+
340
+ To uniquely identify the examples is one of the requirements for the correctness
341
+ of the RSpec Tracer. Sometimes, it would not be possible to do so depending upon
342
+ how we have written the specs. The following attributes determine the uniqueness:
343
+
344
+ - The example group
345
+ - The example full description
346
+ - The spec file location, i.e., file name and line number
347
+ - All the shared examples and contexts
348
+
349
+ Consider the following `Calculator` module:
350
+ ```ruby
351
+ module Calculator
352
+ module_function
353
+
354
+ def add(a, b) a + b; end
355
+ def sub(a, b) a - b; end
356
+ def mul(a, b) a * b; end
357
+ end
358
+ ```
359
+
360
+ And the corresponding spec file `spec/calculator_spec.rb`:
361
+ ```ruby
362
+ RSpec.describe Calculator do
363
+ describe '#add' do
364
+ [
365
+ [1, 2, 3],
366
+ [0, 0, 0],
367
+ [5, 32, 37],
368
+ [-1, -8, -9],
369
+ [10, -10, 0]
370
+ ].each { |a, b, r| it { expect(described_class.add(a, b)).to eq(r) } }
371
+ end
372
+
373
+ describe '#sub' do
374
+ [
375
+ [1, 2, -1],
376
+ [10, 0, 10],
377
+ [37, 5, 32],
378
+ [-1, -8, 7],
379
+ [10, 10, 0]
380
+ ].each do |a, b, r|
381
+ it 'performs subtraction' do
382
+ expect(described_class.sub(a, b)).to eq(r)
383
+ end
384
+ end
385
+ end
386
+
387
+ describe '#mul' do
388
+ [
389
+ [1, 2, -2],
390
+ [10, 0, 0],
391
+ [5, 7, 35],
392
+ [-1, -8, 8],
393
+ [10, 10, 100]
394
+ ].each do |a, b, r|
395
+ it "multiplies #{a} and #{b} to #{r}" do
396
+ expect(described_class.mul(a, b)).to eq(r)
397
+ end
398
+ end
399
+ end
400
+ end
401
+ ```
402
+
403
+ Running the spec with `bundle exec rspec spec/calculator_spec.rb` generates the
404
+ following output:
405
+ ```
406
+ Calculator
407
+ #mul
408
+ multiplies 5 and 7 to 35
409
+ multiplies 10 and 10 to 100
410
+ multiplies 10 and 0 to 0
411
+ multiplies 1 and 2 to -2 (FAILED - 1)
412
+ multiplies -1 and -8 to 8
413
+ #add
414
+ example at ./spec/calculator_spec.rb:13
415
+ example at ./spec/calculator_spec.rb:13
416
+ example at ./spec/calculator_spec.rb:13
417
+ example at ./spec/calculator_spec.rb:13
418
+ example at ./spec/calculator_spec.rb:13
419
+ #sub
420
+ performs subtraction
421
+ performs subtraction
422
+ performs subtraction
423
+ performs subtraction
424
+ performs subtraction
425
+ ```
426
+
427
+ In this scenario, RSpec Tracer cannot determine the `Calculator#add` and
428
+ `Calculator#sub` group examples. Also, it will ask you not to use the gem unless
429
+ you have made some changes to your spec files.
430
+
431
+ ```
432
+ ================================================================================
433
+ IMPORTANT NOTICE -- DO NOT USE RSPEC TRACER
434
+ ================================================================================
435
+ It would be best to make changes so that the RSpec tracer can uniquely
436
+ identify all the examples, and then you can enable the RSpec tracer back.
437
+ ================================================================================
438
+
439
+ RSpec tracer could not uniquely identify the following 10 examples:
440
+ - Example ID: eabd51a899db4f64d5839afe96004f03 (5 examples)
441
+ * Calculator#add (spec/calculator_spec.rb:13)
442
+ * Calculator#add (spec/calculator_spec.rb:13)
443
+ * Calculator#add (spec/calculator_spec.rb:13)
444
+ * Calculator#add (spec/calculator_spec.rb:13)
445
+ * Calculator#add (spec/calculator_spec.rb:13)
446
+ - Example ID: 72171b502c5a42b9aa133f165cf09ec2 (5 examples)
447
+ * Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
448
+ * Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
449
+ * Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
450
+ * Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
451
+ * Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
452
+ ```
453
+
343
454
  ## Contributing
344
455
 
345
456
  Read the [contribution guide](https://github.com/avmnu-sng/rspec-tracer/blob/main/.github/CONTRIBUTING.md).
@@ -15,6 +15,7 @@ module RSpecTracer
15
15
 
16
16
  def register_example(example)
17
17
  @all_examples[example[:example_id]] = example
18
+ @duplicate_examples[example[:example_id]] << example
18
19
  end
19
20
 
20
21
  def on_example_skipped(example_id)
@@ -106,6 +107,17 @@ module RSpecTracer
106
107
  file_deleted?(file_name) || file_modified?(file_name)
107
108
  end
108
109
 
110
+ def incorrect_analysis?
111
+ @duplicate_examples.select! { |_, examples| examples.count > 1 }
112
+
113
+ return false if @duplicate_examples.empty?
114
+
115
+ print_not_use_notice
116
+ print_duplicate_examples
117
+
118
+ true
119
+ end
120
+
109
121
  def register_dependency(example_id, file_name)
110
122
  @dependency[example_id] << file_name
111
123
  end
@@ -169,6 +181,7 @@ module RSpecTracer
169
181
 
170
182
  def initialize_examples
171
183
  @all_examples = {}
184
+ @duplicate_examples = Hash.new { |examples, example_id| examples[example_id] = [] }
172
185
  @passed_examples = Set.new
173
186
  @possibly_flaky_examples = Set.new
174
187
  @flaky_examples = Set.new
@@ -226,6 +239,45 @@ module RSpecTracer
226
239
  @reverse_dependency = report.to_h
227
240
  end
228
241
 
242
+ def print_not_use_notice
243
+ justify = ' ' * 4
244
+ four_justify = justify * 4
245
+
246
+ puts '=' * 80
247
+ puts "#{four_justify}IMPORTANT NOTICE -- DO NOT USE RSPEC TRACER"
248
+ puts '=' * 80
249
+ puts "#{justify}It would be best to make changes so that the RSpec tracer can uniquely"
250
+ puts "#{justify}identify all the examples, and then you can enable the RSpec tracer back."
251
+ puts '=' * 80
252
+ puts
253
+ end
254
+
255
+ # rubocop:disable Metrics/AbcSize
256
+ def print_duplicate_examples
257
+ total = @duplicate_examples.sum { |_, examples| examples.length }
258
+
259
+ puts "RSpec tracer could not uniquely identify the following #{total} examples:"
260
+
261
+ justify = ' ' * 2
262
+ nested_justify = justify * 3
263
+
264
+ @duplicate_examples.each_pair do |example_id, examples|
265
+ puts "#{justify}- Example ID: #{example_id} (#{examples.count} examples)"
266
+
267
+ examples.each do |example|
268
+ description = example[:full_description].strip
269
+ file_name = example[:rerun_file_name].sub(%r{^/}, '')
270
+ line_number = example[:rerun_line_number]
271
+ location = "#{file_name}:#{line_number}"
272
+
273
+ puts "#{nested_justify}* #{description} (#{location})"
274
+ end
275
+ end
276
+
277
+ puts
278
+ end
279
+ # rubocop:enable Metrics/AbcSize
280
+
229
281
  def write_all_examples_report
230
282
  file_name = File.join(@cache_dir, 'all_examples.json')
231
283
 
@@ -3,13 +3,23 @@
3
3
  module RSpecTracer
4
4
  module RSpecRunner
5
5
  # rubocop:disable Metrics/AbcSize
6
- def run_specs(_example_groups)
6
+ def run_specs(example_groups)
7
7
  actual_count = RSpec.world.example_count
8
+ RSpecTracer.no_examples = actual_count.zero?
9
+
10
+ if RSpecTracer.no_examples
11
+ RSpecTracer.running = true
12
+
13
+ super(example_groups)
14
+
15
+ return
16
+ end
17
+
8
18
  starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
9
- filtered_examples, example_groups = RSpecTracer.filter_examples
19
+ filtered_examples, filtered_example_groups = RSpecTracer.filter_examples
10
20
 
11
21
  RSpec.world.instance_variable_set(:@filtered_examples, filtered_examples)
12
- RSpec.world.instance_variable_set(:@example_groups, example_groups)
22
+ RSpec.world.instance_variable_set(:@example_groups, filtered_example_groups)
13
23
 
14
24
  current_count = RSpec.world.example_count
15
25
  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@@ -23,7 +33,7 @@ module RSpecTracer
23
33
 
24
34
  RSpecTracer.running = true
25
35
 
26
- super(example_groups)
36
+ super(filtered_example_groups)
27
37
  end
28
38
  # rubocop:enable Metrics/AbcSize
29
39
  end
@@ -63,6 +63,10 @@ module RSpecTracer
63
63
  @reporter.register_deleted_examples(@cache.all_examples)
64
64
  end
65
65
 
66
+ def incorrect_analysis?
67
+ @reporter.incorrect_analysis?
68
+ end
69
+
66
70
  # rubocop:disable Metrics/AbcSize
67
71
  def generate_missed_coverage
68
72
  missed_coverage = Hash.new do |files_coverage, file_path|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpecTracer
4
- VERSION = '0.8.0'
4
+ VERSION = '0.9.0'
5
5
  end
data/lib/rspec_tracer.rb CHANGED
@@ -28,7 +28,7 @@ require_relative 'rspec_tracer/version'
28
28
 
29
29
  module RSpecTracer
30
30
  class << self
31
- attr_accessor :running, :pid
31
+ attr_accessor :running, :pid, :no_examples
32
32
 
33
33
  def start(&block)
34
34
  RSpecTracer.running = false
@@ -74,7 +74,11 @@ module RSpecTracer
74
74
  def at_exit_behavior
75
75
  return unless RSpecTracer.pid == Process.pid && RSpecTracer.running
76
76
 
77
+ ::Kernel.exit(1) if runner.incorrect_analysis?
78
+
77
79
  run_exit_tasks
80
+ ensure
81
+ RSpecTracer.running = false
78
82
  end
79
83
 
80
84
  def start_example_trace
@@ -154,15 +158,11 @@ module RSpecTracer
154
158
  def setup_coverage
155
159
  @simplecov = defined?(SimpleCov) && SimpleCov.running
156
160
 
157
- if simplecov?
158
- # rubocop:disable Lint/EmptyBlock
159
- SimpleCov.at_exit {}
160
- # rubocop:enable Lint/EmptyBlock
161
- else
162
- require 'coverage'
161
+ return if simplecov?
163
162
 
164
- ::Coverage.start
165
- end
163
+ require 'coverage'
164
+
165
+ ::Coverage.start
166
166
  end
167
167
 
168
168
  def setup_trace_point
@@ -175,11 +175,13 @@ module RSpecTracer
175
175
  end
176
176
 
177
177
  def run_exit_tasks
178
- generate_reports
178
+ if RSpecTracer.no_examples
179
+ puts 'Skipped reports generation since all examples were filtered out'
180
+ else
181
+ generate_reports
182
+ end
179
183
 
180
184
  simplecov? ? run_simplecov_exit_task : run_coverage_exit_task
181
- ensure
182
- RSpecTracer.running = false
183
185
  end
184
186
 
185
187
  def generate_reports
@@ -224,12 +226,13 @@ module RSpecTracer
224
226
 
225
227
  puts 'SimpleCov will now generate coverage report (<3 RSpec tracer)'
226
228
 
227
- SimpleCov.result.format!
229
+ coverage_reporter.record_coverage if RSpecTracer.no_examples
228
230
  end
229
231
 
230
232
  def run_coverage_exit_task
231
233
  starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
232
234
 
235
+ coverage_reporter.record_coverage if RSpecTracer.no_examples
233
236
  coverage_reporter.generate_final_coverage
234
237
 
235
238
  file_name = File.join(RSpecTracer.coverage_path, 'coverage.json')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abhimanyu Singh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-13 00:00:00.000000000 Z
11
+ date: 2021-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile
@@ -50,9 +50,11 @@ dependencies:
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
52
  version: 3.6.0
53
- description: RSpec Tracer is a specs dependency analysis tool and a test skipper for
54
- RSpec. It maintains a list of files for each test, enabling itself to skip tests
55
- in the subsequent runs if none of the dependent files are changed.
53
+ description: RSpec Tracer is a specs dependency analyzer, flaky tests detector, tests
54
+ accelerator, and coverage reporter tool for RSpec. It maintains a list of files
55
+ for each test, enabling itself to skip tests in the subsequent runs if none of the
56
+ dependent files are changed. It uses Ruby's built-in coverage library to keep track
57
+ of the coverage for each test
56
58
  email:
57
59
  - abhisinghabhimanyu@gmail.com
58
60
  executables: []
@@ -111,7 +113,7 @@ licenses:
111
113
  - MIT
112
114
  metadata:
113
115
  homepage_uri: https://github.com/avmnu-sng/rspec-tracer
114
- source_code_uri: https://github.com/avmnu-sng/rspec-tracer/tree/v0.8.0
116
+ source_code_uri: https://github.com/avmnu-sng/rspec-tracer/tree/v0.9.0
115
117
  changelog_uri: https://github.com/avmnu-sng/rspec-tracer/blob/main/CHANGELOG.md
116
118
  bug_tracker_uri: https://github.com/avmnu-sng/rspec-tracer/issues
117
119
  post_install_message:
@@ -132,5 +134,6 @@ requirements: []
132
134
  rubygems_version: 3.2.26
133
135
  signing_key:
134
136
  specification_version: 4
135
- summary: RSpec Tracer is a specs dependency analysis tool and a test skipper for RSpec
137
+ summary: RSpec Tracer is a specs dependency analyzer, flaky tests detector, tests
138
+ accelerator, and coverage reporter tool.
136
139
  test_files: []