Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit c1d092d

Browse files
authored
Merge pull request #2280 from eugeneius/fix_adding_hooks_to_existing_groups
Fix adding config hooks to existing example groups
2 parents 9b84b78 + 7e1799d commit c1d092d

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

lib/rspec/core/configuration.rb

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,7 +1749,8 @@ def before(scope=nil, *meta, &block)
17491749
handle_suite_hook(scope, meta) do
17501750
@before_suite_hooks << Hooks::BeforeHook.new(block, {})
17511751
end || begin
1752-
on_existing_matching_groups({}) { |g| g.before(scope, *meta, &block) }
1752+
metadata = Metadata.build_hash_from(meta.dup)
1753+
on_existing_matching_groups(metadata, scope) { |g| g.before(scope, *meta, &block) }
17531754
super(scope, *meta, &block)
17541755
end
17551756
end
@@ -1772,7 +1773,8 @@ def prepend_before(scope=nil, *meta, &block)
17721773
handle_suite_hook(scope, meta) do
17731774
@before_suite_hooks.unshift Hooks::BeforeHook.new(block, {})
17741775
end || begin
1775-
on_existing_matching_groups({}) { |g| g.prepend_before(scope, *meta, &block) }
1776+
metadata = Metadata.build_hash_from(meta.dup)
1777+
on_existing_matching_groups(metadata, scope) { |g| g.prepend_before(scope, *meta, &block) }
17761778
super(scope, *meta, &block)
17771779
end
17781780
end
@@ -1790,7 +1792,8 @@ def after(scope=nil, *meta, &block)
17901792
handle_suite_hook(scope, meta) do
17911793
@after_suite_hooks.unshift Hooks::AfterHook.new(block, {})
17921794
end || begin
1793-
on_existing_matching_groups({}) { |g| g.after(scope, *meta, &block) }
1795+
metadata = Metadata.build_hash_from(meta.dup)
1796+
on_existing_matching_groups(metadata, scope) { |g| g.after(scope, *meta, &block) }
17941797
super(scope, *meta, &block)
17951798
end
17961799
end
@@ -1813,7 +1816,8 @@ def append_after(scope=nil, *meta, &block)
18131816
handle_suite_hook(scope, meta) do
18141817
@after_suite_hooks << Hooks::AfterHook.new(block, {})
18151818
end || begin
1816-
on_existing_matching_groups({}) { |g| g.append_after(scope, *meta, &block) }
1819+
metadata = Metadata.build_hash_from(meta.dup)
1820+
on_existing_matching_groups(metadata, scope) { |g| g.append_after(scope, *meta, &block) }
18171821
super(scope, *meta, &block)
18181822
end
18191823
end
@@ -1822,8 +1826,8 @@ def append_after(scope=nil, *meta, &block)
18221826
#
18231827
# See {Hooks#around} for full `around` hook docs.
18241828
def around(scope=nil, *meta, &block)
1825-
on_existing_matching_groups({}) { |g| g.around(scope, *meta, &block) }
1826-
1829+
metadata = Metadata.build_hash_from(meta.dup)
1830+
on_existing_matching_groups(metadata, scope) { |g| g.around(scope, *meta, &block) }
18271831
super(scope, *meta, &block)
18281832
end
18291833

@@ -2027,9 +2031,18 @@ def configure_group_with(group, module_list, application_method)
20272031
end
20282032
end
20292033

2030-
def on_existing_matching_groups(meta)
2031-
world.all_example_groups.each do |group|
2032-
yield group if meta.empty? || MetadataFilter.apply?(:any?, meta, group.metadata)
2034+
def on_existing_matching_groups(meta, scope=:ignore)
2035+
groups = world.example_groups.dup
2036+
2037+
until groups.empty?
2038+
group = groups.shift
2039+
2040+
if scope == :example || scope == :each || scope.nil? ||
2041+
meta.empty? || MetadataFilter.apply?(:any?, meta, group.metadata)
2042+
yield group
2043+
else
2044+
groups.concat(group.children)
2045+
end
20332046
end
20342047
end
20352048

spec/rspec/core/hooks_filtering_spec.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,62 @@ module RSpec::Core
129129
group.run
130130
expect(sequence).to eq [:example]
131131
end
132+
133+
it "only runs example hooks once when there are multiple nested example groups" do
134+
sequence = []
135+
136+
group = RSpec.describe do
137+
context do
138+
example { sequence << :ex_1 }
139+
example { sequence << :ex_2 }
140+
end
141+
end
142+
143+
RSpec.configure do |c|
144+
c.before(:example) { sequence << :before_ex_2 }
145+
c.prepend_before(:example) { sequence << :before_ex_1 }
146+
147+
c.after(:example) { sequence << :after_ex_1 }
148+
c.append_after(:example) { sequence << :after_ex_2 }
149+
150+
c.around(:example) do |ex|
151+
sequence << :around_before_ex
152+
ex.run
153+
sequence << :around_after_ex
154+
end
155+
end
156+
157+
group.run
158+
159+
expect(sequence).to eq [
160+
:around_before_ex, :before_ex_1, :before_ex_2, :ex_1, :after_ex_1, :after_ex_2, :around_after_ex,
161+
:around_before_ex, :before_ex_1, :before_ex_2, :ex_2, :after_ex_1, :after_ex_2, :around_after_ex
162+
]
163+
end
164+
165+
it "only runs context hooks around the highest level group with matching filters" do
166+
sequence = []
167+
168+
group = RSpec.describe do
169+
before(:context) { sequence << :before_context }
170+
after(:context) { sequence << :after_context }
171+
172+
context "", :match do
173+
context "", :match do
174+
example { sequence << :example }
175+
end
176+
end
177+
end
178+
179+
RSpec.configure do |config|
180+
config.before(:context, :match) { sequence << :before_hook }
181+
config.after(:context, :match) { sequence << :after_hook }
182+
end
183+
184+
group.run
185+
186+
expect(sequence).to eq [:before_context, :before_hook, :example, :after_hook, :after_context]
187+
end
132188
end
133189

134190
describe "unfiltered hooks" do

0 commit comments

Comments
 (0)