Skip to content

Instantly share code, notes, and snippets.

@gudongfeng
Last active April 24, 2018 14:07
Show Gist options
  • Save gudongfeng/7547f23446cfdcaf1aad66ea6cbc3971 to your computer and use it in GitHub Desktop.
Save gudongfeng/7547f23446cfdcaf1aad66ea6cbc3971 to your computer and use it in GitHub Desktop.
Rails ActionCable Channel Rspec test
# spec/channels/stubs/test_adapter.rb
class SuccessAdapter < ActionCable::SubscriptionAdapter::Base
def broadcast(channel, payload)
end
def subscribe(channel, callback, success_callback = nil)
end
def unsubscribe(channel, callback)
end
end
# app/channels/test_channel.rb
class TestChannel < ApplicationCable::Channel
def subscribed
# each user subscribe to a single channel
stream_from "user_#{params[:id]}"
end
def unsubscribed
# user finished request
end
# user make a request
def speak(data)
request = current_user.requests.new(category: data["category"])
# create a request record in the dataset
if request.save
# broadcast the user request to the tutor channel
ActionCable.server.broadcast("tutor_#{data["region"]}",
request.as_json)
else
# request save error
ActionCable.server.broadcast("user_#{current_user.id}",
I18n.t('requests.errors.save'))
end
end
end
# spec/channels/test_channel_spec.rb
require 'rails_helper'
require_relative 'stubs/test_connection'
RSpec.describe TestChannel, type: :channel do
before do
@user = create(:user) # factorygirl to create a user
@connection = TestConnection.new(@user)
@channel = TestChannel.new @connection, {}
@action_cable = ActionCable.server
end
let(:data) do
{
"action" => "speak",
"category" => "regular",
"region" => "us"
}
end
it "broadcasts request successfully" do
expect(@action_cable).to receive(:broadcast).\
with("tutor_#{data["region"]}", any_args)
@channel.perform_action(data)
end
it "fails to broadcast request" do
data["category"] = nil
expect(@action_cable).to receive(:broadcast).\
with("user_#{@user.id}", any_args)
@channel.perform_action(data)
end
end
# spec/channels/stubs/test_connection.rb
require 'rails_helper'
require_relative 'test_adapter'
require_relative 'test_server'
class TestConnection
attr_reader :identifiers, :logger, :current_user, :server, :transmissions
delegate :pubsub, to: :server
def initialize(user, coder: ActiveSupport::JSON,
subscription_adapter: SuccessAdapter)
@coder = coder
@current_user = user
@identifiers = [ :current_user ]
@logger = ActiveSupport::TaggedLogging.new ActiveSupport::Logger.new(StringIO.new)
@server = TestServer.new(subscription_adapter: subscription_adapter)
@transmissions = []
end
def transmit(cable_message)
@transmissions << encode(cable_message)
end
def last_transmission
decode @transmissions.last if @transmissions.any?
end
def decode(websocket_message)
@coder.decode websocket_message
end
def encode(cable_message)
@coder.encode cable_message
end
end
# spec/channels/stubs/test_server.rb
require 'ostruct'
require 'rails_helper'
class TestServer
include ActionCable::Server::Connections
include ActionCable::Server::Broadcasting
attr_reader :logger, :config, :mutex
def initialize(subscription_adapter: SuccessAdapter)
@logger = ActiveSupport::TaggedLogging.new ActiveSupport::Logger.new(StringIO.new)
@config = OpenStruct.new(log_tags: [], subscription_adapter: subscription_adapter)
@mutex = Monitor.new
end
def pubsub
@pubsub ||= @config.subscription_adapter.new(self)
end
def event_loop
@event_loop ||= ActionCable::Connection::StreamEventLoop.new.tap do |loop|
loop.instance_variable_set(:@executor, Concurrent.global_io_executor)
end
end
def worker_pool
@worker_pool ||= ActionCable::Server::Worker.new(max_size: 5)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment