From 0cbd5b22460dc876e6ec347529c1454c22e5774c Mon Sep 17 00:00:00 2001 From: Ignatius Reza Date: Tue, 7 May 2019 19:59:05 +0900 Subject: [PATCH] add support for recognizing mailer many jobs: - parameterized mailer when RAILS_VERSION >= 5.1 - unified mailer job when RAILS_VERSION >= 6.0 --- lib/rspec/rails/feature_check.rb | 8 +++ lib/rspec/rails/matchers/active_job.rb | 7 ++- .../rails/matchers/have_enqueued_mail.rb | 50 ++++++++------- .../rails/matchers/have_enqueued_mail_spec.rb | 63 +++++++++++++++++++ 4 files changed, 104 insertions(+), 24 deletions(-) diff --git a/lib/rspec/rails/feature_check.rb b/lib/rspec/rails/feature_check.rb index 35006f2c8c..9a9990c219 100644 --- a/lib/rspec/rails/feature_check.rb +++ b/lib/rspec/rails/feature_check.rb @@ -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 diff --git a/lib/rspec/rails/matchers/active_job.rb b/lib/rspec/rails/matchers/active_job.rb index 90d6a2f07a..c1501c78cd 100644 --- a/lib/rspec/rails/matchers/active_job.rb +++ b/lib/rspec/rails/matchers/active_job.rb @@ -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 @@ -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) @@ -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 diff --git a/lib/rspec/rails/matchers/have_enqueued_mail.rb b/lib/rspec/rails/matchers/have_enqueued_mail.rb index 96cd6eb119..c96b98aa65 100644 --- a/lib/rspec/rails/matchers/have_enqueued_mail.rb +++ b/lib/rspec/rails/matchers/have_enqueued_mail.rb @@ -14,11 +14,10 @@ class HaveEnqueuedMail < ActiveJob::HaveEnqueuedJob 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 end def description @@ -27,7 +26,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) @@ -67,24 +66,23 @@ def mailer_class_name @mailer_class ? @mailer_class.name : 'ActionMailer::Base' end - def mailer_args - if @mail_args.any? - base_mailer_args + @mail_args - elsif @mailer_class && @method_name - mailer_method_arity = @mailer_class.instance_method(@method_name).arity + def job_match?(job) + legacy_mail?(job) || parameterized_mail?(job) || unified_mail?(job) + end - number_of_args = if mailer_method_arity < 0 - (mailer_method_arity + 1).abs - else - mailer_method_arity - end + 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 - base_mailer_args + Array.new(number_of_args) { anything } - elsif @mailer_class - [mailer_class_name, any_args] - else - [] - end + super(job) end def base_mailer_args @@ -103,7 +101,7 @@ def check_active_job_adapter def unmatching_mail_jobs @unmatching_jobs.select do |job| - job[:job] == mailer_job + job_match?(job) end end @@ -129,8 +127,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 diff --git a/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb b/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb index 1c74e26dd0..4e46c335f9 100644 --- a/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb +++ b/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb @@ -14,6 +14,15 @@ def email_with_optional_args(required_arg, optional_arg = nil); end class AnotherTestMailer < ActionMailer::Base def test_email; 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 @@ -327,5 +336,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