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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +156 -45
- data/lib/rspec_tracer/reporter.rb +52 -0
- data/lib/rspec_tracer/rspec_runner.rb +14 -4
- data/lib/rspec_tracer/runner.rb +4 -0
- data/lib/rspec_tracer/version.rb +1 -1
- data/lib/rspec_tracer.rb +16 -13
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1df1d0c90323ae123f24629f74f654bce0fff93bba8e8b052388d582dfb64d8f
|
4
|
+
data.tar.gz: 5caabede1fb71ffcbbd70f0e9bfe8ca355303e843dbb99cacf14f146149afe5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ad9ec360d867ed745039fc2cf2a4aef314912a5b6a596c8c79e9d6615b00f2b578f5d3a164c2725ed710d9b0aa055855c607eebe52f7b032d1b959d483cb079
|
7
|
+
data.tar.gz: 347236ad3e59372ff1cf33aa3c812ae5a22911ff6b46bfdfced44b96ef80161c4da0798a9afecf96846bc44963713bac4aa625c714266431b975c3152ebd92b1
|
data/CHANGELOG.md
CHANGED
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.
|
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
|
-
|
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
|
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
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
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
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
291
|
-
```
|
278
|
+
```
|
292
279
|
|
293
|
-
Block filters receive a `Hash` object and expect your block
|
294
|
-
(if the file is to be removed from the result) or false
|
295
|
-
In the
|
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
|
-
|
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
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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(
|
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,
|
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,
|
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(
|
36
|
+
super(filtered_example_groups)
|
27
37
|
end
|
28
38
|
# rubocop:enable Metrics/AbcSize
|
29
39
|
end
|
data/lib/rspec_tracer/runner.rb
CHANGED
@@ -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|
|
data/lib/rspec_tracer/version.rb
CHANGED
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
|
-
|
165
|
-
|
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
|
-
|
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
|
-
|
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.
|
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-
|
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
|
54
|
-
RSpec. It maintains a list of files
|
55
|
-
in the subsequent runs if none of the
|
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.
|
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
|
137
|
+
summary: RSpec Tracer is a specs dependency analyzer, flaky tests detector, tests
|
138
|
+
accelerator, and coverage reporter tool.
|
136
139
|
test_files: []
|