action-cable-testing 0.0.6.1 → 0.0.7
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/README.md +48 -0
- data/lib/action_cable/channel/test_case.rb +2 -2
- data/lib/action_cable/subscription_adapter/test.rb +1 -1
- data/lib/action_cable/test_helper.rb +2 -2
- data/lib/action_cable/testing/rspec.rb +1 -0
- data/lib/action_cable/testing/version.rb +1 -1
- data/lib/generators/rspec/channel/channel_generator.rb +16 -0
- data/lib/generators/rspec/channel/templates/channel_spec.rb.erb +7 -0
- data/lib/rspec/rails/matchers/action_cable.rb +195 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96625e06dd39e7a58e78f77601bdc84d440cad8a
|
4
|
+
data.tar.gz: e125b688d9c10e7ad1ed89efeb25bc8c2e7f225b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17592526b34d09527d340b414dd0d9664a11fab820fd5d8aa49f5f67ea55c5494cb0044f83d6555d23d6ed745603923e808015b544cc797c6018dc0eb5289f57
|
7
|
+
data.tar.gz: e9c91223b1702d725293ff5e7303e2c2d6bc39a8b90f550ff1d37a98bedd19367c55dd414d8b2a9eced77e922de03e74d792ec441dd9f418b322682f3ff0085a
|
data/README.md
CHANGED
@@ -124,6 +124,54 @@ end
|
|
124
124
|
|
125
125
|
### RSpec Usage
|
126
126
|
|
127
|
+
|
128
|
+
First, set your adapter to `test` in `cable.yml`:
|
129
|
+
|
130
|
+
```yml
|
131
|
+
# config/cable.yml
|
132
|
+
test:
|
133
|
+
adapter: test
|
134
|
+
```
|
135
|
+
|
136
|
+
Now you can use `have_broadcasted_to` / `broadcast_to` matchers anywhere in your specs. For example:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
RSpec.describe CommentsController do
|
140
|
+
describe "POST #create" do
|
141
|
+
expect { post :create, comment: { text: 'Cool!' } }.to
|
142
|
+
have_broadcasted_to("comments").with(text: 'Cool!')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
You can also unit-test your channels:
|
148
|
+
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
# spec/channels/chat_channel_spec.rb
|
152
|
+
|
153
|
+
require "rails_helper"
|
154
|
+
|
155
|
+
RSpec.describe ChatChannel, type: :channel do
|
156
|
+
before do
|
157
|
+
# initialize connection with identifiers
|
158
|
+
stub_connection user_id: user.id
|
159
|
+
end
|
160
|
+
|
161
|
+
it "rejects when no room id" do
|
162
|
+
subscribe
|
163
|
+
expect(subscription).to be_rejected
|
164
|
+
end
|
165
|
+
|
166
|
+
it "subscribes to a stream when room id is provided" do
|
167
|
+
subscribe(room_id: 42)
|
168
|
+
|
169
|
+
expect(subscription).to be_confirmed
|
170
|
+
expect(streams).to include("chat_42")
|
171
|
+
end
|
172
|
+
end
|
173
|
+
```
|
174
|
+
|
127
175
|
For more RSpec documentation see https://relishapp.com/palkan/action-cable-testing/docs.
|
128
176
|
|
129
177
|
### Generators
|
@@ -97,7 +97,7 @@ module ActionCable
|
|
97
97
|
#
|
98
98
|
# perform :speak, message: "Hello, Rails!"
|
99
99
|
#
|
100
|
-
# assert_equal "Hello, Rails!", transmissions.last["
|
100
|
+
# assert_equal "Hello, Rails!", transmissions.last["text"]
|
101
101
|
# end
|
102
102
|
#
|
103
103
|
# == Special methods
|
@@ -110,7 +110,7 @@ module ActionCable
|
|
110
110
|
# <b>subscription</b>::
|
111
111
|
# An instance of the current channel, created when you call `subscribe`.
|
112
112
|
# <b>transmissions</b>::
|
113
|
-
# A list of all messages that have been transmitted into the
|
113
|
+
# A list of all messages that have been transmitted into the channel.
|
114
114
|
# <b>streams</b>::
|
115
115
|
# A list of all created streams subscriptions (as identifiers) for the subscription.
|
116
116
|
#
|
@@ -112,9 +112,9 @@ module ActionCable
|
|
112
112
|
(old_messages + new_messages).each { |m| pubsub_adapter.broadcast(channel, m) }
|
113
113
|
end
|
114
114
|
|
115
|
-
|
115
|
+
message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
|
116
116
|
|
117
|
-
|
117
|
+
assert message, "No messages sent with #{data} to #{channel}"
|
118
118
|
end
|
119
119
|
|
120
120
|
def pubsub_adapter # :nodoc:
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "generators/rspec"
|
4
|
+
|
5
|
+
module Rspec
|
6
|
+
module Generators
|
7
|
+
# @private
|
8
|
+
class ChannelGenerator < Base
|
9
|
+
source_root File.expand_path("../templates", __FILE__)
|
10
|
+
|
11
|
+
def create_channel_spec
|
12
|
+
template "channel_spec.rb.erb", File.join("spec/channels", class_path, "#{file_name}_channel_spec.rb")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# rubocop: disable Style/FrozenStringLiteralComment
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Rails
|
5
|
+
module Matchers
|
6
|
+
# Namespace for various implementations of ActionCable features
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
module ActionCable
|
10
|
+
# rubocop: disable Style/ClassLength
|
11
|
+
# @private
|
12
|
+
class HaveBroadcastedTo < RSpec::Matchers::BuiltIn::BaseMatcher
|
13
|
+
def initialize(stream)
|
14
|
+
@stream = stream
|
15
|
+
@block = Proc.new {}
|
16
|
+
set_expected_number(:exactly, 1)
|
17
|
+
end
|
18
|
+
|
19
|
+
def with(data = nil)
|
20
|
+
@data = data
|
21
|
+
@data = @data.with_indifferent_access if @data.is_a?(Hash)
|
22
|
+
@block = Proc.new if block_given?
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def exactly(count)
|
27
|
+
set_expected_number(:exactly, count)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def at_least(count)
|
32
|
+
set_expected_number(:at_least, count)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def at_most(count)
|
37
|
+
set_expected_number(:at_most, count)
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def times
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def once
|
46
|
+
exactly(:once)
|
47
|
+
end
|
48
|
+
|
49
|
+
def twice
|
50
|
+
exactly(:twice)
|
51
|
+
end
|
52
|
+
|
53
|
+
def thrice
|
54
|
+
exactly(:thrice)
|
55
|
+
end
|
56
|
+
|
57
|
+
def failure_message
|
58
|
+
"expected to broadcast #{base_message}".tap do |msg|
|
59
|
+
if @unmatching_msgs.any?
|
60
|
+
msg << "\nBroadcasted messages to #{@stream}:"
|
61
|
+
@unmatching_msgs.each do |data|
|
62
|
+
msg << "\n #{data}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def failure_message_when_negated
|
69
|
+
"expected not to broadcast #{base_message}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def message_expectation_modifier
|
73
|
+
case @expectation_type
|
74
|
+
when :exactly then "exactly"
|
75
|
+
when :at_most then "at most"
|
76
|
+
when :at_least then "at least"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def supports_block_expectations?
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def matches?(proc)
|
85
|
+
raise ArgumentError, "have_broadcasted_to and broadcast_to only support block expectations" unless Proc === proc
|
86
|
+
|
87
|
+
original_sent_messages_count = pubsub_adapter.broadcasts(@stream).size
|
88
|
+
proc.call
|
89
|
+
in_block_messages = pubsub_adapter.broadcasts(@stream).drop(original_sent_messages_count)
|
90
|
+
|
91
|
+
check(in_block_messages)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def check(messages)
|
97
|
+
@matching_msgs, @unmatching_msgs = messages.partition do |msg|
|
98
|
+
decoded = ActiveSupport::JSON.decode(msg)
|
99
|
+
decoded = decoded.with_indifferent_access if decoded.is_a?(Hash)
|
100
|
+
|
101
|
+
if @data.nil? || @data === decoded
|
102
|
+
@block.call(decoded)
|
103
|
+
true
|
104
|
+
else
|
105
|
+
false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
@matching_msgs_count = @matching_msgs.size
|
110
|
+
|
111
|
+
case @expectation_type
|
112
|
+
when :exactly then @expected_number == @matching_msgs_count
|
113
|
+
when :at_most then @expected_number >= @matching_msgs_count
|
114
|
+
when :at_least then @expected_number <= @matching_msgs_count
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def set_expected_number(relativity, count)
|
119
|
+
@expectation_type = relativity
|
120
|
+
@expected_number =
|
121
|
+
case count
|
122
|
+
when :once then 1
|
123
|
+
when :twice then 2
|
124
|
+
when :thrice then 3
|
125
|
+
else Integer(count)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def base_message
|
130
|
+
"#{message_expectation_modifier} #{@expected_number} messages to #{@stream}".tap do |msg|
|
131
|
+
msg << " with #{data_description(@data)}" unless @data.nil?
|
132
|
+
msg << ", but broadcast #{@matching_msgs_count}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def data_description(data)
|
137
|
+
if data.is_a?(RSpec::Matchers::Composable)
|
138
|
+
data.description
|
139
|
+
else
|
140
|
+
data
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def pubsub_adapter
|
145
|
+
::ActionCable.server.pubsub
|
146
|
+
end
|
147
|
+
end
|
148
|
+
# rubocop: enable Style/ClassLength
|
149
|
+
end
|
150
|
+
|
151
|
+
# @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.
|
153
|
+
#
|
154
|
+
# @example
|
155
|
+
# expect {
|
156
|
+
# ActionCable.server.broadcast "messages", text: 'Hi!'
|
157
|
+
# }.to have_broadcasted_to("messages")
|
158
|
+
#
|
159
|
+
# # Using alias
|
160
|
+
# expect {
|
161
|
+
# ActionCable.server.broadcast "messages", text: 'Hi!'
|
162
|
+
# }.to broadcast_to("messages")
|
163
|
+
#
|
164
|
+
# expect {
|
165
|
+
# ActionCable.server.broadcast "messages", text: 'Hi!'
|
166
|
+
# ActionCable.server.broadcast "all", text: 'Hi!'
|
167
|
+
# }.to have_broadcasted_to("messages").exactly(:once)
|
168
|
+
#
|
169
|
+
# expect {
|
170
|
+
# 3.times { ActionCable.server.broadcast "messages", text: 'Hi!' }
|
171
|
+
# }.to have_broadcasted_to("messages").at_least(2).times
|
172
|
+
#
|
173
|
+
# expect {
|
174
|
+
# ActionCable.server.broadcast "messages", text: 'Hi!'
|
175
|
+
# }.to have_broadcasted_to("messages").at_most(:twice)
|
176
|
+
#
|
177
|
+
# expect {
|
178
|
+
# ActionCable.server.broadcast "messages", text: 'Hi!'
|
179
|
+
# }.to have_broadcasted_to("messages").with(text: 'Hi!')
|
180
|
+
def have_broadcasted_to(stream = nil)
|
181
|
+
check_action_cable_adapter
|
182
|
+
ActionCable::HaveBroadcastedTo.new(stream)
|
183
|
+
end
|
184
|
+
alias_method :broadcast_to, :have_broadcasted_to
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
# @private
|
189
|
+
def check_action_cable_adapter
|
190
|
+
return if ::ActionCable::SubscriptionAdapter::Test === ::ActionCable.server.pubsub
|
191
|
+
raise StandardError, "To use ActionCable matchers set `adapter: :test` in your cable.yml"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
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.0.
|
4
|
+
version: 0.0.7
|
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-10-
|
11
|
+
date: 2017-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actioncable
|
@@ -154,9 +154,12 @@ files:
|
|
154
154
|
- lib/action_cable/testing.rb
|
155
155
|
- lib/action_cable/testing/rspec.rb
|
156
156
|
- lib/action_cable/testing/version.rb
|
157
|
+
- lib/generators/rspec/channel/channel_generator.rb
|
158
|
+
- lib/generators/rspec/channel/templates/channel_spec.rb.erb
|
157
159
|
- lib/generators/test_unit/channel/channel_generator.rb
|
158
160
|
- lib/generators/test_unit/channel/templates/unit_test.rb.erb
|
159
161
|
- lib/rspec/rails/example/channel_example_group.rb
|
162
|
+
- lib/rspec/rails/matchers/action_cable.rb
|
160
163
|
homepage: http://github.com/palkan/action-cable-testing
|
161
164
|
licenses:
|
162
165
|
- MIT
|