Skip to content

Commit

Permalink
Support fixture class derivation when a model_class is specified
Browse files Browse the repository at this point in the history
  • Loading branch information
TobiasBales committed Apr 16, 2024
1 parent b94e574 commit 389170c
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 4 deletions.
39 changes: 35 additions & 4 deletions lib/tapioca/dsl/compilers/active_record_fixtures.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# typed: strict
# frozen_string_literal: true

return unless defined?(Rails) && defined?(ActiveSupport::TestCase) && defined?(ActiveRecord::TestFixtures)
return unless defined?(Rails) &&
defined?(ActiveSupport::TestCase) &&
defined?(ActiveRecord::TestFixtures) &&
defined?(ActiveRecord::FixtureSet)

module Tapioca
module Dsl
Expand Down Expand Up @@ -127,16 +130,44 @@ def create_fixture_method(mod, name)

sig { params(fixture_name: String).returns(String) }
def return_type_for_fixture(fixture_name)
model_name_from_fixture_sets = T.unsafe(fixture_loader).fixture_sets[fixture_name]
model_name_from_fixture_files = fixture_file_class_mapping[fixture_name]
return model_name_from_fixture_files if model_name_from_fixture_files

model_name_from_fixture_sets = T.unsafe(fixture_loader).fixture_sets[fixture_name]
if model_name_from_fixture_sets
model_name = T.unsafe(ActiveRecord::FixtureSet).default_fixture_model_name(model_name_from_fixture_sets)

model_name = ActiveRecord::FixtureSet.default_fixture_model_name(model_name_from_fixture_sets)
return model_name if Object.const_defined?(model_name)
end

"T.untyped"
end

sig { returns(T::Hash[String, String]) }
def fixture_file_class_mapping
@fixture_file_class_mapping ||= T.let(
begin
fixture_paths = if T.unsafe(fixture_loader).respond_to?(:fixture_paths)
T.unsafe(fixture_loader).fixture_paths
else
T.unsafe(fixture_loader).fixture_path
end

fixture_paths.each_with_object({}) do |path, mapping|
Dir["#{path}{.yml,/{**,*}/*.yml}"].select do |file|
next unless ::File.file?(file)

ActiveRecord::FixtureSet::File.open(file) do |fh|
next unless fh.model_class

fixuture_name = file.delete_prefix(path.to_s).delete_prefix("/").delete_suffix(".yml")
mapping[fixuture_name] = fh.model_class
end
end
end
end,
T.nilable(T::Hash[String, String]),
)
end
end
end
end
Expand Down
16 changes: 16 additions & 0 deletions sorbet/rbi/shims/active_record_fixture_set.rbi
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# typed: strict

# ActiveRecord::TestFixtures can't be loaded outside of a Rails application

class ActiveRecord::FixtureSet
sig { params(name: String).returns(String) }
def self.default_fixture_model_name(name); end
end

class ActiveRecord::FixtureSet::File
sig { returns(T.nilable(String)) }
def modle_class; end

sig params(filename: String, blk: T.proc.params(arg0: ActiveRecord::FixtureSet::File).void)
def self.open(filename, &block); end
end
29 changes: 29 additions & 0 deletions spec/tapioca/dsl/compilers/active_record_fixtures_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,35 @@ def users(fixture_name, *other_fixtures); end
assert_equal(expected, rbi_for("ActiveSupport::TestCase"))
end

it "generates methods for fixtures with explicit class name" do
add_content_file("test/fixtures/posts_with_other_names.yml", <<~YAML)
_fixture:
model_class: Post
super_post:
title: An incredible Ruby post
author: Johnny Developer
created_at: 2021-09-08 11:00:00
updated_at: 2021-09-08 11:00:00
YAML

add_ruby_file("test_models.rb", <<~RUBY)
class Post < ActiveRecord::Base
end
RUBY

expected = <<~RBI
# typed: strong
class ActiveSupport::TestCase
sig { params(fixture_name: T.any(String, Symbol), other_fixtures: NilClass).returns(Post) }
sig { params(fixture_name: T.any(String, Symbol), other_fixtures: T.any(String, Symbol)).returns(T::Array[Post]) }
def posts_with_other_names(fixture_name, *other_fixtures); end
end
RBI

assert_equal(expected, rbi_for("ActiveSupport::TestCase"))
end

it "generates methods for fixtures with a fallback to T.untyped if no matching model exists" do
add_content_file("test/fixtures/posts.yml", <<~YAML)
super_post:
Expand Down

0 comments on commit 389170c

Please sign in to comment.