active_delivery 1.1.0 → 1.2.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +53 -21
  4. data/lib/.rbnext/3.0/abstract_notifier/async_adapters/active_job.rb +2 -2
  5. data/lib/.rbnext/3.0/abstract_notifier/base.rb +4 -4
  6. data/lib/.rbnext/3.0/active_delivery/base.rb +8 -8
  7. data/lib/.rbnext/3.0/active_delivery/lines/base.rb +4 -4
  8. data/lib/.rbnext/3.0/active_delivery/testing/minitest.rb +58 -0
  9. data/lib/.rbnext/3.0/active_delivery/testing.rb +1 -0
  10. data/lib/.rbnext/3.1/abstract_notifier/async_adapters/active_job.rb +2 -2
  11. data/lib/.rbnext/3.1/abstract_notifier/base.rb +4 -4
  12. data/lib/.rbnext/3.1/active_delivery/base.rb +8 -8
  13. data/lib/.rbnext/3.1/active_delivery/lines/base.rb +4 -4
  14. data/lib/.rbnext/3.1/active_delivery/testing/minitest.rb +58 -0
  15. data/lib/.rbnext/3.2/abstract_notifier/async_adapters/active_job.rb +36 -0
  16. data/lib/.rbnext/3.2/abstract_notifier/base.rb +223 -0
  17. data/lib/.rbnext/3.2/abstract_notifier/testing/rspec.rb +164 -0
  18. data/lib/.rbnext/3.2/abstract_notifier/testing.rb +53 -0
  19. data/lib/.rbnext/3.2/active_delivery/base.rb +249 -0
  20. data/lib/.rbnext/3.2/active_delivery/lines/base.rb +101 -0
  21. data/lib/.rbnext/3.2/active_delivery/lines/notifier.rb +57 -0
  22. data/lib/.rbnext/3.2/active_delivery/testing/rspec.rb +222 -0
  23. data/lib/abstract_notifier/async_adapters/active_job.rb +2 -2
  24. data/lib/abstract_notifier/base.rb +4 -4
  25. data/lib/abstract_notifier/testing/minitest.rb +1 -1
  26. data/lib/abstract_notifier/testing/rspec.rb +4 -4
  27. data/lib/abstract_notifier/testing.rb +2 -2
  28. data/lib/active_delivery/base.rb +8 -8
  29. data/lib/active_delivery/lines/base.rb +4 -4
  30. data/lib/active_delivery/lines/notifier.rb +6 -6
  31. data/lib/active_delivery/testing/minitest.rb +58 -0
  32. data/lib/active_delivery/testing/rspec.rb +4 -4
  33. data/lib/active_delivery/testing.rb +1 -0
  34. data/lib/active_delivery/version.rb +1 -1
  35. metadata +17 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfc96638e6c019dd1b13f57eef8ab3b9bf2a34df2b58ca7f7ea8ea167886c59e
4
- data.tar.gz: b50d556edef4a01fc7d1a8af1659a05f99a821584c2d4818418401f3a03350dd
3
+ metadata.gz: d05087cb016af8444f7668b81681675248b7b63f41f77a1d9fdb22b65ccb6845
4
+ data.tar.gz: d60851ccb9d9ea6557d131289942edf57b39c79a499e37d41f8f1d06b480446f
5
5
  SHA512:
6
- metadata.gz: 518d226591f5114383c2d138c163b4bac13e62666cce4f7edde7d2df5bca7e770c17576f00fee378b9a8733cc72372960efa2692839a6dc4d274d130787fcb41
7
- data.tar.gz: 2bd5eed0775fd32d83ca45364d8ecdc4f28c275eb2ffbbcad768ef98d8581b1cd0e66eb72f7e012c9d4dbd0a18e8a72cb40a858f0459614e18a5ee3e24fb0420
6
+ metadata.gz: 5a94a2fd3e2f19d9e99c0df6494752b23649802b064b390ea50d65506b01beb57650f31f5cd140495d6befa847a65423cc141ec8c313a6a116de69a4cd5576df
7
+ data.tar.gz: 4febe7f49e314d27f370642fa43085c5020dae8bac7fa9a3512514a6b861d17b726d4685ed91f081eab22f4c2af68a4117d37f8f29a576c78fe323f2c73b58e2
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.2.0 (2024-02-05)
6
+
7
+ - Add Minitest assertions (`assert_deliveries`, `assert_no_deliveries`, `assert_delivery_enqueued`). ([@palkan][])
8
+
5
9
  ## 1.1.0 (2023-12-01) ❄️
