Skip to content

Include ActiveRecord::TestFixtures in the fixtures RBI - #2707

Merged
KaanOzkan merged 3 commits into
Shopify:mainfrom
mokevnin:fixtures-include
Sep 3, 2026
Merged

Include ActiveRecord::TestFixtures in the fixtures RBI#2707
KaanOzkan merged 3 commits into
Shopify:mainfrom
mokevnin:fixtures-include

Conversation

@mokevnin

@mokevnin mokevnin commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Motivation

Rails mixes ActiveRecord::TestFixtures into ActiveSupport::TestCase from the :active_support_test_case load hook in rails/test_help.rb. That file is required from an app's test_helper.rb, so the hook never runs during RBI generation, the include never makes it into the gem RBI, and Sorbet doesn't see the class methods the module contributes through mixes_in_class_methods — most visibly fixtures:

class PostTest < ActiveSupport::TestCase
  fixtures :all # Method `fixtures` does not exist on `T.class_of(PostTest)` (7003)
end

Today every Rails app using fixtures shims this by hand (a sorbet/rbi/shims entry, or a local DSL compiler that emits nothing but the include). ActiveRecordFixtures already targets ActiveSupport::TestCase and already knows Rails is loaded, so it's the natural place to make the include explicit.

Implementation

One line in decoratemod.create_include("ActiveRecord::TestFixtures") — inside the existing create_path.

The early return now sits above the select! that drops fixture sets whose model constant can't be resolved, so the two cases it used to conflate are separated: an app with no fixture files at all still generates no RBI, while an app that has fixture files but no matching models gets an RBI with just the include (it writes fixtures :all too).

Tests

spec/tapioca/dsl/compilers/active_record_fixtures_spec.rb updated for the extra line, plus a new case for fixtures with no associated model at all; the whole file passes. bin/typecheck and rubocop are clean, and manual/ is regenerated via bin/docs.

@mokevnin
mokevnin requested a review from a team as a code owner August 28, 2026 17:07

@KaanOzkan KaanOzkan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a unique change but I think it's beneficial to have it in the compiler as you said.

# ~~~
#
# The `include` is generated because Rails mixes `ActiveRecord::TestFixtures` into
# `ActiveSupport::TestCase` from the `active_record.test_fixtures` railtie initializer, which

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find that initializer, I think it's being included through this load hook https://github.com/rails/rails/blob/4130768a1b0d95da640ac792920e54988cf2d12f/railties/lib/rails/test_help.rb#L15-L24. Can we change the wording here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, there is no such initializer — thanks for digging. It's the :active_support_test_case load hook in rails/test_help.rb, which an app requires from test_helper.rb, so it never runs during RBI generation. Reworded here, in manual/ and in the PR description.

Comment thread lib/tapioca/dsl/compilers/active_record_fixtures.rb
@KaanOzkan KaanOzkan added the enhancement New feature or request label Sep 2, 2026
mokevnin and others added 2 commits September 2, 2026 17:57
Rails mixes `ActiveRecord::TestFixtures` into `ActiveSupport::TestCase` from the
`active_record.test_fixtures` railtie initializer. Initializers do not run during
gem RBI generation, so the include is missing from the gem RBI and Sorbet never
sees the class methods the module contributes through `mixes_in_class_methods` —
most visibly `fixtures`, so `fixtures :all` in a test case is an error under
`srb tc` unless every app shims it by hand.

The compiler already targets `ActiveSupport::TestCase` and knows Rails is loaded,
so it is the natural place to make the include explicit.
…ed fixtures

Two fixes from review.

The include does not come from a railtie initializer — there is none. It comes
from the `:active_support_test_case` load hook in `rails/test_help.rb`, which an
app requires from `test_helper.rb`, so it never runs during RBI generation.
Reword the comment and the manual accordingly.

The early return sat below the `select!` that drops fixture sets whose model
constant cannot be resolved, so an app with fixture files but no matching models
wrote `fixtures :all` and still got no include. Move the return above the
`select!`: apps with no fixture files at all keep generating nothing, everything
else gets the include.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Remove the accessor-dependent early return so the DSL RBI always records the Rails test mixin. Combine the no-fixture output and typechecking coverage, and clarify why the runtime `include` is otherwise missing.
@KaanOzkan
KaanOzkan enabled auto-merge September 3, 2026 13:54
@KaanOzkan
KaanOzkan merged commit 514a5fa into Shopify:main Sep 3, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants