rspec-sidekiq 4.2.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 545725855a34595908bcd584dfcee30045ad1519fbd8295bf5fbf6aed7fdd254
4
- data.tar.gz: 26905978185b4e101e0f3d40b2318c0c47143d92a4a762286e5951be92942824
3
+ metadata.gz: 56ce84afbf67491fa24da1f527bced61c54afa3d62dbb50e6a09a89e8c0bc16c
4
+ data.tar.gz: 5b4a368bbb098d580713009fb9381d66326c37eced31c91eaf85b43158a85db5
5
5
  SHA512:
6
- metadata.gz: 2f9c854985b82b12fdcd32fa0a3ec68185e1ad22ebc554f3f1e7a4b0d29d1c399706e31eef4155de6805fe61628c670a91634386eb05cf9de6762693369f3276
7
- data.tar.gz: a0033e0cd3b6a6e03f5042dd04931393e87806adca9f7e78cd3bf034c2018cf89da309826e78e7a067e5a5950e86ff3aef79a2e55bb6ede116a37392000123fa
6
+ metadata.gz: 4ec18b3d6ceff7390807d7358259b44f236ca6d81b1b9175c069b6c4912041b914082042a5396c7cf1eb0b602a5448d9aacd9e23b3cee211ad7222c3ec3719af
7
+ data.tar.gz: 4f0232e7b482f7c565a5cca98be9b7143e51adbe6015329f9d052e393fd857fe97e2449fb53f9e3d209ff6319c54e23e9e2919e7003a44bfc00834692039eed0
data/CHANGES.md CHANGED
@@ -1,10 +1,20 @@
1
1
  Unreleased
2
2
  ---
