class RSpec::Rails::Matchers::HaveEnqueuedMail

@see RSpec::Rails::Matchers#have_enqueued_mail
@private
Matcher class for ‘have_enqueued_mail`. Should not be instantiated directly.

def arguments_match?(job)

def arguments_match?(job)
  @args =
    if @mail_args.any?
      base_mailer_args + @mail_args
    elsif @mailer_class && @method_name
      base_mailer_args + [any_args]
    elsif @mailer_class
      [mailer_class_name, any_args]
    else
      []
    end
  super(job)
end

def base_mailer_args

def base_mailer_args
  [mailer_class_name, @method_name.to_s, MAILER_JOB_METHOD]
end

def base_message

def base_message
  [mailer_class_name, @method_name].compact.join('.').tap do |msg|
    msg << " #{expected_count_message}"
    msg << " with #{@mail_args}," if @mail_args.any?
    msg << " on queue #{@queue}," if @queue
    msg << " at #{@at.inspect}," if @at
    msg << " but enqueued #{@matching_jobs.size}"
  end
end

def check_active_job_adapter

def check_active_job_adapter
  return if ::ActiveJob::QueueAdapters::TestAdapter === ::ActiveJob::Base.queue_adapter
  raise StandardError, "To use HaveEnqueuedMail matcher set `ActiveJob::Base.queue_adapter = :test`"
end

def description

def description
  "enqueues #{mailer_class_name}.#{@method_name}"
end

def deserialize_arguments(job)

so we override the active job implementation and customise it here.
Ruby 3.1 changed how params were serialized on Rails 6.1
def deserialize_arguments(job)
  args = super
  return args unless Hash === args.last
  hash = args.pop
  if hash.key?("_aj_ruby2_keywords")
    keywords = hash["_aj_ruby2_keywords"]
    original_hash = keywords.each_with_object({}) { |new_hash, keyword| new_hash[keyword.to_sym] = hash[keyword] }
    args + [original_hash]
  elsif hash.key?(:args) && hash.key?(:params)
    args + [hash]
  elsif hash.key?(:args)
    args + hash[:args]
  else
    args + [hash]
  end
end

def expected_count_message

def expected_count_message
  "#{message_expectation_modifier} #{@expected_number} #{@expected_number == 1 ? 'time' : 'times'}"
end

def failure_message

def failure_message
  "expected to enqueue #{base_message}".tap do |msg|
    msg << "\n#{unmatching_mail_jobs_message}" if unmatching_mail_jobs.any?
  end
end

def failure_message_when_negated

def failure_message_when_negated
  "expected not to enqueue #{base_message}"
end

def initialize(mailer_class, method_name)

def initialize(mailer_class, method_name)
  super(nil)
  @mailer_class = mailer_class
  @method_name = method_name
  @mail_args = []
end

def job_match?(job)

def job_match?(job)
  legacy_mail?(job) || parameterized_mail?(job) || unified_mail?(job)
end

def legacy_mail?(job)

def legacy_mail?(job)
  job[:job] <= ActionMailer::DeliveryJob
end

def mail_job_message(job)

def mail_job_message(job)
  job_args = deserialize_arguments(job)
  mailer_method = job_args[0..1].join('.')
  mailer_args = job_args[3..-1]
  msg_parts = []
  msg_parts << "with #{mailer_args}" if mailer_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 mailer_class_name

def mailer_class_name
  @mailer_class ? @mailer_class.name : 'ActionMailer::Base'
end

def matches?(block)

def matches?(block)
  raise ArgumentError, 'have_enqueued_mail and enqueue_mail only work with block arguments' unless block.respond_to?(:call)
  check_active_job_adapter
  super
end

def parameterized_mail?(job)

def parameterized_mail?(job)
  RSpec::Rails::FeatureCheck.has_action_mailer_parameterized? && job[:job] <= ActionMailer::Parameterized::DeliveryJob
end

def unified_mail?(job)

def unified_mail?(job)
  RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? && job[:job] <= ActionMailer::MailDeliveryJob
end

def unmatching_mail_jobs

def unmatching_mail_jobs
  @unmatching_jobs.select do |job|
    job_match?(job)
  end
end

def unmatching_mail_jobs_message

def unmatching_mail_jobs_message
  msg = "Queued deliveries:"
  unmatching_mail_jobs.each do |job|
    msg << "\n  #{mail_job_message(job)}"
  end
  msg
end

def with(*args, &block)

def with(*args, &block)
  @mail_args = args
  block.nil? ? super : super(&yield_mail_args(block))
end

def yield_mail_args(block)

def yield_mail_args(block)
  proc { |*job_args| block.call(*(job_args - base_mailer_args)) }
end