Skip to content

Commit

Permalink
Merge pull request #1921 from Shopify/vs/handle_fixtures_with_no_model
Browse files Browse the repository at this point in the history
Handle fixtures with no associated model
  • Loading branch information
vinistock authored Jun 14, 2024
2 parents a983c84 + f5c6053 commit 9a65f59
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
15 changes: 10 additions & 5 deletions lib/tapioca/dsl/compilers/active_record_fixtures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class ActiveRecordFixtures < Compiler
extend T::Sig

ConstantType = type_member { { fixed: T.class_of(ActiveSupport::TestCase) } }
MISSING = Object.new

sig { override.void }
def decorate
Expand All @@ -46,6 +47,7 @@ def decorate
method_names_from_eager_fixture_loader
end

method_names.select! { |name| fixture_class_mapping_from_fixture_files[name] != MISSING }
return if method_names.empty?

root.create_path(constant) do |mod|
Expand Down Expand Up @@ -96,15 +98,14 @@ def method_names_from_lazy_fixture_loader
T.unsafe(fixture_loader).fixture_sets.keys
end

sig { returns(T::Array[Symbol]) }
sig { returns(T::Array[String]) }
def method_names_from_eager_fixture_loader
fixture_loader.ancestors # get all ancestors from class that includes AR fixtures
.drop(1) # drop the anonymous class itself from the array
.reject(&:name) # only collect anonymous ancestors because fixture methods are always on an anonymous module
.map! do |mod|
[mod.private_instance_methods(false), mod.instance_methods(false)]
.flat_map do |mod|
mod.private_instance_methods(false).map(&:to_s) + mod.instance_methods(false).map(&:to_s)
end
.flatten # merge methods into a single list
end

sig { params(mod: RBI::Scope, name: String).void }
Expand Down Expand Up @@ -190,10 +191,14 @@ def fixture_class_mapping_from_fixture_files
next unless ::File.file?(file)

ActiveRecord::FixtureSet::File.open(file) do |fh|
fixture_name = file.delete_prefix(path.to_s).delete_prefix("/").delete_suffix(".yml")
next unless fh.model_class

fixture_name = file.delete_prefix(path.to_s).delete_prefix("/").delete_suffix(".yml")
mapping[fixture_name] = fh.model_class
rescue ActiveRecord::Fixture::FormatError
# For fixtures that are not associated to any models and just contain raw data or fixtures that
# contain invalid formatting, we want to skip them and avoid crashing
mapping[fixture_name] = MISSING
end
end
end
Expand Down
34 changes: 34 additions & 0 deletions spec/tapioca/dsl/compilers/active_record_fixtures_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,40 @@ class User
assert_equal(expected, rbi_for("ActiveSupport::TestCase"))
end

it "ignores fixtures that do not have an associated model" do
add_content_file("test/fixtures/serialized_data.yml", <<~YAML)
---
field1: 123
name: Hello
YAML

add_content_file("test/fixtures/posts.yml", <<~YAML)
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: NilClass, other_fixtures: NilClass).returns(T::Array[Post]) }
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(fixture_name = nil, *other_fixtures); end
end
RBI

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

it "generates methods for fixtures" do
add_content_file("test/fixtures/posts.yml", <<~YAML)
super_post:
Expand Down

0 comments on commit 9a65f59

Please sign in to comment.