'How can I test ActionCable channels using RSpec?

I am wondering how to test ActionCable channels.

Let's say I have the following chat channel:

class ChatChannel < ApplicationCable::Channel
  def subscribed
    current_user.increment!(:num_of_chats)

    stream_from "chat_#{params[:chat_id]}"
    stream_from "chat_stats_#{params[:chat_id]}"
  end
end

The subscribed method updates the db and defines two streams to be broadcasted across the channel, but the details are not very important since my question is a more general one:

  • How can I set up a test to test the logic involved by subscribing to this channel?

RSpec provides a lot of helper methods and various utilities when testing similar interactions like controller actions, but I couldn't find anything regarding RSpec and ActionCable.



Solution 1:[1]

You can use `action-cable-testing` gem.

Add this to your Gemfile
gem 'action-cable-testing'
Then run
$ bundle install

Then add following spec

# spec/channels/chat_channel_spec.rb

require "rails_helper"

RSpec.describe ChatChannel, type: :channel do
  before do
    # initialize connection with identifiers
    stub_connection current_user: current_user
  end

  it "rejects when no room id" do
    subscribe
    expect(subscription).to be_rejected
  end

  it "subscribes to a stream when room id is provided" do
    subscribe(chat_id: 42)

    expect(subscription).to be_confirmed
    expect(streams).to include("chat_42")
    expect(streams).to include("chat_stats_42")
  end
end

For more information see readme in github repo.

https://github.com/palkan/action-cable-testing

There are examples for both rspec and test_case

Solution 2:[2]

I would install and configure TCR gem for recording sockets interaction ('its like VCR for websockets')

A spec for this in your case might look something like this...

describe ChatChannel do
  context ".subscribed" do
    it "updates db and defines opens 2 streams for one channel" do
      TCR.use_cassette("subscribed_action") do |cassette|
        # ...
        ChatChannel.subscribed
        expect(cassette).to include "something ..."
      end
    end
  end
end

Solution 3:[3]

Now Rails 6 includes the action-cable-test gem

So there is no need to add a gem. You can do either

assert_has_stream "chat_1"

or, with rspec:

expect(subscription).to have_stream_from("chat_1") 

Solution 4:[4]

Look like it was merged to Rails 6. Checkout the release note Action cable testing and the pr AC testing PR

Solution 5:[5]

The example you've got is for implementing this from a list view I believe. I've updated it below to be a fairly straightforward invocable method. I'm sure you've figured it out by now, but for anyone else looking!

public class UserManagementController {
  
  //Use method with extreme caution. Data can't be recovered.   
  @InvocableMethod(label='User Management' description='Obfuscate User data and more')
  static public void obfuscate(List<Id> ids)
  {
    for (Id id : ids) {
      System.UserManagement.obfuscateUser(id);
    }
     
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 MilesStanfield
Solution 3 Tabare
Solution 4
Solution 5 João Dias