JT Book a call

Blog

assert_has_no_stream: Testing Stopped Action Cable Streams

Published

2 min read

assert_has_no_stream: Testing Stopped Action Cable Streams
In this post

Previously, developers encountered a significant challenge verifying if streams ceased operation correctly. This issue often led to the creation of intricate workarounds or the omission of proper testing.

The Old Way #

Here’s an example:

assert_not ActionCable.server.pubsub.redis_connection_for_subscriptions.subscribed_to?("messages")

This code works but isn’t straightforward to update.

The New Solution #

The next release after 7.1, Rails 7.2, introduces assert_has_no_stream and assert_has_no_stream_for. These new methods simplify the testing of stopped streams.

assert_has_no_stream "messages"
assert_has_no_stream_for User.find(42)

With these new assertion methods, you can straightforwardly express your test goals. This simplicity and clarity strengthen your tests and make them easier to maintain, giving you confidence in the reliability of your code.

Rails 7.2 and later #

The methods are not in any Rails 7.1.x release. They first shipped in Rails 7.2.0, where the Action Cable changelog credits Sebastian Pöll and Junichi Sato. If assert_has_no_stream raises NoMethodError in your test, check your Rails version first.

A full test #

Here is a channel that starts a stream on subscribe and stops it when the user leaves:

class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "messages"
  end

  def leave
    stop_stream_from "messages"
  end
end

And the test:

class ChatChannelTest < ActionCable::Channel::TestCase
  test "stops streaming when the user leaves" do
    subscribe
    assert_has_stream "messages"

    perform :leave
    assert_has_no_stream "messages"
  end
end

assert_has_no_stream_for works the same way for a stream started with stream_for and stopped with stop_stream_for. You pass the object, such as a user, and Rails builds the stream name from it.

On Rails 8.1 both versions behave the same way: if the stream is still running, the assertion fails with Stream messages has been started.

Assert the stream started first #

assert_has_no_stream only checks that the stream isn’t in the list right now. It also passes when the channel never started the stream at all, for example after someone renames "messages" in subscribed. That is why the test above calls assert_has_stream before perform :leave. Without that line, a broken subscribed method would still give you a green test.

Read next

Tell us what you need built

JetThoughts has been building software since 2008. Book a call, or write to sales@jetthoughts.com. You'll leave the call with a written one-page scope within 2 working days.

#01 Paul Keen
Paul KeenFounder & Open Source Contributor

A 30-minute call; pick a time.