Skip to content

Commit d3bbe58

Browse files
odlpJonRowe
authored andcommitted
Fail ActiveJob matcher if arguments don't match signature
Preferable for a matcher to fail instead of directly raising ArgumentError when a mismatch is detected. #2745 (comment)
1 parent 53fefbd commit d3bbe58

File tree

4 files changed

+75
-22
lines changed

4 files changed

+75
-22
lines changed

lib/rspec/rails/matchers/active_job.rb

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ def thrice
7171
end
7272

7373
def failure_message
74+
return @failure_message if defined?(@failure_message)
75+
7476
"expected to #{self.class::FAILURE_MESSAGE_EXPECTATION_ACTION} #{base_message}".tap do |msg|
7577
if @unmatching_jobs.any?
7678
msg << "\nQueued jobs:"
@@ -103,13 +105,18 @@ def check(jobs)
103105
@matching_jobs, @unmatching_jobs = jobs.partition do |job|
104106
if job_match?(job) && arguments_match?(job) && queue_match?(job) && at_match?(job)
105107
args = deserialize_arguments(job)
106-
verify_arguments_match_signature!(job, args)
107108
@block.call(*args)
108109
true
109110
else
110111
false
111112
end
112113
end
114+
115+
if (signature_mismatch = detect_args_signature_mismatch(@matching_jobs))
116+
@failure_message = signature_mismatch
117+
return false
118+
end
119+
113120
@matching_jobs_count = @matching_jobs.size
114121

115122
case @expectation_type
@@ -153,16 +160,25 @@ def arguments_match?(job)
153160
end
154161
end
155162

156-
def verify_arguments_match_signature!(job, args)
157-
job_method = job.fetch(:job).public_instance_method(:perform)
158-
verify_signature!(job_method, args)
163+
def detect_args_signature_mismatch(jobs)
164+
jobs.each do |job|
165+
args = deserialize_arguments(job)
166+
167+
if (signature_mismatch = check_args_signature_mismatch(job.fetch(:job), :perform, args))
168+
return signature_mismatch
169+
end
170+
end
171+
172+
nil
159173
end
160174

161-
def verify_signature!(job_method, args)
162-
signature = Support::MethodSignature.new(job_method)
175+
def check_args_signature_mismatch(job_class, job_method, args)
176+
signature = Support::MethodSignature.new(job_class.public_instance_method(job_method))
163177
verifier = Support::StrictSignatureVerifier.new(signature, args)
164178

165-
raise ArgumentError, verifier.error_message unless verifier.valid?
179+
unless verifier.valid?
180+
"Incorrect arguments passed to #{job_class.name}: #{verifier.error_message}"
181+
end
166182
end
167183

168184
def queue_match?(job)

lib/rspec/rails/matchers/have_enqueued_mail.rb

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def matches?(block)
4141
end
4242

4343
def failure_message
44+
return @failure_message if defined?(@failure_message)
45+
4446
"expected to enqueue #{base_message}".tap do |msg|
4547
msg << "\n#{unmatching_mail_jobs_message}" if unmatching_mail_jobs.any?
4648
end
@@ -89,19 +91,20 @@ def arguments_match?(job)
8991
super(job)
9092
end
9193

92-
def verify_arguments_match_signature!(job, args)
94+
def detect_args_signature_mismatch(jobs)
9395
return if @method_name.nil?
9496

95-
mailer_method = mailer_class_name.constantize.public_instance_method(@method_name)
96-
mailer_args = args - base_mailer_args
97+
mailer_class = mailer_class_name.constantize
9798

98-
if parameterized_mail?(job)
99-
mailer_args = mailer_args[1..-1] # ignore parameterized params
100-
elsif mailer_args.last.is_a?(Hash) && mailer_args.last.key?(:args)
101-
mailer_args = args.last[:args]
99+
jobs.each do |job|
100+
mailer_args = extract_args_without_parameterized_params(job)
101+
102+
if (signature_mismatch = check_args_signature_mismatch(mailer_class, @method_name, mailer_args))
103+
return signature_mismatch
104+
end
102105
end
103106

104-
verify_signature!(mailer_method, mailer_args)
107+
nil
105108
end
106109

107110
def base_mailer_args
@@ -172,6 +175,19 @@ def deserialize_arguments(job)
172175
end
173176
end
174177

