action-cable-testing 0.3.4 → 0.4.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
  SHA256:
3
- metadata.gz: ee3c261b614627cd0d9d72bc9084cb4b7408bacaca953260d4c372da8774676c
4
- data.tar.gz: bbdde5b4fdb2deb81571c23198443674733962100311b8f013311f4a5a778307
3
+ metadata.gz: 6e9a6464f3ec1cc6ee48f51d97f0a8e0bebd34c3fee8f9523f01a6e0b6f19382
4
+ data.tar.gz: 3db543599b78e0944fa89679d47ab02275c09714b59b134430662a74163cddd8
5
5
  SHA512:
6
- metadata.gz: 4ebdc170789756ee2885f503241048270ecf815b35881474a972373cc51697d25f47d823ebc8fa8b8f0a55f2f2ffa30d31fac3e19b6939e001058f72ad523ea0
7
- data.tar.gz: 588e39d4f0c257b0786b966780be8b9ec8299ed87809a98da94fcf3e612c3d3abca5f5dfb861562abe60d9b5a3282cc0ce2439746c8da6f78b4cc8c64bd0d561
6
+ metadata.gz: 787512840b4dda952c365f770fcfb5858d6cbfb0ce261ca9fcbeb3384fd32a0102f490e4a1e1840a4fa1a3f68b9d4a24a4840322104a33af1a3164036b02bf5b
7
+ data.tar.gz: 2558049b61e39c42f57bd7a5a98f85522129a7d27001c5721e6525c56ba24136d9de913d579c02fd95205a8653eefed99006da3e722602b3fa7815eae69c9eda
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.4.0 (2019-01-10)
6
+
7
+ - Add stream assert methods and matchers. ([@sponomarev][])
8
+
9
+ See https://github.com/palkan/action-cable-testing/pull/42
10
+
5
11
  - Add session support for connection. ([@sponomarev][])
6
12
 
7
13
  See https://github.com/palkan/action-cable-testing/pull/35
data/README.md CHANGED
@@ -79,7 +79,10 @@ class ChatChannelTest < ActionCable::Channel::TestCase
79
79
  assert subscription.confirmed?
80
80
 
81
81
  # Asserts that the channel subscribes connection to a stream
82
- assert "chat_1", streams.last
82
+ assert_has_stream "chat_1"
83
+
84
+ # Asserts that the channel subscribes connection to a stream created with `stream_for`
85
+ assert_has_stream_for Room.find(1)
83
86
  end
84
87
 
85
88
  def test_does_not_subscribe_without_room_number
@@ -87,6 +90,9 @@ class ChatChannelTest < ActionCable::Channel::TestCase
87
90
 
88
91
  # Asserts that the subscription was rejected
89
92
  assert subscription.rejected?
93
+
94
+ # Asserts that no streams was started
95
+ assert_no_streams
90
96
  end
91
97
  end
92
98
  ```
@@ -252,13 +258,19 @@ RSpec.describe ChatChannel, type: :channel do
252
258
  it "rejects when no room id" do
253
259
  subscribe
254
260
  expect(subscription).to be_rejected
261
+ expect(subscription).not_to have_streams
255
262
  end
256
263
 
257
264
  it "subscribes to a stream when room id is provided" do
258
265
  subscribe(room_id: 42)
259
266
 
260
267
  expect(subscription).to be_confirmed
261
- expect(streams).to include("chat_42")
268
+
269
+ # check particular stream by name
270
+ expect(subscription).to have_stream_from("chat_42")
271
+
272
+ # or directly by model if you create streams with `stream_for`
273
+ expect(subscription).to have_stream_for(Room.find(42))
262
274
  end
263
275
  end
264
276
  ```
@@ -84,7 +84,18 @@ module ActionCable
84
84
  # assert subscription.confirmed?
85
85
  #
86
86
  # # Asserts that the channel subscribes connection to a stream
87
- # assert_equal "chat_1", streams.last
87
+ # assert_has_stream "chat_1"
88
+ #
89
+ # # Asserts that the channel subscribes connection to a specific
90
+ # # stream created for a model
91
+ # assert_has_stream_for Room.find(1)
92
+ # end
93
+ #
94
+ # def test_does_not_stream_with_incorrect_room_number
95
+ # subscribe room_number: -1
96
+ #
97
+ # # Asserts that not streams was started
98
+ # assert_no_streams
88
99
  # end
