rspec_telemetry 0.3.0 → 0.4.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 +17 -1
- data/README.md +6 -0
- data/lib/rspec_telemetry/compare_cli.rb +56 -34
- data/lib/rspec_telemetry/console_report.rb +4 -5
- data/lib/rspec_telemetry/factory_comparison.rb +50 -23
- data/lib/rspec_telemetry/formatting.rb +26 -0
- data/lib/rspec_telemetry/recorder.rb +2 -1
- data/lib/rspec_telemetry/summary.rb +7 -10
- data/lib/rspec_telemetry/version.rb +1 -1
- data/lib/rspec_telemetry.rb +7 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5c0f4a3e6ec69cd97b7aa3c4a5160d354339e30cdd0f9954dee2866674fdef68
|
|
4
|
+
data.tar.gz: f5ceb63cd260c16f06fb9b51e6ce843c89f141b9f9ae2ae246cc559e0d41022e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1070d3497148bcaf1241ce4b30228c3b6089327194b93c52ec94aff5ccd720af11dc6c10d9fda5d4e9dd868298861aff712345c8104d1d0f3af7a26db9cb3c0c
|
|
7
|
+
data.tar.gz: ee999d564466cac64f328b95503f1e3161fbd850b1badff30691b99d48baae5e357491b64a0dfb84c134b92a3abff4e5990c6e2b5f5d601c4670adfce7286c9a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.4.0] - 2026-06-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `rspec-telemetry-compare --by-factory` to combine strategies (create/build)
|
|
9
|
+
and compare by factory name only. Works together with `--all-depths`.
|
|
10
|
+
- `rspec-telemetry-compare` now prints a `TOTAL` row summing all factories.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- `rspec-telemetry-compare` now reuses `FactoryAggregation` and keys rows by
|
|
14
|
+
`factory:strategy`, so create and build of the same factory are compared
|
|
15
|
+
separately.
|
|
16
|
+
|
|
3
17
|
## [0.3.0] - 2026-06-25
|
|
4
18
|
|
|
5
19
|
### Added
|
|
@@ -30,6 +44,8 @@
|
|
|
30
44
|
|
|
31
45
|
First public release.
|
|
32
46
|
|
|
33
|
-
[Unreleased]: https://github.com/takahashim/rspec_telemetry/compare/v0.
|
|
47
|
+
[Unreleased]: https://github.com/takahashim/rspec_telemetry/compare/v0.4.0...HEAD
|
|
48
|
+
[0.4.0]: https://github.com/takahashim/rspec_telemetry/compare/v0.3.0...v0.4.0
|
|
49
|
+
[0.3.0]: https://github.com/takahashim/rspec_telemetry/compare/v0.2.0...v0.3.0
|
|
34
50
|
[0.2.0]: https://github.com/takahashim/rspec_telemetry/compare/v0.1.0...v0.2.0
|
|
35
51
|
[0.1.0]: https://github.com/takahashim/rspec_telemetry/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -120,6 +120,10 @@ $ bundle exec rspec-telemetry-compare \
|
|
|
120
120
|
tmp/rspec_telemetry.after.ndjson
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
+
Factories are grouped by `factory:strategy`, so `user:create` and `user:build`
|
|
124
|
+
are compared separately. Use `--by-factory` to combine strategies and compare by
|
|
125
|
+
factory name only (e.g. one `user` row).
|
|
126
|
+
|
|
123
127
|
By default, only root factory events (`depth == 0`) are counted, and their
|
|
124
128
|
inclusive `duration_ms` is compared.
|
|
125
129
|
|
|
@@ -131,6 +135,8 @@ counting while showing the actual number and cost of associated factories.
|
|
|
131
135
|
rspec-telemetry-compare --sort count BEFORE AFTER
|
|
132
136
|
rspec-telemetry-compare --sort factory BEFORE AFTER
|
|
133
137
|
rspec-telemetry-compare --all-depths BEFORE AFTER
|
|
138
|
+
rspec-telemetry-compare --by-factory BEFORE AFTER # combine create/build
|
|
139
|
+
rspec-telemetry-compare --all-depths --by-factory BEFORE AFTER
|
|
134
140
|
```
|
|
135
141
|
|
|
136
142
|
## TUI viewer: `rspec-telemetry-viewer`
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "optparse"
|
|
4
4
|
|
|
5
5
|
require_relative "factory_comparison"
|
|
6
|
+
require_relative "formatting"
|
|
6
7
|
|
|
7
8
|
module RSpecTelemetry
|
|
8
9
|
class CompareCLI
|
|
@@ -10,7 +11,7 @@ module RSpecTelemetry
|
|
|
10
11
|
@argv = argv
|
|
11
12
|
@out = out
|
|
12
13
|
@err = err
|
|
13
|
-
@options = {all_depths: false, sort: "duration"}
|
|
14
|
+
@options = {all_depths: false, by_factory: false, sort: "duration"}
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def run
|
|
@@ -20,9 +21,13 @@ module RSpecTelemetry
|
|
|
20
21
|
return 1
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
comparison = FactoryComparison.new(
|
|
24
|
+
comparison = FactoryComparison.new(
|
|
25
|
+
paths[0], paths[1],
|
|
26
|
+
all_depths: @options[:all_depths],
|
|
27
|
+
by_factory: @options[:by_factory]
|
|
28
|
+
)
|
|
24
29
|
rows = sort_rows(comparison.rows)
|
|
25
|
-
@out.puts(render(rows, duration_label: comparison.
|
|
30
|
+
@out.puts(render(rows, duration_label: comparison.duration_label, label_heading: label_heading))
|
|
26
31
|
0
|
|
27
32
|
rescue Errno::ENOENT => e
|
|
28
33
|
@err.puts("File not found: #{e.message}")
|
|
@@ -40,6 +45,9 @@ module RSpecTelemetry
|
|
|
40
45
|
options.on("--all-depths", "Include nested FactoryBot events") do
|
|
41
46
|
@options[:all_depths] = true
|
|
42
47
|
end
|
|
48
|
+
options.on("--by-factory", "Combine strategies (create/build) per factory") do
|
|
49
|
+
@options[:by_factory] = true
|
|
50
|
+
end
|
|
43
51
|
options.on(
|
|
44
52
|
"--sort KEY",
|
|
45
53
|
%w[duration count factory],
|
|
@@ -59,17 +67,21 @@ module RSpecTelemetry
|
|
|
59
67
|
def sort_rows(rows)
|
|
60
68
|
case @options[:sort]
|
|
61
69
|
when "count"
|
|
62
|
-
rows.sort_by { |row| [-row.count_diff.abs, row.
|
|
70
|
+
rows.sort_by { |row| [-row.count_diff.abs, row.label] }
|
|
63
71
|
when "factory"
|
|
64
|
-
rows.sort_by(&:
|
|
72
|
+
rows.sort_by(&:label)
|
|
65
73
|
else
|
|
66
|
-
rows.sort_by { |row| [-row.duration_diff_ms.abs, row.
|
|
74
|
+
rows.sort_by { |row| [-row.duration_diff_ms.abs, row.label] }
|
|
67
75
|
end
|
|
68
76
|
end
|
|
69
77
|
|
|
70
|
-
def
|
|
78
|
+
def label_heading
|
|
79
|
+
@options[:by_factory] ? "Factory" : "Factory:Strategy"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def render(rows, duration_label:, label_heading:)
|
|
71
83
|
headings = [
|
|
72
|
-
|
|
84
|
+
label_heading,
|
|
73
85
|
"Before",
|
|
74
86
|
"After",
|
|
75
87
|
"Diff",
|
|
@@ -79,51 +91,61 @@ module RSpecTelemetry
|
|
|
79
91
|
"Diff(ms)",
|
|
80
92
|
"Change"
|
|
81
93
|
]
|
|
82
|
-
body = rows.map
|
|
83
|
-
|
|
84
|
-
row.factory,
|
|
85
|
-
row.before_count.to_s,
|
|
86
|
-
row.after_count.to_s,
|
|
87
|
-
signed_integer(row.count_diff),
|
|
88
|
-
percent(row.count_change_percent),
|
|
89
|
-
decimal(row.before_duration_ms),
|
|
90
|
-
decimal(row.after_duration_ms),
|
|
91
|
-
signed_decimal(row.duration_diff_ms),
|
|
92
|
-
percent(row.duration_change_percent)
|
|
93
|
-
]
|
|
94
|
-
end
|
|
94
|
+
body = rows.map { |row| columns_for(row) }
|
|
95
|
+
total = columns_for(totals_row(rows))
|
|
95
96
|
|
|
96
97
|
widths = headings.each_index.map do |index|
|
|
97
|
-
([headings[index]] + body.map { |columns| columns[index] }).map(&:length).max
|
|
98
|
+
([headings[index]] + (body + [total]).map { |columns| columns[index] }).map(&:length).max
|
|
98
99
|
end
|
|
99
100
|
|
|
100
101
|
lines = []
|
|
101
102
|
lines << format_row(headings, widths)
|
|
102
|
-
lines << widths
|
|
103
|
+
lines << separator(widths)
|
|
103
104
|
body.each { |columns| lines << format_row(columns, widths) }
|
|
105
|
+
lines << separator(widths)
|
|
106
|
+
lines << format_row(total, widths)
|
|
104
107
|
lines.join("\n")
|
|
105
108
|
end
|
|
106
109
|
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
def columns_for(row)
|
|
111
|
+
[
|
|
112
|
+
row.label,
|
|
113
|
+
row.before_count.to_s,
|
|
114
|
+
row.after_count.to_s,
|
|
115
|
+
Formatting.signed_integer(row.count_diff),
|
|
116
|
+
percent(row.count_change_percent),
|
|
117
|
+
Formatting.fixed(row.before_duration_ms),
|
|
118
|
+
Formatting.fixed(row.after_duration_ms),
|
|
119
|
+
Formatting.signed_fixed(row.duration_diff_ms),
|
|
120
|
+
percent(row.duration_change_percent)
|
|
121
|
+
]
|
|
111
122
|
end
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
# Reuse Row so the total's diff/percent math matches every other line.
|
|
125
|
+
def totals_row(rows)
|
|
126
|
+
FactoryComparison::Row.new(
|
|
127
|
+
label: "TOTAL",
|
|
128
|
+
before_count: rows.sum(&:before_count),
|
|
129
|
+
after_count: rows.sum(&:after_count),
|
|
130
|
+
before_duration_ms: rows.sum(&:before_duration_ms),
|
|
131
|
+
after_duration_ms: rows.sum(&:after_duration_ms)
|
|
132
|
+
)
|
|
115
133
|
end
|
|
116
134
|
|
|
117
|
-
def
|
|
118
|
-
|
|
135
|
+
def separator(widths)
|
|
136
|
+
widths.map { |width| "-" * width }.join("-+-")
|
|
119
137
|
end
|
|
120
138
|
|
|
121
|
-
def
|
|
122
|
-
|
|
139
|
+
def format_row(columns, widths)
|
|
140
|
+
columns.each_with_index.map do |value, index|
|
|
141
|
+
index.zero? ? value.ljust(widths[index]) : value.rjust(widths[index])
|
|
142
|
+
end.join(" | ")
|
|
123
143
|
end
|
|
124
144
|
|
|
145
|
+
# "-" marks a missing baseline (before count/duration was zero), which is a
|
|
146
|
+
# table rule rather than number formatting, so it stays here.
|
|
125
147
|
def percent(value)
|
|
126
|
-
value ?
|
|
148
|
+
value ? Formatting.signed_percent(value) : "-"
|
|
127
149
|
end
|
|
128
150
|
end
|
|
129
151
|
end
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "formatting"
|
|
4
|
+
|
|
3
5
|
module RSpecTelemetry
|
|
4
6
|
class ConsoleReport
|
|
5
7
|
module Helpers
|
|
6
8
|
module_function
|
|
7
9
|
|
|
8
|
-
def fmt(ms)
|
|
9
|
-
ms = ms.to_f
|
|
10
|
-
ms >= 1000 ? format("%.2fs", ms / 1000.0) : format("%.1fms", ms)
|
|
11
|
-
end
|
|
10
|
+
def fmt(ms) = Formatting.duration(ms)
|
|
12
11
|
|
|
13
|
-
def pct(ratio) =
|
|
12
|
+
def pct(ratio) = Formatting.percent(ratio * 100)
|
|
14
13
|
|
|
15
14
|
def truncate(str, len) = str.length > len ? "#{str[0, len - 1]}…" : str
|
|
16
15
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "ndjson"
|
|
4
|
+
require_relative "factory_aggregation"
|
|
4
5
|
|
|
5
6
|
module RSpecTelemetry
|
|
6
7
|
class FactoryComparison
|
|
7
|
-
FactoryStat = Struct.new(:count, :duration_ms)
|
|
8
8
|
Row = Struct.new(
|
|
9
|
-
:
|
|
9
|
+
:label,
|
|
10
10
|
:before_count,
|
|
11
11
|
:after_count,
|
|
12
12
|
:before_duration_ms,
|
|
@@ -38,47 +38,75 @@ module RSpecTelemetry
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
attr_reader :before_path, :after_path, :all_depths
|
|
41
|
+
attr_reader :before_path, :after_path, :all_depths, :by_factory
|
|
42
42
|
|
|
43
|
-
def initialize(before_path, after_path, all_depths: false)
|
|
43
|
+
def initialize(before_path, after_path, all_depths: false, by_factory: false)
|
|
44
44
|
@before_path = before_path
|
|
45
45
|
@after_path = after_path
|
|
46
46
|
@all_depths = all_depths
|
|
47
|
+
@by_factory = by_factory
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def duration_label
|
|
51
|
+
all_depths ? "Self(ms)" : "Total(ms)"
|
|
47
52
|
end
|
|
48
53
|
|
|
49
54
|
def rows
|
|
50
55
|
before = aggregate(before_path)
|
|
51
56
|
after = aggregate(after_path)
|
|
52
57
|
|
|
53
|
-
(before.keys | after.keys).sort.map do |
|
|
54
|
-
before_stat = before
|
|
55
|
-
after_stat = after
|
|
58
|
+
(before.keys | after.keys).sort.map do |key|
|
|
59
|
+
before_stat = before[key]
|
|
60
|
+
after_stat = after[key]
|
|
56
61
|
|
|
57
62
|
Row.new(
|
|
58
|
-
|
|
59
|
-
before_count: before_stat
|
|
60
|
-
after_count: after_stat
|
|
61
|
-
before_duration_ms: before_stat
|
|
62
|
-
after_duration_ms: after_stat
|
|
63
|
+
label: key,
|
|
64
|
+
before_count: before_stat&.count || 0,
|
|
65
|
+
after_count: after_stat&.count || 0,
|
|
66
|
+
before_duration_ms: duration_for(before_stat),
|
|
67
|
+
after_duration_ms: duration_for(after_stat)
|
|
63
68
|
)
|
|
64
69
|
end
|
|
65
70
|
end
|
|
66
71
|
|
|
67
72
|
private
|
|
68
73
|
|
|
74
|
+
# Reuse the shared accumulator so counts, durations, and the factory:strategy
|
|
75
|
+
# granularity stay identical to the live summary, CLI report, and viewer.
|
|
76
|
+
# create and build are kept as separate keys (e.g. "user:create") unless
|
|
77
|
+
# by_factory rolls every strategy up under the bare factory name.
|
|
69
78
|
def aggregate(path)
|
|
70
|
-
|
|
79
|
+
acc = FactoryAggregation::Accumulator.new
|
|
71
80
|
|
|
72
81
|
File.foreach(path) do |line|
|
|
73
82
|
event = Ndjson.parse(line)
|
|
74
83
|
next unless factory_event?(event)
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
acc.add(
|
|
86
|
+
factory: event["factory"],
|
|
87
|
+
strategy: event["strategy"],
|
|
88
|
+
duration_ms: event["duration_ms"],
|
|
89
|
+
self_duration_ms: event["self_duration_ms"]
|
|
90
|
+
)
|
|
79
91
|
end
|
|
80
92
|
|
|
81
|
-
stats
|
|
93
|
+
stats = by_factory ? merge_by_factory(acc.stats) : acc.stats
|
|
94
|
+
stats.to_h { |stat| [stat.key, stat] }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Collapse create/build/etc. into a single row keyed by the factory name.
|
|
98
|
+
def merge_by_factory(stats)
|
|
99
|
+
stats.group_by(&:factory).map do |factory, group|
|
|
100
|
+
FactoryAggregation::Stat.new(
|
|
101
|
+
key: factory,
|
|
102
|
+
factory: factory,
|
|
103
|
+
strategy: nil,
|
|
104
|
+
count: group.sum(&:count),
|
|
105
|
+
total_ms: group.sum(&:total_ms),
|
|
106
|
+
self_total_ms: group.sum(&:self_total_ms),
|
|
107
|
+
max_ms: group.map(&:max_ms).max
|
|
108
|
+
)
|
|
109
|
+
end
|
|
82
110
|
end
|
|
83
111
|
|
|
84
112
|
def factory_event?(event)
|
|
@@ -89,13 +117,12 @@ module RSpecTelemetry
|
|
|
89
117
|
event["depth"].to_i.zero?
|
|
90
118
|
end
|
|
91
119
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
# Default mode compares inclusive time on root events; --all-depths compares
|
|
121
|
+
# self time so nested children are not double-counted.
|
|
122
|
+
def duration_for(stat)
|
|
123
|
+
return 0.0 unless stat
|
|
96
124
|
|
|
97
|
-
|
|
98
|
-
FactoryStat.new(0, 0.0)
|
|
125
|
+
all_depths ? stat.self_total_ms : stat.total_ms
|
|
99
126
|
end
|
|
100
127
|
end
|
|
101
128
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RSpecTelemetry
|
|
4
|
+
# Single source of truth for how telemetry numbers are rendered, so the decimal
|
|
5
|
+
# places, sign convention, and ms/s threshold stay consistent across the console
|
|
6
|
+
# report, the comparison table, and the live summary.
|
|
7
|
+
module Formatting
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
# Human-friendly duration: seconds past 1000ms, otherwise milliseconds.
|
|
11
|
+
def duration(ms)
|
|
12
|
+
ms = ms.to_f
|
|
13
|
+
ms >= 1000 ? format("%.2fs", ms / 1000.0) : format("%.1fms", ms)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fixed(value) = format("%.1f", value.to_f)
|
|
17
|
+
|
|
18
|
+
def signed_fixed(value) = format("%+.1f", value.to_f)
|
|
19
|
+
|
|
20
|
+
def signed_integer(value) = format("%+d", value.to_i)
|
|
21
|
+
|
|
22
|
+
def percent(value) = format("%.1f%%", value.to_f)
|
|
23
|
+
|
|
24
|
+
def signed_percent(value) = format("%+.1f%%", value.to_f)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "time"
|
|
4
4
|
|
|
5
|
+
require_relative "summary"
|
|
6
|
+
|
|
5
7
|
module RSpecTelemetry
|
|
6
8
|
class Recorder
|
|
7
9
|
# FactoryBot notifications read this to attach themselves to the active example.
|
|
@@ -43,7 +45,6 @@ module RSpecTelemetry
|
|
|
43
45
|
def finish
|
|
44
46
|
return unless @started
|
|
45
47
|
|
|
46
|
-
SummaryPrinter.print(@summary, @config) if @config.print_summary
|
|
47
48
|
@writer.close
|
|
48
49
|
@started = false
|
|
49
50
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "factory_aggregation"
|
|
4
|
+
require_relative "formatting"
|
|
4
5
|
|
|
5
6
|
module RSpecTelemetry
|
|
6
7
|
class Summary
|
|
@@ -102,10 +103,10 @@ module RSpecTelemetry
|
|
|
102
103
|
tops.each_with_index do |f, i|
|
|
103
104
|
lines << "#{i + 1}. #{f.key}"
|
|
104
105
|
lines << " count: #{f.count}"
|
|
105
|
-
lines << " self_total: #{
|
|
106
|
-
lines << " total: #{
|
|
107
|
-
lines << " avg: #{
|
|
108
|
-
lines << " max: #{
|
|
106
|
+
lines << " self_total: #{Formatting.fixed(f.self_total_ms)}ms"
|
|
107
|
+
lines << " total: #{Formatting.fixed(f.total_ms)}ms"
|
|
108
|
+
lines << " avg: #{Formatting.fixed(f.avg_ms)}ms"
|
|
109
|
+
lines << " max: #{Formatting.fixed(f.max_ms)}ms"
|
|
109
110
|
lines << ""
|
|
110
111
|
end
|
|
111
112
|
|
|
@@ -119,16 +120,12 @@ module RSpecTelemetry
|
|
|
119
120
|
lines = ["Slow examples:", ""]
|
|
120
121
|
slow.each_with_index do |e, i|
|
|
121
122
|
lines << "#{i + 1}. #{e.example_id}"
|
|
122
|
-
lines << " duration: #{
|
|
123
|
-
lines << " factory_bot_total: #{
|
|
123
|
+
lines << " duration: #{Formatting.fixed(e.duration_ms)}ms"
|
|
124
|
+
lines << " factory_bot_total: #{Formatting.fixed(e.factory_bot_total_ms)}ms (#{e.factory_bot_count} calls)"
|
|
124
125
|
lines << ""
|
|
125
126
|
end
|
|
126
127
|
|
|
127
128
|
lines
|
|
128
129
|
end
|
|
129
|
-
|
|
130
|
-
def round(value)
|
|
131
|
-
value.to_f.round(1)
|
|
132
|
-
end
|
|
133
130
|
end
|
|
134
131
|
end
|
data/lib/rspec_telemetry.rb
CHANGED
|
@@ -32,7 +32,13 @@ module RSpecTelemetry
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def finish!
|
|
35
|
-
@recorder
|
|
35
|
+
active = @recorder
|
|
36
|
+
if active&.started?
|
|
37
|
+
# Printing the end-of-run summary is a reporting concern owned by the
|
|
38
|
+
# lifecycle, not by the Recorder (which only records events).
|
|
39
|
+
SummaryPrinter.print(active.summary, config)
|
|
40
|
+
end
|
|
41
|
+
active&.finish
|
|
36
42
|
unsubscribe!
|
|
37
43
|
end
|
|
38
44
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rspec_telemetry
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- takahashimm
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- lib/rspec_telemetry/factory_aggregation.rb
|
|
64
64
|
- lib/rspec_telemetry/factory_comparison.rb
|
|
65
65
|
- lib/rspec_telemetry/formatter.rb
|
|
66
|
+
- lib/rspec_telemetry/formatting.rb
|
|
66
67
|
- lib/rspec_telemetry/ndjson.rb
|
|
67
68
|
- lib/rspec_telemetry/recorder.rb
|
|
68
69
|
- lib/rspec_telemetry/subscribers/factory_bot.rb
|