{"id":14991252,"url":"https://github.com/palkan/action-cable-testing","last_synced_at":"2025-04-12T19:50:21.534Z","repository":{"id":40462010,"uuid":"107864288","full_name":"palkan/action-cable-testing","owner":"palkan","description":"Action Cable testing utils","archived":false,"fork":false,"pushed_at":"2021-01-18T16:12:46.000Z","size":172,"stargazers_count":213,"open_issues_count":4,"forks_count":17,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-03T23:11:34.472Z","etag":null,"topics":["actioncable","minitest","rails","rspec","testing"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/palkan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-22T12:34:33.000Z","updated_at":"2024-09-24T05:48:26.000Z","dependencies_parsed_at":"2022-08-29T06:50:55.184Z","dependency_job_id":null,"html_url":"https://github.com/palkan/action-cable-testing","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palkan%2Faction-cable-testing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palkan%2Faction-cable-testing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palkan%2Faction-cable-testing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palkan%2Faction-cable-testing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/palkan","download_url":"https://codeload.github.com/palkan/action-cable-testing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248625501,"owners_count":21135513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actioncable","minitest","rails","rspec","testing"],"created_at":"2024-09-24T14:22:00.541Z","updated_at":"2025-04-12T19:50:21.512Z","avatar_url":"https://github.com/palkan.png","language":"Ruby","readme":"[![Gem Version](https://badge.fury.io/rb/action-cable-testing.svg)](https://rubygems.org/gems/action-cable-testing)\n![Build](https://github.com/palkan/action-cable-testing/workflows/Build/badge.svg)\n[![Build Status](https://travis-ci.org/palkan/action-cable-testing.svg?branch=master)](https://travis-ci.org/palkan/action-cable-testing)[![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/action-cable-testing)\n\n# Action Cable Testing\n\nThis gem provides missing testing utils for [Action Cable][].\n\n**NOTE:** this gem [has](https://github.com/rails/rails/pull/33659) [been](https://github.com/rails/rails/pull/33969) [merged](https://github.com/rails/rails/pull/34845) into Rails 6.0 and [into RSpec 4](https://github.com/rspec/rspec-rails/pull/2113).\n\nIf you're using Minitest – you don't need this gem anymore.\n\nIf you're using RSpec \u003c 4, you still can use this gem to write Action Cable specs even for Rails 6.\n\n## Installation\n# For Rails \u003c 6.0 ONLY:\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'action-cable-testing'\n```\n\nAnd then execute:\n\n    $ bundle\n    \n# For Usage with Rspec (any version of Rails, including 6+):\nadd to `spec/rails_helper.rb`\n```\nRSpec.configure do |config|\n //more rspec configs...\n config.include ActionCable::TestHelper\nend\n```\n\n(note in older versions of Rails you will make Rspec config changes in `spec_helper.rb`)\n\n## Usage\n\n### Test Adapter and Broadcasting\n\nWe add `ActionCable::SubscriptionAdapter::Test` (very similar Active Job and Action Mailer tests adapters) and `ActionCable::TestCase` with a couple of matchers to track broadcasting messages in our tests:\n\n```ruby\n# Using ActionCable::TestCase\nclass MyCableTest \u003c ActionCable::TestCase\n  def test_broadcasts\n    # Check the number of messages broadcasted to the stream\n    assert_broadcasts 'messages', 0\n    ActionCable.server.broadcast 'messages', { text: 'hello' }\n    assert_broadcasts 'messages', 1\n\n    # Check the number of messages broadcasted to the stream within a block\n    assert_broadcasts('messages', 1) do\n      ActionCable.server.broadcast 'messages', { text: 'hello' }\n    end\n\n    # Check that no broadcasts has been made\n    assert_no_broadcasts('messages') do\n      ActionCable.server.broadcast 'another_stream', { text: 'hello' }\n    end\n  end\nend\n\n# Or including ActionCable::TestHelper\nclass ExampleTest \u003c ActionDispatch::IntegrationTest\n  include ActionCable::TestHelper\n\n  def test_broadcasts\n    room = rooms(:office)\n\n    assert_broadcast_on(\"messages:#{room.id}\", text: 'Hello!') do\n      post \"/say/#{room.id}\", xhr: true, params: { message: 'Hello!' }\n    end\n  end\nend\n```\n\nIf you want to test the broadcasting made with `Channel.broadcast_to`, you should use\n`Channel.broadcasting_for`\\* to generate an underlying stream name and **use Rails 6 compatibility refinement**:\n\n```ruby\n# app/jobs/chat_relay_job.rb\nclass ChatRelayJob \u003c ApplicationJob\n  def perform_later(room, message)\n    ChatChannel.broadcast_to room, text: message\n  end\nend\n\n\n# test/jobs/chat_relay_job_test.rb\nrequire \"test_helper\"\n\n# Activate Rails 6 compatible API (for `broadcasting_for`)\nusing ActionCable::Testing::Rails6\n\nclass ChatRelayJobTest \u003c ActiveJob::TestCase\n  include ActionCable::TestHelper\n\n  test \"broadcast message to room\" do\n    room = rooms(:all)\n\n    assert_broadcast_on(ChatChannel.broadcasting_for(room), text: \"Hi!\") do\n      ChatRelayJob.perform_now(room, \"Hi!\")\n    end\n  end\nend\n```\n\n\\* **NOTE:** in Rails 6.0 you should use `.broadcasting_for`, but it's not backward compatible\nand we cannot use it in Rails 5.x. See https://github.com/rails/rails/pull/35021.\nNote also, that this feature hasn't been released in Rails 6.0.0.beta1, so you still need the refinement.\n\n### Channels Testing\n\nChannels tests are written as follows:\n1. First, one uses the `subscribe` method to simulate subscription creation.\n2. Then, one asserts whether the current state is as expected. \"State\" can be anything:\ntransmitted messages, subscribed streams, etc.\n\nFor example:\n\n```ruby\nclass ChatChannelTest \u003c ActionCable::Channel::TestCase\n  def test_subscribed_with_room_number\n    # Simulate a subscription creation\n    subscribe room_number: 1\n\n    # Asserts that the subscription was successfully created\n    assert subscription.confirmed?\n\n    # Asserts that the channel subscribes connection to a stream\n    assert_has_stream \"chat_1\"\n\n    # Asserts that the channel subscribes connection to a stream created with `stream_for`\n    assert_has_stream_for Room.find(1)\n  end\n\n  def test_subscribed_without_room_number\n    subscribe\n\n    assert subscription.confirmed?\n    # Asserts that no streams was started\n    # (e.g., we want to subscribe later by performing an action)\n    assert_no_streams\n  end\n\n  def test_does_not_subscribe_with_invalid_room_number\n    subscribe room_number: -1\n\n    # Asserts that the subscription was rejected\n    assert subscription.rejected?\n  end\nend\n```\n\nYou can also perform actions:\n\n```ruby\ndef test_perform_speak\n  subscribe room_number: 1\n\n  perform :speak, message: \"Hello, Rails!\"\n\n  # `transmissions` stores messages sent directly to the channel (i.e. with `transmit` method)\n  assert_equal \"Hello, Rails!\", transmissions.last[\"text\"]\nend\n```\n\nYou can set up your connection identifiers:\n\n```ruby\nclass ChatChannelTest \u003c ActionCable::Channel::TestCase\n  include ActionCable::TestHelper\n\n  def test_identifiers\n    stub_connection(user: users[:john])\n\n    subscribe room_number: 1\n\n    assert_broadcast_on(\"messages_1\", text: \"I'm here!\", from: \"John\") do\n      perform :speak, message: \"I'm here!\"\n    end\n  end\nend\n```\nWhen broadcasting to an object:\n\n```ruby\nclass ChatChannelTest \u003c ActionCable::Channel::TestCase\n  def setup\n    @room = Room.find 1\n\n    stub_connection(user: users[:john])\n    subscribe room_number: room.id\n  end\n\n  def test_broadcasting\n    assert_broadcasts(@room, 1) do\n      perform :speak, message: \"I'm here!\"\n    end\n  end\n\n  # or\n\n  def test_broadcasted_data\n    assert_broadcast_on(@room, text: \"I'm here!\", from: \"John\") do\n      perform :speak, message: \"I'm here!\"\n    end\n  end\nend\n```\n\n### Connection Testing\n\nConnection unit tests are written as follows:\n1. First, one uses the `connect` method to simulate connection.\n2. Then, one asserts whether the current state is as expected (e.g. identifiers).\n\nFor example:\n\n```ruby\nmodule ApplicationCable\n  class ConnectionTest \u003c ActionCable::Connection::TestCase\n    def test_connects_with_cookies\n      cookies.signed[:user_id] = users[:john].id\n\n      # Simulate a connection\n      connect\n\n      # Asserts that the connection identifier is correct\n      assert_equal \"John\", connection.user.name\n    end\n\n    def test_does_not_connect_without_user\n      assert_reject_connection do\n        connect\n      end\n    end\n  end\nend\n```\n\nYou can also provide additional information about underlying HTTP request:\n\n```ruby\ndef test_connect_with_headers_and_query_string\n  connect \"/cable?user_id=1\", headers: { \"X-API-TOKEN\" =\u003e 'secret-my' }\n\n  assert_equal connection.user_id, \"1\"\nend\n\ndef test_connect_with_session\n  connect \"/cable\", session: { users[:john].id }\n\n  assert_equal connection.user_id, \"1\"\nend\n```\n\n### RSpec Usage\n\nFirst, you need to have [rspec-rails](https://github.com/rspec/rspec-rails) installed.\n\nSecond, add this to your `\"rails_helper.rb\"` after requiring `environment.rb`:\n\n```ruby\nrequire \"action_cable/testing/rspec\"\n```\n\nTo use `have_broadcasted_to` / `broadcast_to` matchers anywhere in your specs, set your adapter to `test` in `cable.yml`:\n\n```yml\n# config/cable.yml\ntest:\n  adapter: test\n```\n\nAnd then use these matchers, for example:\n\n\n```ruby\nRSpec.describe CommentsController do\n  describe \"POST #create\" do\n    expect { post :create, comment: { text: 'Cool!' } }.to\n      have_broadcasted_to(\"comments\").with(text: 'Cool!')\n  end\nend\n```\n\nOr when broadcasting to an object:\n\n```ruby\nRSpec.describe CommentsController do\n  describe \"POST #create\" do\n    let(:the_post) { create :post }\n\n    expect { post :create, comment: { text: 'Cool!', post_id: the_post.id } }.to\n      have_broadcasted_to(the_post).from_channel(PostChannel).with(text: 'Cool!')\n  end\nend\n```\n\nYou can also unit-test your channels:\n\n\n```ruby\n# spec/channels/chat_channel_spec.rb\n\nrequire \"rails_helper\"\n\nRSpec.describe ChatChannel, type: :channel do\n  before do\n    # initialize connection with identifiers\n    stub_connection user_id: user.id\n  end\n\n  it \"subscribes without streams when no room id\" do\n    subscribe\n\n    expect(subscription).to be_confirmed\n    expect(subscription).not_to have_streams\n  end\n\n  it \"rejects when room id is invalid\" do\n    subscribe(room_id: -1)\n\n    expect(subscription).to be_rejected\n  end\n\n  it \"subscribes to a stream when room id is provided\" do\n    subscribe(room_id: 42)\n\n    expect(subscription).to be_confirmed\n\n    # check particular stream by name\n    expect(subscription).to have_stream_from(\"chat_42\")\n\n    # or directly by model if you create streams with `stream_for`\n    expect(subscription).to have_stream_for(Room.find(42))\n  end\nend\n```\n\nAnd, of course, connections:\n\n```ruby\nrequire \"rails_helper\"\n\nRSpec.describe ApplicationCable::Connection, type: :channel do\n  it \"successfully connects\" do\n    connect \"/cable\", headers: { \"X-USER-ID\" =\u003e \"325\" }\n    expect(connection.user_id).to eq \"325\"\n  end\n\n  it \"rejects connection\" do\n    expect { connect \"/cable\" }.to have_rejected_connection\n  end\nend\n```\n\n**NOTE:** for connections testing you must use `type: :channel` too.\n\n#### Shared contexts to switch between adapters\n\n**NOTE:** this feature is gem-only and hasn't been migrated to RSpec 4. You can still use the gem for that by adding `require \"rspec/rails/shared_contexts/action_cable\"` to your `rspec_helper.rb`.\n\nSometimes you may want to use _real_ Action Cable adapter instead of the test one (for example, in Capybara-like tests).\n\nWe provide shared contexts to do that:\n\n```ruby\n# Use async adapter for this example group only\nRSpec.describe \"cable case\", action_cable: :async do\n # ...\n\n  context \"inline cable\", action_cable: :inline do\n    # ...\n  end\n\n  # or test adapter\n  context \"test cable\", action_cable: :test do\n    # ...\n  end\n\n  # you can also include contexts by names\n  context \"by name\" do\n    include \"action_cable:async\"\n    # ...\n  end\nend\n```\n\nWe also provide an integration for _feature_ specs (having `type: :feature`). Just add `require \"action_cable/testing/rspec/features\"`:\n\n```ruby\n# rails_helper.rb\nrequire \"action_cable/testing/rspec\"\nrequire \"action_cable/testing/rspec/features\"\n\n# spec/features/my_feature_spec.rb\nfeature \"Cables!\" do\n  # here we have \"action_cable:async\" context included automatically!\nend\n```\n\nFor more RSpec documentation see https://relishapp.com/palkan/action-cable-testing/docs.\n\n### Generators\n\nThis gem also provides Rails generators:\n\n```sh\n# Generate a channel test case for ChatChannel\nrails generate test_unit:channel chat\n\n# or for RSpec\nrails generate rspec:channel chat\n```\n\n## Development\n\nAfter checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake` to run the tests.\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/palkan/action-cable-testing.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n[Action Cable]: http://guides.rubyonrails.org/action_cable_overview.html\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalkan%2Faction-cable-testing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpalkan%2Faction-cable-testing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalkan%2Faction-cable-testing/lists"}