89
100
  #
90
101
  # def test_does_not_subscribe_without_room_number
@@ -115,8 +126,6 @@ module ActionCable
115
126
  # An instance of the current channel, created when you call `subscribe`.
116
127
  # <b>transmissions</b>::
117
128
  # A list of all messages that have been transmitted into the channel.
118
- # <b>streams</b>::
119
- # A list of all created streams subscriptions (as identifiers) for the subscription.
120
129
  #
121
130
  #
122
131
  # == Channel is automatically inferred
@@ -149,7 +158,13 @@ module ActionCable
149
158
  class_attribute :_channel_class
150
159
 
151
160
  attr_reader :subscription
152
- delegate :streams, to: :subscription
161
+
162
+ def streams
163
+ ActiveSupport::Deprecation.warn "Use appropriate `assert_has_stream`, `assert_has_stream_for`, `assert_no_streams` " +
164
+ "assertion methods for minitest or `have_stream`, `have_stream_for` and `have_stream_from` matchers " +
165
+ "for RSpec. Direct access to `streams` is deprecated and is going to be removed in version 1.0"
166
+ subscription.streams
167
+ end
153
168
 
154
169
  ActiveSupport.run_load_hooks(:action_cable_channel_test_case, self)
155
170
  end
@@ -227,10 +242,51 @@ module ActionCable
227
242
  connection.transmissions.map { |data| data["message"] }.compact
228
243
  end
229
244
 
245
+ # Asserts that no streams have been started.
246
+ #
247
+ # def test_assert_no_started_stream
248
+ # subscribe
249
+ # assert_no_streams
250
+ # end
251
+ #
252
+ def assert_no_streams
253
+ assert subscription.streams.empty?, "No streams started was expected, but #{subscription.streams.count} found"
254
+ end
255
+
256
+ # Asserts that the specified stream has been started.
257
+ #
258
+ # def test_assert_started_stream
259
+ # subscribe
260
+ # assert_has_stream 'messages'
261
+ # end
262
+ #
263
+ def assert_has_stream(stream)
264
+ assert subscription.streams.include?(stream), "Stream #{stream} has not been started"
265
+ end
266
+
267
+ # Asserts that the specified stream for a model has started.
268
+ #
269
+ # def test_assert_started_stream_for
270
+ # subscribe id: 42
271
+ # assert_has_stream_for User.find(42)
272
+ # end
273
+ #
274
+ def assert_has_stream_for(object)
275
+ assert_has_stream(broadcasting_for(object))
276
+ end
277
+
230
278
  private
231
279
  def check_subscribed!
232
280
  raise "Must be subscribed!" if subscription.nil? || subscription.rejected?
233
281
  end
282
+
283
+ def broadcasting_for(stream_or_object)
284
+ return stream_or_object if stream_or_object.is_a?(String)
285
+
286
+ self.class.channel_class.broadcasting_for(
287
+ [self.class.channel_class.channel_name, stream_or_object]
288
+ )
289
+ end
234
290
  end
235
291
 
236
292
  include Behavior
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActionCable
4
4
  module Testing
5
- VERSION = "0.3.4"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rspec/rails/matchers/action_cable/have_streams"
4
+
3
5
  module RSpec
4
6
  module Rails
5
7
  # @api public
@@ -39,6 +41,24 @@ if defined?(ActionCable)
39
41
  def have_rejected_connection
40
42
  raise_error(::ActionCable::Connection::Authorization::UnauthorizedError)
41
43
  end
44
+
45
+ def have_streams
46
+ check_subscribed!
47
+
48
+ RSpec::Rails::Matchers::ActionCable::HaveStream.new
49
+ end
50
+
51
+ def have_stream_from(stream)
52
+ check_subscribed!
53
+
54
+ RSpec::Rails::Matchers::ActionCable::HaveStream.new(stream)
55
+ end
56
+
57
+ def have_stream_for(object)
58
+ check_subscribed!
59
+
60
+ RSpec::Rails::Matchers::ActionCable::HaveStream.new(broadcasting_for(object))
61
+ end
42
62
  end
