action-cable-testing 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1937dec963674b1c524cc2e89fa7e3019861ddc8
4
- data.tar.gz: 35c43aacde8ee6c44ce0a0921f4aa8a795e519e9
3
+ metadata.gz: 49ea4d058ad808b422aee252af3404f7ffc19b09
4
+ data.tar.gz: fc2a1ab66b7d9dbbcb34a8c59d51f614fe715e8e
5
5
  SHA512:
6
- metadata.gz: 65a6dbcf9d077659e1da92cc5237b01fa7194f5c929a31790f0ae14aad2d66a02a859c4ec16fbaf099ffbb85362f5b4bef62fdff319ddb1ce06845a3d6b0d4e9
7
- data.tar.gz: f74589aff6ea7a682c26107687601c0b4efa3555a783e2e01f20edcfefc6cd9d6cadad8506a1481110e4d53e4557461c41a5fa16b32be67678aafd9507a053ca
6
+ metadata.gz: 6457b2c9afabf9c6e758a5cbe1cad993c7585734dec33bfed1a96e4d606dcc415e507cefc3d0e6fc7acbcca877edd4d558798919ef2f700846c40d7185faecd7
7
+ data.tar.gz: 9cc75eb56ad1f4b6f30540e5d3b523be3ab6278604bbc97325e1b3d1d84024dbd72ea9e7feb0894732b134c4832a4040c2c76843d6d14d4e690ae244c91d2b81
@@ -1,8 +1,18 @@
1
1
  # Change log
2
2
 
3
- ## 0.1.2 (2017-11-14) ([@palkan][])
3
+ ## 0.2.0
4
4
 
5
- - Add RSpec shared contexts to switch between adapters.
5
+ - Update minitest's `assert_broadcast_on` and `assert_broadcasts` matchers to support a record as an argument. ([@thesmartnik][])
6
+
7
+ See https://github.com/palkan/action-cable-testing/issues/11
8
+
9
+ - Update `have_broadcasted_to` matcher to support a record as an argument. ([@thesmartnik][])
10
+
11
+ See https://github.com/palkan/action-cable-testing/issues/9
12
+
13
+ ## 0.1.2 (2017-11-14)
14
+
15
+ - Add RSpec shared contexts to switch between adapters. ([@palkan][])
6
16
 
7
17
  See https://github.com/palkan/action-cable-testing/issues/4.
8
18
 
@@ -15,3 +25,4 @@ See https://github.com/palkan/action-cable-testing/issues/4.
15
25
  - Initial version. ([@palkan][])
16
26
 
17
27
  [@palkan]: https://github.com/palkan
28
+ [@thesmartnik]: https://github.com/thesmartnik
data/README.md CHANGED
@@ -52,10 +52,16 @@ class ExampleTest < ActionDispatch::IntegrationTest
52
52
 
53
53
  def test_broadcasts
54
54
  room = rooms(:office)
55
-
55
+
56
56
  assert_broadcast_on("messages:#{room.id}", text: 'Hello!') do
57
57
  post "/say/#{room.id}", xhr: true, params: { message: 'Hello!' }
58
58
  end
