ably 0.1.5 → 0.1.6
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 +11 -1
- data/ably.gemspec +4 -3
- data/lib/ably.rb +6 -2
- data/lib/ably/auth.rb +24 -16
- data/lib/ably/exceptions.rb +16 -5
- data/lib/ably/{realtime/models → models}/error_info.rb +9 -11
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +57 -26
- data/lib/ably/{realtime/models → models}/message.rb +45 -38
- data/lib/ably/{realtime/models → models}/nil_channel.rb +4 -4
- data/lib/ably/{rest/models/paged_resource.rb → models/paginated_resource.rb} +21 -10
- data/lib/ably/models/presence_message.rb +126 -0
- data/lib/ably/{realtime/models → models}/protocol_message.rb +76 -38
- data/lib/ably/models/token.rb +74 -0
- data/lib/ably/modules/channels_collection.rb +49 -0
- data/lib/ably/modules/conversions.rb +2 -0
- data/lib/ably/modules/event_emitter.rb +43 -8
- data/lib/ably/modules/event_machine_helpers.rb +1 -0
- data/lib/ably/modules/http_helpers.rb +9 -2
- data/lib/ably/modules/message_pack.rb +14 -0
- data/lib/ably/modules/model_common.rb +29 -0
- data/lib/ably/modules/{state.rb → state_emitter.rb} +8 -7
- data/lib/ably/realtime.rb +37 -7
- data/lib/ably/realtime/channel.rb +154 -31
- data/lib/ably/realtime/channels.rb +47 -0
- data/lib/ably/realtime/client.rb +39 -33
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +50 -21
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +9 -11
- data/lib/ably/realtime/connection.rb +148 -79
- data/lib/ably/realtime/connection/connection_state_machine.rb +111 -0
- data/lib/ably/realtime/connection/websocket_transport.rb +161 -0
- data/lib/ably/realtime/presence.rb +270 -0
- data/lib/ably/rest.rb +14 -3
- data/lib/ably/rest/channel.rb +3 -3
- data/lib/ably/rest/channels.rb +26 -12
- data/lib/ably/rest/client.rb +42 -25
- data/lib/ably/rest/middleware/exceptions.rb +21 -23
- data/lib/ably/rest/middleware/external_exceptions.rb +8 -10
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
- data/lib/ably/rest/middleware/parse_json.rb +9 -2
- data/lib/ably/rest/middleware/parse_message_pack.rb +6 -2
- data/lib/ably/rest/presence.rb +4 -4
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +125 -0
- data/spec/acceptance/realtime/channel_spec.rb +135 -63
- data/spec/acceptance/realtime/connection_spec.rb +86 -0
- data/spec/acceptance/realtime/message_spec.rb +116 -94
- data/spec/acceptance/realtime/presence_history_spec.rb +0 -0
- data/spec/acceptance/realtime/presence_spec.rb +277 -0
- data/spec/acceptance/rest/auth_spec.rb +351 -347
- data/spec/acceptance/rest/base_spec.rb +43 -26
- data/spec/acceptance/rest/channel_spec.rb +88 -83
- data/spec/acceptance/rest/channels_spec.rb +32 -28
- data/spec/acceptance/rest/presence_spec.rb +83 -63
- data/spec/acceptance/rest/stats_spec.rb +38 -37
- data/spec/acceptance/rest/time_spec.rb +10 -6
- data/spec/integration/modules/{state_spec.rb → state_emitter_spec.rb} +16 -2
- data/spec/spec_helper.rb +14 -0
- data/spec/support/api_helper.rb +4 -0
- data/spec/support/model_helper.rb +28 -9
- data/spec/support/protocol_msgbus_helper.rb +8 -1
- data/spec/support/test_app.rb +24 -14
- data/spec/unit/{realtime → models}/error_info_spec.rb +4 -4
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +46 -9
- data/spec/unit/models/message_spec.rb +229 -0
- data/spec/unit/{rest/paged_resource_spec.rb → models/paginated_resource_spec.rb} +19 -11
- data/spec/unit/models/presence_message_spec.rb +230 -0
- data/spec/unit/models/protocol_message_spec.rb +280 -0
- data/spec/unit/{token_spec.rb → models/token_spec.rb} +18 -22
- data/spec/unit/modules/conversions_spec.rb +1 -1
- data/spec/unit/modules/event_emitter_spec.rb +36 -4
- data/spec/unit/realtime/channel_spec.rb +76 -2
- data/spec/unit/realtime/channels_spec.rb +50 -0
- data/spec/unit/realtime/client_spec.rb +31 -1
- data/spec/unit/realtime/connection_spec.rb +8 -15
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +6 -6
- data/spec/unit/realtime/presence_spec.rb +100 -0
- data/spec/unit/rest/channels_spec.rb +48 -0
- metadata +72 -38
- data/lib/ably/realtime/models/shared.rb +0 -17
- data/lib/ably/rest/models/message.rb +0 -64
- data/lib/ably/rest/models/presence_message.rb +0 -21
- data/lib/ably/token.rb +0 -80
- data/spec/unit/realtime/message_spec.rb +0 -117
- data/spec/unit/realtime/protocol_message_spec.rb +0 -172
- data/spec/unit/rest/message_spec.rb +0 -75
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/model_helper'
|
3
|
+
|
4
|
+
describe Ably::Models::ProtocolMessage do
|
5
|
+
include Ably::Modules::Conversions
|
6
|
+
subject { Ably::Models::ProtocolMessage }
|
7
|
+
|
8
|
+
def new_protocol_message(options)
|
9
|
+
subject.new({ action: 1 }.merge(options))
|
10
|
+
end
|
11
|
+
|
12
|
+
it_behaves_like 'a model',
|
13
|
+
with_simple_attributes: %w(id channel channel_serial connection_id),
|
14
|
+
base_model_options: { action: 1 } do
|
15
|
+
|
16
|
+
let(:model_args) { [] }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'initializer action coercion' do
|
20
|
+
it 'ignores actions that are Integers' do
|
21
|
+
protocol_message = subject.new(action: 14)
|
22
|
+
expect(protocol_message.hash[:action]).to eql(14)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'converts actions to Integers if a symbol' do
|
26
|
+
protocol_message = subject.new(action: :message)
|
27
|
+
expect(protocol_message.hash[:action]).to eql(15)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'converts actions to Integers if a ACTION' do
|
31
|
+
protocol_message = subject.new(action: Ably::Models::ProtocolMessage::ACTION.Message)
|
32
|
+
expect(protocol_message.hash[:action]).to eql(15)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'raises an argument error if nil' do
|
36
|
+
expect { subject.new({}) }.to raise_error(ArgumentError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'attributes' do
|
41
|
+
let(:unique_value) { SecureRandom.hex }
|
42
|
+
|
43
|
+
context 'Java naming' do
|
44
|
+
let(:protocol_message) { new_protocol_message(channelSerial: unique_value) }
|
45
|
+
|
46
|
+
it 'converts the attribute to ruby symbol naming convention' do
|
47
|
+
expect(protocol_message.channel_serial).to eql(unique_value)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context '#action' do
|
52
|
+
let(:protocol_message) { new_protocol_message(action: 14) }
|
53
|
+
|
54
|
+
it 'returns an Enum that behaves like a symbol' do
|
55
|
+
expect(protocol_message.action).to eq(:presence)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns an Enum that behaves like a Numeric' do
|
59
|
+
expect(protocol_message.action).to eq(14)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns an Enum that behaves like a String' do
|
63
|
+
expect(protocol_message.action).to eq('Presence')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'returns an Enum that matchdes the ACTION constant' do
|
67
|
+
expect(protocol_message.action).to eql(Ably::Models::ProtocolMessage::ACTION.Presence)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context '#timestamp' do
|
72
|
+
let(:protocol_message) { new_protocol_message(timestamp: as_since_epoch(Time.now)) }
|
73
|
+
it 'retrieves attribute :timestamp' do
|
74
|
+
expect(protocol_message.timestamp).to be_a(Time)
|
75
|
+
expect(protocol_message.timestamp.to_i).to be_within(1).of(Time.now.to_i)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context '#count' do
|
80
|
+
context 'when missing' do
|
81
|
+
let(:protocol_message) { new_protocol_message({}) }
|
82
|
+
it 'is 1' do
|
83
|
+
expect(protocol_message.count).to eql(1)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when non numeric' do
|
88
|
+
let(:protocol_message) { new_protocol_message(count: 'A') }
|
89
|
+
it 'is 1' do
|
90
|
+
expect(protocol_message.count).to eql(1)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when greater than 1' do
|
95
|
+
let(:protocol_message) { new_protocol_message(count: '666') }
|
96
|
+
it 'is the value of count' do
|
97
|
+
expect(protocol_message.count).to eql(666)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context '#message_serial' do
|
103
|
+
let(:protocol_message) { new_protocol_message(msg_serial: "55") }
|
104
|
+
it 'converts :msg_serial to an Integer' do
|
105
|
+
expect(protocol_message.message_serial).to be_a(Integer)
|
106
|
+
expect(protocol_message.message_serial).to eql(55)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context '#has_message_serial?' do
|
111
|
+
context 'without msg_serial' do
|
112
|
+
let(:protocol_message) { new_protocol_message({}) }
|
113
|
+
|
114
|
+
it 'returns false' do
|
115
|
+
expect(protocol_message.has_message_serial?).to eql(false)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'with msg_serial' do
|
120
|
+
let(:protocol_message) { new_protocol_message(msg_serial: "55") }
|
121
|
+
|
122
|
+
it 'returns true' do
|
123
|
+
expect(protocol_message.has_message_serial?).to eql(true)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context '#connection_serial' do
|
129
|
+
let(:protocol_message) { new_protocol_message(connection_serial: "55") }
|
130
|
+
it 'converts :connection_serial to an Integer' do
|
131
|
+
expect(protocol_message.connection_serial).to be_a(Integer)
|
132
|
+
expect(protocol_message.connection_serial).to eql(55)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context '#has_connection_serial?' do
|
137
|
+
context 'without connection_serial' do
|
138
|
+
let(:protocol_message) { new_protocol_message({}) }
|
139
|
+
|
140
|
+
it 'returns false' do
|
141
|
+
expect(protocol_message.has_connection_serial?).to eql(false)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'with connection_serial' do
|
146
|
+
let(:protocol_message) { new_protocol_message(connection_serial: "55") }
|
147
|
+
|
148
|
+
it 'returns true' do
|
149
|
+
expect(protocol_message.has_connection_serial?).to eql(true)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context '#serial' do
|
155
|
+
context 'with underlying msg_serial' do
|
156
|
+
let(:protocol_message) { new_protocol_message(msg_serial: "55") }
|
157
|
+
it 'converts :msg_serial to an Integer' do
|
158
|
+
expect(protocol_message.serial).to be_a(Integer)
|
159
|
+
expect(protocol_message.serial).to eql(55)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'with underlying connection_serial' do
|
164
|
+
let(:protocol_message) { new_protocol_message(connection_serial: "55") }
|
165
|
+
it 'converts :connection_serial to an Integer' do
|
166
|
+
expect(protocol_message.serial).to be_a(Integer)
|
167
|
+
expect(protocol_message.serial).to eql(55)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'with underlying connection_serial and msg_serial' do
|
172
|
+
let(:protocol_message) { new_protocol_message(connection_serial: "99", msg_serial: "11") }
|
173
|
+
it 'prefers connection_serial and converts :connection_serial to an Integer' do
|
174
|
+
expect(protocol_message.serial).to be_a(Integer)
|
175
|
+
expect(protocol_message.serial).to eql(99)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context '#has_serial?' do
|
181
|
+
context 'without msg_serial or connection_serial' do
|
182
|
+
let(:protocol_message) { new_protocol_message({}) }
|
183
|
+
|
184
|
+
it 'returns false' do
|
185
|
+
expect(protocol_message.has_serial?).to eql(false)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'with msg_serial' do
|
190
|
+
let(:protocol_message) { new_protocol_message(msg_serial: "55") }
|
191
|
+
|
192
|
+
it 'returns true' do
|
193
|
+
expect(protocol_message.has_serial?).to eql(true)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'with connection_serial' do
|
198
|
+
let(:protocol_message) { new_protocol_message(connection_serial: "55") }
|
199
|
+
|
200
|
+
it 'returns true' do
|
201
|
+
expect(protocol_message.has_serial?).to eql(true)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context '#error' do
|
207
|
+
context 'with no error attribute' do
|
208
|
+
let(:protocol_message) { new_protocol_message(action: 1) }
|
209
|
+
|
210
|
+
it 'returns nil' do
|
211
|
+
expect(protocol_message.error).to be_nil
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'with nil error' do
|
216
|
+
let(:protocol_message) { new_protocol_message(error: nil) }
|
217
|
+
|
218
|
+
it 'returns nil' do
|
219
|
+
expect(protocol_message.error).to be_nil
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
context 'with error' do
|
224
|
+
let(:protocol_message) { new_protocol_message(error: { message: 'test_error' }) }
|
225
|
+
|
226
|
+
it 'returns a valid ErrorInfo object' do
|
227
|
+
expect(protocol_message.error).to be_a(Ably::Models::ErrorInfo)
|
228
|
+
expect(protocol_message.error.message).to eql('test_error')
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context '#to_json' do
|
235
|
+
let(:json_object) { JSON.parse(model.to_json) }
|
236
|
+
let(:message) { { 'name' => 'event', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
237
|
+
let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached }
|
238
|
+
let(:message_action) { Ably::Models::ProtocolMessage::ACTION.Message }
|
239
|
+
|
240
|
+
context 'with valid data' do
|
241
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message] }) }
|
242
|
+
|
243
|
+
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
244
|
+
expect(json_object["channelSerial"]).to eql('unique')
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'populates the messages' do
|
248
|
+
expect(json_object["messages"].first).to include(message)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
context 'with missing msg_serial for ack message' do
|
253
|
+
let(:model) { new_protocol_message({ :action => message_action }) }
|
254
|
+
|
255
|
+
it 'it raises an exception' do
|
256
|
+
expect { model.to_json }.to raise_error TypeError, /msg_serial.*missing/
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'is aliased by #to_s' do
|
261
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message], :timestamp => as_since_epoch(Time.now) }) }
|
262
|
+
|
263
|
+
specify do
|
264
|
+
expect(json_object).to eql(JSON.parse("#{model}"))
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
context '#to_msgpack' do
|
270
|
+
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [message] }) }
|
271
|
+
let(:message) { { 'name' => 'event', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
272
|
+
let(:packed) { model.to_msgpack }
|
273
|
+
let(:unpacked) { MessagePack.unpack(packed) }
|
274
|
+
|
275
|
+
it 'returns a unpackable msgpack object' do
|
276
|
+
expect(unpacked['connectionSerial']).to eq('unique')
|
277
|
+
expect(unpacked['messages'][0]['name']).to eq('event')
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
@@ -1,38 +1,34 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Ably::Token do
|
3
|
+
describe Ably::Models::Token do
|
4
|
+
subject { Ably::Models::Token }
|
5
|
+
|
6
|
+
it_behaves_like 'a model', with_simple_attributes: %w(id capability client_id nonce) do
|
7
|
+
let(:model_args) { [] }
|
8
|
+
end
|
9
|
+
|
4
10
|
context 'defaults' do
|
5
11
|
let(:one_hour) { 60 * 60 }
|
6
12
|
let(:all_capabilities) { { "*" => ["*"] } }
|
7
13
|
|
8
14
|
it 'should default TTL to 1 hour' do
|
9
|
-
expect(Ably::Token::DEFAULTS[:ttl]).to eql(one_hour)
|
15
|
+
expect(Ably::Models::Token::DEFAULTS[:ttl]).to eql(one_hour)
|
10
16
|
end
|
11
17
|
|
12
18
|
it 'should default capability to all' do
|
13
|
-
expect(Ably::Token::DEFAULTS[:capability]).to eql(all_capabilities)
|
19
|
+
expect(Ably::Models::Token::DEFAULTS[:capability]).to eql(all_capabilities)
|
14
20
|
end
|
15
21
|
|
16
22
|
it 'should only have defaults for :ttl and :capability' do
|
17
|
-
expect(Ably::Token::DEFAULTS.keys).to contain_exactly(:ttl, :capability)
|
23
|
+
expect(Ably::Models::Token::DEFAULTS.keys).to contain_exactly(:ttl, :capability)
|
18
24
|
end
|
19
25
|
end
|
20
26
|
|
21
27
|
context 'attributes' do
|
22
28
|
let(:unique_value) { 'unique_value' }
|
23
29
|
|
24
|
-
%w(id capability client_id nonce).each do |attribute|
|
25
|
-
context "##{attribute}" do
|
26
|
-
subject { Ably::Token.new({ attribute.to_sym => unique_value }) }
|
27
|
-
|
28
|
-
it "retrieves attribute :#{attribute}" do
|
29
|
-
expect(subject.public_send(attribute)).to eql(unique_value)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
30
|
context '#key_id' do
|
35
|
-
subject { Ably::Token.new({ key: unique_value }) }
|
31
|
+
subject { Ably::Models::Token.new({ key: unique_value }) }
|
36
32
|
it 'retrieves attribute :key' do
|
37
33
|
expect(subject.key_id).to eql(unique_value)
|
38
34
|
end
|
@@ -41,7 +37,7 @@ describe Ably::Token do
|
|
41
37
|
{ :issued_at => :issued_at, :expires_at => :expires }.each do |method_name, attribute|
|
42
38
|
let(:time) { Time.now }
|
43
39
|
context "##{method_name}" do
|
44
|
-
subject { Ably::Token.new({ attribute.to_sym => time.to_i }) }
|
40
|
+
subject { Ably::Models::Token.new({ attribute.to_sym => time.to_i }) }
|
45
41
|
|
46
42
|
it "retrieves attribute :#{attribute} as Time" do
|
47
43
|
expect(subject.public_send(method_name)).to be_a(Time)
|
@@ -51,10 +47,10 @@ describe Ably::Token do
|
|
51
47
|
end
|
52
48
|
|
53
49
|
context '#expired?' do
|
54
|
-
let(:expire_time) { Time.now + Ably::Token::TOKEN_EXPIRY_BUFFER }
|
50
|
+
let(:expire_time) { Time.now + Ably::Models::Token::TOKEN_EXPIRY_BUFFER }
|
55
51
|
|
56
52
|
context 'once grace period buffer has passed' do
|
57
|
-
subject { Ably::Token.new(expires: expire_time - 1) }
|
53
|
+
subject { Ably::Models::Token.new(expires: expire_time - 1) }
|
58
54
|
|
59
55
|
it 'is true' do
|
60
56
|
expect(subject.expired?).to eql(true)
|
@@ -62,7 +58,7 @@ describe Ably::Token do
|
|
62
58
|
end
|
63
59
|
|
64
60
|
context 'within grace period buffer' do
|
65
|
-
subject { Ably::Token.new(expires: expire_time + 1) }
|
61
|
+
subject { Ably::Models::Token.new(expires: expire_time + 1) }
|
66
62
|
|
67
63
|
it 'is false' do
|
68
64
|
expect(subject.expired?).to eql(false)
|
@@ -75,16 +71,16 @@ describe Ably::Token do
|
|
75
71
|
let(:token_attributes) { { id: 'unique' } }
|
76
72
|
|
77
73
|
it 'is true when attributes are the same' do
|
78
|
-
new_token = -> { Ably::Token.new(token_attributes) }
|
74
|
+
new_token = -> { Ably::Models::Token.new(token_attributes) }
|
79
75
|
expect(new_token[]).to eq(new_token[])
|
80
76
|
end
|
81
77
|
|
82
78
|
it 'is false when attributes are not the same' do
|
83
|
-
expect(Ably::Token.new(id: 1)).to_not eq(Ably::Token.new(id: 2))
|
79
|
+
expect(Ably::Models::Token.new(id: 1)).to_not eq(Ably::Models::Token.new(id: 2))
|
84
80
|
end
|
85
81
|
|
86
82
|
it 'is false when class type differs' do
|
87
|
-
expect(Ably::Token.new(id: 1)).to_not eq(nil)
|
83
|
+
expect(Ably::Models::Token.new(id: 1)).to_not eq(nil)
|
88
84
|
end
|
89
85
|
end
|
90
86
|
end
|
@@ -49,7 +49,7 @@ describe Ably::Modules::Conversions do
|
|
49
49
|
let(:seconds) { Time.new.to_f }
|
50
50
|
|
51
51
|
it 'converts to Time from milliseconds by default' do
|
52
|
-
expect(subject.as_time_from_epoch(millisecond).to_f).to be_within(0.
|
52
|
+
expect(subject.as_time_from_epoch(millisecond).to_f).to be_within(0.01).of(time.to_f)
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'converts to Time from seconds' do
|
@@ -16,16 +16,18 @@ describe Ably::Modules::EventEmitter do
|
|
16
16
|
|
17
17
|
context 'event fan out' do
|
18
18
|
specify do
|
19
|
-
expect(obj).to receive(:received_message).with(msg).twice
|
20
19
|
2.times do
|
21
20
|
subject.on(:message) { |msg| obj.received_message msg }
|
22
21
|
end
|
22
|
+
|
23
|
+
expect(obj).to receive(:received_message).with(msg).twice
|
23
24
|
subject.trigger :message, msg
|
24
25
|
end
|
25
26
|
|
26
27
|
it 'sends only messages to matching event names' do
|
27
|
-
expect(obj).to receive(:received_message).with(msg).once
|
28
28
|
subject.on(:valid) { |msg| obj.received_message msg }
|
29
|
+
|
30
|
+
expect(obj).to receive(:received_message).with(msg).once
|
29
31
|
subject.trigger :valid, msg
|
30
32
|
subject.trigger :ignored, msg
|
31
33
|
subject.trigger 'valid', msg
|
@@ -37,19 +39,49 @@ describe Ably::Modules::EventEmitter do
|
|
37
39
|
end
|
38
40
|
|
39
41
|
it 'calls the provided proc to coerce the event name' do
|
40
|
-
expect(obj).to receive(:received_message).with(msg).once
|
41
42
|
subject.on('valid') { |msg| obj.received_message msg }
|
43
|
+
|
44
|
+
expect(obj).to receive(:received_message).with(msg).once
|
42
45
|
subject.trigger :valid, msg
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
46
49
|
context 'without coercion' do
|
47
50
|
it 'only matches event names on type matches' do
|
48
|
-
expect(obj).to_not receive(:received_message).with(msg)
|
49
51
|
subject.on('valid') { |msg| obj.received_message msg }
|
52
|
+
|
53
|
+
expect(obj).to_not receive(:received_message).with(msg)
|
50
54
|
subject.trigger :valid, msg
|
51
55
|
end
|
52
56
|
end
|
57
|
+
|
58
|
+
context 'subscribe to multiple events' do
|
59
|
+
it 'with the same block' do
|
60
|
+
subject.on(:click, :hover) { |msg| obj.received_message msg }
|
61
|
+
|
62
|
+
expect(obj).to receive(:received_message).with(msg).twice
|
63
|
+
|
64
|
+
subject.trigger :click, msg
|
65
|
+
subject.trigger :hover, msg
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context '#once' do
|
71
|
+
it 'calls the block the first time an event is emitted only' do
|
72
|
+
block_called = 0
|
73
|
+
subject.once('event') { block_called += 1 }
|
74
|
+
3.times { subject.trigger 'event', 'data' }
|
75
|
+
expect(block_called).to eql(1)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'does not remove other blocks after it is called' do
|
79
|
+
block_called = 0
|
80
|
+
subject.once('event') { block_called += 1 }
|
81
|
+
subject.on('event') { block_called += 1 }
|
82
|
+
3.times { subject.trigger 'event', 'data' }
|
83
|
+
expect(block_called).to eql(4)
|
84
|
+
end
|
53
85
|
end
|
54
86
|
|
55
87
|
context '#off' do
|