From 86db479a4f4b6f2ad7c1ebfd3a368806f2ce6f6f Mon Sep 17 00:00:00 2001 From: Simon Fish Date: Wed, 4 Sep 2024 16:36:16 +0100 Subject: [PATCH 1/2] Improve implicit description for RSpec::Rails::Matchers::ActionCable::HaveBroadcastedTo Previously, tests defined like this: ```rb it do expect { some_action }.to have_broadcasted_to("stream_name").from_channel(SomeChannel).with("some_data") end ``` would implicitly be given the description `have broadcasted to`, which is derived from the name of the matcher method. This didn't carry any extra information about the data we're expecting to be broadcast from the channel - behaviour which would be very welcome in combination with Turbo Streams. With a matcher for Turbo Streams, we might benefit from a description like "broadcast exactly 1 messages to stream with turbo-stream[action="append"][target="some_list"]". Co-authored-by: Jon Rowe Co-authored-by: Phil Pirozhkov --- lib/rspec/rails/matchers/action_cable.rb | 8 ++++- .../action_cable/have_broadcasted_to.rb | 13 ++++++-- .../action_cable/have_broadcasted_to_spec.rb | 31 +++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/lib/rspec/rails/matchers/action_cable.rb b/lib/rspec/rails/matchers/action_cable.rb index 12b811d7b4..978fcca0a4 100644 --- a/lib/rspec/rails/matchers/action_cable.rb +++ b/lib/rspec/rails/matchers/action_cable.rb @@ -3,6 +3,8 @@ module RSpec module Rails module Matchers + extend RSpec::Matchers::DSL + # Namespace for various implementations of ActionCable features # # @api private @@ -45,12 +47,16 @@ module ActionCable # expect { # ActionCable.server.broadcast "messages", text: 'Hi!' # }.to have_broadcasted_to("messages").with(text: 'Hi!') + def have_broadcasted_to(target = nil) check_action_cable_adapter ActionCable::HaveBroadcastedTo.new(target, channel: described_class) end - alias_method :broadcast_to, :have_broadcasted_to + + alias_matcher :broadcast_to, :have_broadcasted_to do |desc| + desc.gsub("have broadcasted", "broadcast") + end private diff --git a/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb b/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb index 297d7cfcf3..090065c2a2 100644 --- a/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +++ b/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb @@ -51,6 +51,10 @@ def thrice exactly(:thrice) end + def description + "have broadcasted #{base_description}" + end + def failure_message "expected to broadcast #{base_message}".tap do |msg| if @unmatching_msgs.any? @@ -140,18 +144,21 @@ def set_expected_number(relativity, count) end end - def base_message + def base_description "#{message_expectation_modifier} #{@expected_number} messages to #{stream}".tap do |msg| msg << " with #{data_description(@data)}" unless @data.nil? - msg << ", but broadcast #{@matching_msgs_count}" end end + def base_message + "#{base_description}, but broadcast #{@matching_msgs_count}" + end + def data_description(data) if data.is_a?(RSpec::Matchers::Composable) data.description else - data + data.inspect end end diff --git a/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb b/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb index 815a9225a8..47648ff1a0 100644 --- a/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb +++ b/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb @@ -226,5 +226,36 @@ def broadcast(stream, msg) end end end + + it "has an appropriate description" do + expect(have_broadcasted_to("my_stream").description).to eq("have broadcasted exactly 1 messages to my_stream") + end + + it "has an appropriate description when aliased" do + expect(broadcast_to("my_stream").description).to eq("broadcast exactly 1 messages to my_stream") + end + + it "has an appropriate description when stream name is passed as an array" do + expect(have_broadcasted_to(%w[my_stream stream_2]).from_channel(channel).description).to eq("have broadcasted exactly 1 messages to broadcast:my_stream:stream_2") + end + + it "has an appropriate description not mentioning the channel when qualified with `#from_channel`" do + expect(have_broadcasted_to("my_stream").from_channel(channel).description).to eq("have broadcasted exactly 1 messages to my_stream") + end + + it "has an appropriate description including the expected contents when qualified with `#with`" do + expect(have_broadcasted_to("my_stream").from_channel(channel).with("hello world").description).to eq("have broadcasted exactly 1 messages to my_stream with \"hello world\"") + end + + it { expect("foo").to eq("foo") } + + it "has an appropriate description including the matcher's description when qualified with `#with` and a composable matcher" do + expect( + have_broadcasted_to("my_stream") + .from_channel(channel) + .with(a_hash_including(a: :b)) + .description + ).to eq("have broadcasted exactly 1 messages to my_stream with a hash including {:a => :b}") + end end end From 3e85bd20199d4e1ca9248bab3f1f3cbf2c4a36af Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sat, 7 Sep 2024 11:17:41 +0100 Subject: [PATCH 2/2] Remove accidentally commited spec and excess ws --- lib/rspec/rails/matchers/action_cable.rb | 1 - .../rails/matchers/action_cable/have_broadcasted_to_spec.rb | 3 --- 2 files changed, 4 deletions(-) diff --git a/lib/rspec/rails/matchers/action_cable.rb b/lib/rspec/rails/matchers/action_cable.rb index 978fcca0a4..d33de16bfd 100644 --- a/lib/rspec/rails/matchers/action_cable.rb +++ b/lib/rspec/rails/matchers/action_cable.rb @@ -47,7 +47,6 @@ module ActionCable # expect { # ActionCable.server.broadcast "messages", text: 'Hi!' # }.to have_broadcasted_to("messages").with(text: 'Hi!') - def have_broadcasted_to(target = nil) check_action_cable_adapter diff --git a/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb b/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb index 47648ff1a0..7e9470b3fc 100644 --- a/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb +++ b/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb @@ -246,9 +246,6 @@ def broadcast(stream, msg) it "has an appropriate description including the expected contents when qualified with `#with`" do expect(have_broadcasted_to("my_stream").from_channel(channel).with("hello world").description).to eq("have broadcasted exactly 1 messages to my_stream with \"hello world\"") end - - it { expect("foo").to eq("foo") } - it "has an appropriate description including the matcher's description when qualified with `#with` and a composable matcher" do expect( have_broadcasted_to("my_stream")