class RSpec::Rails::Matchers::HaveEnqueuedMail

Matcher class for ‘have_enqueued_mail`. Should not be instantiated directly.

@private @see RSpec::Rails::Matchers#have_enqueued_mail

Constants

MAILER_JOB_METHOD

Public Class Methods

new(mailer_class, method_name) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 20
def initialize(mailer_class, method_name)
  super(nil)
  @mailer_class = mailer_class
  @method_name = method_name
  @mail_args = []
end

Public Instance Methods

description() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 27
def description
  "enqueues #{mailer_class_name}.#{@method_name}"
end
failure_message() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 43
def failure_message
  "expected to enqueue #{base_message}".tap do |msg|
    msg << "\n#{unmatching_mail_jobs_message}" if unmatching_mail_jobs.any?
  end
end
failure_message_when_negated() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 49
def failure_message_when_negated
  "expected not to enqueue #{base_message}"
end
matches?(block) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 36
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
with(*args, &block) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 31
def with(*args, &block)
  @mail_args = args
  block.nil? ? super : super(&yield_mail_args(block))
end

Private Instance Methods

arguments_match?(job) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 77
def arguments_match?(job)
  @args =
    if @mail_args.any?
      base_mailer_args + process_arguments(job, @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
base_mailer_args() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 111
def base_mailer_args
  [mailer_class_name, @method_name.to_s, MAILER_JOB_METHOD]
end
base_message() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 55
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
check_active_job_adapter() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 126
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
display_mailer_args(mailer_args) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 161
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
expected_count_message() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 65
def expected_count_message
  "#{message_expectation_modifier} #{@expected_number} #{@expected_number == 1 ? 'time' : 'times'}"
end
job_match?(job) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 73
def job_match?(job)
  legacy_mail?(job) || parameterized_mail?(job) || unified_mail?(job)
end
legacy_mail?(job) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 167
def legacy_mail?(job)
  RSpec::Rails::FeatureCheck.has_action_mailer_legacy_delivery_job? && job[:job] <= ActionMailer::DeliveryJob
end
mail_job_message(job) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 148
def mail_job_message(job)
  mailer_method = job[:args][0..1].join('.')
  mailer_args = deserialize_arguments(job)[3..-1]
  mailer_args = mailer_args.first[:args] if unified_mail?(job)
  msg_parts = []
  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
mailer_class_name() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 69
def mailer_class_name
  @mailer_class ? @mailer_class.name : 'ActionMailer::Base'
end
parameterized_mail?(job) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 171
def parameterized_mail?(job)
  RSpec::Rails::FeatureCheck.has_action_mailer_parameterized? && job[:job] <= ActionMailer::Parameterized::DeliveryJob
end
process_arguments(job, given_mail_args) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 92
def process_arguments(job, given_mail_args)
  # Old matcher behavior working with all builtin classes but 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?
    [hash_including(params: given_mail_args[0], args: given_mail_args.drop(1))]
  else
    [hash_including(args: given_mail_args)]
  end
end
unified_mail?(job) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 175
def unified_mail?(job)
  RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? && job[:job] <= ActionMailer::MailDeliveryJob
end
unmatching_mail_jobs() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 132
def unmatching_mail_jobs
  @unmatching_jobs.select do |job|
    job_match?(job)
  end
end
unmatching_mail_jobs_message() click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 138
def unmatching_mail_jobs_message
  msg = "Queued deliveries:"

  unmatching_mail_jobs.each do |job|
    msg << "\n  #{mail_job_message(job)}"
  end

  msg
end
use_given_mail_args?(job) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 104
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
yield_mail_args(block) click to toggle source
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 115
def yield_mail_args(block)
  proc do |*job_args|
    mailer_args = job_args - base_mailer_args
    if mailer_args.first.is_a?(Hash)
      block.call(*mailer_args.first[:args])
    else
      block.call(*mailer_args)
    end
  end
end