59
+
60
+ # When testing broadcast to an object outside of channel test,
61
+ # channel should be explicitly specified
62
+ assert_broadcast_on(room, { text: 'Hello!' }, { channel: ChatChannel } do
63
+ post "/say/#{room.id}", xhr: true, params: { message: 'Hello!' }
64
+ end
59
65
  end
60
66
  end
61
67
  ```
@@ -121,6 +127,34 @@ class ChatChannelTest < ActionCable::Channel::TestCase
121
127
  end
122
128
  end
123
129
  ```
130
+ When broadcasting to an object:
131
+
132
+ ```ruby
133
+ class ChatChannelTest < ActionCable::Channel::TestCase
134
+ include ActionCable::TestHelper
135
+
136
+ def setup
137
+ @room = Room.find 1
138
+
139
+ stub_connection(user: users[:john])
140
+ subscribe room_number: room.id
141
+ end
142
+
143
+ def test_broadcating
144
+ assert_broadcasts(@room, 1) do
145
+ perform :speak, message: "I'm here!"
146
+ end
147
+ end
148
+
149
+ # or
150
+
151
+ def test_broadcasted_data
152
+ assert_broadcasts_on(@room, text: "I'm here!", from: "John") do
153
+ perform :speak, message: "I'm here!"
154
+ end
155
+ end
156
+ end
157
+ ```
124
158
 
125
159
  ### RSpec Usage
126
160
 
@@ -152,6 +186,19 @@ RSpec.describe CommentsController do
152
186
  end
153
187
  ```
154
188
 
189
+ Or when broacasting to an object:
190
+
191
+ ```ruby
192
+ RSpec.describe CommentsController do
193
+ describe "POST #create" do
194
+ let(:post) { create :post }
195
+
196
+ expect { post :create, comment: { text: 'Cool!', post_id: post.id } }.to
197
+ have_broadcasted_to(post).from_channel(PostChannel).with(text: 'Cool!')
198
+ end
199
+ end
200
+ ```
201
+
155
202
  You can also unit-test your channels:
156
203
 
157
204
 
@@ -3,6 +3,8 @@
3
3
  module ActionCable
4
4
  # Provides helper methods for testing Action Cable broadcasting
5
5
  module TestHelper
6
+ CHANNEL_NOT_FOUND = ArgumentError.new("Broadcastnig channel can't be infered. Please, specify it with `:channel`")
7
+
6
8
  def before_setup # :nodoc:
7
9
  server = ActionCable.server
8
10
  test_adapter = ActionCable::SubscriptionAdapter::Test.new(server)
@@ -42,15 +44,17 @@ module ActionCable
42
44
  # end
43
45
  # end
44
46
  #
45
- def assert_broadcasts(channel, number)
47
+ def assert_broadcasts(target, number, channel: nil)
48
+ stream = stream(target, channel)
49
+
46
50
  if block_given?
47
- original_count = broadcasts_size(channel)
51
+ original_count = broadcasts_size(stream)
48
52
  yield
49
- new_count = broadcasts_size(channel)
50
- assert_equal number, new_count - original_count, "#{number} broadcasts to #{channel} expected, but #{new_count - original_count} were sent"
53
+ new_count = broadcasts_size(stream)
54
+ assert_equal number, new_count - original_count, "#{number} broadcasts to #{stream} expected, but #{new_count - original_count} were sent"
51
55
  else
52
- actual_count = broadcasts_size(channel)
53
- assert_equal number, actual_count, "#{number} broadcasts to #{channel} expected, but #{actual_count} were sent"
56
+ actual_count = broadcasts_size(stream)
57
+ assert_equal number, actual_count, "#{number} broadcasts to #{stream} expected, but #{actual_count} were sent"
54
58
  end
55
59
  end
56
60
 
@@ -74,8 +78,8 @@ module ActionCable
74
78
  #
75
79
  # assert_broadcasts 'messages', 0, &block
76
80
  #
77
- def assert_no_broadcasts(channel, &block)
78
- assert_broadcasts channel, 0, &block
81
+ def assert_no_broadcasts(target, &block)
82
+ assert_broadcasts target, 0, &block
79
83
  end
80
84
 
81
85
  # Asserts that the specified message has been sent to the channel.
@@ -93,28 +97,30 @@ module ActionCable
93
97
  # end
94
98
  # end
95
99
  #
96
- def assert_broadcast_on(channel, data)
100
+ def assert_broadcast_on(target, data, channel: nil)
97
101
  # Encode to JSON and back–we want to use this value to compare
98
102
  # with decoded JSON.
99
103
  # Comparing JSON strings doesn't work due to the order if the keys.
100
104
  serialized_msg =
101
105
  ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data))
102
- new_messages = broadcasts(channel)
106
+ stream = stream(target, channel)
107
+
108
+ new_messages = broadcasts(stream)
103
109
  if block_given?
104
110
  old_messages = new_messages
105
- clear_messages(channel)
111
+ clear_messages(stream)
106
112
 
107
113
  yield
108
- new_messages = broadcasts(channel)
109
- clear_messages(channel)
114
+ new_messages = broadcasts(stream)
115
+ clear_messages(stream)
110
116
 
111
117
  # Restore all sent messages
112
- (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(channel, m) }
118
+ (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(stream, m) }
113
119
  end
114
120
 
115
121
  message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
116
122
 
117
- assert message, "No messages sent with #{data} to #{channel}"
123
+ assert message, "No messages sent with #{data} to #{stream}"
118
124
  end
119
125
 
120
126
  def pubsub_adapter # :nodoc:
@@ -127,5 +133,14 @@ module ActionCable
127
133
  def broadcasts_size(channel) # :nodoc:
128
134
  broadcasts(channel).size
129
135
  end
136
+
137
+ def stream(target, channel = nil)
138
+ return target if target.is_a?(String)
139
+
140
+ channel ||= @subscription
141
+ raise CHANNEL_NOT_FOUND unless channel && channel.respond_to?(:channel_name)
142
+
143
+ channel.broadcasting_for([channel.channel_name, target])
144
+ end
130
145
  end
131
146
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActionCable
4
4
  module Testing
5
- VERSION = "0.1.2"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
@@ -10,8 +10,9 @@ module RSpec
10
10
  # rubocop: disable Style/ClassLength
11
11
  # @private
12
12
  class HaveBroadcastedTo < RSpec::Matchers::BuiltIn::BaseMatcher
13
- def initialize(stream)
14
- @stream = stream
13
+ def initialize(target, channel:)
14
+ @target = target
15
+ @channel = channel
15
16
  @block = Proc.new {}
16
17
  set_expected_number(:exactly, 1)
17
18
  end
@@ -57,7 +58,7 @@ module RSpec
57
58
  def failure_message
58
59
  "expected to broadcast #{base_message}".tap do |msg|
59
60
  if @unmatching_msgs.any?
60
- msg << "\nBroadcasted messages to #{@stream}:"
61
+ msg << "\nBroadcasted messages to #{stream}:"
61
62
  @unmatching_msgs.each do |data|
62
63
  msg << "\n #{data}"
63
64
  end
@@ -84,15 +85,29 @@ module RSpec
84
85
  def matches?(proc)
85
86
  raise ArgumentError, "have_broadcasted_to and broadcast_to only support block expectations" unless Proc === proc
86
87
 
87
- original_sent_messages_count = pubsub_adapter.broadcasts(@stream).size
88
+ original_sent_messages_count = pubsub_adapter.broadcasts(stream).size
88
89
  proc.call
89
- in_block_messages = pubsub_adapter.broadcasts(@stream).drop(original_sent_messages_count)
90
+ in_block_messages = pubsub_adapter.broadcasts(stream).drop(original_sent_messages_count)
90
91
 
91
92
  check(in_block_messages)
92
93
  end
93
94
 
95
+ def from_channel(channel)
96
+ @channel = channel
97
+ self
98
+ end
99
+
94
100
  private
95
101
 
102
+ def stream
103
+ @stream ||= if @target.is_a?(String)
104
+ @target
105
+ else
106
+ check_channel_presence
107
+ @channel.broadcasting_for([@channel.channel_name, @target])
108
+ end
109
+ end
110
+
96
111
  def check(messages)
97
112
  @matching_msgs, @unmatching_msgs = messages.partition do |msg|
98
113
  decoded = ActiveSupport::JSON.decode(msg)
@@ -127,7 +142,7 @@ module RSpec
127
142
  end
128
143
 
129
144
  def base_message
130
- "#{message_expectation_modifier} #{@expected_number} messages to #{@stream}".tap do |msg|
145
+ "#{message_expectation_modifier} #{@expected_number} messages to #{stream}".tap do |msg|
131
146
  msg << " with #{data_description(@data)}" unless @data.nil?
132
147
  msg << ", but broadcast #{@matching_msgs_count}"
133
148
  end
@@ -144,18 +159,32 @@ module RSpec
144
159
  def pubsub_adapter
145
160
  ::ActionCable.server.pubsub
146
161
  end
162
+
163
+ def check_channel_presence
164
+ return if @channel.present? && @channel.respond_to?(:channel_name)
165
+
166
+ error_msg = "Broadcastnig channel can't be infered. Please, specify it with `from_channel`"
167
+ raise ArgumentError, error_msg
168
+ end
147
169
  end
148
170
  # rubocop: enable Style/ClassLength
149
171
  end
150
172
 
151
173
  # @api public
152
- # Passes if a message has been sent to a stream inside block. May chain at_least, at_most or exactly to specify a number of times.
174
+ # Passes if a message has been sent to a stream/object inside a block.
175
+ # May chain `at_least`, `at_most` or `exactly` to specify a number of times.
176
+ # To specify channel from which message has been broadcasted to object use `from_channel`.
177
+ #
153
178
  #
154
179
  # @example
155
180
  # expect {
156
181
  # ActionCable.server.broadcast "messages", text: 'Hi!'
157
182
  # }.to have_broadcasted_to("messages")
158
183
  #
184
+ # expect {
185
+ # SomeChannel.broadcast_to(user)
186
+ # }.to have_broadcasted_to(user).from_channel(SomeChannel)
187
+ #
159
188
  # # Using alias
160
189
  # expect {
161
190
  # ActionCable.server.broadcast "messages", text: 'Hi!'
@@ -177,9 +206,11 @@ module RSpec
177
206
  # expect {
178
207
  # ActionCable.server.broadcast "messages", text: 'Hi!'
179
208
  # }.to have_broadcasted_to("messages").with(text: 'Hi!')
180
- def have_broadcasted_to(stream = nil)
209
+
210
+ def have_broadcasted_to(target = nil)
181
211
  check_action_cable_adapter
182
- ActionCable::HaveBroadcastedTo.new(stream)
212
+
213
+ ActionCable::HaveBroadcastedTo.new(target, channel: described_class)
183
214
  end
184
215
  alias_method :broadcast_to, :have_broadcasted_to
185
216
 
@@ -188,7 +219,7 @@ module RSpec
188
219
  # @private
189
220
  def check_action_cable_adapter
190
221
  return if ::ActionCable::SubscriptionAdapter::Test === ::ActionCable.server.pubsub
191
- raise StandardError, "To use ActionCable matchers set `adapter: :test` in your cable.yml"
222
+ raise StandardError, "To use ActionCable matchers set `adapter: test` in your cable.yml"
192
223
  end
193
224
  end
194
225
  end
@@ -3,7 +3,7 @@
3
3
  # Generate contexts to use specific Action Cable adapter:
4
4
  # - "action_cable:async" (action_cable: :async)
5
5
  # - "action_cable:inline" (action_cable: :inline)
6
- # - "action_cable:test" (action_cabke: :test)
6
+ # - "action_cable:test" (action_cable: :test)
7
7
  %w[async inline test].each do |adapter|
8
8
  RSpec.shared_context "action_cable:#{adapter}" do
9
9
  require "action_cable/subscription_adapter/#{adapter}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action-cable-testing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-14 00:00:00.000000000 Z
11
+ date: 2017-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actioncable