123456789_123456789_123456789_123456789_123456789_

Class: RSpec::Rails::Matchers::HaveEnqueuedMail Private

Do not use. This class is for internal use only.

Overview

Matcher class for #have_enqueued_mail. Should not be instantiated directly.

Constant Summary

BaseMatcher - Inherited

UNDEFINED

ActiveJob::HaveEnqueuedJob - Inherited

FAILURE_MESSAGE_EXPECTATION_ACTION, MESSAGE_EXPECTATION_ACTION

Class Method Summary

ActiveJob::HaveEnqueuedJob - Inherited

ActiveJob::Base - Inherited

BaseMatcher - Inherited

.matcher_name, .new,
.underscore

Borrowed from ActiveSupport.

Instance Attribute Summary

ActiveJob::Base - Inherited

BaseMatcher - Inherited

#actual,
#diffable?

::RSpec::Rails::Matchers are not diffable by default.

#expected, #expects_call_stack_jump?, #matcher_name, #matcher_name=, #rescued_exception,
#supports_block_expectations?

Most matchers are value matchers (i.e. meant to work with ‘expect(value)`) rather than block matchers (i.e. meant to work with `expect { }`), so this defaults to false.

Instance Method Summary

::RSpec::Mocks::ArgumentMatchers - Included

#a_kind_of
#an_instance_of
#any_args

Acts like an arg splat, matching any number of args at any point in an arg list.

#anything

Matches any argument at all.

#array_excluding

Matches an array that excludes the specified items.

#array_including

Matches an array that includes the specified items at least once.

#boolean

Matches a boolean value.

#duck_type

Matches if the actual argument responds to the specified messages.

#hash_excluding

Matches a hash that doesn’t include the specified key(s) or key/value.

#hash_including

Matches a hash that includes the specified key(s) or key/value pairs.

#hash_not_including
#instance_of

Matches if ‘arg.instance_of?(klass)`.

#kind_of

Matches if ‘arg.kind_of?(klass)`.

#no_args

Matches no arguments.

ActiveJob::HaveEnqueuedJob - Inherited

ActiveJob::Base - Inherited

BaseMatcher - Inherited

#actual_formatted,
#description

Generates a description using ::RSpec::Matchers::EnglishPhrasing.

#expected_formatted,
#match_unless_raises

Used to wrap a block of code that will indicate failure by raising one of the named exceptions.

#matches?

Indicates if the match is successful.

#assert_ivars, #present_ivars

BaseMatcher::DefaultFailureMessages - Included

#failure_message

Provides a good generic failure message.

#failure_message_when_negated

Provides a good generic negative failure message.

BaseMatcher::HashFormatting - Included

#improve_hash_formatting

‘{ :a => 5, :b => 2 }.inspect` produces:

::RSpec::Matchers::Composable - Included

#&
#===

Delegates to #matches?.

#and

Creates a compound and expectation.

#description_of

Returns the description of the given object in a way that is aware of composed matchers.

#or

Creates a compound or expectation.

#values_match?

This provides a generic way to fuzzy-match an expected value against an actual value.

#|
#should_enumerate?

We should enumerate arrays as long as they are not recursive.

#surface_descriptions_in

Transforms the given data structure (typically a hash or array) into a new data structure that, when #inspect is called on it, will provide descriptions of any contained matchers rather than the normal #inspect output.

#unreadable_io?,
#with_matchers_cloned

Historically, a single matcher instance was only checked against a single value.

Instance Method Details

#arguments_match?(job) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 79

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

#base_mailer_args (private)

[ GitHub ]

  
# File 'rspec-rails/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 (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 57

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 (private)

Raises:

  • (StandardError)
[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 119

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

#description

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 27

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

#deserialize_arguments(job) (private)

Ruby 3.1 changed how params were serialized on ::RSpec::Rails 6.1 so we override the active job implementation and customize it here.

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 157

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({}) { |keyword, new_hash| 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

#detect_args_signature_mismatch(jobs) (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 94

def detect_args_signature_mismatch(jobs)
  return if @method_name.nil?
  return if skip_signature_verification?

  mailer_class = mailer_class_name.constantize

  jobs.each do |job|
    mailer_args = extract_args_without_parameterized_params(job)

    if (signature_mismatch = check_args_signature_mismatch(mailer_class, @method_name, mailer_args))
      return signature_mismatch
    end
  end

  nil
end

#expected_count_message (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 67

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

#extract_args_without_parameterized_params(job) (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 179

def extract_args_without_parameterized_params(job)
  args = deserialize_arguments(job)
  mailer_args = args - base_mailer_args

  if parameterized_mail?(job)
    mailer_args = mailer_args[1..-1] # ignore parameterized params
  elsif mailer_args.last.is_a?(Hash) && mailer_args.last.key?(:args)
    mailer_args = args.last[:args]
  end

  mailer_args
end

#failure_message

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 43

def failure_message
  return @failure_message if defined?(@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

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 51

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

#job_matches?(job) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 75

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

#legacy_mail?(job) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 192

def legacy_mail?(job)
  RSpec::Rails::FeatureCheck.has_action_mailer_legacy_delivery_job? && job[:job] <= ActionMailer::DeliveryJob
end

#mail_job_message(job) (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 141

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

#mailer_class_name (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 71

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

#matches?(block) ⇒ Boolean

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'rspec-rails/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

#parameterized_mail?(job) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 196

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

#unified_mail?(job) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 200

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

#unmatching_mail_jobs (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 125

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

#unmatching_mail_jobs_message (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 131

def unmatching_mail_jobs_message
  msg = "Queued deliveries:"

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

  msg
end

#with(*args, &block)

[ GitHub ]

  
# File 'rspec-rails/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

#yield_mail_args(block) (private)

[ GitHub ]

  
# File 'rspec-rails/lib/rspec/rails/matchers/have_enqueued_mail.rb', line 115

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