From 2d32ff26e9cb55c6cb189760bf4c184306c68ab5 Mon Sep 17 00:00:00 2001 From: Will Spurgin Date: Wed, 26 Jul 2023 09:40:43 -0500 Subject: [PATCH 1/2] Show each job arg and option on its own line --- .../sidekiq/matchers/have_enqueued_job.rb | 12 +++++++-- .../matchers/have_enqueued_job_spec.rb | 25 ++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/rspec/sidekiq/matchers/have_enqueued_job.rb b/lib/rspec/sidekiq/matchers/have_enqueued_job.rb index 124a30f..bd7c9a2 100644 --- a/lib/rspec/sidekiq/matchers/have_enqueued_job.rb +++ b/lib/rspec/sidekiq/matchers/have_enqueued_job.rb @@ -164,8 +164,16 @@ def failure_message message << " with options:" if expected_options.any? message << " -#{expected_options}" if expected_options.any? message << "but have enqueued only jobs" - message.concat([" with arguments:"], actual_arguments.sort_by { |a| a[0].to_s }.map { |a| " -#{a}" }) if expected_arguments - message.concat([" with options:"], actual_options.sort_by { |a| a.to_a[0].to_s }.map { |o| " -#{o}" }) if expected_options.any? + if expected_arguments + message << " with arguments:" + message << actual_arguments.sort_by { |a| a[0].to_s }.map { |a| " -#{a}" }.join("\n") + end + + if expected_options.any? + message << " with options:" + message << actual_options.sort_by { |a| a.to_a[0].to_s }.map { |o| " -#{o}" }.join("\n") + end + message.join("\n") end diff --git a/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb b/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb index 34dd546..0d59a0f 100644 --- a/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb +++ b/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb @@ -116,15 +116,34 @@ it 'returns message' do worker.perform_async *worker_args argument_subject.matches? worker - expect(argument_subject.failure_message).to eq <<-eos.gsub(/^ {6}/, '').strip + expect(argument_subject.failure_message).to eq <<~eos.strip expected to have an enqueued #{worker} job with arguments: - -[\"string\", 1, true, {\"key\"=>\"value\", \"bar\"=>\"foo\", \"nested\"=>[{\"hash\"=>true}]}] + -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] but have enqueued only jobs with arguments: - -[\"string\", 1, true, {\"key\"=>\"value\", \"bar\"=>\"foo\", \"nested\"=>[{\"hash\"=>true}]}] + -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] eos end + + context "when expected arguments is an array and multiple jobs enqueued" do + let(:wrapped_args) { [worker_args] } + let(:argument_subject) { RSpec::Sidekiq::Matchers::HaveEnqueuedJob.new wrapped_args } + + it "returns a message showing the wrapped array in expectations but each job on its own line" do + 2.times { worker.perform_async *worker_args } + argument_subject.matches? worker + expect(argument_subject.failure_message).to eq <<~eos.strip + expected to have an enqueued #{worker} job + with arguments: + -[["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}]] + but have enqueued only jobs + with arguments: + -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] + -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] + eos + end + end end describe '#failure_message_when_negated' do From 3e5f31840939adde6d7beece382b202eca481537 Mon Sep 17 00:00:00 2001 From: Will Spurgin Date: Wed, 26 Jul 2023 10:09:03 -0500 Subject: [PATCH 2/2] Refactor description to group actuals by Job --- .../sidekiq/matchers/have_enqueued_job.rb | 59 +++++++++++-------- .../matchers/have_enqueued_job_spec.rb | 9 +-- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/lib/rspec/sidekiq/matchers/have_enqueued_job.rb b/lib/rspec/sidekiq/matchers/have_enqueued_job.rb index bd7c9a2..1bfd047 100644 --- a/lib/rspec/sidekiq/matchers/have_enqueued_job.rb +++ b/lib/rspec/sidekiq/matchers/have_enqueued_job.rb @@ -74,29 +74,39 @@ def active_job_original_args end end + class EnqueuedJob + extend Forwardable + attr_reader :job + delegate :[] => :@job + + def initialize(job) + @job = job + end + + def jid + job["jid"] + end + + def args + @actual_arguments ||= JobArguments.new(job).unwrapped_arguments + end + + def context + @actual_options ||= job.except("args") + end + end + class EnqueuedJobs attr_reader :jobs def initialize(klass) - @jobs = unwrap_jobs(klass.jobs) + @jobs = unwrap_jobs(klass.jobs).map { |job| EnqueuedJob.new(job) } end def includes?(arguments, options) !!jobs.find { |job| matches?(job, arguments, options) } end - def actual_arguments - @actual_arguments ||= jobs.map { |job| JobArguments.new(job).unwrapped_arguments } - end - - def actual_options - @actual_options ||= if jobs.is_a?(Hash) - jobs.values - else - jobs.flatten.map { |j| {"at" => j["at"]} } - end - end - private def matches?(job, arguments, options) @@ -124,21 +134,18 @@ def unwrap_jobs(jobs) end class HaveEnqueuedJob - attr_reader :klass, :expected_arguments, :actual_arguments, :expected_options, :actual_options + attr_reader :klass, :expected_arguments, :expected_options, :actual_jobs def initialize(expected_arguments) @expected_arguments = expected_arguments @expected_options = {} end - def matches?(klass) @klass = klass enqueued_jobs = EnqueuedJobs.new(klass) - - @actual_arguments = enqueued_jobs.actual_arguments - @actual_options = enqueued_jobs.actual_options + @actual_jobs = enqueued_jobs.jobs enqueued_jobs.includes?(jsonified_expected_arguments, expected_options) end @@ -165,13 +172,17 @@ def failure_message message << " -#{expected_options}" if expected_options.any? message << "but have enqueued only jobs" if expected_arguments - message << " with arguments:" - message << actual_arguments.sort_by { |a| a[0].to_s }.map { |a| " -#{a}" }.join("\n") - end + job_messages = actual_jobs.map do |job| + base = " -JID:#{job.jid} with arguments:" + base << "\n -#{job.args}" + if expected_options.any? + base << "\n with options: #{job.context.inspect}" + end + + base + end - if expected_options.any? - message << " with options:" - message << actual_options.sort_by { |a| a.to_a[0].to_s }.map { |o| " -#{o}" }.join("\n") + message << job_messages.join("\n") end message.join("\n") diff --git a/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb b/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb index 0d59a0f..e082bd6 100644 --- a/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb +++ b/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb @@ -114,14 +114,14 @@ describe '#failure_message' do it 'returns message' do - worker.perform_async *worker_args + jid = worker.perform_async *worker_args argument_subject.matches? worker expect(argument_subject.failure_message).to eq <<~eos.strip expected to have an enqueued #{worker} job with arguments: -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] but have enqueued only jobs - with arguments: + -JID:#{jid} with arguments: -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] eos end @@ -131,15 +131,16 @@ let(:argument_subject) { RSpec::Sidekiq::Matchers::HaveEnqueuedJob.new wrapped_args } it "returns a message showing the wrapped array in expectations but each job on its own line" do - 2.times { worker.perform_async *worker_args } + jids = 2.times.map { worker.perform_async *worker_args } argument_subject.matches? worker expect(argument_subject.failure_message).to eq <<~eos.strip expected to have an enqueued #{worker} job with arguments: -[["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}]] but have enqueued only jobs - with arguments: + -JID:#{jids[0]} with arguments: -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] + -JID:#{jids[1]} with arguments: -["string", 1, true, {"key"=>"value", "bar"=>"foo", "nested"=>[{"hash"=>true}]}] eos end