README.md in active_delivery-1.1.0 vs README.md in active_delivery-1.2.0

- old
+ new

@@ -8,10 +8,12 @@ Since v1.0, Active Delivery is bundled with [Abstract Notifier](https://github.com/palkan/abstract_notifier). See the docs on how to create custom notifiers [below](#abstract-notifier). 📖 Read the introduction post: ["Crafting user notifications in Rails with Active Delivery"](https://evilmartians.com/chronicles/crafting-user-notifications-in-rails-with-active-delivery) +📖 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. + <a href="https://evilmartians.com/?utm_source=action_policy"> <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a> Requirements: @@ -54,11 +56,11 @@ ## Installation Add this line to your application's Gemfile: ```ruby -gem "active_delivery", "1.0.0.rc2" +gem "active_delivery", "~> 1.0" ``` And then execute: ```sh @@ -289,21 +291,40 @@ #=> Delivery triggered: something_wicked_this_way_comes ``` ## Testing -**NOTE:** Currently, only RSpec matchers are provided. +### Setup +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)). + +For Minitest, you also MUST include the test helper into your test class. For example: + +```ruby +class ActiveSupport::TestCase + # ... + include ActiveDelivery::TestHelper +end +``` + ### Deliveries -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: +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: ```ruby +# RSpec it "delivers notification" do expect { subject }.to have_delivered_to(Community::EventsDelivery, :modified, event) .with(profile: profile) end + +# Minitest +def test_delivers_notification + assert_delivery_enqueued(Community::EventsDelivery, :modified, with: [event]) do + some_action + end +end ``` You can also use such RSpec features as compound expectations and composed matchers: ```ruby @@ -318,18 +339,31 @@ ``` If you want to test that no notification is delivered you can use negation ```ruby +# RSpec specify "when event is not found" do expect do described_class.perform_now(profile.id, "123", "one_hour_before") end.not_to have_delivered_to(Community::EventsDelivery) end + +# Minitest +def test_no_notification_if_event_is_not_found + assert_no_deliveries do + some_action + end + + # Alternatively, you can use the positive assertion + assert_deliveries(0) do + some_action + end +end ``` -or use the `#have_not_delivered_to` matcher: +With RSpec, you can also use the `#have_not_delivered_to` matcher: ```ruby specify "when event is not found" do expect do described_class.perform_now(profile.id, "123", "one_hour_before") @@ -358,11 +392,11 @@ end end end ``` -You can also use the `#deliver_via` matchers as follows: +You can also use the `#deliver_via` RSpec matcher as follows: ```ruby describe PostsDelivery, type: :delivery do let(:user) { build_stubbed(:user) } let(:post) { build_stubbed(:post) } @@ -385,12 +419,10 @@ end end end ``` -**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)). - ## Custom "lines" The _Line_ class describes the way you want to _transfer_ your deliveries. We only provide only Action Mailer _line_ out-of-the-box. @@ -408,12 +440,12 @@ class << self # Add `.with` method as an alias alias_method :with, :new # delegate delivery action to the instance - def message_arrived(*args) - new.message_arrived(*args) + def message_arrived(*) + new.message_arrived(*) end end def initialize(params = {}) # do smth with params @@ -445,21 +477,21 @@ end # Called when we want to send message synchronously # `sender` here either `sender_class` or `sender_class.with(params)` # if params passed. - def notify_now(sender, delivery_action, *args, **kwargs) + def notify_now(sender, delivery_action, *, **) # For example, our EventPigeon class returns some `Pigeon` object - pigeon = sender.public_send(delivery_action, *args, **kwargs) + pigeon = sender.public_send(delivery_action, *, **) # PigeonLaunchService do all the sending job PigeonService.launch pigeon end # Called when we want to send a message asynchronously. # For example, you can use a background job here. - def notify_later(sender, delivery_action, *args, **kwargs) - pigeon = sender.public_send(delivery_action, *args, **kwargs) + def notify_later(sender, delivery_action, *, **) + pigeon = sender.public_send(delivery_action, *, **) # PigeonLaunchService do all the sending job PigeonLaunchJob.perform_later pigeon end end ``` @@ -473,12 +505,12 @@ class << self # Add `.with` method as an alias alias_method :with, :new # delegate delivery action to the instance - def message_arrived(*args) - new.message_arrived(*args) + def message_arrived(*) + new.message_arrived(*) end end def initialize(params = {}) @params = params @@ -489,22 +521,22 @@ # send a pigeon with the message end end class PigeonLine < ActiveDelivery::Lines::Base - def notify_later(sender, delivery_action, *args, **kwargs) + def notify_later(sender, delivery_action, *, **kwargs) # `to_s` is important for serialization. Unless you might have error - PigeonLaunchJob.perform_later sender.class.to_s, delivery_action, *args, **kwargs.merge(params: line.params) + PigeonLaunchJob.perform_later(sender.class.to_s, delivery_action, *, **kwargs.merge(params: line.params)) end end class PigeonLaunchJob < ActiveJob::Base - def perform(sender, delivery_action, *args, params: nil, **kwargs) + def perform(sender, delivery_action, *, params: nil, **) klass = sender.safe_constantize handler = params ? klass.with(**params) : klass.new - handler.public_send(delivery_action, *args, **kwargs) + handler.public_send(delivery_action, *, **) end end ``` **NOTE**: we fall back to the superclass's sender class if `resolve_class` returns nil. @@ -589,15 +621,15 @@ end # We want to broadcast all notifications def notify?(...) = true - def notify_now(context, delivery_action, *args, **kwargs) + def notify_now(context, delivery_action, *, **) # Skip if no user provided return unless context.user payload = {event: [context.scope, delivery_action].join(".")} - payload.merge!(serialized_args(*args, **kwargs)) + payload.merge!(serialized_args(*, **)) DeliveryChannel.broadcast_to context.user, payload end # Broadcasts are asynchronous by nature, so we can just use `notify_now`