6
10
 
7
11
  - Support delayed delivery options (e.g, `wait_until`). ([@palkan][])
data/README.md CHANGED
@@ -10,6 +10,8 @@ Since v1.0, Active Delivery is bundled with [Abstract Notifier](https://github.c
10
10
 
11
11
  📖 Read the introduction post: ["Crafting user notifications in Rails with Active Delivery"](https://evilmartians.com/chronicles/crafting-user-notifications-in-rails-with-active-delivery)
12
12
 
13
+ 📖 Read more about designing notifications layer in Ruby on Rails applications in the [Layered design for Ruby on Rails applications](https://www.packtpub.com/product/layered-design-for-ruby-on-rails-applications/9781801813785) book.
14
+
13
15
  <a href="https://evilmartians.com/?utm_source=action_policy">
14
16
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
15
17
 
@@ -56,7 +58,7 @@ end
56
58
  Add this line to your application's Gemfile:
57
59
 
58
60
  ```ruby
59
- gem "active_delivery", "1.0.0.rc2"
61
+ gem "active_delivery", "~> 1.0"
60
62
  ```
61
63
 
62
64
  And then execute:
@@ -291,17 +293,36 @@ MyDeliver.notify(:something_wicked_this_way_comes)
291
293
 
292
294
  ## Testing
293
295
 
294
- **NOTE:** Currently, only RSpec matchers are provided.
296
+ ### Setup
297
+
298
+ Test mode is activated automatically if `RAILS_ENV` or `RACK_ENV` env variable is equal to "test". Otherwise, add `require "active_delivery/testing/rspec"` to your `spec_helper.rb` / `rails_helper.rb` manually or `require "active_delivery/testing/minitest"`. This is also required if you're using Spring in the test environment (e.g. with help of [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)).
299
+
300
+ For Minitest, you also MUST include the test helper into your test class. For example:
301
+
302
+ ```ruby
303
+ class ActiveSupport::TestCase
304
+ # ...
305
+ include ActiveDelivery::TestHelper
306
+ end
307
+ ```
295
308
 
296
309
  ### Deliveries
297
310
 
298
- Active Delivery provides an elegant way to test deliveries in your code (i.e., when you want to check whether a notification has been sent) through a `have_delivered_to` matcher:
311
+ Active Delivery provides an elegant way to test deliveries in your code (i.e., when you want to check whether a notification has been sent) through a `have_delivered_to` RSpec matcher or `assert_delivery_enqueued` Minitest assertion:
299
312
 
300
313
  ```ruby
314
+ # RSpec
301
315
  it "delivers notification" do
302
316
  expect { subject }.to have_delivered_to(Community::EventsDelivery, :modified, event)
303
317
  .with(profile: profile)
304
318
  end
319
+
320
+ # Minitest
321
+ def test_delivers_notification
322
+ assert_delivery_enqueued(Community::EventsDelivery, :modified, with: [event]) do
323
+ some_action
324
+ end
325
+ end
305
326
  ```
306
327
 
307
328
  You can also use such RSpec features as compound expectations and composed matchers:
@@ -320,14 +341,27 @@ end
320
341
  If you want to test that no notification is delivered you can use negation
321
342
 
322
343
  ```ruby
344
+ # RSpec
323
345
  specify "when event is not found" do
324
346
  expect do
325
347
  described_class.perform_now(profile.id, "123", "one_hour_before")
326
348
  end.not_to have_delivered_to(Community::EventsDelivery)
327
349
  end
350
+
351
+ # Minitest
352
+ def test_no_notification_if_event_is_not_found
353
+ assert_no_deliveries do
354
+ some_action
355
+ end
356
+
357
+ # Alternatively, you can use the positive assertion
358
+ assert_deliveries(0) do
359
+ some_action
360
+ end
361
+ end
328
362
  ```
329
363
 
330
- or use the `#have_not_delivered_to` matcher:
364
+ With RSpec, you can also use the `#have_not_delivered_to` matcher:
331
365
 
332
366
  ```ruby
333
367
  specify "when event is not found" do
@@ -360,7 +394,7 @@ describe PostsDelivery do
360
394
  end
361
395
  ```
362
396
 
363
- You can also use the `#deliver_via` matchers as follows:
397
+ You can also use the `#deliver_via` RSpec matcher as follows:
364
398
 
365
399
  ```ruby
366
400
  describe PostsDelivery, type: :delivery do
@@ -387,8 +421,6 @@ describe PostsDelivery, type: :delivery do
387
421
  end
388
422
  ```
389
423
 
390
- **NOTE:** test mode activated automatically if `RAILS_ENV` or `RACK_ENV` env variable is equal to "test". Otherwise, add `require "active_delivery/testing/rspec"` to your `spec_helper.rb` / `rails_helper.rb` manually. This is also required if you're using Spring in the test environment (e.g. with help of [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)).
391
-
392
424
  ## Custom "lines"
393
425
 
394
426
  The _Line_ class describes the way you want to _transfer_ your deliveries.
@@ -410,8 +442,8 @@ class EventPigeon
410
442
  alias_method :with, :new
411
443
 
412
444
  # delegate delivery action to the instance
413
- def message_arrived(*args)
414
- new.message_arrived(*args)
445
+ def message_arrived(*)
446
+ new.message_arrived(*)
415
447
  end
416
448
  end
417
449
 
@@ -447,17 +479,17 @@ class PigeonLine < ActiveDelivery::Lines::Base
447
479
  # Called when we want to send message synchronously
448
480
  # `sender` here either `sender_class` or `sender_class.with(params)`
449
481
  # if params passed.
450
- def notify_now(sender, delivery_action, *args, **kwargs)
482
+ def notify_now(sender, delivery_action, *, **)
451
483
  # For example, our EventPigeon class returns some `Pigeon` object
452
- pigeon = sender.public_send(delivery_action, *args, **kwargs)
484
+ pigeon = sender.public_send(delivery_action, *, **)
453
485
  # PigeonLaunchService do all the sending job
454
486
  PigeonService.launch pigeon
455
487
  end
456
488
 
457
489
  # Called when we want to send a message asynchronously.
458
490
  # For example, you can use a background job here.
459
- def notify_later(sender, delivery_action, *args, **kwargs)
460
- pigeon = sender.public_send(delivery_action, *args, **kwargs)
491
+ def notify_later(sender, delivery_action, *, **)
492
+ pigeon = sender.public_send(delivery_action, *, **)
461
493
  # PigeonLaunchService do all the sending job
462
494
  PigeonLaunchJob.perform_later pigeon
463
495
  end
@@ -475,8 +507,8 @@ class EventPigeon
475
507
  alias_method :with, :new
476
508
 
477
509
  # delegate delivery action to the instance
478
- def message_arrived(*args)
479
- new.message_arrived(*args)
510
+ def message_arrived(*)
511
+ new.message_arrived(*)
480
512
  end
481
513
  end
482
514
 
@@ -491,18 +523,18 @@ class EventPigeon
491
523
  end
492
524
 
493
525
  class PigeonLine < ActiveDelivery::Lines::Base
494
- def notify_later(sender, delivery_action, *args, **kwargs)
526
+ def notify_later(sender, delivery_action, *, **kwargs)
495
527
  # `to_s` is important for serialization. Unless you might have error
496
- PigeonLaunchJob.perform_later sender.class.to_s, delivery_action, *args, **kwargs.merge(params: line.params)
528
+ PigeonLaunchJob.perform_later(sender.class.to_s, delivery_action, *, **kwargs.merge(params: line.params))
497
529
  end
498
530
  end
499
531
 
500
532
  class PigeonLaunchJob < ActiveJob::Base
501
- def perform(sender, delivery_action, *args, params: nil, **kwargs)
533
+ def perform(sender, delivery_action, *, params: nil, **)
502
534
  klass = sender.safe_constantize
503
535
  handler = params ? klass.with(**params) : klass.new
504
536
 
505
- handler.public_send(delivery_action, *args, **kwargs)
537
+ handler.public_send(delivery_action, *, **)
506
538
  end
507
539
  end
508
540
  ```
@@ -591,12 +623,12 @@ class ActionCableDeliveryLine < ActiveDelivery::Line::Base
591
623
  # We want to broadcast all notifications
592
624
  def notify?(...) = true
593
625
 
594
- def notify_now(context, delivery_action, *args, **kwargs)
626
+ def notify_now(context, delivery_action, *, **)
595
627
  # Skip if no user provided
596
628
  return unless context.user
597
629
 
598
630
  payload = {event: [context.scope, delivery_action].join(".")}
599
- payload.merge!(serialized_args(*args, **kwargs))
631
+ payload.merge!(serialized_args(*, **))
600
632
 
601
633
  DeliveryChannel.broadcast_to context.user, payload
602
634
  end
@@ -22,8 +22,8 @@ module AbstractNotifier
22
22
  job.set(queue: queue).perform_later(...)
23
23
  end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :enqueue)
24
24
 
25
- def enqueue_delivery(delivery, **opts)
26
- job.set(queue: queue, **opts).perform_later(
25
+ def enqueue_delivery(delivery, **__kwrest__)
26
+ job.set(queue: queue, **__kwrest__).perform_later(
27
27
  delivery.notifier_class.name,
28
28
  delivery.action_name,
29
29
  **delivery.delivery_params
@@ -23,9 +23,9 @@ module AbstractNotifier
23
23
 
24
24
  alias_method :notification, :processed
25
25
 
26
- def notify_later(**opts)
26
+ def notify_later(**__kwrest__)
27
27
  if notifier_class.async_adapter.respond_to?(:enqueue_delivery)
28
- notifier_class.async_adapter.enqueue_delivery(self, **opts)
28
+ notifier_class.async_adapter.enqueue_delivery(self, **__kwrest__)
29
29
  else
30
30
  notifier_class.async_adapter.enqueue(notifier_class.name, action_name, params: params, args: args, kwargs: kwargs)
31
31
  end
@@ -73,8 +73,8 @@ module AbstractNotifier
73
73
  end
74
74
  # rubocop:enable Style/MethodMissingSuper
75
75
 
76
- def respond_to_missing?(*args)
77
- notifier_class.respond_to_missing?(*args)
76
+ def respond_to_missing?(*__rest__)
77
+ notifier_class.respond_to_missing?(*__rest__)
78
78
  end
79
79
  end
80
80
 
@@ -77,8 +77,8 @@ module ActiveDelivery
77
77
 
78
78
  # The same as .notify but delivers synchronously
79
79
  # (i.e. #deliver_now for mailers)
80
- def notify!(mid, *args, **hargs)
81
- notify(mid, *args, **hargs, sync: true)
80
+ def notify!(mid, *__rest__, **hargs)
81
+ notify(mid, *__rest__, **hargs, sync: true)
82
82
  end
83
83
 
84
84
  alias_method :notify_now, :notify!
@@ -93,7 +93,7 @@ module ActiveDelivery
93
93
  end
94
94
  end
95
95
 
96
- def register_line(line_id, line_class = nil, notifier: nil, **options)
96
+ def register_line(line_id, line_class = nil, notifier: nil, **__kwrest__)
97
97
  raise ArgumentError, "A line class or notifier configuration must be provided" if line_class.nil? && notifier.nil?
98
98
 
99
99
  # Configure Notifier
@@ -101,7 +101,7 @@ module ActiveDelivery
101
101
  line_class = ActiveDelivery::Lines::Notifier
102
102
  end
103
103
 
104
- delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **options)
104
+ delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **__kwrest__)
105
105
 
106
106
  instance_eval <<~CODE, __FILE__, __LINE__ + 1
107
107
  def #{line_id}(val)
@@ -152,13 +152,13 @@ module ActiveDelivery
152
152
  super
153
153
  end
154
154
 
155
- def method_missing(mid, *args, **kwargs)
155
+ def method_missing(mid, *__rest__, **__kwrest__)
156
156
  return super unless respond_to_missing?(mid)
157
157
 
158
158
  # Lazily define a class method to avoid lookups
159
159
  delivers(mid)
160
160
 
161
- public_send(mid, *args, **kwargs)
161
+ public_send(mid, *__rest__, **__kwrest__)
162
162
  end
163
163
  end
164
164
 
@@ -197,7 +197,7 @@ module ActiveDelivery
197
197
  super
198
198
  end
199
199
 
200
- def method_missing(mid, *args, **kwargs)
200
+ def method_missing(mid, *__rest__, **__kwrest__)
201
201
  return super unless respond_to_missing?(mid)
202
202
 
203
203
  # Lazily define a method to avoid future lookups
@@ -211,7 +211,7 @@ module ActiveDelivery
211
211
  end
212
212
  CODE
213
213
 
214
- public_send(mid, *args, **kwargs)
214
+ public_send(mid, *__rest__, **__kwrest__)
215
215
  end
216
216
 
217
217
  protected
@@ -41,16 +41,16 @@ module ActiveDelivery
41
41
  notify_later(handler, mid, *__rest__, &__block__)
42
42
  end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_later_with_options)
43
43
 
44
- def notify(mid, *args, params:, sync:, enqueue_options:, **kwargs)
44
+ def notify(mid, *__rest__, params:, sync:, enqueue_options:, **__kwrest__)
45
45
  clazz = params.empty? ? handler_class : handler_class.with(**params)
46
46
  if sync
47
- return notify_now(clazz, mid, *args, **kwargs)
47
+ return notify_now(clazz, mid, *__rest__, **__kwrest__)
48
48
  end
49
49
 
50
50
  if enqueue_options.empty?
51
- notify_later(clazz, mid, *args, **kwargs)
51
+ notify_later(clazz, mid, *__rest__, **__kwrest__)
52
52
  else
53
- notify_later_with_options(clazz, enqueue_options, mid, *args, **kwargs)
53
+ notify_later_with_options(clazz, enqueue_options, mid, *__rest__, **__kwrest__)
54
54
  end
55
55
  end
56
56
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveDelivery
4
+ module TestHelper
5
+ def assert_deliveries(count)
6
+ TestDelivery.enable { yield }
7
+
8
+ assert_equal TestDelivery.store.count, count, "Expected #{count} deliveries, got #{TestDelivery.store.count}"
9
+ end
10
+
11
+ def assert_no_deliveries(&__block__) ; assert_deliveries(0, &__block__); end
12
+
13
+ def assert_delivery_enqueued(delivery_class, event, count: 1, params: nil, with: nil)
14
+ TestDelivery.enable { yield }
15
+
16
+ deliveries = TestDelivery.store
17
+
18
+ if with
19
+ args = with
20
+ kwargs = args.pop if args.last.is_a?(Hash)
21
+ end
22
+
23
+ matching_deliveries, _unmatching_deliveries =
24
+ deliveries.partition do |(delivery, options)|
25
+ next false if delivery_class != delivery.owner.class
26
+
27
+ next false if event != delivery.notification
28
+
29
+ next false if params && !hash_include?(delivery.owner.params, params)
30
+
31
+ next true unless with
32
+
33
+ actual_args = delivery.params
34
+ actual_kwargs = delivery.options
35
+
36
+ next false unless args.each.with_index.all? do |arg, i|
37
+ arg === actual_args[i]
38
+ end
39
+
40
+ next false unless kwargs.all? do |k, v|
41
+ v === actual_kwargs[k]
42
+ end
43
+
44
+ true
45
+ end
46
+
47
+ assert_equal count, matching_deliveries.count, "Expected #{count} deliveries, got #{deliveries.count}"
48
+ end
49
+
50
+ private
51
+
52
+ def hash_include?(haystack, needle)
53
+ needle.all? do |k, v|
54
+ haystack.key?(k) && haystack[k] == v
55
+ end
56
+ end
57
+ end
58
+ end
@@ -60,3 +60,4 @@ end
60
60
  ActiveDelivery::Base.prepend ActiveDelivery::TestDelivery
61
61
 
62
62
  require "active_delivery/testing/rspec" if defined?(RSpec::Core)
63
+ require "active_delivery/testing/minitest" if defined?(Minitest::Assertions)
@@ -22,8 +22,8 @@ module AbstractNotifier
22
22
  job.set(queue: queue).perform_later(...)
23
23
  end
24
24
 
25
- def enqueue_delivery(delivery, **opts)
26
- job.set(queue: queue, **opts).perform_later(
25
+ def enqueue_delivery(delivery, **__kwrest__)
26
+ job.set(queue: queue, **__kwrest__).perform_later(
27
27
  delivery.notifier_class.name,
28
28
  delivery.action_name,
29
29
  **delivery.delivery_params
@@ -23,9 +23,9 @@ module AbstractNotifier
23
23
 
24
24
  alias_method :notification, :processed
25
25
 
26
- def notify_later(**opts)
26
+ def notify_later(**__kwrest__)
27
27
  if notifier_class.async_adapter.respond_to?(:enqueue_delivery)
28
- notifier_class.async_adapter.enqueue_delivery(self, **opts)
28
+ notifier_class.async_adapter.enqueue_delivery(self, **__kwrest__)
29
29
  else
30
30
  notifier_class.async_adapter.enqueue(notifier_class.name, action_name, params: params, args: args, kwargs: kwargs)
31
31
  end
@@ -73,8 +73,8 @@ module AbstractNotifier
73
73
  end
74
74
  # rubocop:enable Style/MethodMissingSuper
75
75
 
76
- def respond_to_missing?(*args)
77
- notifier_class.respond_to_missing?(*args)
76
+ def respond_to_missing?(*__rest__)
77
+ notifier_class.respond_to_missing?(*__rest__)
78
78
  end
79
79
  end
80
80
 
@@ -77,8 +77,8 @@ module ActiveDelivery
77
77
 
78
78
  # The same as .notify but delivers synchronously
79
79
  # (i.e. #deliver_now for mailers)
80
- def notify!(mid, *args, **hargs)
81
- notify(mid, *args, **hargs, sync: true)
80
+ def notify!(mid, *__rest__, **hargs)
81
+ notify(mid, *__rest__, **hargs, sync: true)
82
82
  end
83
83
 
84
84
  alias_method :notify_now, :notify!
@@ -93,7 +93,7 @@ module ActiveDelivery
93
93
  end
94
94
  end
95
95
 
96
- def register_line(line_id, line_class = nil, notifier: nil, **options)
96
+ def register_line(line_id, line_class = nil, notifier: nil, **__kwrest__)
97
97
  raise ArgumentError, "A line class or notifier configuration must be provided" if line_class.nil? && notifier.nil?
98
98
 
99
99
  # Configure Notifier
@@ -101,7 +101,7 @@ module ActiveDelivery
101
101
  line_class = ActiveDelivery::Lines::Notifier
102
102
  end
103
103
 
104
- delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **options)
104
+ delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **__kwrest__)
105
105
 
106
106
  instance_eval <<~CODE, __FILE__, __LINE__ + 1
107
107
  def #{line_id}(val)
@@ -152,13 +152,13 @@ module ActiveDelivery
152
152
  super
153
153
  end
154
154
 
155
- def method_missing(mid, *args, **kwargs)
155
+ def method_missing(mid, *__rest__, **__kwrest__)
156
156
  return super unless respond_to_missing?(mid)
157
157
 
158
158
  # Lazily define a class method to avoid lookups
159
159
  delivers(mid)
160
160
 
161
- public_send(mid, *args, **kwargs)
161
+ public_send(mid, *__rest__, **__kwrest__)
162
162
  end
163
163
  end
164
164
 
@@ -197,7 +197,7 @@ module ActiveDelivery
197
197
  super
198
198
  end
199
199
 
200
- def method_missing(mid, *args, **kwargs)
200
+ def method_missing(mid, *__rest__, **__kwrest__)
201
201
  return super unless respond_to_missing?(mid)
202
202
 
203
203
  # Lazily define a method to avoid future lookups
@@ -211,7 +211,7 @@ module ActiveDelivery
211
211
  end
212
212
  CODE
213
213
 
214
- public_send(mid, *args, **kwargs)
214
+ public_send(mid, *__rest__, **__kwrest__)
215
215
  end
216
216
 
217
217
  protected
@@ -41,16 +41,16 @@ module ActiveDelivery
41
41
  notify_later(handler, mid, ...)
42
42
  end
43
43
 
44
- def notify(mid, *args, params:, sync:, enqueue_options:, **kwargs)
44
+ def notify(mid, *__rest__, params:, sync:, enqueue_options:, **__kwrest__)
45
45
  clazz = params.empty? ? handler_class : handler_class.with(**params)
46
46
  if sync
47
- return notify_now(clazz, mid, *args, **kwargs)
47
+ return notify_now(clazz, mid, *__rest__, **__kwrest__)
48
48
  end
49
49
 
50
50
  if enqueue_options.empty?
51
- notify_later(clazz, mid, *args, **kwargs)
51
+ notify_later(clazz, mid, *__rest__, **__kwrest__)
52
52
  else
53
- notify_later_with_options(clazz, enqueue_options, mid, *args, **kwargs)
53
+ notify_later_with_options(clazz, enqueue_options, mid, *__rest__, **__kwrest__)
54
54
  end
55
55
  end
56
56
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveDelivery
4
+ module TestHelper
5
+ def assert_deliveries(count)
6
+ TestDelivery.enable { yield }
7
+
8
+ assert_equal TestDelivery.store.count, count, "Expected #{count} deliveries, got #{TestDelivery.store.count}"
9
+ end
10
+
11
+ def assert_no_deliveries(&__block__) = assert_deliveries(0, &__block__)
12
+
13
+ def assert_delivery_enqueued(delivery_class, event, count: 1, params: nil, with: nil)
14
+ TestDelivery.enable { yield }
15
+
16
+ deliveries = TestDelivery.store
17
+
18
+ if with
19
+ args = with
20
+ kwargs = args.pop if args.last.is_a?(Hash)
21
+ end
22
+
23
+ matching_deliveries, _unmatching_deliveries =
24
+ deliveries.partition do |(delivery, options)|
25
+ next false if delivery_class != delivery.owner.class
26
+
27
+ next false if event != delivery.notification
28
+
29
+ next false if params && !hash_include?(delivery.owner.params, params)
30
+
31
+ next true unless with
32
+
33
+ actual_args = delivery.params
34
+ actual_kwargs = delivery.options
35
+
36
+ next false unless args.each.with_index.all? do |arg, i|
37
+ arg === actual_args[i]
38
+ end
39
+
40
+ next false unless kwargs.all? do |k, v|
41
+ v === actual_kwargs[k]
42
+ end
43
+
44
+ true
45
+ end
46
+
47
+ assert_equal count, matching_deliveries.count, "Expected #{count} deliveries, got #{deliveries.count}"
48
+ end
49
+
50
+ private
51
+
52
+ def hash_include?(haystack, needle)
53
+ needle.all? do |k, v|
54
+ haystack.key?(k) && haystack[k] == v
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AbstractNotifier
4
+ module AsyncAdapters
5
+ class ActiveJob
6
+ class DeliveryJob < ::ActiveJob::Base
7
+ def perform(notifier_class, ...)
8
+ AbstractNotifier::NotificationDelivery.new(notifier_class.constantize, ...).notify_now
9
+ end
10
+ end
11
+
12
+ DEFAULT_QUEUE = "notifiers"
13
+
14
+ attr_reader :job, :queue
15
+
16
+ def initialize(queue: DEFAULT_QUEUE, job: DeliveryJob)
17
+ @job = job
18
+ @queue = queue
19
+ end
20
+
21
+ def enqueue(...)
22
+ job.set(queue:).perform_later(...)
23
+ end
24
+
25
+ def enqueue_delivery(delivery, **__kwrest__)
26
+ job.set(queue:, **__kwrest__).perform_later(
27
+ delivery.notifier_class.name,
28
+ delivery.action_name,
29
+ **delivery.delivery_params
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ AbstractNotifier.async_adapter ||= :active_job