diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52fa6cafb..ba6cfc8ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,7 @@ jobs: - 3.1.4 - 3.0.6 appraisal: + - rails_7_1 - rails_7_0 - rails_6_1 adapter: @@ -38,9 +39,8 @@ jobs: - postgresql exclude: - { ruby: 3.2.2, appraisal: rails_6_1 } - - { ruby: 3.1.4, appraisal: rails_5_2 } - - { ruby: 3.0.6, appraisal: rails_5_2 } - { ruby: 3.0.6, appraisal: rails_7_0 } + - { ruby: 3.0.6, appraisal: rails_7_1 } env: DATABASE_ADAPTER: ${{ matrix.adapter }} BUNDLE_GEMFILE: gemfiles/${{ matrix.appraisal }}.gemfile diff --git a/Appraisals b/Appraisals index bab3a9ed9..f24fbf8e5 100644 --- a/Appraisals +++ b/Appraisals @@ -68,3 +68,31 @@ appraise 'rails_7_0' do gem 'sqlite3', '~> 1.4' gem 'pg', '~> 1.1' end + +appraise 'rails_7_1' do + instance_eval(&shared_spring_dependencies) + instance_eval(&controller_test_dependency) + + gem 'rails', '7.1.0' + gem 'sprockets-rails' + gem 'puma', '~> 6.0' + gem 'importmap-rails' + gem 'turbo-rails' + gem 'stimulus-rails' + gem 'jbuilder' + gem 'bootsnap', require: false + gem 'capybara' + gem 'selenium-webdriver' + gem 'webdrivers' + + # test dependencies + gem 'rspec-rails', '~> 6.0' + gem 'shoulda-context', '~> 2.0.0' + + # other dependencies + gem 'bcrypt', '~> 3.1.7' + + # Database adapters + gem 'sqlite3', '~> 1.4' + gem 'pg', '~> 1.1' +end diff --git a/gemfiles/rails_7_1.gemfile b/gemfiles/rails_7_1.gemfile new file mode 100644 index 000000000..22a183d93 --- /dev/null +++ b/gemfiles/rails_7_1.gemfile @@ -0,0 +1,42 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "2.4.0" +gem "bundler", "~> 2.0" +gem "pry" +gem "pry-byebug" +gem "rake", "13.0.1" +gem "rspec", "~> 3.9" +gem "rubocop", require: false +gem "rubocop-packaging", require: false +gem "rubocop-rails", require: false +gem "warnings_logger" +gem "zeus", require: false +gem "fssm" +gem "redcarpet" +gem "rouge" +gem "yard" +gem "spring" +gem "spring-watcher-listen", "~> 2.0.0" +gem "rails-controller-testing", ">= 1.0.1" +gem "rails", "7.1.0" +gem "sprockets-rails" +gem "puma", "~> 6.0" +gem "importmap-rails" +gem "turbo-rails" +gem "stimulus-rails" +gem "jbuilder" +gem "bootsnap", require: false +gem "capybara" +gem "selenium-webdriver" +gem "webdrivers" +gem "rspec-rails", "~> 6.0" +gem "shoulda-context", "~> 2.0.0" +gem "bcrypt", "~> 3.1.7" +gem "sqlite3", "~> 1.4" +gem "pg", "~> 1.1" + +if RUBY_VERSION >= "3.1" && RUBY_VERSION < "3.2" + gem "error_highlight", ">= 0.4.0", platforms: [:ruby] +end diff --git a/gemfiles/rails_7_1.gemfile.lock b/gemfiles/rails_7_1.gemfile.lock new file mode 100644 index 000000000..7cbc7e9f7 --- /dev/null +++ b/gemfiles/rails_7_1.gemfile.lock @@ -0,0 +1,362 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.1.0) + actionpack (= 7.1.0) + activesupport (= 7.1.0) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + zeitwerk (~> 2.6) + actionmailbox (7.1.0) + actionpack (= 7.1.0) + activejob (= 7.1.0) + activerecord (= 7.1.0) + activestorage (= 7.1.0) + activesupport (= 7.1.0) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.1.0) + actionpack (= 7.1.0) + actionview (= 7.1.0) + activejob (= 7.1.0) + activesupport (= 7.1.0) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.2) + actionpack (7.1.0) + actionview (= 7.1.0) + activesupport (= 7.1.0) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.0) + actionpack (= 7.1.0) + activerecord (= 7.1.0) + activestorage (= 7.1.0) + activesupport (= 7.1.0) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.1.0) + activesupport (= 7.1.0) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.0) + activesupport (= 7.1.0) + globalid (>= 0.3.6) + activemodel (7.1.0) + activesupport (= 7.1.0) + activerecord (7.1.0) + activemodel (= 7.1.0) + activesupport (= 7.1.0) + timeout (>= 0.4.0) + activestorage (7.1.0) + actionpack (= 7.1.0) + activejob (= 7.1.0) + activerecord (= 7.1.0) + activesupport (= 7.1.0) + marcel (~> 1.0) + activesupport (7.1.0) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) + addressable (2.8.5) + public_suffix (>= 2.0.2, < 6.0) + appraisal (2.4.0) + bundler + rake + thor (>= 0.14.0) + ast (2.4.2) + base64 (0.1.1) + bcrypt (3.1.19) + bigdecimal (3.1.4) + bootsnap (1.16.0) + msgpack (~> 1.2) + builder (3.2.4) + byebug (11.1.3) + capybara (3.39.2) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + coderay (1.1.3) + concurrent-ruby (1.2.2) + connection_pool (2.4.1) + crass (1.0.6) + date (3.3.3) + diff-lcs (1.5.0) + drb (2.1.1) + ruby2_keywords + erubi (1.12.0) + ffi (1.16.3) + fssm (0.2.10) + globalid (1.2.1) + activesupport (>= 6.1) + i18n (1.14.1) + concurrent-ruby (~> 1.0) + importmap-rails (1.2.1) + actionpack (>= 6.0.0) + railties (>= 6.0.0) + io-console (0.6.0) + irb (1.8.1) + rdoc + reline (>= 0.3.8) + jbuilder (2.11.5) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) + json (2.6.3) + language_server-protocol (3.17.0.3) + listen (3.8.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + loofah (2.21.3) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) + matrix (0.4.2) + method_source (1.0.0) + mini_mime (1.1.5) + minitest (5.20.0) + msgpack (1.7.2) + mutex_m (0.1.2) + net-imap (0.4.0) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.1) + timeout + net-smtp (0.4.0) + net-protocol + nio4r (2.5.9) + nokogiri (1.15.4-arm64-darwin) + racc (~> 1.4) + nokogiri (1.15.4-x86_64-linux) + racc (~> 1.4) + parallel (1.23.0) + parser (3.2.2.4) + ast (~> 2.4.1) + racc + pg (1.5.4) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.10.1) + byebug (~> 11.0) + pry (>= 0.13, < 0.15) + psych (5.1.0) + stringio + public_suffix (5.0.3) + puma (6.4.0) + nio4r (~> 2.0) + racc (1.7.1) + rack (3.0.8) + rack-session (2.0.0) + rack (>= 3.0.0) + rack-test (2.1.0) + rack (>= 1.3) + rackup (2.1.0) + rack (>= 3) + webrick (~> 1.8) + rails (7.1.0) + actioncable (= 7.1.0) + actionmailbox (= 7.1.0) + actionmailer (= 7.1.0) + actionpack (= 7.1.0) + actiontext (= 7.1.0) + actionview (= 7.1.0) + activejob (= 7.1.0) + activemodel (= 7.1.0) + activerecord (= 7.1.0) + activestorage (= 7.1.0) + activesupport (= 7.1.0) + bundler (>= 1.15.0) + railties (= 7.1.0) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (7.1.0) + actionpack (= 7.1.0) + activesupport (= 7.1.0) + irb + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) + rainbow (3.1.1) + rake (13.0.1) + rb-fsevent (0.11.2) + rb-inotify (0.10.1) + ffi (~> 1.0) + rdoc (6.5.0) + psych (>= 4.0.0) + redcarpet (3.6.0) + regexp_parser (2.8.1) + reline (0.3.9) + io-console (~> 0.5) + rexml (3.2.6) + rouge (4.1.3) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.6) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-rails (6.0.3) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.12) + rspec-expectations (~> 3.12) + rspec-mocks (~> 3.12) + rspec-support (~> 3.12) + rspec-support (3.12.1) + rubocop (1.56.4) + base64 (~> 0.1.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.2.2.3) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.28.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.29.0) + parser (>= 3.2.1.0) + rubocop-packaging (0.5.2) + rubocop (>= 1.33, < 2.0) + rubocop-rails (2.21.2) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + ruby-progressbar (1.13.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + selenium-webdriver (4.10.0) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) + shoulda-context (2.0.0) + spring (2.1.1) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (4.2.1) + concurrent-ruby (~> 1.0) + rack (>= 2.2.4, < 4) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) + sqlite3 (1.6.6-arm64-darwin) + sqlite3 (1.6.6-x86_64-linux) + stimulus-rails (1.2.2) + railties (>= 6.0.0) + stringio (3.0.8) + thor (1.2.2) + timeout (0.4.0) + turbo-rails (1.4.0) + actionpack (>= 6.0.0) + activejob (>= 6.0.0) + railties (>= 6.0.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (2.5.0) + warnings_logger (0.1.1) + webdrivers (5.3.1) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (~> 4.0, < 4.11) + webrick (1.8.1) + websocket (1.2.10) + websocket-driver (0.7.6) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + yard (0.9.34) + zeitwerk (2.6.12) + zeus (0.15.14) + method_source (>= 0.6.7) + +PLATFORMS + arm64-darwin-22 + x86_64-linux + +DEPENDENCIES + appraisal (= 2.4.0) + bcrypt (~> 3.1.7) + bootsnap + bundler (~> 2.0) + capybara + fssm + importmap-rails + jbuilder + pg (~> 1.1) + pry + pry-byebug + puma (~> 6.0) + rails (= 7.1.0) + rails-controller-testing (>= 1.0.1) + rake (= 13.0.1) + redcarpet + rouge + rspec (~> 3.9) + rspec-rails (~> 6.0) + rubocop + rubocop-packaging + rubocop-rails + selenium-webdriver + shoulda-context (~> 2.0.0) + spring + spring-watcher-listen (~> 2.0.0) + sprockets-rails + sqlite3 (~> 1.4) + stimulus-rails + turbo-rails + warnings_logger + webdrivers + yard + zeus + +BUNDLED WITH + 2.4.13 diff --git a/lib/shoulda/matchers/rails_shim.rb b/lib/shoulda/matchers/rails_shim.rb index 5c903d4e5..079b8d2de 100644 --- a/lib/shoulda/matchers/rails_shim.rb +++ b/lib/shoulda/matchers/rails_shim.rb @@ -146,6 +146,10 @@ def supports_full_attributes_api?(model) model.respond_to?(:attribute_types) end + def validates_column_options? + Gem::Requirement.new('>= 7.1.0').satisfied_by?(active_record_version) + end + private def simply_generate_validation_message( diff --git a/spec/acceptance/rails_integration_spec.rb b/spec/acceptance/rails_integration_spec.rb index ec761f5ac..9f16600da 100644 --- a/spec/acceptance/rails_integration_spec.rb +++ b/spec/acceptance/rails_integration_spec.rb @@ -4,7 +4,21 @@ before do create_rails_application - write_file 'db/migrate/1_create_users.rb', <<-FILE + write_file 'db/migrate/1_create_defaults.rb', <<-FILE + class CreateDefaults < #{migration_class_name} + def self.up + create_table :action_text_rich_texts + create_table :active_storage_variant_records + create_table :active_storage_blobs + create_table :active_storage_attachments + create_table :action_mailbox_inbound_emails do |t| + t.integer :status + end + end + end + FILE + + write_file 'db/migrate/2_create_users.rb', <<-FILE class CreateUsers < #{migration_class_name} def self.up create_table :users do |t| diff --git a/spec/support/unit/active_record/create_table.rb b/spec/support/unit/active_record/create_table.rb index 208207675..ed93268f0 100644 --- a/spec/support/unit/active_record/create_table.rb +++ b/spec/support/unit/active_record/create_table.rb @@ -92,6 +92,7 @@ def add_column_to_table(table, column_name, column_specification) column_specification = column_specification.dup column_type = column_specification.delete(:type) column_options = column_specification.delete(:options) { {} } + column_options.merge!({ _skip_validate_options: true }) if Shoulda::Matchers::RailsShim.validates_column_options? if column_options[:array] && !database_supports_array_columns? raise ArgumentError.new( diff --git a/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb b/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb index 14bcc5006..d711f1b0b 100644 --- a/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb @@ -230,7 +230,7 @@ def params_with_conditional_require(params, *filters) matcher.matches?(controller) - expect(actual_user_params).to eq('some' => 'params') + expect(actual_user_params).to eq ActionController::Parameters.new('some' => 'params') expect(actual_foo_param).to eq 'bar' end @@ -252,7 +252,7 @@ def params_with_conditional_require(params, *filters) matcher.matches?(controller) - expect(actual_user_params).to eq expected_user_params + expect(actual_user_params).to eq ActionController::Parameters.new(expected_user_params) end it 'does not permanently stub the params hash' do diff --git a/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb b/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb index afa52e816..a54c029b2 100644 --- a/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb @@ -56,51 +56,102 @@ expect(&assertion).to fail_with_message(message) end - context 'when the attribute is decorated with serialize' do - context 'and the serializer is a built-in Ruby type' do - context 'and the type is a string' do + if rails_version >= 7.1 + context 'when the attribute is decorated with serialize' do + context 'and the serializer is a built-in Ruby type' do + context 'and the type is a string' do + it 'still works' do + record = record_validating_presence_of(:traits) do + serialize :traits, type: String, coder: YAML + end + + expect(record).to validate_presence_of(:traits) + end + end + + context 'and the type is not a string' do + it 'still works' do + record = record_validating_presence_of(:traits) do + serialize :traits, type: Array, coder: YAML + end + + expect(record).to validate_presence_of(:traits) + end + end + end + + context 'and the serializer is JSON' do it 'still works' do record = record_validating_presence_of(:traits) do - serialize :traits, String + serialize :traits, coder: JSON end expect(record).to validate_presence_of(:traits) end end - context 'and the type is not a string' do + context 'and the serializer is something custom' do it 'still works' do - record = record_validating_presence_of(:traits) do - serialize :traits, Array + serializer = Class.new do + define_singleton_method(:dump) { |value| value } + define_singleton_method(:load) { |value| value } end - expect(record).to validate_presence_of(:traits) + record = record_validating_presence_of(:data) do + serialize :data, coder: serializer + end + + expect(record).to validate_presence_of(:data) end end end + else + context 'when the attribute is decorated with serialize' do + context 'and the serializer is a built-in Ruby type' do + context 'and the type is a string' do + it 'still works' do + record = record_validating_presence_of(:traits) do + serialize :traits, String + end - context 'and the serializer is JSON' do - it 'still works' do - record = record_validating_presence_of(:traits) do - serialize :traits, JSON + expect(record).to validate_presence_of(:traits) + end end - expect(record).to validate_presence_of(:traits) - end - end + context 'and the type is not a string' do + it 'still works' do + record = record_validating_presence_of(:traits) do + serialize :traits, Array + end - context 'and the serializer is something custom' do - it 'still works' do - serializer = Class.new do - define_singleton_method(:dump) { |value| value } - define_singleton_method(:load) { |value| value } + expect(record).to validate_presence_of(:traits) + end end + end + + context 'and the serializer is JSON' do + it 'still works' do + record = record_validating_presence_of(:traits) do + serialize :traits, JSON + end - record = record_validating_presence_of(:data) do - serialize :data, serializer + expect(record).to validate_presence_of(:traits) end + end + + context 'and the serializer is something custom' do + it 'still works' do + serializer = Class.new do + define_singleton_method(:dump) { |value| value } + define_singleton_method(:load) { |value| value } + end + + record = record_validating_presence_of(:data) do + serialize :data, serializer + end - expect(record).to validate_presence_of(:data) + expect(record).to validate_presence_of(:data) + end end end end diff --git a/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb b/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb index 13e564d00..04db4d3c6 100644 --- a/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb @@ -124,12 +124,12 @@ context 'with primary option' do it 'accepts a column that is primary' do - expect(with_table(:custom_id, :integer, primary: true)). - to have_db_column(:id).with_options(primary: true) + expect(with_table_custom_primary_key(:custom_id)). + to have_db_column(:custom_id).with_options(primary: true) end it 'rejects a column that is not primary' do - expect(with_table(:whatever, :integer, primary: false)). + expect(with_table(:whatever, :integer, {})). not_to have_db_column(:whatever).with_options(primary: true) end end @@ -161,9 +161,16 @@ def model(options = {}) end def with_table(column_name, column_type, options) - create_table 'employees' do |table| + create_table 'employees', id: false do |table| table.__send__(column_type, column_name, **options) end define_model_class('Employee').new end + + def with_table_custom_primary_key(column_name, options = {}) + create_table 'employees', id: false do |table| + table.__send__(:primary_key, column_name, **options) + end + define_model_class('Employee').new + end end diff --git a/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb b/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb index 574ee7bea..399a02a45 100644 --- a/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb @@ -67,7 +67,11 @@ it 'does not match when missing a token column' do create_table(:users) - invalid_model = define_model_class(:User) { has_secure_token } + invalid_model = if rails_version >= 7.1 + define_model_class(:User) { has_secure_token(on: :create) } + else + define_model_class(:User) { has_secure_token } + end expected_message = 'Expected User to have :token as a secure token but the following ' \ @@ -125,9 +129,11 @@ it 'does not match when missing a column for a custom attribute' do create_table(:users) - invalid_model = define_model_class(:User) do - has_secure_token(:auth_token) - end + invalid_model = if rails_version >= 7.1 + define_model_class(:User) { has_secure_token(:auth_token, on: :create) } + else + define_model_class(:User) { has_secure_token(:auth_token) } + end expected_message = 'Expected User to have :auth_token as a secure token but the ' \ diff --git a/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb b/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb index 6f90583c3..7e63b6d1b 100644 --- a/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb @@ -41,38 +41,40 @@ def unserialized_model context 'an attribute that will end up being serialized as YAML' do it 'accepts when the types match' do - expect(with_serialized_attr(Hash)).to serialize(:attr).as(Hash) + expect(with_serialized_attr(type: Hash, coder: JSON)).to serialize(:attr).as(Hash) end it 'rejects when the types do not match' do - expect(with_serialized_attr(Hash)).not_to serialize(:attr).as(String) + expect(with_serialized_attr(type: Hash)).not_to serialize(:attr).as(String) end it 'rejects when using as_instance_of' do - expect(with_serialized_attr(Hash)).not_to serialize(:attr).as_instance_of(Hash) + expect(with_serialized_attr(type: Hash)).not_to serialize(:attr).as_instance_of(Hash) end end context 'a serializer that is an instance of a class' do it 'accepts when using #as_instance_of' do define_serializer(:ExampleSerializer) - expect(with_serialized_attr(ExampleSerializer.new)). + expect(with_serialized_attr(coder: ExampleSerializer.new)). to serialize(:attr).as_instance_of(ExampleSerializer) end it 'rejects when using #as' do define_serializer(:ExampleSerializer) - expect(with_serialized_attr(ExampleSerializer.new)). + expect(with_serialized_attr(coder: ExampleSerializer.new)). not_to serialize(:attr).as(ExampleSerializer) end end - def with_serialized_attr(type = nil) + def with_serialized_attr(type: nil, coder: YAML) + type_or_coder = rails_version >= 7.1 ? nil : type || coder + define_model(:example, attr: :string) do if type - serialize :attr, type + serialize :attr, type_or_coder, type: type, coder: coder else - serialize :attr + serialize :attr, type_or_coder, coder: coder end end.new end