44require "rspec/mocks/argument_matchers"
55require "rspec/rails/matchers/active_job"
66
7+ # rubocop: disable Metrics/ClassLength
78module RSpec
89 module Rails
910 module Matchers
@@ -12,6 +13,7 @@ module Matchers
1213 # @private
1314 # @see RSpec::Rails::Matchers#have_enqueued_mail
1415 class HaveEnqueuedMail < ActiveJob ::HaveEnqueuedJob
16+
1517 MAILER_JOB_METHOD = 'deliver_now' . freeze
1618
1719 include RSpec ::Mocks ::ArgumentMatchers
@@ -76,7 +78,7 @@ def job_match?(job)
7678 def arguments_match? ( job )
7779 @args =
7880 if @mail_args . any?
79- base_mailer_args + process_arguments ( job , @mail_args )
81+ base_mailer_args + @mail_args
8082 elsif @mailer_class && @method_name
8183 base_mailer_args + [ any_args ]
8284 elsif @mailer_class
@@ -88,38 +90,12 @@ def arguments_match?(job)
8890 super ( job )
8991 end
9092
91- def process_arguments ( job , given_mail_args )
92- # Old matcher behavior working with all builtin classes but ActionMailer::MailDeliveryJob
93- return given_mail_args if use_given_mail_args? ( job )
94-
95- # If matching args starts with a hash and job instance has params match with them
96- if given_mail_args . first . is_a? ( Hash ) && job [ :args ] [ 3 ] [ 'params' ] . present?
97- [ hash_including ( params : given_mail_args [ 0 ] , args : given_mail_args . drop ( 1 ) ) ]
98- else
99- [ hash_including ( args : given_mail_args ) ]
100- end
101- end
102-
103- def use_given_mail_args? ( job )
104- return true if FeatureCheck . has_action_mailer_parameterized? && job [ :job ] <= ActionMailer ::Parameterized ::DeliveryJob
105- return false if FeatureCheck . ruby_3_1?
106-
107- !( FeatureCheck . has_action_mailer_unified_delivery? && job [ :job ] <= ActionMailer ::MailDeliveryJob )
108- end
109-
11093 def base_mailer_args
11194 [ mailer_class_name , @method_name . to_s , MAILER_JOB_METHOD ]
11295 end
11396
11497 def yield_mail_args ( block )
115- proc do |*job_args |
116- mailer_args = job_args - base_mailer_args
117- if mailer_args . first . is_a? ( Hash )
118- block . call ( *mailer_args . first [ :args ] )
119- else
120- block . call ( *mailer_args )
121- end
122- end
98+ proc { |*job_args | block . call ( *( job_args - base_mailer_args ) ) }
12399 end
124100
125101 def check_active_job_adapter
@@ -145,22 +121,41 @@ def unmatching_mail_jobs_message
145121 end
146122
147123 def mail_job_message ( job )
148- mailer_method = job [ :args ] [ 0 ..1 ] . join ( '.' )
149- mailer_args = deserialize_arguments ( job ) [ 3 ..-1 ]
150- mailer_args = mailer_args . first [ :args ] if unified_mail? ( job )
124+ job_args = deserialize_arguments ( job )
125+
126+ mailer_method = job_args [ 0 ..1 ] . join ( '.' )
127+ mailer_args = job_args [ 3 ..-1 ]
128+
151129 msg_parts = [ ]
152- display_args = display_mailer_args ( mailer_args )
153- msg_parts << "with #{ display_args } " if display_args . any?
130+ msg_parts << "with #{ mailer_args } " if mailer_args . any?
154131 msg_parts << "on queue #{ job [ :queue ] } " if job [ :queue ] && job [ :queue ] != 'mailers'
155132 msg_parts << "at #{ Time . at ( job [ :at ] ) } " if job [ :at ]
156133
157134 "#{ mailer_method } #{ msg_parts . join ( ', ' ) } " . strip
158135 end
159136
160- def display_mailer_args ( mailer_args )
161- return mailer_args unless mailer_args . first . is_a? ( Hash ) && mailer_args . first . key? ( :args )
137+ # Ruby 3.1 changed how params were serialized on Rails 6.1
138+ # so we override the active job implementation and customise it here.
139+ def deserialize_arguments ( job )
140+ args = super
141+
142+ return args unless Hash === args . last
143+
144+ hash = args . pop
162145
163- mailer_args . first [ :args ]
146+ if hash . key? ( "_aj_ruby2_keywords" )
147+ keywords = hash [ "_aj_ruby2_keywords" ]
148+
149+ original_hash = keywords . each_with_object ( { } ) { |new_hash , keyword | new_hash [ keyword . to_sym ] = hash [ keyword ] }
150+
151+ args + [ original_hash ]
152+ elsif hash . key? ( :args ) && hash . key? ( :params )
153+ args + [ hash ]
154+ elsif hash . key? ( :args )
155+ args + hash [ :args ]
156+ else
157+ args + [ hash ]
158+ end
164159 end
165160
166161 def legacy_mail? ( job )
@@ -174,6 +169,7 @@ def parameterized_mail?(job)
174169 def unified_mail? ( job )
175170 RSpec ::Rails ::FeatureCheck . has_action_mailer_unified_delivery? && job [ :job ] <= ActionMailer ::MailDeliveryJob
176171 end
172+
177173 end
178174 # @api public
179175 # Passes if an email has been enqueued inside block.
@@ -229,3 +225,4 @@ def have_enqueued_mail(mailer_class = nil, mail_method_name = nil)
229225 end
230226 end
231227end
228+ # rubocop: enable Metrics/ClassLength
0 commit comments