Skip to content

Commit f2b8d3d

Browse files
nganclaude
andcommitted
Fix fixture declarations not propagating to auto-included shared example groups
When shared example groups are auto-included via `config.include_context` with metadata filters, RSpec creates those child groups during configuration — before the spec file's `fixture` call sets the declaration on the parent group's metadata. Since RSpec snapshots parent metadata into child groups at creation time, the child's metadata never includes the fixture declaration, and the `prepend_before` hook never fires for those examples. The fix uses RSpec's own `update_inherited_metadata` to propagate the fixture declaration to any child groups that already exist when `fixture` is called. This is the same mechanism RSpec uses internally to push metadata updates to descendants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 527b476 commit f2b8d3d

4 files changed

Lines changed: 45 additions & 1 deletion

File tree

lib/fixture_kit/rspec.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ module ClassMethods
3030
def fixture(name = nil, extends: nil, &block)
3131
definition = Definition.new(extends: extends, &block) if block_given?
3232
declaration = ::RSpec.configuration.fixture_kit.register(name || definition, self)
33-
metadata[DECLARATION_METADATA_KEY] = declaration
33+
# Use update_inherited_metadata to set the declaration on this group
34+
# AND propagate to any child groups already created (e.g., shared
35+
# example groups auto-included via `config.include_context` during
36+
# RSpec configuration).
37+
update_inherited_metadata(DECLARATION_METADATA_KEY => declaration)
3438

3539
prepend_before(:context) do
3640
self.class.metadata[DECLARATION_METADATA_KEY].generate

spec/dummy/spec/integration/fixture_kit_integration.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ module FixtureKitIntegrationTimeHelpers
1212
config.include(FixtureKitIntegrationTimeHelpers)
1313
end
1414

15+
# Shared examples auto-included via config.include_context to reproduce the
16+
# ordering issue: RSpec creates the shared group during configuration (before
17+
# the host group's `fixture` call sets metadata), so fixture declarations
18+
# must propagate through runtime metadata inheritance.
19+
RSpec.shared_examples "auto-included shared examples" do
20+
context "inside auto-included shared context" do
21+
let(:shared_user) { User.find_by!(email: "alice@team.test") }
22+
23+
it "can access fixture data through let blocks defined in the host group" do
24+
expect(fixture.alice.email).to eq("alice@team.test")
25+
expect(shared_user).to eq(fixture.alice)
26+
puts "FKIT_ASSERT:SHARED_EXAMPLE_FIXTURE_ACCESS"
27+
end
28+
end
29+
end
30+
31+
RSpec.configure do |config|
32+
config.include_context "auto-included shared examples", :include_shared_fixture_test
33+
end
34+
1535
RSpec.describe "FixtureKit integration" do
1636
describe "fixture preload timing" do
1737
fixture "teams/basic"
@@ -220,6 +240,15 @@ module FixtureKitIntegrationTimeHelpers
220240
end
221241
end
222242

243+
describe "fixture with auto-included shared examples", :include_shared_fixture_test do
244+
fixture "teams/basic"
245+
246+
it "works in the host group" do
247+
expect(fixture.alice.name).to eq("Alice")
248+
puts "FKIT_ASSERT:SHARED_EXAMPLE_HOST_FIXTURE"
249+
end
250+
end
251+
223252
describe "fixture instance reader without declaration" do
224253
it "raises a helpful error message" do
225254
expect do

spec/integration/dummy_app_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ def run_dummy_tests
7676
"FKIT_ASSERT:UNDECLARED_FIXTURE_READER"
7777
]
7878

79+
if INTEGRATION_FRAMEWORK == "rspec"
80+
expected_markers += [
81+
"FKIT_ASSERT:SHARED_EXAMPLE_FIXTURE_ACCESS",
82+
"FKIT_ASSERT:SHARED_EXAMPLE_HOST_FIXTURE"
83+
]
84+
end
85+
7986
expected_markers.each do |marker|
8087
expect(output).to include(marker), "Expected marker #{marker.inspect} in output.\nOutput:\n#{output}"
8188
end

spec/unit/rspec_entrypoint_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ def build_group(parent_metadata = {})
109109
@fixture_kit_before_context_hook
110110
end
111111

112+
define_singleton_method(:update_inherited_metadata) do |updates|
113+
metadata.update(updates)
114+
end
115+
112116
define_singleton_method(:append_after) do |scope, &block|
113117
raise "Unexpected scope: #{scope}" unless scope == :context
114118

0 commit comments

Comments
 (0)