Skip to content

Commit

Permalink
Improve implicit description for RSpec::Rails::Matchers::ActionCable:…
Browse files Browse the repository at this point in the history
…: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"]".
  • Loading branch information
boardfish committed Sep 4, 2024
1 parent 38d2b51 commit 622523a
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 deletions.
8 changes: 7 additions & 1 deletion lib/rspec/rails/matchers/action_cable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ def have_broadcasted_to(target = nil)

ActionCable::HaveBroadcastedTo.new(target, channel: described_class)
end
alias_method :broadcast_to, :have_broadcasted_to

def broadcast_to(target = nil)
RSpec::Matchers::AliasedMatcher.new(
have_broadcasted_to(target),
->(old_desc) { old_desc.gsub("have broadcasted", "broadcast") }
)
end

private

Expand Down
13 changes: 11 additions & 2 deletions lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -140,9 +144,14 @@ 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?
end
end

def base_message
base_description.tap do |msg|
msg << ", but broadcast #{@matching_msgs_count}"
end
end
Expand All @@ -151,7 +160,7 @@ def data_description(data)
if data.is_a?(RSpec::Matchers::Composable)
data.description
else
data
data.inspect
end
end

Expand Down
41 changes: 41 additions & 0 deletions spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -226,5 +226,46 @@ def broadcast(stream, msg)
end
end
end

it "has a description when not chained" do
expect(have_broadcasted_to("stream").description).to eq("have broadcasted exactly 1 messages to stream")
end

it "has a description when not chained and aliased" do
expect(broadcast_to("stream").description).to eq("broadcast exactly 1 messages to stream")
end

it "has a description when stream name is passed as an array" do
expect(have_broadcasted_to(%w[stream stream_2]).from_channel(channel).description).to eq("have broadcasted exactly 1 messages to broadcast:stream:stream_2")
end

it "has a description when stream name is passed as an array and aliased" do
expect(broadcast_to(%w[stream stream_2]).from_channel(channel).description).to eq("broadcast exactly 1 messages to broadcast:stream:stream_2")
end

it "has a description when chained with `from_channel" do
# We don't include the channel in the failure message, so we don't include it in the description either.
expect(have_broadcasted_to("stream").from_channel(channel).description).to eq("have broadcasted exactly 1 messages to stream")
end

it "has a description when chained with `from_channel" do
# We don't include the channel in the failure message, so we don't include it in the description either.
expect(have_broadcasted_to("stream").from_channel(channel).description).to eq("have broadcasted exactly 1 messages to stream")
end

it "has a description when chained with `with`" do
# We don't include the channel in the failure message, so we don't include it in the description either.
expect(have_broadcasted_to("stream").from_channel(channel).with("hello world").description).to eq("have broadcasted exactly 1 messages to stream with \"hello world\"")
end

it "has a description when chained with `with` and a composable matcher" do
# We don't include the channel in the failure message, so we don't include it in the description either.
expect(
have_broadcasted_to("stream")
.from_channel(channel)
.with(a_hash_including(a: :b))
.description
).to eq("have broadcasted exactly 1 messages to stream with a hash including {:a => :b}")
end
end
end

0 comments on commit 622523a

Please sign in to comment.