3
+ * Add `until` matcher for Sidekiq Enterprise unique jobs (#232, #147)
4
+ * Add `with_context` matcher for matching against job contexts (#222)
5
+ * Support for Sidekiq 8 (#233)
6
+ * Add `frozen_string_literal: true` (#220)
7
+ * Fix queue always nil in default_retries_exhausted_message (#229)
8
+ * Fix pattern matching warnings on Ruby 2.7 (#227)
9
+
10
+ 5.0.0
11
+ ---
12
+ * [BREAKING] Make `have_enqueued_sidekiq_job()` match jobs with any arguments (same as `enqueue_sidekiq_job()` or `have_enqueued_sidekiq_job(any_args)`) (#215)
13
+ * Add support for expected number of jobs to both `enqueue_sidekiq_job` and `have_enqueued_sidekiq_job` (#219)
3
14
 
4
15
  4.2.0
5
16
  ---
6
- * Add warning about `have_enqueued_sidekiq_job` with no arguments (default will
7
- change in next major release) (#216, #217)
17
+ * Add warning about `have_enqueued_sidekiq_job` with no arguments (default will change in next major release) (#216, #217)
8
18
 
9
19
  4.1.0
10
20
  ---
data/README.md CHANGED
@@ -1,5 +1,3 @@
1
- **Welcome @wspurgin as new maintainer for `rspec-sidekiq`!**
2
-
3
1
  [![Gem Version](https://badge.fury.io/rb/rspec-sidekiq.svg)](https://badge.fury.io/rb/rspec-sidekiq)
4
2
  [![Github Actions CI][github_actions_badge]][github_actions]
5
3
 
@@ -34,14 +32,16 @@ end
34
32
  ```
35
33
 
36
34
  ## Matchers
37
- * [enqueue_sidekiq_job](#enqueue_sidekiq_job)
38
- * [have_enqueued_sidekiq_job](#have_enqueued_sidekiq_job)
39
- * [be_processed_in](#be_processed_in)
40
- * [be_retryable](#be_retryable)
41
- * [be_unique](#be_unique)
42
- * [be_delayed (_deprecated_)](#be_delayed)
35
+ * [```enqueue_sidekiq_job```](#enqueue_sidekiq_job)
36
+ * [```have_enqueued_sidekiq_job```](#have_enqueued_sidekiq_job)
37
+ * [```be_processed_in```](#be_processed_in)
38
+ * [```be_retryable```](#be_retryable)
39
+ * [```save_backtrace```](#save_backtrace)
40
+ * [```be_unique```](#be_unique)
41
+ * [```be_expired_in```](#be_expired_in)
42
+ * [```be_delayed``` (_deprecated_)](#be_delayed)
43
43
 
44
- ### enqueue_sidekiq_job
44
+ ### ```enqueue_sidekiq_job```
45
45
 
46
46
  *Describes that the block should enqueue a job*. Optionally specify the
47
47
  specific job class, arguments, timing, and other context
@@ -68,6 +68,28 @@ freeze_time do
68
68
  expect { AwesomeJob.perform_in(1.hour) }.to enqueue_sidekiq_job.in(1.hour)
69
69
  end
70
70
 
71
+ # A specific number of times
72
+
73
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.once
74
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.exactly(1).time
75
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.exactly(:once)
76
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_least(1).time
77
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_least(:once)
78
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_most(2).times
79
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_most(:twice)
80
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_most(:thrice)
81
+
82
+ # With specific context:
83
+ # Useful for testing anything `set` on the job, including
84
+ # overrides to things like `retry`
85
+ expect {
86
+ AwesomeJob.set(trace_id: "something").perform_async
87
+ }.to enqueue_sidekiq_job.with_context(trace_id: anything)
88
+
89
+ expect {
90
+ AwesomeJob.set(retry: 5).perform_async
91
+ }.to enqueue_sidekiq_job.with_context(retry: 5)
92
+
71
93
  # Combine and chain them as desired
72
94
  expect { AwesomeJob.perform_at(specific_time, "Awesome!") }.to(
73
95
  enqueue_sidekiq_job(AwesomeJob)
@@ -83,13 +105,14 @@ expect do
83
105
  end.to enqueue_sidekiq_job(AwesomeJob).and enqueue_sidekiq_job(OtherJob)
84
106
  ```
85
107
 
86
- ### have_enqueued_sidekiq_job
108
+ ### ```have_enqueued_sidekiq_job```
87
109
 
88
- Describes that there should be an enqueued job with the **specified arguments**
110
+ Describes that there should be an enqueued job (with the specified arguments):
89
111
 
90
112
  ```ruby
91
113
  AwesomeJob.perform_async 'Awesome', true
92
114
  # test with...
115
+ expect(AwesomeJob).to have_enqueued_sidekiq_job
93
116
  expect(AwesomeJob).to have_enqueued_sidekiq_job('Awesome', true)
94
117
  ```
95
118
 
@@ -106,6 +129,26 @@ expect(AwesomeJob).to have_enqueued_sidekiq_job(hash_excluding("bad_stuff" => an
106
129
  expect(AwesomeJob).to have_enqueued_sidekiq_job(any_args).and have_enqueued_sidekiq_job(hash_including("something" => "Awesome"))
107
130
  ```
108
131
 
132
+ You can specify the number of jobs enqueued:
133
+
134
+ ```ruby
135
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.once
136
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.exactly(1).time
137
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.exactly(:once)
138
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_least(1).time
139
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_least(:once)
140
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_most(2).times
141
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_most(:twice)
142
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_most(:thrice)
143
+ ```
144
+
145
+ Likewise, specify what should be in the context:
146
+ ```ruby
147
+ AwesomeJob.set(trace_id: "something").perform_async
148
+
149
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.with_context(trace_id: anything)
150
+ ```
151
+
109
152
  #### Testing scheduled jobs
110
153
 
111
154
  *Use chainable matchers `#at`, `#in` and `#immediately`*
@@ -166,30 +209,7 @@ expect(Sidekiq::Worker).to have_enqueued_sidekiq_job(
166
209
  )
167
210
  ```
168
211
 
169
- #### Testing a job is _not_ enqueued
170
-
171
- The negative case for `have_enqueued_sidekiq_job` is provided, but it's
172
- important to remember that `have_enqueued_sidekiq_job` is an expectation that a
173
- job is enqueued _with specific arguments_. In other words, passing no arguments
174
- to `have_enqueued_sidekiq_job` is implicitly telling the matcher to look for
175
- jobs _without_ arguments.
176
-
177
- In short, unless you tell the matcher that _no_ jobs with _any_ arguments should be enqueued, you'll get the wrong result:
178
-
179
- ```ruby
180
- # example this is a test that we'd expect to fail
181
- AwesomeJob.perform_async "Actually not awesome"
182
-
183
- ### BAD - saying there shouldn't be a job enqueued _without_ args
184
- expect(AwesomeJob).not_to have_enqueued_sidekiq_job
185
- # => passes! 😱 Our job was enqueued _with_ args so no job exists without args.
186
-
187
- ### Good
188
- expect(AwesomeJob).not_to have_enqueued_sidekiq_job(any_args)
189
- # => fails
190
- ```
191
-
192
- ### be_processed_in
212
+ ### ```be_processed_in```
193
213
  *Describes the queue that a job should be processed in*
194
214
  ```ruby
195
215
  sidekiq_options queue: :download
@@ -198,8 +218,12 @@ expect(AwesomeJob).to be_processed_in :download # or
198
218
  it { is_expected.to be_processed_in :download }
199
219
  ```
200
220
 
201
- ### be_retryable
221
+ ### ```be_retryable```
202
222
  *Describes if a job should retry when there is a failure in its execution*
223
+
224
+ Note: this only tests against the `retry` option in the job's Sidekiq options.
225
+ To test an enqueued job's retry, i.e. `AwesomeJob.set(retry: 5)`, use
226
+ `with_context`
203
227
  ```ruby
204
228
  sidekiq_options retry: 5
205
229
  # test with...
@@ -213,7 +237,7 @@ expect(AwesomeJob).to be_retryable false # or
213
237
  it { is_expected.to be_retryable false }
214
238
  ```
215
239
 
216
- ### save_backtrace
240
+ ### ```save_backtrace```
217
241
  *Describes if a job should save the error backtrace when there is a failure in its execution*
218
242
  ```ruby
219
243
  sidekiq_options backtrace: 5
@@ -230,16 +254,35 @@ it { is_expected.to_not save_backtrace } # or
230
254
  it { is_expected.to save_backtrace false }
231
255
  ```
232
256
 
233
- ### be_unique
257
+ ### ```be_unique```
258
+
259
+ :warning: This is intended to for Sidekiq Enterprise unique job implementation.
260
+ There is _limited_ support for Sidekiq Unique Jobs, but compatibility is not
261
+ guaranteed.
262
+
234
263
  *Describes when a job should be unique within its queue*
235
264
  ```ruby
236
- sidekiq_options unique: true
265
+ sidekiq_options unique_for: 1.hour
237
266
  # test with...
238
267
  expect(AwesomeJob).to be_unique
239
268
  it { is_expected.to be_unique }
269
+
270
+ # specify a specific interval
271
+ sidekiq_options unique_for: 1.hour
272
+ it { is_expected.to be_unique.for(1.hour) }
240
273
  ```
241
274
 
242
- ### be_expired_in
275
+ #### `until` sub-matcher
276
+
277
+ :warning: This sub-matcher only works for Sidekiq Enterprise
278
+
279
+ ```ruby
280
+ sidekiq_options unique_for: 1.hour, unique_until: :start
281
+ it { is_expected.to be_unique.until(:start) }
282
+ ```
283
+
284
+
285
+ ### ```be_expired_in```
243
286
  *Describes when a job should expire*
244
287
  ```ruby
245
288
  sidekiq_options expires_in: 1.hour
@@ -248,7 +291,7 @@ it { is_expected.to be_expired_in 1.hour }
248
291
  it { is_expected.to_not be_expired_in 2.hours }
249
292
  ```
250
293
 
251
- ### be_delayed
294
+ ### ```be_delayed```
252
295
 
253
296
  **This matcher is deprecated**. Use of it with Sidekiq 7+ will raise an error.
254
297
  Sidekiq 7 [dropped Delayed
@@ -1,4 +1,7 @@
1
- require 'rspec/core'
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/core"
4
+ require "rspec/support/fuzzy_matcher"
2
5
 
3
6
  if defined? Sidekiq::Batch
4
7
  module RSpec
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rubygems"
2
4
  require "set"
3
5
 
@@ -22,6 +24,10 @@ module RSpec
22
24
  Gem::Version.new(::Sidekiq::VERSION) >= Gem::Version.new("7.0.0")
23
25
  end
24
26
 
27
+ def sidekiq_gte_8?
28
+ Gem::Version.new(::Sidekiq::VERSION) >= Gem::Version.new("8.0.0")
29
+ end
30
+
25
31
  def silence_warning(symbol)
26
32
  @silence_warnings << symbol
27
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sidekiq
2
4
  module Worker
3
5
  module ClassMethods
@@ -8,15 +10,15 @@ module Sidekiq
8
10
 
9
11
  def default_retries_exhausted_message
10
12
  {
11
- 'queue' => get_sidekiq_options[:worker],
13
+ 'queue' => get_sidekiq_options['queue'],
12
14
  'class' => name,
13
15
  'args' => [],
14
- 'error_message' => 'An error occured'
16
+ 'error_message' => 'An error occurred'
15
17
  }
16
18
  end
17
19
 
18
20
  def default_retries_exhausted_exception
19
- StandardError.new('An error occured')
21
+ StandardError.new('An error occurred')
20
22
  end
21
23
  end
22
24
  end
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec/core'
2
4
  require 'rspec/sidekiq/helpers/within_sidekiq_retries_exhausted_block'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -26,7 +28,7 @@ module RSpec
26
28
  # send to custom evaluator
27
29
  at_evaluator(value)
28
30
  else
29
- job.context.has_key?(key) && job.context[key] == value
31
+ job.context.has_key?(key) && RSpec::Support::FuzzyMatcher.values_match?(value, job.context[key])
30
32
  end
31
33
  end
32
34
  end
@@ -58,7 +60,11 @@ module RSpec
58
60
  private
59
61
 
60
62
  def active_job?
61
- job["class"] == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
63
+ if RSpec::Sidekiq.configuration.sidekiq_gte_8?
64
+ job["class"] == "Sidekiq::ActiveJob::Wrapper"
65
+ else
66
+ job["class"] == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
67
+ end
62
68
  end
63
69
 
64
70
  def deserialized_active_job_args
@@ -118,8 +124,19 @@ module RSpec
118
124
  @jobs = unwrap_jobs(klass.jobs).map { |job| EnqueuedJob.new(job) }
119
125
  end
120
126
 
121
- def includes?(arguments, options)
122
- !!jobs.find { |job| matches?(job, arguments, options) }
127
+ def includes?(arguments, options, count)
128
+ matching = jobs.filter { |job| matches?(job, arguments, options) }
129
+
130
+ case count[0]
131
+ when :exactly
132
+ matching.size == count[1]
133
+ when :at_least
134
+ matching.size >= count[1]
135
+ when :at_most
136
+ matching.size <= count[1]
137
+ else
138
+ matching.size > 0
139
+ end
123
140
  end
124
141
 
125
142
  def each(&block)
@@ -164,11 +181,12 @@ module RSpec
164
181
  include RSpec::Mocks::ArgumentMatchers
165
182
  include RSpec::Matchers::Composable
166
183
 
167
- attr_reader :expected_arguments, :expected_options, :klass, :actual_jobs
184
+ attr_reader :expected_arguments, :expected_options, :klass, :actual_jobs, :expected_count
168
185
 
169
186
  def initialize
170
187
  @expected_arguments = [any_args]
171
188
  @expected_options = {}
189
+ set_expected_count :positive, 1
172
190
  end
173
191
 
174
192
  def with(*expected_arguments)
@@ -196,12 +214,79 @@ module RSpec
196
214
  self
197
215
  end
198
216
 
217
+ def once
218
+ set_expected_count :exactly, 1
219
+ self
220
+ end
221
+
222
+ def twice
223
+ set_expected_count :exactly, 2
224
+ self
225
+ end
226
+
227
+ def thrice
228
+ set_expected_count :exactly, 3
229
+ self
230
+ end
231
+
232
+ def exactly(n)
233
+ set_expected_count :exactly, n
234
+ self
235
+ end
236
+
237
+ def at_least(n)
238
+ set_expected_count :at_least, n
239
+ self
240
+ end
241
+
242
+ def at_most(n)
243
+ set_expected_count :at_most, n
244
+ self
245
+ end
246
+
247
+ def times
248
+ self
249
+ end
250
+ alias :time :times
251
+
252
+ def with_context(**kwargs)
253
+ raise ArgumentError, "Must specify keyword arguments to with_context" if kwargs.empty?
254
+
255
+ # gather keys and compare against currently set expected_options
256
+ # Someone could have accidentally used with_context and other
257
+ # chainables with different expectations. Better to explicitly
258
+ # inform loudly of clashes than let them overwrite silently
259
+ normalized = normalize_arguments(kwargs)
260
+ already_set = normalized.keys & @expected_options.keys
261
+ if already_set.any?
262
+ prettied = already_set.map { |key| "'#{key}'" }
263
+ raise ArgumentError, "There are already expectations against #{prettied.join(",")}. Did you already call other context chainables like `on` or `at`?"
264
+ end
265
+
266
+ # We're good, no accidental overwrites of expectations
267
+ @expected_options.merge!(normalized)
268
+
269
+ self
270
+ end
271
+
272
+ def set_expected_count(relativity, n)
273
+ n =
274
+ case n
275
+ when Integer then n
276
+ when :once then 1
277
+ when :twice then 2
278
+ when :thrice then 3
279
+ else raise ArgumentError, "Unsupported #{n} in '#{relativity} #{n}'. Use either an Integer, :once, :twice, or :thrice."
280
+ end
281
+ @expected_count = [relativity, n]
282
+ end
283
+
199
284
  def description
200
- "have an enqueued #{klass} job with arguments #{expected_arguments}"
285
+ "#{common_message} with arguments #{expected_arguments}"
201
286
  end
202
287
 
203
288
  def failure_message
204
- message = ["expected to have an enqueued #{klass} job"]
289
+ message = ["expected to #{common_message}"]
205
290
  if expected_arguments
206
291
  message << " with arguments:"
207
292
  message << " -#{formatted(expected_arguments)}"
@@ -213,27 +298,48 @@ module RSpec
213
298
  end
214
299
 
215
300
  if actual_jobs.any?
216
- message << "but have enqueued only jobs"
301
+ message << "but enqueued only jobs"
217
302
  if expected_arguments
218
303
  job_messages = actual_jobs.map do |job|
219
- base = " -JID:#{job.jid} with arguments:"
220
- base << "\n -#{formatted(job.args)}"
304
+ base = [" -JID:#{job.jid} with arguments:"]
305
+ base << " -#{formatted(job.args)}"
221
306
  if expected_options.any?
222
- base << "\n with context: #{formatted(job.context)}"
307
+ base << " with context: #{formatted(job.context)}"
223
308
  end
224
309
 
225
- base
310
+ base.join("\n")
226
311
  end
227
312
 
228
313
  message << job_messages.join("\n")
229
314
  end
315
+ else
316
+ message << "but enqueued 0 jobs"
230
317
  end
231
318
 
232
319
  message.join("\n")
233
320
  end
234
321
 
322
+ def common_message
323
+ "#{prefix_message} #{count_message} #{klass} #{expected_count.last == 1 ? "job" : "jobs"}"
324
+ end
325
+
326
+ def prefix_message
327
+ raise NotImplementedError
328
+ end
329
+
330
+ def count_message
331
+ case expected_count[0]
332
+ when :positive
333
+ "a"
334
+ when :exactly
335
+ expected_count[1]
336
+ else
337
+ "#{expected_count[0].to_s.gsub('_', ' ')} #{expected_count[1]}"
338
+ end
339
+ end
340
+
235
341
  def failure_message_when_negated
236
- message = ["expected not to have an enqueued #{klass} job"]
342
+ message = ["expected not to #{common_message} but enqueued #{actual_jobs.count}"]
237
343
  message << " arguments: #{expected_arguments}" if expected_arguments.any?
238
344
  message << " options: #{expected_options}" if expected_options.any?
239
345
  message.join("\n")
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -25,6 +27,9 @@ module RSpec
25
27
  if !interval_matches? && @expected_interval
26
28
  "expected #{@klass} to be unique for #{@expected_interval} seconds, "\
27
29
  "but its interval was #{actual_interval} seconds"
30
+ elsif !expiration_matches?
31
+ "expected #{@klass} to be unique until #{@expected_expiration}, "\
32
+ "but its unique_until was #{actual_expiration || 'not specified'}"
28
33
  else
29
34
  "expected #{@klass} to be unique in the queue"
30
35
  end
@@ -33,7 +38,7 @@ module RSpec
33
38
  def matches?(job)
34
39
  @klass = job.is_a?(Class) ? job : job.class
35
40
  @actual = @klass.get_sidekiq_options[unique_key]
36
- !!(value_matches? && interval_matches?)
41
+ !!(value_matches? && interval_matches? && expiration_matches?)
37
42
  end
38
43
 
39
44
  def for(interval)
@@ -41,6 +46,11 @@ module RSpec
41
46
  self
42
47
  end
43
48
 
49
+ def until(expiration)
50
+ @expected_expiration = expiration
51
+ self
52
+ end
53
+
44
54
  def interval_specified?
45
55
  @expected_interval
46
56
  end
@@ -49,6 +59,10 @@ module RSpec
49
59
  !interval_specified? || actual_interval == @expected_interval
50
60
  end
51
61
 
62
+ def expiration_matches?
63
+ @expected_expiration.nil? || actual_expiration == @expected_expiration
64
+ end
65
+
52
66
  def failure_message_when_negated
53
67
  "expected #{@klass} to not be unique in the queue"
54
68
  end
@@ -59,6 +73,10 @@ module RSpec
59
73
  @klass.get_sidekiq_options['unique_job_expiration']
60
74
  end
61
75
 
76
+ def actual_expiration
77
+ fail 'until is not supported for SidekiqUniqueJobs'
78
+ end
79
+
62
80
  def value_matches?
63
81
  [true, :all].include?(@actual)
64
82
  end
@@ -73,6 +91,10 @@ module RSpec
73
91
  @actual
74
92
  end
75
93
 
94
+ def actual_expiration
95
+ @klass.get_sidekiq_options['unique_until']
96
+ end
97
+
76
98
  def value_matches?
77
99
  @actual && @actual > 0
78
100
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -27,24 +29,11 @@ module RSpec
27
29
  return false
28
30
  end
29
31
 
30
- @actual_jobs.includes?(expected_arguments, expected_options)
32
+ @actual_jobs.includes?(expected_arguments, expected_options, expected_count)
31
33
  end
32
34
 
33
- def failure_message
34
- if @actual_jobs.none?
35
- "expected to enqueue a job but enqueued 0"
36
- else
37
- super
38
- end
39
- end
40
-
41
- def failure_message_when_negated
42
- messages = ["expected not to enqueue a #{@klass} job but enqueued #{actual_jobs.count}"]
43
-
44
- messages << " with arguments #{formatted(expected_arguments)}" if expected_arguments
45
- messages << " with context #{formatted(expected_options)}" if expected_options
46
-
47
- messages.join("\n")
35
+ def prefix_message
36
+ "enqueue"
48
37
  end
49
38
 
50
39
  def supports_block_expectations?
@@ -85,6 +74,9 @@ module RSpec
85
74
  # expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.immediately
86
75
  # expect { AwesomeJob.perform_at(1.hour.ago) }.to enqueue_sidekiq_job.immediately
87
76
  #
77
+ # # With specific context
78
+ # expect { AwesomeJob.set(trace_id: "something").perform_async }.to enqueue_sidekiq_job.with_context(trace_id: anything)
79
+ #
88
80
  # ## Composable
89
81
  #
90
82
  # expect do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -7,18 +9,8 @@ module RSpec
7
9
 
8
10
  # @api private
9
11
  class HaveEnqueuedSidekiqJob < Base
10
- DEPRECATION = [
11
- "[WARNING] `have_enqueued_sidekiq_job()` without arguments default behavior will change in next major release.",
12
- "Use `have_enqueued_sidekiq_job(no_args)` to maintain legacy behavior.",
13
- "More available here: https://github.com/wspurgin/rspec-sidekiq/wiki/have_enqueued_sidekiq_job-without-argument-default-behavior"
14
- ].join(" ").freeze
15
-
16
12
  def initialize(expected_arguments)
17
13
  super()
18
-
19
- if expected_arguments == [] && RSpec::Sidekiq.configuration.warn_for?(:have_enqueued_sidekiq_job_default)
20
- Kernel.warn(DEPRECATION, uplevel: 3)
21
- end
22
14
  @expected_arguments = normalize_arguments(expected_arguments)
23
15
  end
24
16
 
@@ -26,7 +18,16 @@ module RSpec
26
18
  @klass = job_class
27
19
 
28
20
  @actual_jobs = EnqueuedJobs.new(klass)
29
- actual_jobs.includes?(expected_arguments, expected_options)
21
+
22
+ actual_jobs.includes?(
23
+ expected_arguments == [] ? any_args : expected_arguments,
24
+ expected_options,
25
+ expected_count
26
+ )
27
+ end
28
+
29
+ def prefix_message
30
+ "have enqueued"
30
31
  end
31
32
  end
32
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  module Matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rspec/core"
2
4
  require "rspec/matchers"
3
5
  require "rspec/mocks/argument_list_matcher"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
5
  class << self
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RSpec
2
4
  module Sidekiq
3
- VERSION = "4.2.0"
5
+ VERSION = "5.1.0"
4
6
  end
5
7
  end
data/lib/rspec-sidekiq.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
 
3
5
  require 'sidekiq'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aidan Coyle
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-04-16 00:00:00.000000000 Z
13
+ date: 2025-03-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec-core
@@ -63,7 +63,7 @@ dependencies:
63
63
  version: '5'
64
64
  - - "<"
65
65
  - !ruby/object:Gem::Version
66
- version: '8'
66
+ version: '9'
67
67
  type: :runtime
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
@@ -73,7 +73,7 @@ dependencies:
73
73
  version: '5'
74
74
  - - "<"
75
75
  - !ruby/object:Gem::Version
76
- version: '8'
76
+ version: '9'
77
77
  - !ruby/object:Gem::Dependency
78
78
  name: pry
79
79
  requirement: !ruby/object:Gem::Requirement
@@ -228,6 +228,20 @@ dependencies:
228
228
  - - ">="
229
229
  - !ruby/object:Gem::Version
230
230
  version: '0'
231
+ - !ruby/object:Gem::Dependency
232
+ name: railties
233
+ requirement: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - ">="
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ type: :development
239
+ prerelease: false
240
+ version_requirements: !ruby/object:Gem::Requirement
241
+ requirements:
242
+ - - ">="
243
+ - !ruby/object:Gem::Version
244
+ version: '0'
231
245
  description: Simple testing of Sidekiq jobs via a collection of matchers and helpers
232
246
  email:
233
247
  executables: []
@@ -257,7 +271,8 @@ files:
257
271
  homepage: http://github.com/wspurgin/rspec-sidekiq
258
272
  licenses:
259
273
  - MIT
260
- metadata: {}
274
+ metadata:
275
+ changelog_uri: https://github.com/wspurgin/rspec-sidekiq/blob/main/CHANGES.md
261
276
  post_install_message:
262
277
  rdoc_options: []
263
278
  require_paths:
@@ -273,7 +288,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
288
  - !ruby/object:Gem::Version
274
289
  version: '0'
275
290
  requirements: []
276
- rubygems_version: 3.3.26
291
+ rubygems_version: 3.5.22
277
292
  signing_key:
278
293
  specification_version: 4
279
294
  summary: RSpec for Sidekiq