43
63
  end
44
64
  end
@@ -1,5 +1,7 @@
1
1
  # rubocop: disable Style/FrozenStringLiteralComment
2
2
 
3
+ require "rspec/rails/matchers/action_cable/have_broadcasted_to"
4
+
3
5
  module RSpec
4
6
  module Rails
5
7
  module Matchers
@@ -7,167 +9,6 @@ module RSpec
7
9
  #
8
10
  # @api private
9
11
  module ActionCable
10
- # rubocop: disable Metrics/ClassLength
11
- # @private
12
- class HaveBroadcastedTo < RSpec::Matchers::BuiltIn::BaseMatcher
13
- def initialize(target, channel:)
14
- @target = target
15
- @channel = channel
16
- @block = Proc.new {}
17
- set_expected_number(:exactly, 1)
18
- end
19
-
20
- def with(data = nil)
21
- @data = data
22
- @data = @data.with_indifferent_access if @data.is_a?(Hash)
23
- @block = Proc.new if block_given?
24
- self
25
- end
26
-
27
- def exactly(count)
28
- set_expected_number(:exactly, count)
29
- self
30
- end
31
-
32
- def at_least(count)
33
- set_expected_number(:at_least, count)
34
- self
35
- end
36
-
37
- def at_most(count)
38
- set_expected_number(:at_most, count)
39
- self
40
- end
41
-
42
- def times
43
- self
44
- end
45
-
46
- def once
47
- exactly(:once)
48
- end
49
-
50
- def twice
51
- exactly(:twice)
52
- end
53
-
54
- def thrice
55
- exactly(:thrice)
56
- end
57
-
58
- def failure_message
59
- "expected to broadcast #{base_message}".tap do |msg|
60
- if @unmatching_msgs.any?
61
- msg << "\nBroadcasted messages to #{stream}:"
62
- @unmatching_msgs.each do |data|
63
- msg << "\n #{data}"
64
- end
65
- end
66
- end
67
- end
68
-
69
- def failure_message_when_negated
70
- "expected not to broadcast #{base_message}"
71
- end
72
-
73
- def message_expectation_modifier
74
- case @expectation_type
75
- when :exactly then "exactly"
76
- when :at_most then "at most"
77
- when :at_least then "at least"
78
- end
79
- end
80
-
81
- def supports_block_expectations?
82
- true
83
- end
84
-
85
- def matches?(proc)
86
- raise ArgumentError, "have_broadcasted_to and broadcast_to only support block expectations" unless Proc === proc
87
-
88
- original_sent_messages_count = pubsub_adapter.broadcasts(stream).size
89
- proc.call
90
- in_block_messages = pubsub_adapter.broadcasts(stream).drop(original_sent_messages_count)
91
-
92
- check(in_block_messages)
93
- end
94
-
95
- def from_channel(channel)
96
- @channel = channel
97
- self
98
- end
99
-
100
- private
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
-
111
- def check(messages)
112
- @matching_msgs, @unmatching_msgs = messages.partition do |msg|
113
- decoded = ActiveSupport::JSON.decode(msg)
114
- decoded = decoded.with_indifferent_access if decoded.is_a?(Hash)
115
-
116
- if @data.nil? || @data === decoded
117
- @block.call(decoded)
118
- true
119
- else
120
- false
121
- end
122
- end
123
-
124
- @matching_msgs_count = @matching_msgs.size
125
-
126
- case @expectation_type
127
- when :exactly then @expected_number == @matching_msgs_count
128
- when :at_most then @expected_number >= @matching_msgs_count
129
- when :at_least then @expected_number <= @matching_msgs_count
130
- end
131
- end
132
-
133
- def set_expected_number(relativity, count)
134
- @expectation_type = relativity
135
- @expected_number =
136
- case count
137
- when :once then 1
138
- when :twice then 2
139
- when :thrice then 3
140
- else Integer(count)
141
- end
142
- end
143
-
144
- def base_message
145
- "#{message_expectation_modifier} #{@expected_number} messages to #{stream}".tap do |msg|
146
- msg << " with #{data_description(@data)}" unless @data.nil?
147
- msg << ", but broadcast #{@matching_msgs_count}"
148
- end
149
- end
150
-
151
- def data_description(data)
152
- if data.is_a?(RSpec::Matchers::Composable)
153
- data.description
154
- else
155
- data
156
- end
157
- end
158
-
159
- def pubsub_adapter
160
- ::ActionCable.server.pubsub
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
169
- end
170
- # rubocop: enable Metrics/ClassLength
171
12
  end
