rspec-sidekiq 4.1.0 → 5.0.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: a4f0ece401056914cf478dc4657d19aad569156ebf40ee29ee85c36fc430cfc3
4
- data.tar.gz: 858c2c49ae54497a5201eab4cb3d9179fbe21a1684b11663719dfd17dd198cb2
3
+ metadata.gz: e2bbe8c4c2097c67abf526af45ba5a3652fa83e898ccb82732f3639b83cc7d33
4
+ data.tar.gz: ec606df39e62123fd43d595c412f9dd70edc5c93389395b6d6e58f53deccf32a
5
5
  SHA512:
6
- metadata.gz: 831dfa10d07623e001f2253072b6d8e5311a0d887661421ba3eb914fce8f5020b73e5c7bda02264ebf4be6b6f23c2b02f8082a149d7ff5836895525ae61d697c
7
- data.tar.gz: fda99d4e3bd9b43fb55ed60e96f77fd0ca54156bc6dcc42df3f1d2fb9323fff9fc63f5495a595766e937d0214fff10736ef18b9b468fccf4b97b91b2aae5e296
6
+ metadata.gz: 7a601baf7161f039f0fb8b78a8ea3bed432b418431eae0b2e149365922f88d7f7c543450433175c4c16ba974ab91b8050ba1dc927619bbc2162a229f34de94ad
7
+ data.tar.gz: 2964a340caee3c386a99eb8a69a79552782ff2e9cfcdacd9140d50232939138f95297b313620ec658f1e21fa044d946e3f030d8a8a212b3b1af2e1c89a175c6a
data/CHANGES.md CHANGED
@@ -1,3 +1,15 @@
1
+ Unreleased
2
+ ---
3
+
4
+ 5.0.0
5
+ ---
6
+ * [BREAKING] Make `have_enqueued_sidekiq_job()` match jobs with any arguments (same as `enqueue_sidekiq_job()` or `have_enqueued_sidekiq_job(any_args)`) (#215)
7
+ * Add support for expected number of jobs to both `enqueue_sidekiq_job` and `have_enqueued_sidekiq_job` (#219)
8
+
9
+ 4.2.0
10
+ ---
11
+ * Add warning about `have_enqueued_sidekiq_job` with no arguments (default will change in next major release) (#216, #217)
12
+
1
13
  4.1.0
2
14
  ---
3
15
  * Add Composable support to `enqueue_sidekiq_job` and
data/README.md CHANGED
@@ -34,14 +34,16 @@ end
34
34
  ```
35
35
 
36
36
  ## 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)
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
+ * [```save_backtrace```](#save_backtrace)
42
+ * [```be_unique```](#be_unique)
43
+ * [```be_expired_in```](#be_expired_in)
44
+ * [```be_delayed``` (_deprecated_)](#be_delayed)
43
45
 
44
- ### enqueue_sidekiq_job
46
+ ### ```enqueue_sidekiq_job```
45
47
 
46
48
  *Describes that the block should enqueue a job*. Optionally specify the
47
49
  specific job class, arguments, timing, and other context
@@ -68,6 +70,17 @@ freeze_time do
68
70
  expect { AwesomeJob.perform_in(1.hour) }.to enqueue_sidekiq_job.in(1.hour)
69
71
  end
70
72
 
73
+ # A specific number of times
74
+
75
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.once
76
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.exactly(1).time
77
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.exactly(:once)
78
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_least(1).time
79
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_least(:once)
80
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_most(2).times
81
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_most(:twice)
82
+ expect { AwesomeJob.perform_async }.to enqueue_sidekiq_job.at_most(:thrice)
83
+
71
84
  # Combine and chain them as desired
72
85
  expect { AwesomeJob.perform_at(specific_time, "Awesome!") }.to(
73
86
  enqueue_sidekiq_job(AwesomeJob)
@@ -83,13 +96,14 @@ expect do
83
96
  end.to enqueue_sidekiq_job(AwesomeJob).and enqueue_sidekiq_job(OtherJob)
84
97
  ```
85
98
 
86
- ### have_enqueued_sidekiq_job
99
+ ### ```have_enqueued_sidekiq_job```
87
100
 
88
- Describes that there should be an enqueued job with the **specified arguments**
101
+ Describes that there should be an enqueued job (with the specified arguments):
89
102
 
90
103
  ```ruby
91
104
  AwesomeJob.perform_async 'Awesome', true
92
105
  # test with...
106
+ expect(AwesomeJob).to have_enqueued_sidekiq_job
93
107
  expect(AwesomeJob).to have_enqueued_sidekiq_job('Awesome', true)
94
108
  ```
95
109
 
@@ -106,6 +120,19 @@ expect(AwesomeJob).to have_enqueued_sidekiq_job(hash_excluding("bad_stuff" => an
106
120
  expect(AwesomeJob).to have_enqueued_sidekiq_job(any_args).and have_enqueued_sidekiq_job(hash_including("something" => "Awesome"))
107
121
  ```
108
122
 
123
+ You can specify the number of jobs enqueued:
124
+
125
+ ```ruby
126
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.once
127
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.exactly(1).time
128
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.exactly(:once)
129
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_least(1).time
130
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_least(:once)
131
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_most(2).times
132
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_most(:twice)
133
+ expect(AwesomeJob).to have_enqueued_sidekiq_job.at_most(:thrice)
134
+ ```
135
+
109
136
  #### Testing scheduled jobs
110
137
 
111
138
  *Use chainable matchers `#at`, `#in` and `#immediately`*
@@ -166,30 +193,7 @@ expect(Sidekiq::Worker).to have_enqueued_sidekiq_job(
166
193
  )
167
194
  ```
168
195
 
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
196
+ ### ```be_processed_in```
193
197
  *Describes the queue that a job should be processed in*
194
198
  ```ruby
195
199
  sidekiq_options queue: :download
@@ -198,7 +202,7 @@ expect(AwesomeJob).to be_processed_in :download # or
198
202
  it { is_expected.to be_processed_in :download }
199
203
  ```
200
204
 
201
- ### be_retryable
205
+ ### ```be_retryable```
202
206
  *Describes if a job should retry when there is a failure in its execution*
203
207
  ```ruby
204
208
  sidekiq_options retry: 5
@@ -213,7 +217,7 @@ expect(AwesomeJob).to be_retryable false # or
213
217
  it { is_expected.to be_retryable false }
214
218
  ```
215
219
 
216
- ### save_backtrace
220
+ ### ```save_backtrace```
217
221
  *Describes if a job should save the error backtrace when there is a failure in its execution*
218
222
  ```ruby
219
223
  sidekiq_options backtrace: 5
@@ -230,7 +234,7 @@ it { is_expected.to_not save_backtrace } # or
230
234
  it { is_expected.to save_backtrace false }
231
235
  ```
232
236
 
233
- ### be_unique
237
+ ### ```be_unique```
234
238
  *Describes when a job should be unique within its queue*
235
239
  ```ruby
236
240
  sidekiq_options unique: true
@@ -239,7 +243,7 @@ expect(AwesomeJob).to be_unique
239
243
  it { is_expected.to be_unique }
240
244
  ```
241
245
 
242
- ### be_expired_in
246
+ ### ```be_expired_in```
243
247
  *Describes when a job should expire*
244
248
  ```ruby
245
249
  sidekiq_options expires_in: 1.hour
@@ -248,7 +252,7 @@ it { is_expected.to be_expired_in 1.hour }
248
252
  it { is_expected.to_not be_expired_in 2.hours }
249
253
  ```
250
254
 
251
- ### be_delayed
255
+ ### ```be_delayed```
252
256
 
253
257
  **This matcher is deprecated**. Use of it with Sidekiq 7+ will raise an error.
254
258
  Sidekiq 7 [dropped Delayed
@@ -1,4 +1,5 @@
1
1
  require "rubygems"
2
+ require "set"
2
3
 
3
4
  module RSpec
4
5
  module Sidekiq
@@ -14,11 +15,20 @@ module RSpec
14
15
  # Functional settings defaults
15
16
  @clear_all_enqueued_jobs = true
16
17
  @warn_when_jobs_not_processed_by_sidekiq = true
18
+ @silence_warnings = Set.new
17
19
  end
18
20
 
19
21
  def sidekiq_gte_7?
20
22
  Gem::Version.new(::Sidekiq::VERSION) >= Gem::Version.new("7.0.0")
21
23
  end
24
+
25
+ def silence_warning(symbol)
26
+ @silence_warnings << symbol
27
+ end
28
+
29
+ def warn_for?(symbol)
30
+ !@silence_warnings.include?(symbol)
31
+ end
22
32
  end
23
33
  end
24
34
  end
@@ -118,8 +118,19 @@ module RSpec
118
118
  @jobs = unwrap_jobs(klass.jobs).map { |job| EnqueuedJob.new(job) }
119
119
  end
120
120
 
121
- def includes?(arguments, options)
122
- !!jobs.find { |job| matches?(job, arguments, options) }
121
+ def includes?(arguments, options, count)
122
+ matching = jobs.filter { |job| matches?(job, arguments, options) }
123
+
124
+ case count
125
+ in [:exactly, n]
126
+ matching.size == n
127
+ in [:at_least, n]
128
+ matching.size >= n
129
+ in [:at_most, n]
130
+ matching.size <= n
131
+ else
132
+ matching.size > 0
133
+ end
123
134
  end
124
135
 
125
136
  def each(&block)
@@ -164,11 +175,12 @@ module RSpec
164
175
  include RSpec::Mocks::ArgumentMatchers
165
176
  include RSpec::Matchers::Composable
166
177
 
167
- attr_reader :expected_arguments, :expected_options, :klass, :actual_jobs
178
+ attr_reader :expected_arguments, :expected_options, :klass, :actual_jobs, :expected_count
168
179
 
169
180
  def initialize
170
181
  @expected_arguments = [any_args]
171
182
  @expected_options = {}
183
+ set_expected_count :positive, 1
172
184
  end
173
185
 
174
186
  def with(*expected_arguments)
@@ -196,12 +208,59 @@ module RSpec
196
208
  self
197
209
  end
198
210
 
211
+ def once
212
+ set_expected_count :exactly, 1
213
+ self
214
+ end
215
+
216
+ def twice
217
+ set_expected_count :exactly, 2
218
+ self
219
+ end
220
+
221
+ def thrice
222
+ set_expected_count :exactly, 3
223
+ self
224
+ end
225
+
226
+ def exactly(n)
227
+ set_expected_count :exactly, n
228
+ self
229
+ end
230
+
231
+ def at_least(n)
232
+ set_expected_count :at_least, n
233
+ self
234
+ end
235
+
236
+ def at_most(n)
237
+ set_expected_count :at_most, n
238
+ self
239
+ end
240
+
241
+ def times
242
+ self
243
+ end
244
+ alias :time :times
245
+
246
+ def set_expected_count(relativity, n)
247
+ n =
248
+ case n
249
+ when Integer then n
250
+ when :once then 1
251
+ when :twice then 2
252
+ when :thrice then 3
253
+ else raise ArgumentError, "Unsupported #{n} in '#{relativity} #{n}'. Use either an Integer, :once, :twice, or :thrice."
254
+ end
255
+ @expected_count = [relativity, n]
256
+ end
257
+
199
258
  def description
200
- "have an enqueued #{klass} job with arguments #{expected_arguments}"
259
+ "#{common_message} with arguments #{expected_arguments}"
201
260
  end
202
261
 
203
262
  def failure_message
204
- message = ["expected to have an enqueued #{klass} job"]
263
+ message = ["expected to #{common_message}"]
205
264
  if expected_arguments
206
265
  message << " with arguments:"
207
266
  message << " -#{formatted(expected_arguments)}"
@@ -213,7 +272,7 @@ module RSpec
213
272
  end
214
273
 
215
274
  if actual_jobs.any?
216
- message << "but have enqueued only jobs"
275
+ message << "but enqueued only jobs"
217
276
  if expected_arguments
218
277
  job_messages = actual_jobs.map do |job|
219
278
  base = " -JID:#{job.jid} with arguments:"
@@ -227,13 +286,34 @@ module RSpec
227
286
 
228
287
  message << job_messages.join("\n")
229
288
  end
289
+ else
290
+ message << "but enqueued 0 jobs"
230
291
  end
231
292
 
232
293
  message.join("\n")
233
294
  end
234
295
 
296
+ def common_message
297
+ "#{prefix_message} #{count_message} #{klass} #{expected_count.last == 1 ? "job" : "jobs"}"
298
+ end
299
+
300
+ def prefix_message
301
+ raise NotImplementedError
302
+ end
303
+
304
+ def count_message
305
+ case expected_count
306
+ in [:positive, _]
307
+ "a"
308
+ in [:exactly, n]
309
+ n
310
+ in [relativity, n]
311
+ "#{relativity.to_s.gsub('_', ' ')} #{n}"
312
+ end
313
+ end
314
+
235
315
  def failure_message_when_negated
236
- message = ["expected not to have an enqueued #{klass} job"]
316
+ message = ["expected not to #{common_message} but enqueued #{actual_jobs.count}"]
237
317
  message << " arguments: #{expected_arguments}" if expected_arguments.any?
238
318
  message << " options: #{expected_options}" if expected_options.any?
239
319
  message.join("\n")
@@ -27,24 +27,11 @@ module RSpec
27
27
  return false
28
28
  end
29
29
 
30
- @actual_jobs.includes?(expected_arguments, expected_options)
30
+ @actual_jobs.includes?(expected_arguments, expected_options, expected_count)
31
31
  end
32
32
 
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")
33
+ def prefix_message
34
+ "enqueue"
48
35
  end
49
36
 
50
37
  def supports_block_expectations?
@@ -17,7 +17,15 @@ module RSpec
17
17
 
18
18
  @actual_jobs = EnqueuedJobs.new(klass)
19
19
 
20
- actual_jobs.includes?(expected_arguments, expected_options)
20
+ actual_jobs.includes?(
21
+ expected_arguments == [] ? any_args : expected_arguments,
22
+ expected_options,
23
+ expected_count
24
+ )
25
+ end
26
+
27
+ def prefix_message
28
+ "have enqueued"
21
29
  end
22
30
  end
23
31
  end
@@ -1,4 +1,5 @@
1
1
  require "rspec/core"
2
+ require "rspec/matchers"
2
3
  require "rspec/mocks/argument_list_matcher"
3
4
  require "rspec/mocks/argument_matchers"
4
5
 
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module Sidekiq
3
- VERSION = "4.1.0"
3
+ VERSION = "5.0.0"
4
4
  end
5
5
  end
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.1.0
4
+ version: 5.0.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: 2023-10-27 00:00:00.000000000 Z
13
+ date: 2024-05-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec-core