aboutsummaryrefslogtreecommitdiffstats
path: root/actioncable
diff options
context:
space:
mode:
Diffstat (limited to 'actioncable')
-rw-r--r--actioncable/README.md12
-rw-r--r--actioncable/app/assets/javascripts/action_cable.coffee.erb4
-rw-r--r--actioncable/app/assets/javascripts/action_cable/connection.coffee2
-rw-r--r--actioncable/blade.yml12
-rw-r--r--actioncable/lib/action_cable/channel/streams.rb2
-rw-r--r--actioncable/lib/action_cable/connection/subscriptions.rb6
-rw-r--r--actioncable/lib/action_cable/engine.rb9
-rw-r--r--actioncable/lib/action_cable/server/base.rb16
-rw-r--r--actioncable/lib/action_cable/server/configuration.rb10
-rw-r--r--actioncable/test/channel/stream_test.rb4
-rw-r--r--actioncable/test/client/echo_channel.rb22
-rw-r--r--actioncable/test/client_test.rb79
-rw-r--r--actioncable/test/connection/subscriptions_test.rb1
-rw-r--r--actioncable/test/javascript/src/test.coffee2
-rw-r--r--actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee37
-rw-r--r--actioncable/test/javascript/src/test_helpers/index.coffee3
-rw-r--r--actioncable/test/javascript/src/test_helpers/mock_websocket.coffee21
-rw-r--r--actioncable/test/javascript/src/unit/action_cable_test.coffee17
-rw-r--r--actioncable/test/javascript/src/unit/consumer_test.coffee34
19 files changed, 141 insertions, 152 deletions
diff --git a/actioncable/README.md b/actioncable/README.md
index 1239b555d6..28e2602cbf 100644
--- a/actioncable/README.md
+++ b/actioncable/README.md
@@ -7,7 +7,6 @@ and scalable. It's a full-stack offering that provides both a client-side
JavaScript framework and a server-side Ruby framework. You have access to your full
domain model written with Active Record or your ORM of choice.
-
## Terminology
A single Action Cable server can handle multiple connection instances. It has one
@@ -300,7 +299,6 @@ The rebroadcast will be received by all connected clients, _including_ the clien
See the [rails/actioncable-examples](https://github.com/rails/actioncable-examples) repository for a full example of how to setup Action Cable in a Rails app, and how to add channels.
-
## Configuration
Action Cable has three required configurations: a subscription adapter, allowed request origins, and the cable server URL (which can optionally be set on the client side).
@@ -378,11 +376,11 @@ App.cable = ActionCable.createConsumer()
### Other Configurations
-The other common option to configure is the log tags applied to the per-connection logger. Here's close to what we're using in Basecamp:
+The other common option to configure is the log tags applied to the per-connection logger. Here's an example that uses the user account id if available, else "no-account" while tagging:
```ruby
-Rails.application.config.action_cable.log_tags = [
- -> request { request.env['bc.account_id'] || "no-account" },
+config.action_cable.log_tags = [
+ -> request { request.env['user_account_id'] || "no-account" },
:action_cable,
-> request { request.uuid }
]
@@ -408,7 +406,7 @@ run ActionCable.server
```
Then you start the server using a binstub in bin/cable ala:
-```
+```sh
#!/bin/bash
bundle exec puma -p 28080 cable/config.ru
```
@@ -430,7 +428,7 @@ For every instance of your server you create and for every worker your server sp
### Notes
-Beware that currently the cable server will _not_ auto-reload any changes in the framework. As we've discussed, long-running cable connections mean long-running objects. We don't yet have a way of reloading the classes of those objects in a safe manner. So when you change your channels, or the model your channels use, you must restart the cable server.
+Beware that currently, the cable server will _not_ auto-reload any changes in the framework. As we've discussed, long-running cable connections mean long-running objects. We don't yet have a way of reloading the classes of those objects in a safe manner. So when you change your channels, or the model your channels use, you must restart the cable server.
We'll get all this abstracted properly when the framework is integrated into Rails.
diff --git a/actioncable/app/assets/javascripts/action_cable.coffee.erb b/actioncable/app/assets/javascripts/action_cable.coffee.erb
index 210a3ae17e..e0758dae72 100644
--- a/actioncable/app/assets/javascripts/action_cable.coffee.erb
+++ b/actioncable/app/assets/javascripts/action_cable.coffee.erb
@@ -4,6 +4,8 @@
@ActionCable =
INTERNAL: <%= ActionCable::INTERNAL.to_json %>
+ WebSocket: window.WebSocket
+ logger: window.console
createConsumer: (url) ->
url ?= @getConfig("url") ? @INTERNAL.default_mount_path
@@ -33,4 +35,4 @@
log: (messages...) ->
if @debugging
messages.push(Date.now())
- console.log("[ActionCable]", messages...)
+ @logger.log("[ActionCable]", messages...)
diff --git a/actioncable/app/assets/javascripts/action_cable/connection.coffee b/actioncable/app/assets/javascripts/action_cable/connection.coffee
index d6a6397804..29ad676290 100644
--- a/actioncable/app/assets/javascripts/action_cable/connection.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/connection.coffee
@@ -27,7 +27,7 @@ class ActionCable.Connection
else
ActionCable.log("Opening WebSocket, current state is #{@getState()}, subprotocols: #{protocols}")
@uninstallEventHandlers() if @webSocket?
- @webSocket = new WebSocket(@consumer.url, protocols)
+ @webSocket = new ActionCable.WebSocket(@consumer.url, protocols)
@installEventHandlers()
@monitor.start()
true
diff --git a/actioncable/blade.yml b/actioncable/blade.yml
index e21151099a..e38e9b2f1d 100644
--- a/actioncable/blade.yml
+++ b/actioncable/blade.yml
@@ -17,18 +17,18 @@ plugins:
browsers:
Google Chrome:
os: Mac, Windows
- version: -2
+ version: -1
Firefox:
os: Mac, Windows
- version: -2
+ version: -1
Safari:
platform: Mac
- version: -3
+ version: -1
Microsoft Edge:
- version: -2
+ version: -1
Internet Explorer:
version: 11
iPhone:
- version: [9.2, 8.4]
+ version: -1
Motorola Droid 4 Emulator:
- version: [5.1, 4.4]
+ version: -1
diff --git a/actioncable/lib/action_cable/channel/streams.rb b/actioncable/lib/action_cable/channel/streams.rb
index 0a0a95f453..561750d713 100644
--- a/actioncable/lib/action_cable/channel/streams.rb
+++ b/actioncable/lib/action_cable/channel/streams.rb
@@ -138,7 +138,7 @@ module ActionCable
end
# May be overridden to change the default stream handling behavior
- # which decodes JSON and transmits to client.
+ # which decodes JSON and transmits to the client.
#
# TODO: Tests demonstrating this.
#
diff --git a/actioncable/lib/action_cable/connection/subscriptions.rb b/actioncable/lib/action_cable/connection/subscriptions.rb
index 3742f248d1..6051818bfb 100644
--- a/actioncable/lib/action_cable/connection/subscriptions.rb
+++ b/actioncable/lib/action_cable/connection/subscriptions.rb
@@ -26,12 +26,12 @@ module ActionCable
id_key = data['identifier']
id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access
- subscription_klass = connection.server.channel_classes[id_options[:channel]]
+ subscription_klass = id_options[:channel].safe_constantize
- if subscription_klass
+ if subscription_klass && ActionCable::Channel::Base >= subscription_klass
subscriptions[id_key] ||= subscription_klass.new(connection, id_key, id_options)
else
- logger.error "Subscription class not found (#{data.inspect})"
+ logger.error "Subscription class not found: #{id_options[:channel].inspect}"
end
end
diff --git a/actioncable/lib/action_cable/engine.rb b/actioncable/lib/action_cable/engine.rb
index 8ce1b24962..34f9952c71 100644
--- a/actioncable/lib/action_cable/engine.rb
+++ b/actioncable/lib/action_cable/engine.rb
@@ -22,7 +22,7 @@ module ActionCable
initializer "action_cable.set_configs" do |app|
options = app.config.action_cable
- options.allowed_request_origins ||= "http://localhost:3000" if ::Rails.env.development?
+ options.allowed_request_origins ||= /https?:\/\/localhost:\d+/ if ::Rails.env.development?
app.paths.add "config/cable", with: "config/cable.yml"
@@ -31,11 +31,8 @@ module ActionCable
self.cable = Rails.application.config_for(config_path).with_indifferent_access
end
- if 'ApplicationCable::Connection'.safe_constantize
- self.connection_class = ApplicationCable::Connection
- end
-
- self.channel_paths = Rails.application.paths['app/channels'].existent
+ previous_connection_class = self.connection_class
+ self.connection_class = -> { 'ApplicationCable::Connection'.safe_constantize || previous_connection_class.call }
options.each { |k,v| send("#{k}=", v) }
end
diff --git a/actioncable/lib/action_cable/server/base.rb b/actioncable/lib/action_cable/server/base.rb
index 717a60fe4f..0ad1e408a9 100644
--- a/actioncable/lib/action_cable/server/base.rb
+++ b/actioncable/lib/action_cable/server/base.rb
@@ -19,13 +19,13 @@ module ActionCable
def initialize
@mutex = Monitor.new
- @remote_connections = @event_loop = @worker_pool = @channel_classes = @pubsub = nil
+ @remote_connections = @event_loop = @worker_pool = @pubsub = nil
end
# Called by Rack to setup the server.
def call(env)
setup_heartbeat_timer
- config.connection_class.new(self, env).process
+ config.connection_class.call.new(self, env).process
end
# Disconnect all the connections identified by `identifiers` on this server or any others via RemoteConnections.
@@ -67,16 +67,6 @@ module ActionCable
@worker_pool || @mutex.synchronize { @worker_pool ||= ActionCable::Server::Worker.new(max_size: config.worker_pool_size) }
end
- # Requires and returns a hash of all of the channel class constants, which are keyed by name.
- def channel_classes
- @channel_classes || @mutex.synchronize do
- @channel_classes ||= begin
- config.channel_paths.each { |channel_path| require channel_path }
- config.channel_class_names.each_with_object({}) { |name, hash| hash[name] = name.constantize }
- end
- end
- end
-
# Adapter used for all streams/broadcasting.
def pubsub
@pubsub || @mutex.synchronize { @pubsub ||= config.pubsub_adapter.new(self) }
@@ -84,7 +74,7 @@ module ActionCable
# All of the identifiers applied to the connection class associated with this server.
def connection_identifiers
- config.connection_class.identifiers
+ config.connection_class.call.identifiers
end
end
diff --git a/actioncable/lib/action_cable/server/configuration.rb b/actioncable/lib/action_cable/server/configuration.rb
index 0bb378cf03..ada1ac22cc 100644
--- a/actioncable/lib/action_cable/server/configuration.rb
+++ b/actioncable/lib/action_cable/server/configuration.rb
@@ -8,23 +8,15 @@ module ActionCable
attr_accessor :disable_request_forgery_protection, :allowed_request_origins
attr_accessor :cable, :url, :mount_path
- attr_accessor :channel_paths # :nodoc:
-
def initialize
@log_tags = []
- @connection_class = ActionCable::Connection::Base
+ @connection_class = -> { ActionCable::Connection::Base }
@worker_pool_size = 4
@disable_request_forgery_protection = false
end
- def channel_class_names
- @channel_class_names ||= channel_paths.collect do |channel_path|
- Pathname.new(channel_path).basename.to_s.split('.').first.camelize
- end
- end
-
# Returns constant of subscription adapter specified in config/cable.yml.
# If the adapter cannot be found, this will default to the Redis adapter.
# Also makes sure proper dependencies are required.
diff --git a/actioncable/test/channel/stream_test.rb b/actioncable/test/channel/stream_test.rb
index 0b0c72ccf6..38543920d3 100644
--- a/actioncable/test/channel/stream_test.rb
+++ b/actioncable/test/channel/stream_test.rb
@@ -128,10 +128,6 @@ module ActionCable::StreamTests
setup do
@server = TestServer.new(subscription_adapter: ActionCable::SubscriptionAdapter::Inline)
@server.config.allowed_request_origins = %w( http://rubyonrails.com )
- @server.stubs(:channel_classes).returns(
- ChatChannel.name => ChatChannel,
- UserCallbackChannel.name => UserCallbackChannel,
- )
end
test 'custom encoder' do
diff --git a/actioncable/test/client/echo_channel.rb b/actioncable/test/client/echo_channel.rb
deleted file mode 100644
index 5a7bac25c5..0000000000
--- a/actioncable/test/client/echo_channel.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-class EchoChannel < ActionCable::Channel::Base
- def subscribed
- stream_from "global"
- end
-
- def unsubscribed
- 'Goodbye from EchoChannel!'
- end
-
- def ding(data)
- transmit(dong: data['message'])
- end
-
- def delay(data)
- sleep 1
- transmit(dong: data['message'])
- end
-
- def bulk(data)
- ActionCable.server.broadcast "global", wide: data['message']
- end
-end
diff --git a/actioncable/test/client_test.rb b/actioncable/test/client_test.rb
index fe503fd703..82d9f12fdd 100644
--- a/actioncable/test/client_test.rb
+++ b/actioncable/test/client_test.rb
@@ -1,27 +1,48 @@
require 'test_helper'
require 'concurrent'
-require 'active_support/core_ext/hash/indifferent_access'
-require 'pathname'
-
require 'faye/websocket'
require 'json'
+require 'active_support/hash_with_indifferent_access'
+
class ClientTest < ActionCable::TestCase
WAIT_WHEN_EXPECTING_EVENT = 8
WAIT_WHEN_NOT_EXPECTING_EVENT = 0.5
+ class EchoChannel < ActionCable::Channel::Base
+ def subscribed
+ stream_from "global"
+ end
+
+ def unsubscribed
+ 'Goodbye from EchoChannel!'
+ end
+
+ def ding(data)
+ transmit(dong: data['message'])
+ end
+
+ def delay(data)
+ sleep 1
+ transmit(dong: data['message'])
+ end
+
+ def bulk(data)
+ ActionCable.server.broadcast "global", wide: data['message']
+ end
+ end
+
def setup
ActionCable.instance_variable_set(:@server, nil)
server = ActionCable.server
server.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN }
- server.config.cable = { adapter: 'async' }.with_indifferent_access
+ server.config.cable = ActiveSupport::HashWithIndifferentAccess.new(adapter: 'async')
server.config.use_faye = ENV['FAYE'].present?
# and now the "real" setup for our test:
server.config.disable_request_forgery_protection = true
- server.config.channel_paths = [ File.expand_path('client/echo_channel.rb', __dir__) ]
Thread.new { EventMachine.run } unless EventMachine.reactor_running?
Thread.pass until EventMachine.reactor_running?
@@ -148,10 +169,10 @@ class ClientTest < ActionCable::TestCase
with_puma_server do |port|
c = faye_client(port)
assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack
- c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'EchoChannel')
- assert_equal({"identifier"=>"{\"channel\":\"EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
- c.send_message command: 'message', identifier: JSON.generate(channel: 'EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
- assert_equal({"identifier"=>"{\"channel\":\"EchoChannel\"}", "message"=>{"dong"=>"hello"}}, c.read_message)
+ c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel')
+ assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
+ c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
+ assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "message"=>{"dong"=>"hello"}}, c.read_message)
c.close
end
end
@@ -165,12 +186,12 @@ class ClientTest < ActionCable::TestCase
clients.map {|c| Concurrent::Future.execute {
assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack
- c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'EchoChannel')
- assert_equal({"identifier"=>'{"channel":"EchoChannel"}', "type"=>"confirm_subscription"}, c.read_message)
- c.send_message command: 'message', identifier: JSON.generate(channel: 'EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
- assert_equal({"identifier"=>'{"channel":"EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message)
+ c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel')
+ assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "type"=>"confirm_subscription"}, c.read_message)
+ c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
+ assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message)
barrier_1.wait WAIT_WHEN_EXPECTING_EVENT
- c.send_message command: 'message', identifier: JSON.generate(channel: 'EchoChannel'), data: JSON.generate(action: 'bulk', message: 'hello')
+ c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'bulk', message: 'hello')
barrier_2.wait WAIT_WHEN_EXPECTING_EVENT
assert_equal clients.size, c.read_messages(clients.size).size
} }.each(&:wait!)
@@ -185,10 +206,10 @@ class ClientTest < ActionCable::TestCase
clients.map {|c| Concurrent::Future.execute {
assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack
- c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'EchoChannel')
- assert_equal({"identifier"=>'{"channel":"EchoChannel"}', "type"=>"confirm_subscription"}, c.read_message)
- c.send_message command: 'message', identifier: JSON.generate(channel: 'EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
- assert_equal({"identifier"=>'{"channel":"EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message)
+ c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel')
+ assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "type"=>"confirm_subscription"}, c.read_message)
+ c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
+ assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message)
} }.each(&:wait!)
clients.map {|c| Concurrent::Future.execute { c.close } }.each(&:wait!)
@@ -199,17 +220,17 @@ class ClientTest < ActionCable::TestCase
with_puma_server do |port|
c = faye_client(port)
assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack
- c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'EchoChannel')
- assert_equal({"identifier"=>"{\"channel\":\"EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
- c.send_message command: 'message', identifier: JSON.generate(channel: 'EchoChannel'), data: JSON.generate(action: 'delay', message: 'hello')
+ c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel')
+ assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
+ c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'delay', message: 'hello')
c.close # disappear before write
c = faye_client(port)
assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack
- c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'EchoChannel')
- assert_equal({"identifier"=>"{\"channel\":\"EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
- c.send_message command: 'message', identifier: JSON.generate(channel: 'EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
- assert_equal({"identifier"=>'{"channel":"EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message)
+ c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel')
+ assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
+ c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello')
+ assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message)
c.close # disappear before read
end
end
@@ -217,12 +238,12 @@ class ClientTest < ActionCable::TestCase
def test_unsubscribe_client
with_puma_server do |port|
app = ActionCable.server
- identifier = JSON.generate(channel: 'EchoChannel')
+ identifier = JSON.generate(channel: 'ClientTest::EchoChannel')
c = faye_client(port)
assert_equal({"type" => "welcome"}, c.read_message)
c.send_message command: 'subscribe', identifier: identifier
- assert_equal({"identifier"=>"{\"channel\":\"EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
+ assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
assert_equal(1, app.connections.count)
assert(app.remote_connections.where(identifier: identifier))
@@ -242,8 +263,8 @@ class ClientTest < ActionCable::TestCase
with_puma_server do |port|
c = faye_client(port)
assert_equal({"type" => "welcome"}, c.read_message)
- c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'EchoChannel')
- assert_equal({"identifier"=>"{\"channel\":\"EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
+ c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel')
+ assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
ActionCable.server.restart
c.wait_for_close
diff --git a/actioncable/test/connection/subscriptions_test.rb b/actioncable/test/connection/subscriptions_test.rb
index 53e8547245..a5b1e5dcf3 100644
--- a/actioncable/test/connection/subscriptions_test.rb
+++ b/actioncable/test/connection/subscriptions_test.rb
@@ -24,7 +24,6 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase
setup do
@server = TestServer.new
- @server.stubs(:channel_classes).returns(ChatChannel.name => ChatChannel)
@chat_identifier = ActiveSupport::JSON.encode(id: 1, channel: 'ActionCable::Connection::SubscriptionsTest::ChatChannel')
end
diff --git a/actioncable/test/javascript/src/test.coffee b/actioncable/test/javascript/src/test.coffee
index 3ce88c7789..eb95fb2604 100644
--- a/actioncable/test/javascript/src/test.coffee
+++ b/actioncable/test/javascript/src/test.coffee
@@ -1,3 +1,3 @@
#= require action_cable
-#= require_tree ./test_helpers
+#= require ./test_helpers
#= require_tree ./unit
diff --git a/actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee b/actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee
new file mode 100644
index 0000000000..6b145dede8
--- /dev/null
+++ b/actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee
@@ -0,0 +1,37 @@
+#= require mock-socket
+
+{TestHelpers} = ActionCable
+
+TestHelpers.consumerTest = (name, options = {}, callback) ->
+ unless callback?
+ callback = options
+ options = {}
+
+ options.url ?= TestHelpers.testURL
+
+ QUnit.test name, (assert) ->
+ doneAsync = assert.async()
+
+ ActionCable.WebSocket = MockWebSocket
+ server = new MockServer options.url
+ consumer = ActionCable.createConsumer(options.url)
+
+ server.on "connection", ->
+ clients = server.clients()
+ assert.equal clients.length, 1
+ assert.equal clients[0].readyState, WebSocket.OPEN
+
+ done = ->
+ consumer.disconnect()
+ server.close()
+ doneAsync()
+
+ testData = {assert, consumer, server, done}
+
+ if options.connect is false
+ callback(testData)
+ else
+ server.on "connection", ->
+ testData.client = server.clients()[0]
+ callback(testData)
+ consumer.connect()
diff --git a/actioncable/test/javascript/src/test_helpers/index.coffee b/actioncable/test/javascript/src/test_helpers/index.coffee
index e0d1e412cd..d36524d9cc 100644
--- a/actioncable/test/javascript/src/test_helpers/index.coffee
+++ b/actioncable/test/javascript/src/test_helpers/index.coffee
@@ -3,3 +3,6 @@
ActionCable.TestHelpers =
testURL: "ws://cable.example.com/"
+
+originalWebSocket = ActionCable.WebSocket
+QUnit.testDone -> ActionCable.WebSocket = originalWebSocket
diff --git a/actioncable/test/javascript/src/test_helpers/mock_websocket.coffee b/actioncable/test/javascript/src/test_helpers/mock_websocket.coffee
deleted file mode 100644
index b7f86f18f6..0000000000
--- a/actioncable/test/javascript/src/test_helpers/mock_websocket.coffee
+++ /dev/null
@@ -1,21 +0,0 @@
-#= require mock-socket
-
-NativeWebSocket = window.WebSocket
-
-server = null
-consumer = null
-
-ActionCable.TestHelpers.createConsumer = (url, callback) ->
- window.WebSocket = MockWebSocket
- server = new MockServer url
- consumer = ActionCable.createConsumer(url)
- callback(consumer, server)
-
-QUnit.testDone ->
- if consumer?
- consumer.disconnect()
-
- if server?
- server.clients().forEach (client) -> client.close()
- server.close()
- window.WebSocket = NativeWebSocket
diff --git a/actioncable/test/javascript/src/unit/action_cable_test.coffee b/actioncable/test/javascript/src/unit/action_cable_test.coffee
index f9eff64769..3944f3a7f6 100644
--- a/actioncable/test/javascript/src/unit/action_cable_test.coffee
+++ b/actioncable/test/javascript/src/unit/action_cable_test.coffee
@@ -2,6 +2,23 @@
{testURL} = ActionCable.TestHelpers
module "ActionCable", ->
+ module "Adapters", ->
+ module "WebSocket", ->
+ test "default is window.WebSocket", (assert) ->
+ assert.equal ActionCable.WebSocket, window.WebSocket
+
+ test "configurable", (assert) ->
+ ActionCable.WebSocket = ""
+ assert.equal ActionCable.WebSocket, ""
+
+ module "logger", ->
+ test "default is window.console", (assert) ->
+ assert.equal ActionCable.logger, window.console
+
+ test "configurable", (assert) ->
+ ActionCable.logger = ""
+ assert.equal ActionCable.logger, ""
+
module "#createConsumer", ->
test "uses specified URL", (assert) ->
consumer = ActionCable.createConsumer(testURL)
diff --git a/actioncable/test/javascript/src/unit/consumer_test.coffee b/actioncable/test/javascript/src/unit/consumer_test.coffee
index d8b1450ad8..cf8a592255 100644
--- a/actioncable/test/javascript/src/unit/consumer_test.coffee
+++ b/actioncable/test/javascript/src/unit/consumer_test.coffee
@@ -1,31 +1,11 @@
{module, test} = QUnit
-{testURL, createConsumer} = ActionCable.TestHelpers
+{consumerTest} = ActionCable.TestHelpers
module "ActionCable.Consumer", ->
- test "#connect", (assert) ->
- done = assert.async()
+ consumerTest "#connect", connect: false, ({consumer, server, done}) ->
+ server.on("connection", done)
+ consumer.connect()
- createConsumer testURL, (consumer, server) ->
- server.on "connection", ->
- clients = server.clients()
- assert.equal clients.length, 1
- assert.equal clients[0].readyState, WebSocket.OPEN
- done()
-
- consumer.connect()
-
- test "#disconnect", (assert) ->
- done = assert.async()
-
- createConsumer testURL, (consumer, server) ->
- server.on "connection", ->
- clients = server.clients()
- assert.equal clients.length, 1
-
- clients[0].addEventListener "close", (event) ->
- assert.equal event.type, "close"
- done()
-
- consumer.disconnect()
-
- consumer.connect()
+ consumerTest "#disconnect", ({consumer, client, done}) ->
+ client.addEventListener("close", done)
+ consumer.disconnect()