New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ActionCable::Channel::TestCase #33969

Merged
merged 1 commit into from Sep 27, 2018

Conversation

Projects
None yet
3 participants
@palkan
Contributor

palkan commented Sep 24, 2018

Follow-up #33659.

ActionCable::Channel::TestCase provides an ability
to unit-test channel classes.

From #23211 (comment):

There are several reasons to write unit/functional cable tests:

  • Access control (who has access to the channel? who can perform action and with which argument?
  • Frontend-less applications have no system tests at all–and we still need a way to test channels logic.

See previous discussion here #27191

Summary

Channels Testing

Channels tests are written as follows:

  1. First, one uses the subscribe method to simulate subscription creation.
  2. Then, one asserts whether the current state is as expected. "State" can be anything:
    transmitted messages, subscribed streams, etc.

For example:

class ChatChannelTest < ActionCable::Channel::TestCase
  def test_subscribed_with_room_number
    # Simulate a subscription creation
    subscribe room_number: 1

    # Asserts that the subscription was successfully created
    assert subscription.confirmed?

    # Asserts that the channel subscribes connection to a stream
    assert "chat_1", streams.last
  end

  def test_does_not_subscribe_without_room_number
    subscribe

    # Asserts that the subscription was rejected
    assert subscription.rejected?
  end
end

You can also perform actions:

def test_perform_speak
  subscribe room_number: 1

  perform :speak, message: "Hello, Rails!"

  # `transmissions` stores messages sent directly to the channel (i.e. with `transmit` method)
  assert_equal "Hello, Rails!", transmissions.last["text"]
end

You can set up your connection identifiers:

class ChatChannelTest < ActionCable::Channel::TestCase
  include ActionCable::TestHelper

  def test_identifiers
    stub_connection(user: users[:john])

    subscribe room_number: 1

    assert_broadcasts_on("messages_1", text: "I'm here!", from: "John") do
      perform :speak, message: "I'm here!"
    end
  end
end

When broadcasting to an object:

class ChatChannelTest < ActionCable::Channel::TestCase
  def setup
    @room = Room.find 1

    stub_connection(user: users[:john])
    subscribe room_number: room.id
  end

  def test_broadcasting
    assert_broadcasts(@room, 1) do
      perform :speak, message: "I'm here!"
    end
  end

  # or

  def test_broadcasted_data
    assert_broadcasts_on(@room, text: "I'm here!", from: "John") do
      perform :speak, message: "I'm here!"
    end
  end
end
@jeremy

Fantastic, @palkan. Would you add a changelog entry to match?

Show outdated Hide outdated actioncable/lib/action_cable/channel/test_case.rb Outdated
def test_set_channel_class_manual_using_string
assert_equal TestTestChannel, self.class.channel_class
end
end

This comment has been minimized.

@jeremy

jeremy Sep 24, 2018

Member

Let's use more precise language for these, e.g. Crazy → NonInferrable

@jeremy

jeremy Sep 24, 2018

Member

Let's use more precise language for these, e.g. Crazy → NonInferrable

This comment has been minimized.

@palkan

palkan Sep 24, 2018

Contributor

I stole this craziness from action_mailer tests 🙂

Fixed

@palkan

palkan Sep 24, 2018

Contributor

I stole this craziness from action_mailer tests 🙂

Fixed

perform :broadcast_to_user, message: "SOS"
end
end
end

This comment has been minimized.

@jeremy

jeremy Sep 24, 2018

Member

Great test coverage and demonstration of the test case.

@jeremy

jeremy Sep 24, 2018

Member

Great test coverage and demonstration of the test case.

This comment has been minimized.

@palkan

palkan Sep 24, 2018

Contributor

Thanks!

@palkan

palkan Sep 24, 2018

Contributor

Thanks!

Add ActionCable::Channel::TestCase
ActionCable::Channel::TestCase provides an ability
to unit-test channel classes.

There are several reasons to write unit/functional cable tests:
- Access control (who has access to the channel? who can perform action and with which argument?
- Frontend-less applications have no system tests at all–and we still need a way to test channels logic.

See also #27191
@palkan

This comment has been minimized.

Show comment
Hide comment
@palkan

palkan Sep 24, 2018

Contributor

Would you add a changelog entry to match?

I thought we'll add one changelog entry along with the last Action Cable testing PR (this one is not the last one) since we've skipped it in #33969.

@jeremy Do you think it's better to add multiple change log entries?

Contributor

palkan commented Sep 24, 2018

Would you add a changelog entry to match?

I thought we'll add one changelog entry along with the last Action Cable testing PR (this one is not the last one) since we've skipped it in #33969.

@jeremy Do you think it's better to add multiple change log entries?

@jeremy

jeremy approved these changes Sep 27, 2018

Sounds good re. changelog!

@jeremy jeremy merged commit 8541394 into rails:master Sep 27, 2018

2 checks passed

codeclimate All good!
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@jeremy jeremy added this to the 6.0.0 milestone Sep 27, 2018

@subscription.singleton_class.include(ChannelStub)
@subscription.send(:initialize, connection, CHANNEL_IDENTIFIER, params.with_indifferent_access)
# Call subscribe_to_channel if it's public (Rails 5.0.1+)
@subscription.subscribe_to_channel if ActionCable.gem_version >= Gem::Version.new("5.0.1")

This comment has been minimized.

@y-yagi

y-yagi Sep 27, 2018

Member

Is this check still necessary?

@y-yagi

y-yagi Sep 27, 2018

Member

Is this check still necessary?

This comment has been minimized.

@palkan

palkan Sep 27, 2018

Contributor

Oops! No, we don't need it in Rails 6.

Will send a follow-up.

Thanks for catching!

@palkan

palkan Sep 27, 2018

Contributor

Oops! No, we don't need it in Rails 6.

Will send a follow-up.

Thanks for catching!

@palkan palkan deleted the palkan:activerecord/channels-unit-testing branch Sep 27, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment