From 6902cbce1b3ea7babab588171d413b9b78cb3f0f Mon Sep 17 00:00:00 2001 From: Andrew Novoselac Date: Mon, 13 Mar 2023 15:06:31 -0400 Subject: [PATCH] Introducs `TestFixtures#fixture_paths`. Multiple fixture paths can now be specified using the `#fixture_paths` accessor. --- actionmailbox/test/test_helper.rb | 8 ++--- actionpack/test/controller/test_case_test.rb | 11 ++++--- actiontext/test/test_helper.rb | 8 ++--- actionview/test/active_record_unit.rb | 2 +- activerecord/CHANGELOG.md | 15 ++++++++++ activerecord/lib/active_record/fixtures.rb | 24 +++++++-------- .../lib/active_record/test_fixtures.rb | 29 +++++++++++++++---- activerecord/test/cases/fixtures_test.rb | 25 ++++++++++++---- activerecord/test/cases/test_case.rb | 4 +-- activerecord/test/cases/test_fixtures_test.rb | 2 +- activestorage/test/test_helper.rb | 2 +- .../plugin/templates/test/test_helper.rb.tt | 8 ++--- railties/lib/rails/test_help.rb | 6 ++-- .../test/generators/plugin_generator_test.rb | 2 +- 14 files changed, 97 insertions(+), 49 deletions(-) diff --git a/actionmailbox/test/test_helper.rb b/actionmailbox/test/test_helper.rb index bd641b424a2..65e6416272a 100644 --- a/actionmailbox/test/test_helper.rb +++ b/actionmailbox/test/test_helper.rb @@ -14,10 +14,10 @@ require "webmock/minitest" require "rails/test_unit/reporter" Rails::TestUnitReporter.executable = "bin/test" -if ActiveSupport::TestCase.respond_to?(:fixture_path=) - ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) - ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path - ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" +if ActiveSupport::TestCase.respond_to?(:fixture_paths=) + ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)] + ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths + ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files" ActiveSupport::TestCase.fixtures :all end diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index 8d18dbb2050..b3d4d42186a 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -6,7 +6,10 @@ require "active_support/json/decoding" require "rails/engine" class TestCaseTest < ActionController::TestCase - def self.fixture_path; end + def self.fixture_paths + [] + end + self.file_fixture_path = File.expand_path("../fixtures/multipart", __dir__) class TestController < ActionController::Base @@ -931,14 +934,14 @@ class TestCaseTest < ActionController::TestCase assert_equal "45142", @response.body end - def test_fixture_file_upload_ignores_fixture_path_given_full_path - TestCaseTest.stub :fixture_path, __dir__ do + def test_fixture_file_upload_ignores_fixture_paths_given_full_path + TestCaseTest.stub :fixture_paths, __dir__ do uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpeg") assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read end end - def test_fixture_file_upload_ignores_nil_fixture_path + def test_fixture_file_upload_ignores_empty_fixture_paths uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpeg") assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read end diff --git a/actiontext/test/test_helper.rb b/actiontext/test/test_helper.rb index bd95678c263..1504e7fd04a 100644 --- a/actiontext/test/test_helper.rb +++ b/actiontext/test/test_helper.rb @@ -16,10 +16,10 @@ Rails::TestUnitReporter.executable = "bin/test" I18n.enforce_available_locales = false # Load fixtures from the engine -if ActiveSupport::TestCase.respond_to?(:fixture_path=) - ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) - ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path - ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" +if ActiveSupport::TestCase.respond_to?(:fixture_paths=) + ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)] + ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths + ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files" ActiveSupport::TestCase.fixtures :all end diff --git a/actionview/test/active_record_unit.rb b/actionview/test/active_record_unit.rb index 5c56638d504..f49717a5b83 100644 --- a/actionview/test/active_record_unit.rb +++ b/actionview/test/active_record_unit.rb @@ -94,7 +94,7 @@ class ActiveRecordTestCase < ActionController::TestCase # Set our fixture path if ActiveRecordTestConnector.able_to_connect - self.fixture_path = [FIXTURE_LOAD_PATH] + self.fixture_paths = [FIXTURE_LOAD_PATH] self.use_transactional_tests = false end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 8d49924b25e..24d6f3fc301 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,18 @@ +* Introduce `TestFixtures#fixture_paths`. + + Multiple fixture paths can now be specified using the `#fixture_paths` accessor. + Apps will continue to have `test/fixtures` as their one fixture path by default, + but additional fixture paths can be specified. + + ```ruby + ActiveSupport::TestCase.fixture_paths << "component1/test/fixtures" + ActiveSupport::TestCase.fixture_paths << "component2/test/fixtures" + ``` + + `TestFixtures#fixture_path` is now deprecated. + + *Andrew Novoselac* + * Respect `foreign_type` option to `delegated_type` for `{role}_class` method. Usage of `delegated_type` with non-conventional `{role}_type` column names can now be specified with `foreign_type` option. diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 1ff93a88174..1c184667f73 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -17,8 +17,8 @@ module ActiveRecord # \Fixtures are a way of organizing data that you want to test against; in short, sample data. # - # They are stored in YAML files, one file per model, which are placed in the directory - # appointed by ActiveSupport::TestCase.fixture_path=(path) (this is automatically + # They are stored in YAML files, one file per model, which are placed in the directories + # appointed by ActiveSupport::TestCase.fixture_paths=(path) (this is automatically # configured for Rails, so you can just put your files in /test/fixtures/). # The fixture file ends with the +.yml+ file extension, for example: # /test/fixtures/web_sites.yml). @@ -552,7 +552,7 @@ module ActiveRecord end end - def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block) + def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block) fixture_set_names = Array(fixture_set_names).map(&:to_s) class_names = ClassCache.new class_names, config @@ -565,7 +565,7 @@ module ActiveRecord if fixture_files_to_read.any? fixtures_map = read_and_insert( - fixtures_directory, + Array(fixtures_directories), fixture_files_to_read, class_names, connection, @@ -591,15 +591,16 @@ module ActiveRecord end private - def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc: + def read_and_insert(fixtures_directories, fixture_files, class_names, connection) # :nodoc: fixtures_map = {} + directory_glob = "{#{fixtures_directories.join(",")}}" fixture_sets = fixture_files.map do |fixture_set_name| klass = class_names[fixture_set_name] fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new nil, fixture_set_name, klass, - ::File.join(fixtures_directory, fixture_set_name) + ::File.join(directory_glob, fixture_set_name) ) end update_all_loaded_fixtures(fixtures_map) @@ -715,10 +716,13 @@ module ActiveRecord # Loads the fixtures from the YAML file at +path+. # If the file sets the +model_class+ and current instance value is not set, # it uses the file value. + def read_fixture_files(path) - yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f| + yaml_files = Dir["#{path}{.yml,/{**,*}/*.yml}"].select { |f| ::File.file?(f) - } + [yaml_file_path(path)] + } + + raise ArgumentError, "No fixture files found for #{@name}" if yaml_files.empty? yaml_files.each_with_object({}) do |file, fixtures| FixtureSet::File.open(file) do |fh| @@ -730,10 +734,6 @@ module ActiveRecord end end end - - def yaml_file_path(path) - "#{path}.yml" - end end class Fixture # :nodoc: diff --git a/activerecord/lib/active_record/test_fixtures.rb b/activerecord/lib/active_record/test_fixtures.rb index dd4c32a1d40..7d44cdce9f7 100644 --- a/activerecord/lib/active_record/test_fixtures.rb +++ b/activerecord/lib/active_record/test_fixtures.rb @@ -17,7 +17,7 @@ module ActiveRecord end included do - class_attribute :fixture_path, instance_writer: false + class_attribute :fixture_paths, instance_writer: false, default: [] class_attribute :fixture_table_names, default: [] class_attribute :fixture_class_names, default: {} class_attribute :use_transactional_tests, default: true @@ -40,12 +40,24 @@ module ActiveRecord self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys) end + def fixture_path + ActiveRecord.deprecator.warn("TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2. Use #fixture_paths instead.") + fixture_paths + end + + def fixture_path=(path) + ActiveRecord.deprecator.warn("TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2. Use #fixture_paths instead.") + self.fixture_paths = Array(path) + end + def fixtures(*fixture_set_names) if fixture_set_names.first == :all - raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank? - fixture_set_names = Dir[::File.join(fixture_path, "{**,*}/*.{yml}")].uniq - fixture_set_names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path - fixture_set_names.map! { |f| f[fixture_path.to_s.size..-5].delete_prefix("/") } + raise StandardError, "No fixture path found. Please set `#{self}.fixture_paths`." if fixture_paths.blank? + fixture_set_names = fixture_paths.flat_map do |path| + names = Dir[::File.join(path, "{**,*}/*.{yml}")].uniq + names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path + names.map! { |f| f[path.to_s.size..-5].delete_prefix("/") } + end.uniq else fixture_set_names = fixture_set_names.flatten.map(&:to_s) end @@ -81,6 +93,11 @@ module ActiveRecord end end + def fixture_path + ActiveRecord.deprecator.warn("TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2. Use #fixture_paths instead.") + fixture_paths + end + def run_in_transaction? use_transactional_tests && !self.class.uses_transaction?(name) @@ -215,7 +232,7 @@ module ActiveRecord end def load_fixtures(config) - ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name) + ActiveRecord::FixtureSet.create_fixtures(fixture_paths, fixture_table_names, fixture_class_names, config).index_by(&:name) end def instantiate_fixtures diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index c079cbd5ce6..5bcb3d4b0e9 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -482,7 +482,7 @@ class FixturesTest < ActiveRecord::TestCase # Ensure that this file never exists assert_empty Dir[nonexistent_fixture_path + "*"] - assert_raise(Errno::ENOENT) do + assert_raise(ArgumentError) do ActiveRecord::FixtureSet.new(nil, "companies", Company, nonexistent_fixture_path) end end @@ -1125,7 +1125,7 @@ end class LoadAllFixturesTest < ActiveRecord::TestCase def test_all_there - self.class.fixture_path = FIXTURES_ROOT + "/all" + self.class.fixture_paths = [FIXTURES_ROOT + "/all"] self.class.fixtures :all if File.symlink? FIXTURES_ROOT + "/all/admin" @@ -1136,9 +1136,22 @@ class LoadAllFixturesTest < ActiveRecord::TestCase end end +class LoadAllFixturesWithArrayTest < ActiveRecord::TestCase + def test_all_there + self.class.fixture_paths = [FIXTURES_ROOT + "/all", FIXTURES_ROOT + "/categories"] + self.class.fixtures :all + + if File.symlink? FIXTURES_ROOT + "/all/admin" + assert_equal %w(admin/accounts admin/users developers namespaced/accounts people special_categories subsubdir/arbitrary_filename tasks), fixture_table_names.sort + end + ensure + ActiveRecord::FixtureSet.reset_cache + end +end + class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase def test_all_there - self.class.fixture_path = Pathname.new(FIXTURES_ROOT).join("all") + self.class.fixture_paths = [Pathname.new(FIXTURES_ROOT).join("all")] self.class.fixtures :all if File.symlink? FIXTURES_ROOT + "/all/admin" @@ -1482,13 +1495,13 @@ class NilFixturePathTest < ActiveRecord::TestCase error = assert_raises(StandardError) do TestCase = Class.new(ActiveRecord::TestCase) TestCase.class_eval do - self.fixture_path = nil + self.fixture_paths = nil fixtures :all end end assert_equal <<~MSG.squish, error.message No fixture path found. - Please set `NilFixturePathTest::TestCase.fixture_path`. + Please set `NilFixturePathTest::TestCase.fixture_paths`. MSG end end @@ -1499,7 +1512,7 @@ class FileFixtureConflictTest < ActiveRecord::TestCase end test "ignores file fixtures" do - self.class.fixture_path = FIXTURES_ROOT + "/all" + self.class.fixture_paths = [FIXTURES_ROOT + "/all"] self.class.fixtures :all assert_equal %w(developers namespaced/accounts people tasks), fixture_table_names.sort diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index b5ec7a56bef..81409e59a7a 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -27,12 +27,12 @@ module ActiveRecord include LoadSchemaHelper extend LoadSchemaHelper - self.fixture_path = FIXTURES_ROOT + self.fixture_paths = [FIXTURES_ROOT] self.use_instantiated_fixtures = false self.use_transactional_tests = true def create_fixtures(*fixture_set_names, &block) - ActiveRecord::FixtureSet.create_fixtures(ActiveRecord::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block) + ActiveRecord::FixtureSet.create_fixtures(ActiveRecord::TestCase.fixture_paths, fixture_set_names, fixture_class_names, &block) end def teardown diff --git a/activerecord/test/cases/test_fixtures_test.rb b/activerecord/test/cases/test_fixtures_test.rb index 9026d7619cf..64941026611 100644 --- a/activerecord/test/cases/test_fixtures_test.rb +++ b/activerecord/test/cases/test_fixtures_test.rb @@ -32,7 +32,7 @@ class TestFixturesTest < ActiveRecord::TestCase klass = Class.new(Minitest::Test) do include ActiveRecord::TestFixtures - self.fixture_path = tmp_dir + self.fixture_paths = [tmp_dir] self.use_transactional_tests = true fixtures :all diff --git a/activestorage/test/test_helper.rb b/activestorage/test/test_helper.rb index 6972e00f02d..70a3b7bb93e 100644 --- a/activestorage/test/test_helper.rb +++ b/activestorage/test/test_helper.rb @@ -25,7 +25,7 @@ class ActiveSupport::TestCase include ActiveRecord::TestFixtures - self.fixture_path = File.expand_path("fixtures", __dir__) + self.fixture_paths = [File.expand_path("fixtures", __dir__)] setup do ActiveStorage::Current.url_options = { protocol: "https://", host: "example.com", port: nil } diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt index 3984f438c13..23c6ceccfd2 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt @@ -12,10 +12,10 @@ require "rails/test_help" <% unless options[:skip_active_record] -%> # Load fixtures from the engine -if ActiveSupport::TestCase.respond_to?(:fixture_path=) - ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) - ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path - ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" +if ActiveSupport::TestCase.respond_to?(:fixture_paths=) + ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)] + ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths + ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files" ActiveSupport::TestCase.fixtures :all end <% end -%> diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 23492a62e9c..b7e658710b9 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -24,12 +24,12 @@ if defined?(ActiveRecord::Base) include ActiveRecord::TestDatabases include ActiveRecord::TestFixtures - self.fixture_path = "#{Rails.root}/test/fixtures/" - self.file_fixture_path = fixture_path + "files" + self.fixture_paths << "#{Rails.root}/test/fixtures/" + self.file_fixture_path = "#{Rails.root}/test/fixtures/files" end ActiveSupport.on_load(:action_dispatch_integration_test) do - self.fixture_path = ActiveSupport::TestCase.fixture_path + self.fixture_paths += ActiveSupport::TestCase.fixture_paths end else ActiveSupport.on_load(:active_support_test_case) do diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 198c71dabe7..ca2d15276be 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -373,7 +373,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "test/test_helper.rb" do |content| assert_match(/ActiveRecord::Migrator\.migrations_paths.+\.\.\/test\/dummy\/db\/migrate/, content) assert_match(/ActiveRecord::Migrator\.migrations_paths.+<<.+\.\.\/db\/migrate/, content) - assert_match(/ActionDispatch::IntegrationTest\.fixture_path = ActiveSupport::TestCase\.fixture_pat/, content) + assert_match(/ActionDispatch::IntegrationTest\.fixture_paths = ActiveSupport::TestCase\.fixture_pat/, content) assert_no_match(/Rails::TestUnitReporter\.executable = "bin\/test"/, content) end assert_no_file "bin/test"