Skip to content

Commit 2cc9973

Browse files
authored
Add "immediately" matcher (#210)
* Add "immediately" matcher * add spec to EnqueueSidekiqJob * add docs
1 parent 89b5094 commit 2cc9973

File tree

5 files changed

+69
-3
lines changed

5 files changed

+69
-3
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ expect(AwesomeJob).to have_enqueued_sidekiq_job(hash_excluding("bad_stuff" => an
9999

100100
#### Testing scheduled jobs
101101

102-
*Use chainable matchers `#at` and `#in`*
102+
*Use chainable matchers `#at`, `#in` and `#immediately`*
103103

104104
```ruby
105105
time = 5.minutes.from_now
@@ -113,6 +113,13 @@ AwesomeJob.perform_in 5.minutes, 'Awesome', true
113113
expect(AwesomeJob).to have_enqueued_sidekiq_job('Awesome', true).in(5.minutes)
114114
```
115115

116+
```ruby
117+
# Job scheduled for a date in the past are enqueued immediately.
118+
AwesomeJob.perform_later 5.minutes.ago, 'Awesome', true # equivalent to: AwesomeJob.perform_async 'Awesome', true
119+
# test with...
120+
expect(AwesomeJob).to have_enqueued_sidekiq_job('Awesome', true).immediately
121+
```
122+
116123
#### Testing queue set for job
117124

118125
Use the chainable `#on` matcher

lib/rspec/sidekiq/matchers/base.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def matches?(options)
1616
private
1717

1818
def at_evaluator(value)
19-
return false if job["at"].to_s.empty?
19+
return value.nil? if job["at"].to_s.empty?
2020
value == Time.at(job["at"]).to_i
2121
end
2222

@@ -185,6 +185,11 @@ def in(interval)
185185
self
186186
end
187187

188+
def immediately
189+
@expected_options["at"] = nil
190+
self
191+
end
192+
188193
def on(queue)
189194
@expected_options["queue"] = queue
190195
self

lib/rspec/sidekiq/matchers/enqueue_sidekiq_job.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def supports_block_expectations?
5656
#
5757
# Passes if a Job is enqueued as the result of a block. Chainable `with`
5858
# for arguments, `on` for queue, `at` for queued for a specific time, and
59-
# `in` for a specific interval delay to being queued
59+
# `in` for a specific interval delay to being queued, `immediately` for queued without delay.
6060
#
6161
# @example
6262
#
@@ -79,6 +79,11 @@ def supports_block_expectations?
7979
# freeze_time do
8080
# expect { AwesomeJob.perform_in(1.hour) }.to enqueue_sidekiq_job.in(1.hour)
8181
# end
82+
#
83+
# # Without any delay
84+
# expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.immediately
85+
# expect { AwesomeJob.perform_at(1.hour.ago) }.to enqueue_sidekiq_job.immediately
86+
8287
def enqueue_sidekiq_job(job_class = nil)
8388
EnqueueSidekiqJob.new(job_class)
8489
end

spec/rspec/sidekiq/matchers/enqueue_sidekiq_job_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,26 @@
177177
end
178178
end
179179

180+
context "immediately" do
181+
it "passes if the job is enqueued immediately" do
182+
expect { worker.perform_async }.to enqueue_sidekiq_job.immediately
183+
expect { worker.perform_at(1.hour.ago) }.to enqueue_sidekiq_job.immediately
184+
end
185+
186+
it "fails if the job is scheduled" do
187+
specific_time = 1.hour.from_now
188+
expect do
189+
expect { worker.perform_at(specific_time) }.to enqueue_sidekiq_job.immediately
190+
end.to raise_error { |error|
191+
lines = error.message.split("\n")
192+
expect(lines).to include(
193+
match(/expected to have an enqueued .* job/),
194+
match(/-{"at"=>nil}/)
195+
)
196+
}
197+
end
198+
end
199+
180200
describe "chainable" do
181201
it "can chain expectations on the job" do
182202
specific_time = 1.hour.from_now

spec/rspec/sidekiq/matchers/have_enqueued_sidekiq_job_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
RSpec.describe RSpec::Sidekiq::Matchers::HaveEnqueuedSidekiqJob do
44
let(:tomorrow) { DateTime.now + 1 }
5+
let(:yesterday) { DateTime.now - 1 }
56
let(:interval) { 3.minutes }
67
let(:argument_subject) { described_class.new worker_args }
78
let(:matcher_subject) { described_class.new [be_a(String), be_a(Integer), true, be_a(Hash)] }
@@ -223,6 +224,20 @@
223224
expect(matcher_subject.at(tomorrow + 1).matches? worker).to be false
224225
end
225226
end
227+
228+
context 'and past timestamp matches' do
229+
it 'returns true' do
230+
worker.perform_at(yesterday, *worker_args)
231+
expect(matcher_subject.immediately.matches? worker).to be true
232+
end
233+
end
234+
235+
context 'and past timestamp does not match' do
236+
it 'returns true' do
237+
worker.perform_at(tomorrow, *worker_args)
238+
expect(matcher_subject.immediately.matches? worker).to be false
239+
end
240+
end
226241
end
227242

228243
context 'with #perform_in' do
@@ -239,6 +254,20 @@
239254
expect(matcher_subject.in(interval + 1.minute).matches? worker).to be false
240255
end
241256
end
257+
258+
context 'and past interval matches' do
259+
it 'returns true' do
260+
worker.perform_in(-1, *worker_args)
261+
expect(matcher_subject.immediately.matches? worker).to be true
262+
end
263+
end
264+
265+
context 'and interval does not match' do
266+
it 'returns false' do
267+
worker.perform_in(1, *worker_args)
268+
expect(matcher_subject.immediately.matches? worker).to be false
269+
end
270+
end
242271
end
243272
end
244273
end

0 commit comments

Comments
 (0)