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 +4 -4
- data/CHANGELOG.md +13 -2
- data/README.md +48 -1
- data/lib/action_cable/test_helper.rb +30 -15
- data/lib/action_cable/testing/version.rb +1 -1
- data/lib/rspec/rails/matchers/action_cable.rb +41 -10
- data/lib/rspec/rails/shared_contexts/action_cable.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49ea4d058ad808b422aee252af3404f7ffc19b09
|
4
|
+
data.tar.gz: fc2a1ab66b7d9dbbcb34a8c59d51f614fe715e8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6457b2c9afabf9c6e758a5cbe1cad993c7585734dec33bfed1a96e4d606dcc415e507cefc3d0e6fc7acbcca877edd4d558798919ef2f700846c40d7185faecd7
|
7
|
+
data.tar.gz: 9cc75eb56ad1f4b6f30540e5d3b523be3ab6278604bbc97325e1b3d1d84024dbd72ea9e7feb0894732b134c4832a4040c2c76843d6d14d4e690ae244c91d2b81
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,18 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
-
## 0.
|
3
|
+
## 0.2.0
|
4
4
|
|
5
|
-
-
|
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(
|
47
|
+
def assert_broadcasts(target, number, channel: nil)
|
48
|
+
stream = stream(target, channel)
|
49
|
+
|
46
50
|
if block_given?
|
47
|
-
original_count = broadcasts_size(
|
51
|
+
original_count = broadcasts_size(stream)
|
48
52
|
yield
|
49
|
-
new_count = broadcasts_size(
|
50
|
-
assert_equal number, new_count - original_count, "#{number} broadcasts to #{
|
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(
|
53
|
-
assert_equal number, actual_count, "#{number} broadcasts to #{
|
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(
|
78
|
-
assert_broadcasts
|
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(
|
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
|
-
|
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(
|
111
|
+
clear_messages(stream)
|
106
112
|
|
107
113
|
yield
|
108
|
-
new_messages = broadcasts(
|
109
|
-
clear_messages(
|
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(
|
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 #{
|
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
|
@@ -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(
|
14
|
-
@
|
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 #{
|
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(
|
88
|
+
original_sent_messages_count = pubsub_adapter.broadcasts(stream).size
|
88
89
|
proc.call
|
89
|
-
in_block_messages = pubsub_adapter.broadcasts(
|
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 #{
|
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
|
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
|
-
|
209
|
+
|
210
|
+
def have_broadcasted_to(target = nil)
|
181
211
|
check_action_cable_adapter
|
182
|
-
|
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:
|
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" (
|
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.
|
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
|
+
date: 2017-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actioncable
|