Skip to content

Commit

Permalink
add support for recognizing mailer many jobs:
Browse files Browse the repository at this point in the history
- parameterized mailer when RAILS_VERSION >= 5.1
- unified mailer job when RAILS_VERSION >= 6.0
  • Loading branch information
ignatiusreza committed May 14, 2019
1 parent f970835 commit 16a6605
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 19 deletions.
8 changes: 8 additions & 0 deletions lib/rspec/rails/feature_check.rb
Expand Up @@ -38,6 +38,14 @@ def has_action_mailer_show_preview?
::ActionMailer::Base.respond_to?(:show_previews=)
end

def has_action_mailer_parameterized?
has_action_mailer? && defined?(::ActionMailer::Parameterized)
end

def has_action_mailer_unified_delivery?
has_action_mailer? && defined?(::ActionMailer::MailDeliveryJob)
end

def has_action_mailbox?
defined?(::ActionMailbox)
end
Expand Down
7 changes: 5 additions & 2 deletions lib/rspec/rails/matchers/active_job.rb
Expand Up @@ -97,7 +97,7 @@ def supports_block_expectations?

def check(jobs)
@matching_jobs, @unmatching_jobs = jobs.partition do |job|
if arguments_match?(job) && other_attributes_match?(job)
if job_match?(job) && arguments_match?(job) && other_attributes_match?(job)
args = deserialize_arguments(job)
@block.call(*args)
true
Expand Down Expand Up @@ -134,6 +134,10 @@ def base_job_message(job)
end
end

def job_match?(job)
@job ? @job == job[:job] : true
end

def arguments_match?(job)
if @args.any?
deserialized_args = deserialize_arguments(job)
Expand All @@ -151,7 +155,6 @@ def serialized_attributes
{}.tap do |attributes|
attributes[:at] = serialized_at if @at
attributes[:queue] = @queue if @queue
attributes[:job] = @job if @job
end
end

Expand Down
45 changes: 28 additions & 17 deletions lib/rspec/rails/matchers/have_enqueued_mail.rb
Expand Up @@ -9,16 +9,21 @@ module Matchers
# @private
# @see RSpec::Rails::Matchers#have_enqueued_mail
class HaveEnqueuedMail < ActiveJob::HaveEnqueuedJob
MAILER_JOBS = [
:legacy_mail?,
:parameterized_mail?,
:unified_mail?,
].reject(&:blank?)
MAILER_JOB_METHOD = 'deliver_now'.freeze

include RSpec::Mocks::ExampleMethods

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

def description
Expand All @@ -27,7 +32,7 @@ def description

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

def matches?(block)
Expand Down Expand Up @@ -63,20 +68,18 @@ def expected_count_message
"#{message_expectation_modifier} #{@expected_number} #{@expected_number == 1 ? 'time' : 'times'}"
end

def mailer_args
def job_match?(job)
MAILER_JOBS.any? { |mailer_job| send(mailer_job, job) }
end

def arguments_match?(job)
if @mail_args.any?
base_mailer_args + @mail_args
@args = base_mailer_args + @mail_args
else
mailer_method_arity = @mailer_class.instance_method(@method_name).arity

number_of_args = if mailer_method_arity < 0
(mailer_method_arity + 1).abs
else
mailer_method_arity
end

base_mailer_args + Array.new(number_of_args) { anything }
@args = base_mailer_args + [any_args]
end

super(job)
end

def base_mailer_args
Expand All @@ -95,7 +98,7 @@ def check_active_job_adapter

def unmatching_mail_jobs
@unmatching_jobs.select do |job|
job[:job] == mailer_job
job_match?(job)
end
end

Expand All @@ -121,8 +124,16 @@ def mail_job_message(job)
"#{mailer_method} #{msg_parts.join(', ')}".strip
end

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

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

def unified_mail?(job)
RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? && job[:job] == ActionMailer::MailDeliveryJob
end
end
# @api public
Expand Down
63 changes: 63 additions & 0 deletions spec/rspec/rails/matchers/have_enqueued_mail_spec.rb
Expand Up @@ -10,6 +10,15 @@ def test_email; end
def email_with_args(arg1, arg2); end
def email_with_optional_args(required_arg, optional_arg = nil); end
end

if RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery?
class UnifiedMailer < ActionMailer::Base
self.delivery_job = ActionMailer::MailDeliveryJob

def test_email; end
def email_with_args(arg1, arg2); end
end
end
end

RSpec.describe "HaveEnqueuedMail matchers", :skip => !RSpec::Rails::FeatureCheck.has_active_job? do
Expand Down Expand Up @@ -283,5 +292,59 @@ def self.name; "NonMailerJob"; end
expect(second_arg).to eq('noon')
}
end

context 'when parameterized', :skip => !RSpec::Rails::FeatureCheck.has_action_mailer_parameterized? do
it "passes when mailer is parameterized" do
expect {
TestMailer.with('foo' => 'bar').test_email.deliver_later
}.to have_enqueued_mail(TestMailer, :test_email)
end

it "passes when mixing parameterized and non-parameterized emails" do
expect {
TestMailer.with('foo' => 'bar').test_email.deliver_later
TestMailer.email_with_args(1, 2).deliver_later
}.to have_enqueued_mail(TestMailer, :test_email).and have_enqueued_mail(TestMailer, :email_with_args)
end

it "passes with provided argument matchers" do
expect {
TestMailer.with('foo' => 'bar').test_email.deliver_later
}.to have_enqueued_mail(TestMailer, :test_email).with('foo' => 'bar')

expect {
TestMailer.with('foo' => 'bar').email_with_args(1, 2).deliver_later
}.to have_enqueued_mail(TestMailer, :email_with_args).with({ 'foo' => 'bar' }, 1, 2)
end
end

context 'mailer job is unified', :skip => !RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? do
it "passes when mailer is parameterized" do
expect {
UnifiedMailer.with('foo' => 'bar').test_email.deliver_later
}.to have_enqueued_mail(UnifiedMailer, :test_email)
end

it "passes when mixing parameterized and non-parameterized emails" do
expect {
UnifiedMailer.with('foo' => 'bar').test_email.deliver_later
UnifiedMailer.email_with_args(1, 2).deliver_later
}.to have_enqueued_mail(UnifiedMailer, :test_email).and have_enqueued_mail(UnifiedMailer, :email_with_args)
end

it "passes with provided argument matchers" do
expect {
UnifiedMailer.with('foo' => 'bar').test_email.deliver_later
}.to have_enqueued_mail(UnifiedMailer, :test_email).with(
a_hash_including(:params => { 'foo' => 'bar' })
)

expect {
UnifiedMailer.with('foo' => 'bar').email_with_args(1, 2).deliver_later
}.to have_enqueued_mail(UnifiedMailer, :email_with_args).with(
a_hash_including(:params => { 'foo' => 'bar' }, :args => [1, 2])
)
end
end
end
end

0 comments on commit 16a6605

Please sign in to comment.