178+
def extract_args_without_parameterized_params(job)
179+
args = deserialize_arguments(job)
180+
mailer_args = args - base_mailer_args
181+
182+
if parameterized_mail?(job)
183+
mailer_args = mailer_args[1..-1] # ignore parameterized params
184+
elsif mailer_args.last.is_a?(Hash) && mailer_args.last.key?(:args)
185+
mailer_args = args.last[:args]
186+
end
187+
188+
mailer_args
189+
end
190+
175191
def legacy_mail?(job)
176192
RSpec::Rails::FeatureCheck.has_action_mailer_legacy_delivery_job? && job[:job] <= ActionMailer::DeliveryJob
177193
end

spec/rspec/rails/matchers/active_job_spec.rb

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,15 +343,21 @@ def perform; raise StandardError; end
343343
expect {
344344
two_args_job.perform_later(1)
345345
}.to have_enqueued_job.with(1)
346-
}.to raise_error(ArgumentError, /Wrong number of arguments/)
346+
}.to raise_error(
347+
RSpec::Expectations::ExpectationNotMetError,
348+
/Incorrect arguments passed to TwoArgsJob: Wrong number of arguments/
349+
)
347350
end
348351

349352
it "fails if the job's signature/arguments are mismatched keyword/positional arguments" do
350353
expect {
351354
expect {
352355
keyword_args_job.perform_later(1, 2)
353356
}.to have_enqueued_job.with(1, 2)
354-
}.to raise_error(ArgumentError, /Missing required keyword arguments/)
357+
}.to raise_error(
358+
RSpec::Expectations::ExpectationNotMetError,
359+
/Incorrect arguments passed to KeywordArgsJob: Missing required keyword arguments/
360+
)
355361
end
356362

357363
it "passes with provided arguments containing global id object" do
@@ -492,15 +498,21 @@ def perform; raise StandardError; end
492498

493499
expect {
494500
expect(two_args_job).to have_been_enqueued.with(1)
495-
}.to raise_error(ArgumentError, /Wrong number of arguments/)
501+
}.to raise_error(
502+
RSpec::Expectations::ExpectationNotMetError,
503+
/Incorrect arguments passed to TwoArgsJob: Wrong number of arguments/
504+
)
496505
end
497506

498507
it "fails if the job's signature/arguments are mismatched keyword/positional arguments" do
499508
keyword_args_job.perform_later(1, 2)
500509

501510
expect {
502511
expect(keyword_args_job).to have_been_enqueued.with(1, 2)
503-
}.to raise_error(ArgumentError, /Missing required keyword arguments/)
512+
}.to raise_error(
513+
RSpec::Expectations::ExpectationNotMetError,
514+
/Incorrect arguments passed to KeywordArgsJob: Missing required keyword arguments/
515+
)
504516
end
505517

506518
it "fails when negated and several jobs enqueued" do

spec/rspec/rails/matchers/have_enqueued_mail_spec.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,10 @@ def test_email; end
248248
expect {
249249
TestMailer.email_with_args(1).deliver_later
250250
}.to have_enqueued_mail(TestMailer, :email_with_args).with(1)
251-
}.to raise_error(ArgumentError, /Wrong number of arguments/)
251+
}.to raise_error(
252+
RSpec::Expectations::ExpectationNotMetError,
253+
/Incorrect arguments passed to TestMailer: Wrong number of arguments/
254+
)
252255
end
253256

254257
it "generates a failure message" do
@@ -402,7 +405,10 @@ def self.name; "NonMailerJob"; end
402405
expect {
403406
TestMailer.with('foo' => 'bar').email_with_args(1).deliver_later
404407
}.to have_enqueued_mail(TestMailer, :email_with_args).with({ 'foo' => 'bar' }, 1)
405-
}.to raise_error(ArgumentError, /Wrong number of arguments/)
408+
}.to raise_error(
409+
RSpec::Expectations::ExpectationNotMetError,
410+
/Incorrect arguments passed to TestMailer: Wrong number of arguments/
411+
)
406412
end
407413
end
408414

@@ -459,7 +465,10 @@ def self.name; "NonMailerJob"; end
459465
}.to have_enqueued_mail(UnifiedMailer, :email_with_args).with(
460466
a_hash_including(params: { 'foo' => 'bar' }, args: [1])
461467
)
462-
}.to raise_error(ArgumentError, /Wrong number of arguments/)
468+
}.to raise_error(
469+
RSpec::Expectations::ExpectationNotMetError,
470+
/Incorrect arguments passed to UnifiedMailer: Wrong number of arguments/
471+
)
463472
end
464473
end
465474
end

0 commit comments

Comments
 (0)