Blob Blame History Raw
From 948b67be61e09e3225eb6d5dbb47c3e4ed7a8065 Mon Sep 17 00:00:00 2001
From: Peter Goldstein <peter.m.goldstein@gmail.com>
Date: Sat, 8 Jan 2022 15:51:01 -0800
Subject: [PATCH] Fix arguments for have_enqueued_mail matcher

Add additional logic to the ActionMailer argument parsing to accomodate for differences under Ruby 3.1/Rails 6.1

Co-authored-by: Fabio Napoleoni <f.napoleoni@gmail.com>
Co-authored-by: Phil Pirozhkov <hello@fili.pp.ru>
---
 lib/rspec/rails/feature_check.rb              |  4 ++++
 .../rails/matchers/have_enqueued_mail.rb      | 20 +++++++++++++++----
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/lib/rspec/rails/feature_check.rb b/lib/rspec/rails/feature_check.rb
index 4a4d855d75..a866acc79b 100644
--- a/lib/rspec/rails/feature_check.rb
+++ b/lib/rspec/rails/feature_check.rb
@@ -43,6 +43,10 @@ def has_action_mailbox?
         defined?(::ActionMailbox)
       end
 
+      def ruby_3_1?
+        RUBY_VERSION >= "3.1"
+      end
+
       def type_metatag(type)
         "type: :#{type}"
       end
diff --git a/lib/rspec/rails/matchers/have_enqueued_mail.rb b/lib/rspec/rails/matchers/have_enqueued_mail.rb
index 92d7f1e9fb..86aae6c5cc 100644
--- a/lib/rspec/rails/matchers/have_enqueued_mail.rb
+++ b/lib/rspec/rails/matchers/have_enqueued_mail.rb
@@ -8,7 +8,6 @@
 module RSpec
   module Rails
     module Matchers
-      # rubocop: disable Metrics/ClassLength
       # Matcher class for `have_enqueued_mail`. Should not be instantiated directly.
       #
       # @private
@@ -92,7 +91,7 @@ def arguments_match?(job)
 
         def process_arguments(job, given_mail_args)
           # Old matcher behavior working with all builtin classes but ActionMailer::MailDeliveryJob
-          return given_mail_args unless defined?(ActionMailer::MailDeliveryJob) && job[:job] <= ActionMailer::MailDeliveryJob
+          return given_mail_args if use_given_mail_args?(job)
 
           # If matching args starts with a hash and job instance has params match with them
           if given_mail_args.first.is_a?(Hash) && job[:args][3]['params'].present?
@@ -101,6 +101,13 @@ def process_arguments(job, given_mail_args)
           end
         end
 
+        def use_given_mail_args?(job)
+          return true if FeatureCheck.has_action_mailer_parameterized? && job[:job] <= ActionMailer::Parameterized::DeliveryJob
+          return false if FeatureCheck.ruby_3_1?
+
+          !(FeatureCheck.has_action_mailer_unified_delivery? && job[:job] <= ActionMailer::MailDeliveryJob)
+        end
+
         def base_mailer_args
           [mailer_class_name, @method_name.to_s, MAILER_JOB_METHOD]
         end
@@ -143,13 +149,20 @@ def mail_job_message(job)
           mailer_args = deserialize_arguments(job)[3..-1]
           mailer_args = mailer_args.first[:args] if unified_mail?(job)
           msg_parts = []
-          msg_parts << "with #{mailer_args}" if mailer_args.any?
+          display_args = display_mailer_args(mailer_args)
+          msg_parts << "with #{display_args}" if display_args.any?
           msg_parts << "on queue #{job[:queue]}" if job[:queue] && job[:queue] != 'mailers'
           msg_parts << "at #{Time.at(job[:at])}" if job[:at]
 
           "#{mailer_method} #{msg_parts.join(', ')}".strip
         end
 
+        def display_mailer_args(mailer_args)
+          return mailer_args unless mailer_args.first.is_a?(Hash) && mailer_args.first.key?(:args)
+
+          mailer_args.first[:args]
+        end
+
         def legacy_mail?(job)
           RSpec::Rails::FeatureCheck.has_action_mailer_legacy_delivery_job? && job[:job] <= ActionMailer::DeliveryJob
         end
@@ -163,7 +176,6 @@ def unified_mail?(job)
           RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? && job[:job] <= ActionMailer::MailDeliveryJob
         end
       end
-      # rubocop: enable Metrics/ClassLength
 
       # @api public
       # Passes if an email has been enqueued inside block.