action-cable-testing 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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