test-prof 0.12.0 → 1.0.7
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 +155 -463
- data/README.md +9 -9
- data/config/default.yml +0 -15
- data/config/rubocop-rspec.yml +6 -0
- data/lib/test_prof/any_fixture/dump/base_adapter.rb +43 -0
- data/lib/test_prof/any_fixture/dump/digest.rb +29 -0
- data/lib/test_prof/any_fixture/dump/postgresql.rb +91 -0
- data/lib/test_prof/any_fixture/dump/sqlite.rb +42 -0
- data/lib/test_prof/any_fixture/dump.rb +212 -0
- data/lib/test_prof/any_fixture.rb +117 -8
- data/lib/test_prof/before_all/adapters/active_record.rb +15 -5
- data/lib/test_prof/before_all.rb +11 -2
- data/lib/test_prof/cops/rspec/aggregate_examples/its.rb +1 -1
- data/lib/test_prof/cops/rspec/aggregate_examples/line_range_helpers.rb +1 -1
- data/lib/test_prof/cops/rspec/aggregate_examples/matchers_with_side_effects.rb +1 -1
- data/lib/test_prof/cops/rspec/aggregate_examples/metadata_helpers.rb +1 -1
- data/lib/test_prof/cops/rspec/aggregate_examples/node_matchers.rb +1 -1
- data/lib/test_prof/cops/rspec/aggregate_examples.rb +1 -1
- data/lib/test_prof/event_prof/custom_events.rb +1 -1
- data/lib/test_prof/event_prof/instrumentations/active_support.rb +1 -1
- data/lib/test_prof/event_prof/profiler.rb +3 -4
- data/lib/test_prof/factory_prof/nate_heckler.rb +16 -0
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +1 -1
- data/lib/test_prof/factory_prof/printers/nate_heckler.rb +26 -0
- data/lib/test_prof/factory_prof/printers/simple.rb +6 -2
- data/lib/test_prof/factory_prof.rb +24 -4
- data/lib/test_prof/logging.rb +18 -12
- data/lib/test_prof/recipes/logging.rb +1 -1
- data/lib/test_prof/recipes/minitest/before_all.rb +126 -24
- data/lib/test_prof/recipes/rspec/any_fixture.rb +1 -1
- data/lib/test_prof/recipes/rspec/before_all.rb +11 -3
- data/lib/test_prof/recipes/rspec/let_it_be.rb +6 -8
- data/lib/test_prof/rspec_dissect.rb +2 -2
- data/lib/test_prof/rspec_stamp.rb +1 -1
- data/lib/test_prof/rubocop.rb +0 -1
- data/lib/test_prof/ruby_prof.rb +11 -9
- data/lib/test_prof/tag_prof/result.rb +1 -1
- data/lib/test_prof/tag_prof/rspec.rb +3 -5
- data/lib/test_prof/utils/sized_ordered_set.rb +2 -2
- data/lib/test_prof/version.rb +1 -1
- data/lib/test_prof.rb +17 -4
- metadata +19 -14
- data/lib/test_prof/cops/rspec/aggregate_failures.rb +0 -26
- data/lib/test_prof/ext/active_record_3.rb +0 -27
- data/lib/test_prof/recipes/active_record_one_love.rb +0 -6
- data/lib/test_prof/recipes/active_record_shared_connection.rb +0 -77
@@ -1,10 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
if ::ActiveRecord::VERSION::MAJOR < 4
|
4
|
-
require "test_prof/ext/active_record_3"
|
5
|
-
using TestProf::ActiveRecord3Transactions
|
6
|
-
end
|
7
|
-
|
8
3
|
module TestProf
|
9
4
|
module BeforeAll
|
10
5
|
module Adapters
|
@@ -23,6 +18,21 @@ module TestProf
|
|
23
18
|
end
|
24
19
|
::ActiveRecord::Base.connection.rollback_transaction
|
25
20
|
end
|
21
|
+
|
22
|
+
def setup_fixtures(test_object)
|
23
|
+
test_object.instance_eval do
|
24
|
+
@@already_loaded_fixtures ||= {}
|
25
|
+
@fixture_cache ||= {}
|
26
|
+
config = ::ActiveRecord::Base
|
27
|
+
|
28
|
+
if @@already_loaded_fixtures[self.class]
|
29
|
+
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
30
|
+
else
|
31
|
+
@loaded_fixtures = load_fixtures(config)
|
32
|
+
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
end
|
data/lib/test_prof/before_all.rb
CHANGED
@@ -32,6 +32,12 @@ module TestProf
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def setup_fixtures(test_object)
|
36
|
+
raise ArgumentError, "Current adapter doesn't support #setup_fixtures" unless adapter.respond_to?(:setup_fixtures)
|
37
|
+
|
38
|
+
adapter.setup_fixtures(test_object)
|
39
|
+
end
|
40
|
+
|
35
41
|
def config
|
36
42
|
@config ||= Configuration.new
|
37
43
|
end
|
@@ -60,8 +66,11 @@ module TestProf
|
|
60
66
|
class Configuration
|
61
67
|
HOOKS = %i[begin rollback].freeze
|
62
68
|
|
69
|
+
attr_accessor :setup_fixtures
|
70
|
+
|
63
71
|
def initialize
|
64
72
|
@hooks = Hash.new { |h, k| h[k] = HooksChain.new(k) }
|
73
|
+
@setup_fixtures = false
|
65
74
|
end
|
66
75
|
|
67
76
|
# Add `before` hook for `begin` or
|
@@ -70,7 +79,7 @@ module TestProf
|
|
70
79
|
# config.before(:rollback) { ... }
|
71
80
|
def before(type, &block)
|
72
81
|
validate_hook_type!(type)
|
73
|
-
hooks[type].before << block if
|
82
|
+
hooks[type].before << block if block
|
74
83
|
end
|
75
84
|
|
76
85
|
# Add `after` hook for `begin` or
|
@@ -79,7 +88,7 @@ module TestProf
|
|
79
88
|
# config.after(:begin) { ... }
|
80
89
|
def after(type, &block)
|
81
90
|
validate_hook_type!(type)
|
82
|
-
hooks[type].after << block if
|
91
|
+
hooks[type].after << block if block
|
83
92
|
end
|
84
93
|
|
85
94
|
def run_hooks(type) # :nodoc:
|
@@ -5,7 +5,7 @@ require_relative "../language"
|
|
5
5
|
module RuboCop
|
6
6
|
module Cop
|
7
7
|
module RSpec
|
8
|
-
class AggregateExamples < Cop
|
8
|
+
class AggregateExamples < ::RuboCop::Cop::Cop
|
9
9
|
# When aggregated, the expectations will fail when not supposed to or
|
10
10
|
# have a risk of not failing when expected to. One example is
|
11
11
|
# `validate_presence_of :comment` as it leaves an empty comment after
|
@@ -26,7 +26,7 @@ module TestProf::EventProf
|
|
26
26
|
|
27
27
|
class << self
|
28
28
|
def subscribe(event, &block)
|
29
|
-
raise ArgumentError, "Block is required!" unless
|
29
|
+
raise ArgumentError, "Block is required!" unless block
|
30
30
|
|
31
31
|
::ActiveSupport::Notifications.subscribe(event, Subscriber.new(block))
|
32
32
|
end
|
@@ -6,7 +6,7 @@ module TestProf
|
|
6
6
|
attr_reader :event, :total_count, :total_time, :rank_by, :top_count, :per_example,
|
7
7
|
:time, :count, :example_time, :example_count, :absolute_run_time
|
8
8
|
|
9
|
-
|
9
|
+
alias_method :per_example?, :per_example
|
10
10
|
|
11
11
|
def initialize(event:, instrumenter:, rank_by: :time, top_count: 5, per_example: false)
|
12
12
|
@event = event
|
@@ -88,14 +88,13 @@ module TestProf
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def results
|
91
|
-
|
91
|
+
{
|
92
92
|
groups: @groups.to_a
|
93
93
|
}.tap do |data|
|
94
94
|
next unless per_example?
|
95
95
|
|
96
96
|
data[:examples] = @examples.to_a
|
97
97
|
end
|
98
|
-
results
|
99
98
|
end
|
100
99
|
|
101
100
|
def take_time(start_ts)
|
@@ -130,7 +129,7 @@ module TestProf
|
|
130
129
|
end
|
131
130
|
|
132
131
|
def each(&block)
|
133
|
-
if
|
132
|
+
if block
|
134
133
|
@profilers.each(&block)
|
135
134
|
else
|
136
135
|
@profilers.each
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_prof/factory_prof"
|
4
|
+
|
5
|
+
# A standalone Factory Prof printer which is meant to be always enabled
|
6
|
+
|
7
|
+
TestProf::FactoryProf.patch!
|
8
|
+
|
9
|
+
started_at = TestProf.now
|
10
|
+
at_exit do
|
11
|
+
TestProf::FactoryProf::Printers::NateHeckler.dump(
|
12
|
+
TestProf::FactoryProf.result, start_time: started_at
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
TestProf::FactoryProf.start
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_prof/ext/float_duration"
|
4
|
+
|
5
|
+
module TestProf::FactoryProf
|
6
|
+
module Printers
|
7
|
+
# See https://twitter.com/nateberkopec/status/1389945187766456333
|
8
|
+
module NateHeckler # :nodoc: all
|
9
|
+
class << self
|
10
|
+
using TestProf::FloatDuration
|
11
|
+
include TestProf::Logging
|
12
|
+
|
13
|
+
def dump(result, start_time:)
|
14
|
+
return if result.raw_stats == {}
|
15
|
+
|
16
|
+
total_time = result.stats.sum { |stat| stat[:top_level_time] }
|
17
|
+
total_run_time = TestProf.now - start_time
|
18
|
+
|
19
|
+
percentage = ((total_time / total_run_time) * 100).round(2)
|
20
|
+
|
21
|
+
log :info, "Time spent in factories: #{total_time.duration} (#{percentage}% of total time)"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,15 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "test_prof/ext/float_duration"
|
4
|
+
|
3
5
|
module TestProf::FactoryProf
|
4
6
|
module Printers
|
5
7
|
module Simple # :nodoc: all
|
6
8
|
class << self
|
9
|
+
using TestProf::FloatDuration
|
7
10
|
include TestProf::Logging
|
8
11
|
|
9
|
-
def dump(result)
|
12
|
+
def dump(result, start_time:)
|
10
13
|
return log(:info, "No factories detected") if result.raw_stats == {}
|
11
14
|
msgs = []
|
12
15
|
|
16
|
+
total_run_time = TestProf.now - start_time
|
13
17
|
total_count = result.stats.sum { |stat| stat[:total_count] }
|
14
18
|
total_top_level_count = result.stats.sum { |stat| stat[:top_level_count] }
|
15
19
|
total_time = result.stats.sum { |stat| stat[:top_level_time] }
|
@@ -21,7 +25,7 @@ module TestProf::FactoryProf
|
|
21
25
|
|
22
26
|
Total: #{total_count}
|
23
27
|
Total top-level: #{total_top_level_count}
|
24
|
-
Total time: #{
|
28
|
+
Total time: #{total_time.duration} (out of #{total_run_time.duration})
|
25
29
|
Total uniq factories: #{total_uniq_factories}
|
26
30
|
|
27
31
|
total top-level total time time per call top-level time name
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "test_prof/factory_prof/printers/simple"
|
4
4
|
require "test_prof/factory_prof/printers/flamegraph"
|
5
|
+
require "test_prof/factory_prof/printers/nate_heckler"
|
5
6
|
require "test_prof/factory_prof/factory_builders/factory_bot"
|
6
7
|
require "test_prof/factory_prof/factory_builders/fabrication"
|
7
8
|
|
@@ -10,14 +11,23 @@ module TestProf
|
|
10
11
|
# flamegraphs or detect most popular factories
|
11
12
|
module FactoryProf
|
12
13
|
FACTORY_BUILDERS = [FactoryBuilders::FactoryBot,
|
13
|
-
|
14
|
+
FactoryBuilders::Fabrication].freeze
|
14
15
|
|
15
16
|
# FactoryProf configuration
|
16
17
|
class Configuration
|
17
|
-
attr_accessor :mode
|
18
|
+
attr_accessor :mode, :printer
|
18
19
|
|
19
20
|
def initialize
|
20
21
|
@mode = ENV["FPROF"] == "flamegraph" ? :flamegraph : :simple
|
22
|
+
@printer =
|
23
|
+
case ENV["FPROF"]
|
24
|
+
when "flamegraph"
|
25
|
+
Printers::Flamegraph
|
26
|
+
when "nate_heckler"
|
27
|
+
Printers::NateHeckler
|
28
|
+
else
|
29
|
+
Printers::Simple
|
30
|
+
end
|
21
31
|
end
|
22
32
|
|
23
33
|
# Whether we want to generate flamegraphs
|
@@ -74,7 +84,15 @@ module TestProf
|
|
74
84
|
|
75
85
|
log :info, "FactoryProf enabled (#{config.mode} mode)"
|
76
86
|
|
87
|
+
patch!
|
88
|
+
end
|
89
|
+
|
90
|
+
def patch!
|
91
|
+
return if @patched
|
92
|
+
|
77
93
|
FACTORY_BUILDERS.each(&:patch)
|
94
|
+
|
95
|
+
@patched = true
|
78
96
|
end
|
79
97
|
|
80
98
|
# Inits FactoryProf and setups at exit hook,
|
@@ -82,9 +100,11 @@ module TestProf
|
|
82
100
|
def run
|
83
101
|
init
|
84
102
|
|
85
|
-
printer = config.
|
103
|
+
printer = config.printer
|
104
|
+
|
105
|
+
started_at = TestProf.now
|
86
106
|
|
87
|
-
at_exit { printer.dump(result) }
|
107
|
+
at_exit { printer.dump(result, start_time: started_at) }
|
88
108
|
|
89
109
|
start
|
90
110
|
end
|
data/lib/test_prof/logging.rb
CHANGED
@@ -4,23 +4,29 @@ module TestProf
|
|
4
4
|
# Helper for output printing
|
5
5
|
module Logging
|
6
6
|
COLORS = {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
INFO: "\e[34m", # blue
|
8
|
+
WARN: "\e[33m", # yellow
|
9
|
+
ERROR: "\e[31m" # red
|
10
10
|
}.freeze
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
class Formatter
|
13
|
+
def call(severity, _time, progname, msg)
|
14
|
+
colorize(severity.to_sym, "[#{progname} #{severity}] #{msg}\n")
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
private
|
18
|
+
|
19
|
+
def colorize(level, msg)
|
20
|
+
return msg unless TestProf.config.color?
|
19
21
|
|
20
|
-
|
21
|
-
return msg unless TestProf.config.color?
|
22
|
+
return msg unless COLORS.key?(level)
|
22
23
|
|
23
|
-
|
24
|
+
"#{COLORS[level]}#{msg}\e[0m"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def log(level, msg)
|
29
|
+
TestProf.config.logger.public_send(level, "TEST PROF") { msg }
|
24
30
|
end
|
25
31
|
end
|
26
32
|
end
|
@@ -2,77 +2,179 @@
|
|
2
2
|
|
3
3
|
require "test_prof/before_all"
|
4
4
|
|
5
|
+
Minitest.singleton_class.prepend(Module.new do
|
6
|
+
attr_reader :previous_klass
|
7
|
+
@previous_klass = nil
|
8
|
+
|
9
|
+
def run_one_method(klass, method_name)
|
10
|
+
return super unless klass.respond_to?(:parallelized) && klass.parallelized
|
11
|
+
|
12
|
+
if @previous_klass && @previous_klass != klass
|
13
|
+
@previous_klass.before_all_executor&.deactivate!
|
14
|
+
end
|
15
|
+
@previous_klass = klass
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end)
|
20
|
+
|
5
21
|
module TestProf
|
6
22
|
module BeforeAll
|
7
23
|
# Add before_all hook to Minitest: wrap all examples into a transaction and
|
8
24
|
# store instance variables
|
9
25
|
module Minitest # :nodoc: all
|
10
26
|
class Executor
|
11
|
-
attr_reader :active
|
27
|
+
attr_reader :active, :block, :captured_ivars, :teardown_block, :current_test_object,
|
28
|
+
:setup_fixtures, :parent
|
12
29
|
|
13
|
-
|
30
|
+
alias_method :active?, :active
|
31
|
+
alias_method :setup_fixtures?, :setup_fixtures
|
14
32
|
|
15
|
-
def initialize(&block)
|
33
|
+
def initialize(setup_fixtures: false, parent: nil, &block)
|
34
|
+
@parent = parent
|
35
|
+
# Fixtures must be instantiated if any of the executors needs them
|
36
|
+
@setup_fixtures = setup_fixtures || parent&.setup_fixtures
|
16
37
|
@block = block
|
38
|
+
@captured_ivars = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def teardown(&block)
|
42
|
+
@teardown_block = block
|
17
43
|
end
|
18
44
|
|
19
|
-
def activate!(
|
20
|
-
|
45
|
+
def activate!(test_object)
|
46
|
+
@current_test_object = test_object
|
47
|
+
|
48
|
+
return restore_ivars(test_object) if active?
|
49
|
+
|
21
50
|
@active = true
|
22
|
-
|
51
|
+
|
52
|
+
BeforeAll.setup_fixtures(test_object) if setup_fixtures?
|
23
53
|
BeforeAll.begin_transaction do
|
24
|
-
capture!
|
54
|
+
capture!(test_object)
|
25
55
|
end
|
26
56
|
end
|
27
57
|
|
28
|
-
def
|
29
|
-
|
30
|
-
return unless @examples_left.zero?
|
58
|
+
def deactivate!
|
59
|
+
return unless active
|
31
60
|
|
32
61
|
@active = false
|
62
|
+
|
63
|
+
perform_teardown(current_test_object)
|
64
|
+
|
65
|
+
@current_test_object = nil
|
33
66
|
BeforeAll.rollback_transaction
|
34
67
|
end
|
35
68
|
|
36
|
-
def capture!
|
37
|
-
|
69
|
+
def capture!(test_object)
|
70
|
+
before_ivars = test_object.instance_variables
|
71
|
+
|
72
|
+
perform_setup(test_object)
|
73
|
+
|
74
|
+
(test_object.instance_variables - before_ivars).each do |ivar|
|
75
|
+
captured_ivars << [ivar, test_object.instance_variable_get(ivar)]
|
76
|
+
end
|
38
77
|
end
|
39
78
|
|
40
|
-
def
|
41
|
-
|
42
|
-
next if ivar == :@block
|
79
|
+
def restore_ivars(test_object)
|
80
|
+
captured_ivars.each do |(ivar, val)|
|
43
81
|
test_object.instance_variable_set(
|
44
82
|
ivar,
|
45
|
-
|
83
|
+
val
|
46
84
|
)
|
47
85
|
end
|
48
86
|
end
|
87
|
+
|
88
|
+
def perform_setup(test_object)
|
89
|
+
parent&.perform_setup(test_object)
|
90
|
+
test_object.instance_eval(&block) if block
|
91
|
+
end
|
92
|
+
|
93
|
+
def perform_teardown(test_object)
|
94
|
+
current_test_object&.instance_eval(&teardown_block) if teardown_block
|
95
|
+
parent&.perform_teardown(test_object)
|
96
|
+
end
|
49
97
|
end
|
50
98
|
|
51
99
|
class << self
|
52
100
|
def included(base)
|
53
101
|
base.extend ClassMethods
|
102
|
+
|
103
|
+
base.cattr_accessor :parallelized
|
104
|
+
if base.respond_to?(:parallelize_teardown)
|
105
|
+
base.parallelize_teardown do
|
106
|
+
last_klass = ::Minitest.previous_klass
|
107
|
+
if last_klass&.respond_to?(:parallelized) && last_klass&.parallelized
|
108
|
+
last_klass.before_all_executor&.deactivate!
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
if base.respond_to?(:parallelize)
|
114
|
+
base.singleton_class.prepend(Module.new do
|
115
|
+
def parallelize(workers: :number_of_processors, with: :processes)
|
116
|
+
# super.parallelize returns nil when no parallelization is set up
|
117
|
+
if super(workers: workers, with: with).nil?
|
118
|
+
return
|
119
|
+
end
|
120
|
+
|
121
|
+
case with
|
122
|
+
when :processes
|
123
|
+
self.parallelized = true
|
124
|
+
when :threads
|
125
|
+
warn "!!! before_all is not implemented for parallalization with threads and " \
|
126
|
+
"could work incorrectly"
|
127
|
+
else
|
128
|
+
warn "!!! tests are using an unknown parallelization strategy and before_all " \
|
129
|
+
"could work incorrectly"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end)
|
133
|
+
end
|
54
134
|
end
|
55
135
|
end
|
56
136
|
|
57
137
|
module ClassMethods
|
58
|
-
|
138
|
+
attr_writer :before_all_executor
|
59
139
|
|
60
|
-
def
|
61
|
-
|
140
|
+
def before_all_executor
|
141
|
+
return @before_all_executor if instance_variable_defined?(:@before_all_executor)
|
142
|
+
|
143
|
+
@before_all_executor = if superclass.respond_to?(:before_all_executor)
|
144
|
+
superclass.before_all_executor
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def before_all(setup_fixtures: BeforeAll.config.setup_fixtures, &block)
|
149
|
+
self.before_all_executor = Executor.new(
|
150
|
+
setup_fixtures: setup_fixtures,
|
151
|
+
parent: before_all_executor,
|
152
|
+
&block
|
153
|
+
)
|
154
|
+
|
155
|
+
# Do not add patches multiple times
|
156
|
+
return if before_all_executor.parent
|
62
157
|
|
63
158
|
prepend(Module.new do
|
64
|
-
def
|
65
|
-
self.class.before_all_executor.activate!(self
|
66
|
-
self.class.before_all_executor.restore_to(self)
|
159
|
+
def before_setup
|
160
|
+
self.class.before_all_executor.activate!(self)
|
67
161
|
super
|
68
162
|
end
|
163
|
+
end)
|
69
164
|
|
70
|
-
|
165
|
+
singleton_class.prepend(Module.new do
|
166
|
+
def run(*)
|
71
167
|
super
|
72
|
-
|
168
|
+
ensure
|
169
|
+
before_all_executor&.deactivate! unless parallelized
|
73
170
|
end
|
74
171
|
end)
|
75
172
|
end
|
173
|
+
|
174
|
+
def after_all(&block)
|
175
|
+
self.before_all_executor = Executor.new(parent: before_all_executor)
|
176
|
+
before_all_executor.teardown(&block)
|
177
|
+
end
|
76
178
|
end
|
77
179
|
end
|
78
180
|
end
|
@@ -15,7 +15,7 @@ RSpec.configure do |config|
|
|
15
15
|
config.include_context "any_fixture:clean", with_clean_fixture: true
|
16
16
|
|
17
17
|
config.after(:suite) do
|
18
|
-
TestProf::AnyFixture.report_stats if TestProf::AnyFixture.reporting_enabled?
|
18
|
+
TestProf::AnyFixture.report_stats if TestProf::AnyFixture.config.reporting_enabled?
|
19
19
|
TestProf::AnyFixture.reset
|
20
20
|
end
|
21
21
|
end
|
@@ -6,14 +6,22 @@ module TestProf
|
|
6
6
|
module BeforeAll
|
7
7
|
# Helper to wrap the whole example group into a transaction
|
8
8
|
module RSpec
|
9
|
-
def before_all(&block)
|
10
|
-
raise ArgumentError, "Block is required!" unless
|
9
|
+
def before_all(setup_fixtures: BeforeAll.config.setup_fixtures, &block)
|
10
|
+
raise ArgumentError, "Block is required!" unless block
|
11
11
|
|
12
|
-
|
12
|
+
if within_before_all?
|
13
|
+
before(:all) do
|
14
|
+
@__inspect_output = "before_all hook"
|
15
|
+
instance_eval(&block)
|
16
|
+
end
|
17
|
+
return
|
18
|
+
end
|
13
19
|
|
14
20
|
@__before_all_activated__ = true
|
15
21
|
|
16
22
|
before(:all) do
|
23
|
+
@__inspect_output = "before_all hook"
|
24
|
+
BeforeAll.setup_fixtures(self) if setup_fixtures
|
17
25
|
BeforeAll.begin_transaction do
|
18
26
|
instance_eval(&block)
|
19
27
|
end
|
@@ -55,9 +55,7 @@ module TestProf
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def module_for(group)
|
58
|
-
modules[group] ||=
|
59
|
-
Module.new.tap { |mod| group.prepend(mod) }
|
60
|
-
end
|
58
|
+
modules[group] ||= Module.new.tap { |mod| group.prepend(mod) }
|
61
59
|
end
|
62
60
|
|
63
61
|
private
|
@@ -91,8 +89,7 @@ module TestProf
|
|
91
89
|
initializer = proc do
|
92
90
|
instance_variable_set(:"#{TestProf::LetItBe::PREFIX}#{identifier}", instance_exec(&block))
|
93
91
|
rescue FrozenError => e
|
94
|
-
e.message
|
95
|
-
raise
|
92
|
+
raise e.exception("#{e.message}#{TestProf::LetItBe::FROZEN_ERROR_HINT}")
|
96
93
|
end
|
97
94
|
|
98
95
|
default_options = LetItBe.config.default_modifiers.dup
|
@@ -108,8 +105,9 @@ module TestProf
|
|
108
105
|
|
109
106
|
LetItBe.module_for(self).module_eval do
|
110
107
|
define_method(identifier) do
|
111
|
-
# Trying to detect the context
|
112
|
-
|
108
|
+
# Trying to detect the context
|
109
|
+
# Based on https://github.com/rspec/rspec-rails/commit/7cb796db064f58da7790a92e73ab906ef50b1f34
|
110
|
+
if /(before|after)\(:context\)/.match?(@__inspect_output) || @__inspect_output.include?("before_all")
|
113
111
|
instance_variable_get(:"#{PREFIX}#{identifier}")
|
114
112
|
else
|
115
113
|
# Fallback to let definition
|
@@ -242,7 +240,7 @@ end
|
|
242
240
|
RSpec.configure do |config|
|
243
241
|
config.after(:example) do |example|
|
244
242
|
if example.exception&.is_a?(FrozenError)
|
245
|
-
example.exception.message << TestProf::LetItBe::FROZEN_ERROR_HINT
|
243
|
+
example.exception.message << TestProf::LetItBe::FROZEN_ERROR_HINT unless example.exception.message.frozen?
|
246
244
|
end
|
247
245
|
end
|
248
246
|
end
|