How can I test ActionCable channels using RSpec?
Asked Answered
J

5

16

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.

Joycelynjoye answered 5/2, 2016 at 15:29 Comment(0)
K
2

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

Kloman answered 23/5, 2022 at 3:2 Comment(0)
P
8

You probably want to wait* for https://github.com/rails/rails/pull/23211 to be merged. It adds ActionCable::TestCase. Once that's merged, expect the rspec-rails team to do its part: https://github.com/rspec/rspec-rails/issues/1606

* Waiting is optional; You can not wait and based your own work on this "work in progress" and find a solution that works right now.

Promethium answered 8/11, 2016 at 3:50 Comment(0)
M
8

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

Macrobiotic answered 31/1, 2018 at 13:49 Comment(0)
A
3

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
Arrow answered 5/2, 2016 at 16:56 Comment(3)
That's a very good idea, thanks, but (and correct me if I'm wrong) using VCR (and TCR analogously) makes sense when you want to stub external http requests (for example if my controller action issues an external call), but this is not the case here - here I just want to invoke my own internal methods. But once again - it's a good idea and I'll give it a go.Joycelynjoye
Hey Dani, have you found a solution? If so, could you point out a repo that I could check out?Related
Hey @SzilardMagyar have you found any solution?Chamaeleon
R
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") 
Rodriquez answered 11/12, 2020 at 14:35 Comment(0)
K
2

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

Kloman answered 23/5, 2022 at 3:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.