172
13
 
173
14
  # @api public
@@ -0,0 +1,170 @@
1
+ # rubocop: disable Style/FrozenStringLiteralComment
2
+
3
+ module RSpec
4
+ module Rails
5
+ module Matchers
6
+ module ActionCable
7
+ # rubocop: disable Metrics/ClassLength
8
+ # @private
9
+ class HaveBroadcastedTo < RSpec::Matchers::BuiltIn::BaseMatcher
10
+ def initialize(target, channel:)
11
+ @target = target
12
+ @channel = channel
13
+ @block = Proc.new {}
14
+ set_expected_number(:exactly, 1)
15
+ end
16
+
17
+ def with(data = nil)
18
+ @data = data
19
+ @data = @data.with_indifferent_access if @data.is_a?(Hash)
20
+ @block = Proc.new if block_given?
21
+ self
22
+ end
23
+
24
+ def exactly(count)
25
+ set_expected_number(:exactly, count)
26
+ self
27
+ end
28
+
29
+ def at_least(count)
30
+ set_expected_number(:at_least, count)
31
+ self
32
+ end
33
+
34
+ def at_most(count)
35
+ set_expected_number(:at_most, count)
36
+ self
37
+ end
38
+
39
+ def times
40
+ self
41
+ end
42
+
43
+ def once
44
+ exactly(:once)
45
+ end
46
+
47
+ def twice
48
+ exactly(:twice)
49
+ end
50
+
51
+ def thrice
52
+ exactly(:thrice)
53
+ end
54
+
55
+ def failure_message
56
+ "expected to broadcast #{base_message}".tap do |msg|
57
+ if @unmatching_msgs.any?
58
+ msg << "\nBroadcasted messages to #{stream}:"
59
+ @unmatching_msgs.each do |data|
60
+ msg << "\n #{data}"
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def failure_message_when_negated
67
+ "expected not to broadcast #{base_message}"
68
+ end
69
+
70
+ def message_expectation_modifier
71
+ case @expectation_type
72
+ when :exactly then "exactly"
73
+ when :at_most then "at most"
74
+ when :at_least then "at least"
75
+ end
76
+ end
77
+
78
+ def supports_block_expectations?
79
+ true
80
+ end
81
+
82
+ def matches?(proc)
83
+ raise ArgumentError, "have_broadcasted_to and broadcast_to only support block expectations" unless Proc === proc
84
+
85
+ original_sent_messages_count = pubsub_adapter.broadcasts(stream).size
86
+ proc.call
87
+ in_block_messages = pubsub_adapter.broadcasts(stream).drop(original_sent_messages_count)
88
+
89
+ check(in_block_messages)
90
+ end
91
+
92
+ def from_channel(channel)
93
+ @channel = channel
94
+ self
95
+ end
96
+
97
+ private
98
+
99
+ def stream
100
+ @stream ||= if @target.is_a?(String)
101
+ @target
102
+ else
103
+ check_channel_presence
104
+ @channel.broadcasting_for([@channel.channel_name, @target])
105
+ end
106
+ end
107
+
108
+ def check(messages)
109
+ @matching_msgs, @unmatching_msgs = messages.partition do |msg|
110
+ decoded = ActiveSupport::JSON.decode(msg)
111
+ decoded = decoded.with_indifferent_access if decoded.is_a?(Hash)
112
+
113
+ if @data.nil? || @data === decoded
114
+ @block.call(decoded)
115
+ true
116
+ else
117
+ false
118
+ end
119
+ end
120
+
121
+ @matching_msgs_count = @matching_msgs.size
122
+
123
+ case @expectation_type
124
+ when :exactly then @expected_number == @matching_msgs_count
125
+ when :at_most then @expected_number >= @matching_msgs_count
126
+ when :at_least then @expected_number <= @matching_msgs_count
127
+ end
128
+ end
129
+
130
+ def set_expected_number(relativity, count)
131
+ @expectation_type = relativity
132
+ @expected_number =
133
+ case count
134
+ when :once then 1
135
+ when :twice then 2
136
+ when :thrice then 3
137
+ else Integer(count)
138
+ end
139
+ end
140
+
141
+ def base_message
142
+ "#{message_expectation_modifier} #{@expected_number} messages to #{stream}".tap do |msg|
143
+ msg << " with #{data_description(@data)}" unless @data.nil?
144
+ msg << ", but broadcast #{@matching_msgs_count}"
145
+ end
146
+ end
147
+
148
+ def data_description(data)
149
+ if data.is_a?(RSpec::Matchers::Composable)
150
+ data.description
151
+ else
152
+ data
153
+ end
154
+ end
155
+
156
+ def pubsub_adapter
157
+ ::ActionCable.server.pubsub
158
+ end
159
+
160
+ def check_channel_presence
161
+ return if @channel.present? && @channel.respond_to?(:channel_name)
162
+
163
+ error_msg = "Broadcastnig channel can't be infered. Please, specify it with `from_channel`"
164
+ raise ArgumentError, error_msg
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,60 @@
1
+ # rubocop: disable Style/FrozenStringLiteralComment
2
+
3
+ module RSpec
4
+ module Rails
5
+ module Matchers
6
+ module ActionCable
7
+ # @api private
8
+ # Provides the implementation for `have_stream`, `have_stream_for`, and `have_stream_from`.
9
+ # Not intended to be instantiated directly.
10
+ class HaveStream < RSpec::Matchers::BuiltIn::BaseMatcher
11
+ # @api private
12
+ # @return [String]
13
+ def failure_message
14
+ "expected to have #{base_message}"
15
+ end
16
+
17
+ # @api private
18
+ # @return [String]
19
+ def failure_message_when_negated
20
+ "expected not to have #{base_message}"
21
+ end
22
+
23
+ # @api private
24
+ # @return [Boolean]
25
+ def matches?(subscription)
26
+ raise(ArgumentError, "have_streams is used for negated expectations only") if no_expected?
27
+
28
+ match(subscription)
29
+ end
30
+
31
+ # @api private
32
+ # @return [Boolean]
33
+ def does_not_match?(subscription)
34
+ !match(subscription)
35
+ end
36
+
37
+ private
38
+
39
+ def match(subscription)
40
+ case subscription
41
+ when ::ActionCable::Channel::Base
42
+ @actual = subscription.streams
43
+ no_expected? ? actual.any? : actual.any? { |i| expected === i }
44
+ else
45
+ raise ArgumentError, "have_stream, have_stream_from and have_stream_from support expectations on subscription only"
46
+ end
47
+ end
48
+
49
+ def base_message
50
+ no_expected? ? "any stream started" : "stream #{expected_formatted} started, but have #{actual_formatted}"
51
+ end
52
+
53
+ def no_expected?
54
+ !defined?(@expected)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ 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.3.4
4
+ version: 0.4.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: 2018-12-06 00:00:00.000000000 Z
11
+ date: 2019-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actioncable
@@ -28,14 +28,14 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.10'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.10'
41
41
  - !ruby/object:Gem::Dependency
@@ -162,6 +162,8 @@ files:
162
162
  - lib/generators/test_unit/channel/templates/unit_test.rb.erb
163
163
  - lib/rspec/rails/example/channel_example_group.rb
164
164
  - lib/rspec/rails/matchers/action_cable.rb
165
+ - lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb
166
+ - lib/rspec/rails/matchers/action_cable/have_streams.rb
165
167
  - lib/rspec/rails/shared_contexts/action_cable.rb
166
168
  homepage: http://github.com/palkan/action-cable-testing
167
169
  licenses:
@@ -183,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
185
  version: '0'
184
186
  requirements: []
185
187
  rubyforge_project:
186
- rubygems_version: 2.7.7
188
+ rubygems_version: 2.7.6
187
189
  signing_key:
188
190
  specification_version: 4
189
191
  summary: Testing utils for Action Cable