action-cable-testing 0.0.6.1 → 0.0.7

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: 8092ab8d50462d20a5192f06dd233f4876a130e9
4
- data.tar.gz: 37059d739700e6792a972e405c8a2749f65cc2c2
3
+ metadata.gz: 96625e06dd39e7a58e78f77601bdc84d440cad8a
4
+ data.tar.gz: e125b688d9c10e7ad1ed89efeb25bc8c2e7f225b
5
5
  SHA512:
6
- metadata.gz: 11c87c8eda12f74a453985af75907535bafb90f65e63a9ca588cd2e91ab820d769f85fc2aeea8c4ab8d0bdffc5c1502a0c65c60cde07409de272937bcf1983e6
7
- data.tar.gz: 3191e647f6a54aa412c98a9f7585ca45f411d786566c6fb5e1fe54c817aeb2b054907e770d385754a612a7824048c86fe953b530600bdfd709251e49896eb472
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["message"]["text"]
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 connection (without encoding).
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
  #
@@ -21,7 +21,7 @@ module ActionCable
21
21
  channels_data[channel] = []
22
22
  end
23
23
 
24
- def reset!
24
+ def clear
25
25
  @channels_data = nil
26
26
  end
27
27
 
@@ -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
- new_messages = new_messages.map { |msg| ActiveSupport::JSON.decode(msg) }
115
+ message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
116
116
 
117
- assert_includes new_messages, serialized_msg, "No messages sent with #{data} to #{channel}"
117
+ assert message, "No messages sent with #{data} to #{channel}"
118
118
  end
119
119
 
120
120
  def pubsub_adapter # :nodoc:
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rspec/rails/example/channel_example_group"
4
+ require "rspec/rails/matchers/action_cable"
4
5
 
5
6
  module RSpec # :nodoc:
6
7
  module Rails
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActionCable
4
4
  module Testing
5
- VERSION = "0.0.6.1"
5
+ VERSION = "0.0.7"
6
6
  end
7
7
  end
@@ -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,7 @@
1
+ require 'rails_helper'
2
+
3
+ <% module_namespacing do -%>
4
+ RSpec.describe <%= class_name %>Channel, <%= type_metatag(:channel) %> do
5
+ pending "add some examples to (or delete) #{__FILE__}"
6
+ end
7
+ <% 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.6.1
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-23 00:00:00.000000000 Z
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