mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #34933 from palkan/feature/cable-testing-guides
Add Action Cable testing guides and generators
This commit is contained in:
commit
2585e66b55
13 changed files with 195 additions and 5 deletions
|
@ -1,3 +1,7 @@
|
|||
* Merge [`action-cable-testing`](https://github.com/palkan/action-cable-testing) to Rails.
|
||||
|
||||
*Vladimir Dementyev*
|
||||
|
||||
* The JavaScript WebSocket client will no longer try to reconnect
|
||||
when you call `reject_unauthorized_connection` on the connection.
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ module ActionCable
|
|||
# def test_connects_with_proper_cookie
|
||||
# # Simulate the connection request with a cookie.
|
||||
# cookies["user_id"] = users(:john).id
|
||||
|
||||
#
|
||||
# connect
|
||||
#
|
||||
# # Assert the connection identifier matches the fixture.
|
||||
|
|
|
@ -7,6 +7,7 @@ Example:
|
|||
========
|
||||
rails generate channel Chat speak
|
||||
|
||||
creates a Chat channel class and JavaScript asset:
|
||||
creates a Chat channel class, test and JavaScript asset:
|
||||
Channel: app/channels/chat_channel.rb
|
||||
Test: test/channels/chat_channel_test.rb
|
||||
Assets: app/javascript/channels/chat_channel.js
|
||||
|
|
|
@ -11,6 +11,8 @@ module Rails
|
|||
|
||||
check_class_collision suffix: "Channel"
|
||||
|
||||
hook_for :test_framework
|
||||
|
||||
def create_channel_file
|
||||
template "channel.rb", File.join("app/channels", class_path, "#{file_name}_channel.rb")
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module TestUnit
|
||||
module Generators
|
||||
class ChannelGenerator < ::Rails::Generators::NamedBase
|
||||
source_root File.expand_path("templates", __dir__)
|
||||
|
||||
check_class_collision suffix: "ChannelTest"
|
||||
|
||||
def create_test_files
|
||||
template "channel_test.rb", File.join("test/channels", class_path, "#{file_name}_channel_test.rb")
|
||||
end
|
||||
|
||||
private
|
||||
def file_name # :doc:
|
||||
@_file_name ||= super.sub(/_channel\z/i, "")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class <%= class_name %>ChannelTest < ActionCable::Channel::TestCase
|
||||
# test "subscribes" do
|
||||
# subscribe
|
||||
# assert subscription.confirmed?
|
||||
# end
|
||||
end
|
|
@ -8,6 +8,7 @@ Highlights in Rails 6.0:
|
|||
* Action Mailbox
|
||||
* Action Text
|
||||
* Parallel Testing
|
||||
* Action Cable Testing
|
||||
|
||||
These release notes cover only the major changes. To learn about various bug
|
||||
fixes and changes, please refer to the change logs or check out the [list of
|
||||
|
@ -62,6 +63,13 @@ test suite. While forking processes is the default method, threading is
|
|||
supported as well. Running tests in parallel reduces the time it takes
|
||||
your entire test suite to run.
|
||||
|
||||
### Action Cable Testing
|
||||
|
||||
[Pull Request](https://github.com/rails/rails/pull/33659)
|
||||
|
||||
[Action Cable testing tools](testing.html#testing-action-cable) allow you to test your
|
||||
Action Cable functionality at any level: connections, channels, broadcasts.
|
||||
|
||||
Railties
|
||||
--------
|
||||
|
||||
|
|
|
@ -768,3 +768,8 @@ internally, irrespective of whether the application server is multi-threaded or
|
|||
|
||||
Accordingly, Action Cable works with popular servers like Unicorn, Puma, and
|
||||
Passenger.
|
||||
|
||||
## Testing
|
||||
|
||||
You can find detailed instructions on how to test your Action Cable functionality in the
|
||||
[testing guide](testing.html#testing-action-cable).
|
||||
|
|
|
@ -33,11 +33,11 @@ Rails creates a `test` directory for you as soon as you create a Rails project u
|
|||
|
||||
```bash
|
||||
$ ls -F test
|
||||
application_system_test_case.rb fixtures/ integration/ models/ test_helper.rb
|
||||
controllers/ helpers/ mailers/ system/
|
||||
application_system_test_case.rb controllers/ helpers/ mailers/ system/
|
||||
channels/ fixtures/ integration/ models/ test_helper.rb
|
||||
```
|
||||
|
||||
The `helpers`, `mailers`, and `models` directories are meant to hold tests for view helpers, mailers, and models, respectively. The `controllers` directory is meant to hold tests for controllers, routes, and views. The `integration` directory is meant to hold tests for interactions between controllers.
|
||||
The `helpers`, `mailers`, and `models` directories are meant to hold tests for view helpers, mailers, and models, respectively. The `channels` directory is meant to hold tests for Action Cable connection and channels. The `controllers` directory is meant to hold tests for controllers, routes, and views. The `integration` directory is meant to hold tests for interactions between controllers.
|
||||
|
||||
The system test directory holds system tests, which are used for full browser
|
||||
testing of your application. System tests allow you to test your application
|
||||
|
@ -1731,6 +1731,114 @@ class ProductTest < ActiveJob::TestCase
|
|||
end
|
||||
```
|
||||
|
||||
Testing Action Cable
|
||||
--------------------
|
||||
|
||||
Since Action Cable is used at different levels inside your application,
|
||||
you'll need to test both the channels and connection classes themsleves and that other
|
||||
entities broadcast correct messages.
|
||||
|
||||
### Connection Test Case
|
||||
|
||||
By default, when you generate new Rails application with Action Cable, a test for the base connection class (`ApplicationCable::Connection`) is generated as well under `test/channels/application_cable` directory.
|
||||
|
||||
Connection tests aim to check whether a connection's identifiers gets assigned properly
|
||||
or that any improper connection requests are rejected. Here is an example:
|
||||
|
||||
```ruby
|
||||
class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
|
||||
test "connects with params" do
|
||||
# Simulate a connection opening by calling the `connect` method
|
||||
connect params: { user_id: 42 }
|
||||
|
||||
# You can access the Connection object via `connection` in tests
|
||||
assert_equal connection.user_id, "42"
|
||||
end
|
||||
|
||||
test "rejects connection without params" do
|
||||
# Use `assert_reject_connection` matcher to verify that
|
||||
# connection is rejected
|
||||
assert_reject_connection { connect }
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
You can also specify request cookies the same way you do in integration tests:
|
||||
|
||||
|
||||
```ruby
|
||||
test "connects with_cookies" do
|
||||
cookies.signed[:user_id] = "42"
|
||||
|
||||
connect
|
||||
|
||||
assert_equal connection.user_id, "42"
|
||||
end
|
||||
```
|
||||
|
||||
See the API documentation for [`AcionCable::Connection::TestCase`](http://api.rubyonrails.org/classes/ActionCable/Connection/TestCase.html) for more information.
|
||||
|
||||
|
||||
### Channel Test Case
|
||||
|
||||
By default, when you generate a channel, an associated test will be generated as well
|
||||
under the `test/channels` directory. Here's an example test with a chat channel:
|
||||
|
||||
```ruby
|
||||
require "test_helper"
|
||||
|
||||
class ChatChannelTest < ActionCable::Channel::TestCase
|
||||
test "subscribes and stream for room" do
|
||||
# Simulate a subscription creation by calling `subscribe`
|
||||
subscribe room: "15"
|
||||
|
||||
# You can access the Channel object via `subscription` in tests
|
||||
assert subscription.confirmed?
|
||||
assert_has_stream "chat_15"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
This test is pretty simple and only asserts that the channel subscribes the connection to a particular stream.
|
||||
|
||||
You can also specify the underlying connection identifiers. Here's an example test with a web notifications channel:
|
||||
|
||||
```ruby
|
||||
require "test_helper"
|
||||
|
||||
class WebNotificationsChannelTest < ActionCable::Channel::TestCase
|
||||
test "subscribes and stream for user" do
|
||||
stub_connection current_user: users[:john]
|
||||
|
||||
subscribe
|
||||
|
||||
assert_has_stream_for users[:john]
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
See the API documentation for [`AcionCable::Channel::TestCase`](http://api.rubyonrails.org/classes/ActionCable/Channel/TestCase.html) for more information.
|
||||
|
||||
### Custom Assertions And Testing Broadcasts Inside Other Components
|
||||
|
||||
Action Cable ships with a bunch of custom assertions that can be used to lessen the verbosity of tests. For a full list of available assertions, see the API documentation for [`ActionCable::TestHelper`](http://api.rubyonrails.org/classes/ActionCable/TestHelper.html).
|
||||
|
||||
It's a good practice to ensure that the correct message has been broadcasted inside another components (e.g. inside your controllers). This is precisely where
|
||||
the custom assertions provided by Action Cable are pretty useful. For instance,
|
||||
within a model:
|
||||
|
||||
```ruby
|
||||
require 'test_helper'
|
||||
|
||||
class ProductTest < ActionCable::TestCase
|
||||
test "broadcast status after charge" do
|
||||
assert_broadcast_on("products:#{product.id}", type: "charged") do
|
||||
product.charge(account)
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Additional Testing Resources
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ module Rails
|
|||
empty_directory_with_keep_file "test/helpers"
|
||||
empty_directory_with_keep_file "test/integration"
|
||||
|
||||
template "test/channels/application_cable/connection_test.rb"
|
||||
template "test/test_helper.rb"
|
||||
end
|
||||
|
||||
|
@ -440,6 +441,7 @@ module Rails
|
|||
if options[:skip_action_cable]
|
||||
remove_dir "app/javascript/channels"
|
||||
remove_dir "app/channels"
|
||||
remove_dir "test/channels"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
|
||||
# test "connects with cookies" do
|
||||
# cookies.signed[:user_id] = 42
|
||||
#
|
||||
# connect
|
||||
#
|
||||
# assert_equal connection.user_id, "42"
|
||||
# end
|
||||
end
|
|
@ -81,6 +81,7 @@ DEFAULT_APP_FILES = %w(
|
|||
test/test_helper.rb
|
||||
test/fixtures
|
||||
test/fixtures/files
|
||||
test/channels/application_cable/connection_test.rb
|
||||
test/controllers
|
||||
test/models
|
||||
test/helpers
|
||||
|
@ -363,6 +364,8 @@ class AppGeneratorTest < Rails::Generators::TestCase
|
|||
assert_file "#{app_root}/config/environments/production.rb" do |content|
|
||||
assert_no_match(/config\.action_cable/, content)
|
||||
end
|
||||
|
||||
assert_no_file "#{app_root}/test/channels/application_cable/connection_test.rb"
|
||||
end
|
||||
|
||||
def test_app_update_does_not_generate_bootsnap_contents_when_skip_bootsnap_is_given
|
||||
|
|
|
@ -67,12 +67,23 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
|
|||
assert_file "app/javascript/channels/consumer.js"
|
||||
end
|
||||
|
||||
def test_invokes_default_test_framework
|
||||
run_generator %w(chat -t=test_unit)
|
||||
|
||||
assert_file "test/channels/chat_channel_test.rb" do |test|
|
||||
assert_match(/class ChatChannelTest < ActionCable::Channel::TestCase/, test)
|
||||
assert_match(/# test "subscribes" do/, test)
|
||||
assert_match(/# assert subscription.confirmed\?/, test)
|
||||
end
|
||||
end
|
||||
|
||||
def test_channel_on_revoke
|
||||
run_generator ["chat"]
|
||||
run_generator ["chat"], behavior: :revoke
|
||||
|
||||
assert_no_file "app/channels/chat_channel.rb"
|
||||
assert_no_file "app/javascript/channels/chat_channel.js"
|
||||
assert_no_file "test/channels/chat_channel_test.rb"
|
||||
|
||||
assert_file "app/channels/application_cable/channel.rb"
|
||||
assert_file "app/channels/application_cable/connection.rb"
|
||||
|
@ -88,5 +99,8 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
|
|||
|
||||
assert_no_file "app/javascript/channels/chat_channel_channel.js"
|
||||
assert_file "app/javascript/channels/chat_channel.js"
|
||||
|
||||
assert_no_file "test/channels/chat_channel_channel_test.rb"
|
||||
assert_file "test/channels/chat_channel_test.rb"
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue