From 6ca741f3762fa907dbad41151dbeb4090080c08a Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Thu, 28 May 2020 10:24:07 +0100 Subject: [PATCH 1/2] Improve spec for offset times to not need freeze_time --- spec/rspec/rails/matchers/active_job_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/rspec/rails/matchers/active_job_spec.rb b/spec/rspec/rails/matchers/active_job_spec.rb index 1a15b5cf1a..44bbef7033 100644 --- a/spec/rspec/rails/matchers/active_job_spec.rb +++ b/spec/rspec/rails/matchers/active_job_spec.rb @@ -225,10 +225,10 @@ def self.name; "LoggingJob"; end }.to have_enqueued_job.at(time) end - skip_freeze_time = method_defined?(:freeze_time) ? false : "#freeze_time is undefined" - it "works with time offsets", skip: skip_freeze_time do - freeze_time do - time = Time.current + it "works with time offsets" do + # note that Time.current does not replicate Rails behavior for 5 seconds from now. + time = Time.current.change(usec: 0) + travel_to time do expect { hello_job.set(wait: 5).perform_later }.to have_enqueued_job.at(time + 5) end end From f9c3bc18611ce031b1b29b91bc32fa70bc35806e Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Thu, 28 May 2020 10:24:20 +0100 Subject: [PATCH 2/2] Issue warning when the error is a precision error --- lib/rspec/rails/matchers/active_job.rb | 24 +++++++++++++++++++- spec/rspec/rails/matchers/active_job_spec.rb | 11 +++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/rspec/rails/matchers/active_job.rb b/lib/rspec/rails/matchers/active_job.rb index 1a7be83132..217503a52e 100644 --- a/lib/rspec/rails/matchers/active_job.rb +++ b/lib/rspec/rails/matchers/active_job.rb @@ -163,7 +163,29 @@ def at_match?(job) return job[:at].nil? if @at == :no_wait return false unless job[:at] - values_match?(@at, Time.at(job[:at])) + scheduled_at = Time.at(job[:at]) + values_match?(@at, scheduled_at) || check_for_inprecise_value(scheduled_at) + end + + def check_for_inprecise_value(scheduled_at) + return unless Time === @at && values_match?(@at.change(usec: 0), scheduled_at) + + RSpec.warn_with((<<-WARNING).gsub(/^\s+\|/, '').chomp) + |[WARNING] Your expected `at(...)` value does not match the job scheduled_at value + |unless microseconds are removed. This precision error often occurs when checking + |values against `Time.current` / `Time.now` which have usec precision, but Rails + |uses `n.seconds.from_now` internally which has a usec count of `0`. + | + |Use `change(usec: 0)` to correct these values. For example: + | + |`Time.current.change(usec: 0)` + | + |Note: RSpec cannot do this for you because jobs can be scheduled with usec + |precision and we do not know wether it is on purpose or not. + | + | + WARNING + false end def set_expected_number(relativity, count) diff --git a/spec/rspec/rails/matchers/active_job_spec.rb b/spec/rspec/rails/matchers/active_job_spec.rb index 44bbef7033..896cd7db1e 100644 --- a/spec/rspec/rails/matchers/active_job_spec.rb +++ b/spec/rspec/rails/matchers/active_job_spec.rb @@ -233,6 +233,17 @@ def self.name; "LoggingJob"; end end end + it "warns when time offsets are inprecise" do + expect(RSpec).to receive(:warn_with).with(/precision error/) + + time = Time.current.change(usec: 550) + travel_to time do + expect { + expect { hello_job.set(wait: 5).perform_later }.to have_enqueued_job.at(time + 5) + }.to raise_error(/expected to enqueue exactly 1 jobs/) + end + end + it "accepts composable matchers as an at date" do future = 1.minute.from_now slightly_earlier = 58.seconds.from_now