stealth 1.0.4 → 1.1.0.rc1
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 +19 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +32 -77
- data/README.md +1 -0
- data/VERSION +1 -1
- data/docs/03-basics.md +18 -2
- data/docs/04-sessions.md +12 -0
- data/docs/05-controllers.md +3 -3
- data/docs/07-replies.md +42 -1
- data/lib/stealth/base.rb +23 -9
- data/lib/stealth/controller/catch_all.rb +1 -1
- data/lib/stealth/controller/controller.rb +21 -9
- data/lib/stealth/controller/dynamic_delay.rb +64 -0
- data/lib/stealth/controller/replies.rb +55 -14
- data/lib/stealth/flow/base.rb +1 -1
- data/lib/stealth/flow/specification.rb +30 -8
- data/lib/stealth/flow/state.rb +10 -5
- data/lib/stealth/generators/builder/Gemfile +3 -0
- data/lib/stealth/generators/builder/Procfile.dev +1 -1
- data/lib/stealth/generators/builder/bot/controllers/catch_alls_controller.rb +3 -6
- data/lib/stealth/generators/builder/config/services.yml +9 -10
- data/lib/stealth/generators/generate/flow/controllers/controller.tt +0 -19
- data/lib/stealth/generators/generate/flow/helpers/helper.tt +2 -1
- data/lib/stealth/generators/generate/flow/replies/{ask_reply.tt → ask_example.tt} +0 -0
- data/lib/stealth/generators/generate.rb +2 -9
- data/lib/stealth/migrations/tasks.rb +2 -0
- data/lib/stealth/scheduled_reply.rb +1 -1
- data/lib/stealth/server.rb +2 -0
- data/lib/stealth/services/jobs/handle_message_job.rb +1 -1
- data/lib/stealth/session.rb +44 -16
- data/spec/controller/catch_all_spec.rb +2 -1
- data/spec/controller/controller_spec.rb +102 -13
- data/spec/controller/dynamic_delay_spec.rb +72 -0
- data/spec/controller/replies_spec.rb +94 -3
- data/spec/flow/state_spec.rb +33 -4
- data/spec/replies/messages/say_hola.yml+facebook.erb +6 -0
- data/spec/replies/messages/say_hola.yml+twilio.erb +6 -0
- data/spec/replies/messages/say_hola.yml.erb +6 -0
- data/spec/replies/messages/say_howdy_with_dynamic.yml +79 -0
- data/spec/replies/messages/say_offer_with_dynamic.yml +6 -0
- data/spec/replies/messages/say_yo.yml +6 -0
- data/spec/replies/messages/say_yo.yml+twitter +6 -0
- data/spec/session_spec.rb +17 -0
- data/spec/support/sample_messages.rb +24 -26
- data/stealth.gemspec +1 -3
- metadata +25 -41
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
- data/lib/stealth/generators/generate/flow/models/model.tt +0 -2
- data/lib/stealth/generators/generate/flow/replies/say_no_reply.tt +0 -2
- data/lib/stealth/generators/generate/flow/replies/say_yes_reply.tt +0 -2
@@ -46,12 +46,101 @@ describe "Stealth::Controller" do
|
|
46
46
|
state :other_action
|
47
47
|
state :other_action2
|
48
48
|
state :other_action3
|
49
|
+
state :deprecated_action, redirects_to: :other_action
|
50
|
+
state :deprecated_action2, redirects_to: 'mr_robot->my_action'
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
54
|
let(:facebook_message) { SampleMessage.new(service: 'facebook') }
|
53
55
|
let(:controller) { MrTronsController.new(service_message: facebook_message.message_with_text) }
|
54
56
|
|
57
|
+
describe "convenience methods" do
|
58
|
+
it "should make the session ID accessible via current_session_id" do
|
59
|
+
controller.current_session.set(flow: 'mr_tron', state: 'other_action')
|
60
|
+
|
61
|
+
expect(controller.current_session_id).to eq(facebook_message.sender_id)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should make the session ID accessible via current_user_id" do
|
65
|
+
controller.current_session.set(flow: 'mr_tron', state: 'other_action')
|
66
|
+
|
67
|
+
expect(controller.current_user_id).to eq(facebook_message.sender_id)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should make the message available in current_message.message" do
|
71
|
+
expect(controller.current_message.message).to eq(facebook_message.message)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should make the payload available in current_message.payload" do
|
75
|
+
message_with_payload = facebook_message.message_with_payload
|
76
|
+
expect(controller.current_message.payload).to eq(message_with_payload.payload)
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "current_service" do
|
80
|
+
let(:twilio_message) { SampleMessage.new(service: 'twilio') }
|
81
|
+
let(:controller_with_twilio_message) { MrTronsController.new(service_message: twilio_message.message_with_text) }
|
82
|
+
|
83
|
+
it "should detect a Facebook message" do
|
84
|
+
expect(controller.current_service).to eq('facebook')
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should detect a Twilio message" do
|
88
|
+
expect(controller_with_twilio_message.current_service).to eq('twilio')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "messages with location" do
|
93
|
+
let(:message_with_location) { facebook_message.message_with_location }
|
94
|
+
let(:controller_with_location) { MrTronsController.new(service_message: message_with_location) }
|
95
|
+
|
96
|
+
it "should make the location available in current_message.location" do
|
97
|
+
expect(controller_with_location.current_message.location).to eq(message_with_location.location)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should return true for current_message.has_location?" do
|
101
|
+
expect(controller_with_location.has_location?).to be true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "messages with attachments" do
|
106
|
+
let(:message_with_attachments) { facebook_message.message_with_attachments }
|
107
|
+
let(:controller_with_attachment) { MrTronsController.new(service_message: message_with_attachments) }
|
108
|
+
|
109
|
+
it "should make the attachments available in current_message.attachments" do
|
110
|
+
expect(controller_with_attachment.current_message.attachments).to eq(message_with_attachments.attachments)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should return true for current_message.has_attachments?" do
|
114
|
+
expect(controller_with_attachment.has_attachments?).to be true
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "states with redirect_to specified" do
|
120
|
+
it "should step_to the specified redirect state when only a state is specified" do
|
121
|
+
controller.current_session.session = Stealth::Session.canonical_session_slug(flow: 'mr_tron', state: 'deprecated_action')
|
122
|
+
expect(MrTronsController).to receive(:new).and_return(controller)
|
123
|
+
expect(controller).to receive(:other_action)
|
124
|
+
controller.action(action: :deprecated_action)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should step_to the specified redirect flow and state when a session is specified" do
|
128
|
+
controller.current_session.session = Stealth::Session.canonical_session_slug(flow: 'mr_tron', state: 'deprecated_action2')
|
129
|
+
mr_robot_controller = MrTronsController.new(service_message: facebook_message.message_with_text)
|
130
|
+
|
131
|
+
expect(MrRobotsController).to receive(:new).and_return(mr_robot_controller)
|
132
|
+
expect(mr_robot_controller).to receive(:my_action)
|
133
|
+
controller.action(action: :deprecated_action2)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should NOT call the redirected controller action method" do
|
137
|
+
controller.current_session.session = Stealth::Session.canonical_session_slug(flow: 'mr_tron', state: 'deprecated_action')
|
138
|
+
expect(MrTronsController).to receive(:new).and_return(controller)
|
139
|
+
expect(controller).to_not receive(:deprecated_action)
|
140
|
+
controller.action(action: :deprecated_action)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
55
144
|
describe "step_to" do
|
56
145
|
it "should raise an ArgumentError if a session, flow, or state is not specified" do
|
57
146
|
expect {
|
@@ -128,7 +217,7 @@ describe "Stealth::Controller" do
|
|
128
217
|
it "should update session to controller's corresponding action when a session is provided" do
|
129
218
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action3)
|
130
219
|
|
131
|
-
session = Stealth::Session.new(user_id: controller.
|
220
|
+
session = Stealth::Session.new(user_id: controller.current_session_id)
|
132
221
|
session.set(flow: 'mr_robot', state: 'my_action3')
|
133
222
|
|
134
223
|
controller.update_session_to session: session
|
@@ -164,7 +253,7 @@ describe "Stealth::Controller" do
|
|
164
253
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
165
254
|
100.seconds,
|
166
255
|
controller.current_service,
|
167
|
-
controller.
|
256
|
+
controller.current_session_id,
|
168
257
|
'mr_robot',
|
169
258
|
'my_action'
|
170
259
|
)
|
@@ -182,7 +271,7 @@ describe "Stealth::Controller" do
|
|
182
271
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
183
272
|
100.seconds,
|
184
273
|
controller.current_service,
|
185
|
-
controller.
|
274
|
+
controller.current_session_id,
|
186
275
|
'mr_tron',
|
187
276
|
'other_action3'
|
188
277
|
)
|
@@ -198,7 +287,7 @@ describe "Stealth::Controller" do
|
|
198
287
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
199
288
|
100.seconds,
|
200
289
|
controller.current_service,
|
201
|
-
controller.
|
290
|
+
controller.current_session_id,
|
202
291
|
'mr_robot',
|
203
292
|
'my_action3'
|
204
293
|
)
|
@@ -211,13 +300,13 @@ describe "Stealth::Controller" do
|
|
211
300
|
it "should update session to controller's corresponding action when a session is provided" do
|
212
301
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
213
302
|
|
214
|
-
session = Stealth::Session.new(user_id: controller.
|
303
|
+
session = Stealth::Session.new(user_id: controller.current_session_id)
|
215
304
|
session.set(flow: 'mr_robot', state: 'my_action3')
|
216
305
|
|
217
306
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
218
307
|
100.seconds,
|
219
308
|
controller.current_service,
|
220
|
-
controller.
|
309
|
+
controller.current_session_id,
|
221
310
|
'mr_robot',
|
222
311
|
'my_action3'
|
223
312
|
)
|
@@ -233,7 +322,7 @@ describe "Stealth::Controller" do
|
|
233
322
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
234
323
|
100.seconds,
|
235
324
|
controller.current_service,
|
236
|
-
controller.
|
325
|
+
controller.current_session_id,
|
237
326
|
'mr_robot',
|
238
327
|
'my_action3'
|
239
328
|
)
|
@@ -265,7 +354,7 @@ describe "Stealth::Controller" do
|
|
265
354
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
266
355
|
future_timestamp,
|
267
356
|
controller.current_service,
|
268
|
-
controller.
|
357
|
+
controller.current_session_id,
|
269
358
|
'mr_robot',
|
270
359
|
'my_action'
|
271
360
|
)
|
@@ -283,7 +372,7 @@ describe "Stealth::Controller" do
|
|
283
372
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
284
373
|
future_timestamp,
|
285
374
|
controller.current_service,
|
286
|
-
controller.
|
375
|
+
controller.current_session_id,
|
287
376
|
'mr_tron',
|
288
377
|
'other_action3'
|
289
378
|
)
|
@@ -299,7 +388,7 @@ describe "Stealth::Controller" do
|
|
299
388
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
300
389
|
future_timestamp,
|
301
390
|
controller.current_service,
|
302
|
-
controller.
|
391
|
+
controller.current_session_id,
|
303
392
|
'mr_robot',
|
304
393
|
'my_action3'
|
305
394
|
)
|
@@ -312,13 +401,13 @@ describe "Stealth::Controller" do
|
|
312
401
|
it "should update session to controller's corresponding action when a session is provided" do
|
313
402
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
314
403
|
|
315
|
-
session = Stealth::Session.new(user_id: controller.
|
404
|
+
session = Stealth::Session.new(user_id: controller.current_session_id)
|
316
405
|
session.set(flow: 'mr_robot', state: 'my_action3')
|
317
406
|
|
318
407
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
319
408
|
future_timestamp,
|
320
409
|
controller.current_service,
|
321
|
-
controller.
|
410
|
+
controller.current_session_id,
|
322
411
|
'mr_robot',
|
323
412
|
'my_action3'
|
324
413
|
)
|
@@ -334,7 +423,7 @@ describe "Stealth::Controller" do
|
|
334
423
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
335
424
|
future_timestamp,
|
336
425
|
controller.current_service,
|
337
|
-
controller.
|
426
|
+
controller.current_session_id,
|
338
427
|
'mr_robot',
|
339
428
|
'my_action3'
|
340
429
|
)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '/spec_helper'))
|
5
|
+
|
6
|
+
describe "Stealth::Controller::DynamicDelay" do
|
7
|
+
|
8
|
+
let(:facebook_message) { SampleMessage.new(service: 'facebook') }
|
9
|
+
let(:controller) { VadersController.new(service_message: facebook_message.message_with_text) }
|
10
|
+
let(:service_replies) { YAML.load(File.read(File.expand_path("../replies/messages/say_howdy_with_dynamic.yml", __dir__))) }
|
11
|
+
|
12
|
+
it "should return a SHORT_DELAY for a dynamic delay at position 0" do
|
13
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 0)
|
14
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::SHORT_DELAY)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return a SHORT_DELAY for a dynamic delay at position -1" do
|
18
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: -1)
|
19
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::SHORT_DELAY)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return a SHORT_DELAY for text 35 chars long" do
|
23
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 2)
|
24
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::SHORT_DELAY)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return a STANDARD_DELAY for text 120 chars long" do
|
28
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 4)
|
29
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return a (STANDARD_DELAY * 1.5) for text 230 chars long" do
|
33
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 6)
|
34
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY * 1.5)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return a LONG_DELAY for text 350 chars long" do
|
38
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 8)
|
39
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::LONG_DELAY)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should return a STANDARD_DELAY for an image" do
|
43
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 10)
|
44
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return a STANDARD_DELAY for a video" do
|
48
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 12)
|
49
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return a STANDARD_DELAY for an audio" do
|
53
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 14)
|
54
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return a STANDARD_DELAY for a file" do
|
58
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 16)
|
59
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return a STANDARD_DELAY for cards" do
|
63
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 18)
|
64
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return a STANDARD_DELAY for a list" do
|
68
|
+
delay = controller.dynamic_delay(service_replies: service_replies, position: 20)
|
69
|
+
expect(delay).to eq(Stealth::Controller::DynamicDelay::STANDARD_DELAY)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -35,6 +35,10 @@ describe "Stealth::Controller replies" do
|
|
35
35
|
send_replies
|
36
36
|
end
|
37
37
|
|
38
|
+
def say_offer_with_dynamic
|
39
|
+
send_replies
|
40
|
+
end
|
41
|
+
|
38
42
|
def say_uh_oh
|
39
43
|
send_replies
|
40
44
|
end
|
@@ -139,7 +143,7 @@ describe "Stealth::Controller replies" do
|
|
139
143
|
|
140
144
|
it "should translate each reply_type in the reply" do
|
141
145
|
allow(stubbed_client).to receive(:transmit).and_return(true)
|
142
|
-
allow(controller).to receive(:sleep).and_return(true)
|
146
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
143
147
|
|
144
148
|
expect(stubbed_handler).to receive(:text).exactly(2).times
|
145
149
|
expect(stubbed_handler).to receive(:delay).exactly(1).times
|
@@ -149,7 +153,7 @@ describe "Stealth::Controller replies" do
|
|
149
153
|
it "should transmit each reply_type in the reply" do
|
150
154
|
allow(stubbed_handler).to receive(:text).exactly(2).times
|
151
155
|
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
152
|
-
allow(controller).to receive(:sleep).and_return(true)
|
156
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
153
157
|
|
154
158
|
expect(stubbed_client).to receive(:transmit).exactly(3).times
|
155
159
|
controller.say_offer
|
@@ -160,9 +164,96 @@ describe "Stealth::Controller replies" do
|
|
160
164
|
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
161
165
|
allow(stubbed_client).to receive(:transmit).exactly(3).times
|
162
166
|
|
163
|
-
expect(controller).to receive(:sleep).exactly(1).times
|
167
|
+
expect(controller).to receive(:sleep).exactly(1).times.with(2.0)
|
164
168
|
controller.say_offer
|
165
169
|
end
|
166
170
|
end
|
167
171
|
|
172
|
+
describe "dynamic delays" do
|
173
|
+
let(:stubbed_handler) { double("handler") }
|
174
|
+
let(:stubbed_client) { double("client") }
|
175
|
+
|
176
|
+
before(:each) do
|
177
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new).and_return(stubbed_handler)
|
178
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
179
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
180
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_offer_with_dynamic")
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should use the default multiplier if none is set" do
|
184
|
+
allow(stubbed_handler).to receive(:text).exactly(2).times
|
185
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
186
|
+
allow(stubbed_client).to receive(:transmit).exactly(3).times
|
187
|
+
|
188
|
+
delay = Stealth.config.dynamic_delay_muliplier * Stealth::Controller::DynamicDelay::SHORT_DELAY
|
189
|
+
expect(controller).to receive(:sleep).exactly(1).times.with(delay)
|
190
|
+
controller.say_offer_with_dynamic
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should slow down SHORT_DELAY if dynamic_delay_muliplier > 1" do
|
194
|
+
allow(stubbed_handler).to receive(:text).exactly(2).times
|
195
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
196
|
+
allow(stubbed_client).to receive(:transmit).exactly(3).times
|
197
|
+
|
198
|
+
Stealth.config.dynamic_delay_muliplier = 5
|
199
|
+
delay = Stealth.config.dynamic_delay_muliplier * Stealth::Controller::DynamicDelay::SHORT_DELAY
|
200
|
+
expect(controller).to receive(:sleep).exactly(1).times.with(delay)
|
201
|
+
controller.say_offer_with_dynamic
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should speed up SHORT_DELAY if dynamic_delay_muliplier < 1" do
|
205
|
+
allow(stubbed_handler).to receive(:text).exactly(2).times
|
206
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
207
|
+
allow(stubbed_client).to receive(:transmit).exactly(3).times
|
208
|
+
|
209
|
+
Stealth.config.dynamic_delay_muliplier = 0.1
|
210
|
+
delay = Stealth.config.dynamic_delay_muliplier * Stealth::Controller::DynamicDelay::SHORT_DELAY
|
211
|
+
expect(controller).to receive(:sleep).exactly(1).times.with(delay)
|
212
|
+
controller.say_offer_with_dynamic
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "variants" do
|
217
|
+
let(:twilio_message) { SampleMessage.new(service: 'twilio') }
|
218
|
+
let(:twilio_controller) { MessagesController.new(service_message: twilio_message.message_with_text) }
|
219
|
+
|
220
|
+
let(:epsilon_message) { SampleMessage.new(service: 'epsilon') }
|
221
|
+
let(:epsilon_controller) { MessagesController.new(service_message: epsilon_message.message_with_text) }
|
222
|
+
|
223
|
+
let(:gamma_message) { SampleMessage.new(service: 'twitter') }
|
224
|
+
let(:gamma_controller) { MessagesController.new(service_message: gamma_message.message_with_text) }
|
225
|
+
|
226
|
+
it "should load the Facebook reply variant if current_service == facebook" do
|
227
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
228
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_hola")
|
229
|
+
file_contents, selected_preprocessor = controller.send(:action_replies)
|
230
|
+
|
231
|
+
expect(file_contents).to eq(File.read(File.expand_path("../replies/messages/say_hola.yml+facebook.erb", __dir__)))
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should load the Twilio reply variant if current_service == twilio" do
|
235
|
+
allow(twilio_controller.current_session).to receive(:flow_string).and_return("message")
|
236
|
+
allow(twilio_controller.current_session).to receive(:state_string).and_return("say_hola")
|
237
|
+
file_contents, selected_preprocessor = twilio_controller.send(:action_replies)
|
238
|
+
|
239
|
+
expect(file_contents).to eq(File.read(File.expand_path("../replies/messages/say_hola.yml+twilio.erb", __dir__)))
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should load the base reply variant if current_service does not have a custom variant" do
|
243
|
+
allow(epsilon_controller.current_session).to receive(:flow_string).and_return("message")
|
244
|
+
allow(epsilon_controller.current_session).to receive(:state_string).and_return("say_hola")
|
245
|
+
file_contents, selected_preprocessor = epsilon_controller.send(:action_replies)
|
246
|
+
|
247
|
+
expect(file_contents).to eq(File.read(File.expand_path("../replies/messages/say_hola.yml.erb", __dir__)))
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should load the correct variant when there is no preprocessor" do
|
251
|
+
allow(gamma_controller.current_session).to receive(:flow_string).and_return("message")
|
252
|
+
allow(gamma_controller.current_session).to receive(:state_string).and_return("say_yo")
|
253
|
+
file_contents, selected_preprocessor = gamma_controller.send(:action_replies)
|
254
|
+
|
255
|
+
expect(file_contents).to eq(File.read(File.expand_path("../replies/messages/say_yo.yml+twitter", __dir__)))
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
168
259
|
end
|
data/spec/flow/state_spec.rb
CHANGED
@@ -12,6 +12,9 @@ describe Stealth::Flow::State do
|
|
12
12
|
state :new
|
13
13
|
state :get_due_date
|
14
14
|
state :created, fails_to: :new
|
15
|
+
state :created2, fails_to: 'new_todo->new'
|
16
|
+
state :deprecated, redirects_to: 'new'
|
17
|
+
state :deprecated2, redirects_to: 'other_flow->say_hi'
|
15
18
|
state :error
|
16
19
|
end
|
17
20
|
end
|
@@ -35,8 +38,34 @@ describe Stealth::Flow::State do
|
|
35
38
|
|
36
39
|
it "should return the fail_state if a fails_to was specified" do
|
37
40
|
flow_map.init(flow: :new_todo, state: :created)
|
38
|
-
expect(flow_map.current_state.fails_to).to be_a(Stealth::
|
39
|
-
expect(flow_map.current_state.fails_to).to eq
|
41
|
+
expect(flow_map.current_state.fails_to).to be_a(Stealth::Session)
|
42
|
+
expect(flow_map.current_state.fails_to.state_string).to eq 'new'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return the fail_state if a fails_to was specified as a session" do
|
46
|
+
flow_map.init(flow: :new_todo, state: :created2)
|
47
|
+
expect(flow_map.current_state.fails_to).to be_a(Stealth::Session)
|
48
|
+
expect(flow_map.current_state.fails_to.state_string).to eq 'new'
|
49
|
+
expect(flow_map.current_state.fails_to.flow_string).to eq 'new_todo'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "redirects_to" do
|
54
|
+
it "should be nil for a state that has not specified a fails_to" do
|
55
|
+
expect(flow_map.current_state.redirects_to).to be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should return the redirects_to state if a redirects_to was specified" do
|
59
|
+
flow_map.init(flow: :new_todo, state: :deprecated)
|
60
|
+
expect(flow_map.current_state.redirects_to).to be_a(Stealth::Session)
|
61
|
+
expect(flow_map.current_state.redirects_to.state_string).to eq 'new'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return the redirects_to state if a redirects_to was specified as a session" do
|
65
|
+
flow_map.init(flow: :new_todo, state: :deprecated2)
|
66
|
+
expect(flow_map.current_state.redirects_to).to be_a(Stealth::Session)
|
67
|
+
expect(flow_map.current_state.redirects_to.state_string).to eq 'say_hi'
|
68
|
+
expect(flow_map.current_state.redirects_to.flow_string).to eq 'other_flow'
|
40
69
|
end
|
41
70
|
end
|
42
71
|
|
@@ -49,7 +78,7 @@ describe Stealth::Flow::State do
|
|
49
78
|
|
50
79
|
it "should decrement the state" do
|
51
80
|
flow_map.init(flow: :new_todo, state: :error)
|
52
|
-
new_state = flow_map.current_state -
|
81
|
+
new_state = flow_map.current_state - 5.states
|
53
82
|
expect(new_state).to eq(:get_due_date)
|
54
83
|
end
|
55
84
|
|
@@ -61,7 +90,7 @@ describe Stealth::Flow::State do
|
|
61
90
|
|
62
91
|
it "should return the last state if the increment is out of bounds" do
|
63
92
|
flow_map.init(flow: :new_todo, state: :created)
|
64
|
-
new_state = flow_map.current_state +
|
93
|
+
new_state = flow_map.current_state + 10.states
|
65
94
|
expect(new_state).to eq(:error)
|
66
95
|
end
|
67
96
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
- reply_type: delay # position 0
|
2
|
+
duration: dynamic
|
3
|
+
- reply_type: text
|
4
|
+
text: "Lorem ipsum dolor sit amet posuere."
|
5
|
+
- reply_type: delay # position 2
|
6
|
+
duration: dynamic
|
7
|
+
- reply_type: text
|
8
|
+
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin in lobortis ante. Duis elementum lacus sit amet volutpat."
|
9
|
+
- reply_type: delay # position 4
|
10
|
+
duration: dynamic
|
11
|
+
- reply_type: text
|
12
|
+
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer quis fermentum arcu, eget maximus metus. Vivamus ante tortor, scelerisque vel laoreet sit amet, sodales in augue. Nam vel quam a tellus mattis vestibulum non a amet."
|
13
|
+
buttons:
|
14
|
+
- text: "Cool"
|
15
|
+
payload: cool
|
16
|
+
- text: "Show me more"
|
17
|
+
payload: more
|
18
|
+
- reply_type: delay # position 6
|
19
|
+
duration: dynamic
|
20
|
+
- reply_type: text
|
21
|
+
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec quis consequat dolor. Suspendisse sed egestas lacus. Nam a viverra risus. Aliquam erat volutpat. Nunc molestie, metus ut cursus varius, purus quam pharetra nisi, sit amet porttitor tellus nisl sit amet est. Nam volutpat id lorem a condimentum. Sed quam mauris, faucibus sed pharetra sed."
|
22
|
+
- reply_type: delay # position 8
|
23
|
+
duration: dynamic
|
24
|
+
- reply_type: image
|
25
|
+
text: "https://via.placeholder.com/350x150"
|
26
|
+
- reply_type: delay # position 10
|
27
|
+
duration: dynamic
|
28
|
+
- reply_type: video
|
29
|
+
text: "https://via.placeholder.com/350x150"
|
30
|
+
- reply_type: delay # position 12
|
31
|
+
duration: dynamic
|
32
|
+
- reply_type: audio
|
33
|
+
text: "https://via.placeholder.com/350x150"
|
34
|
+
- reply_type: delay # position 14
|
35
|
+
duration: dynamic
|
36
|
+
- reply_type: file
|
37
|
+
text: "https://via.placeholder.com/350x150"
|
38
|
+
- reply_type: delay # position 16
|
39
|
+
duration: dynamic
|
40
|
+
- reply_type: cards
|
41
|
+
sharable: true
|
42
|
+
aspect_ratio: horizontal
|
43
|
+
elements:
|
44
|
+
- title: My App
|
45
|
+
subtitle: Download our app below or visit our website for more info.
|
46
|
+
image_url: "https://my-app.com/app-image.png"
|
47
|
+
buttons:
|
48
|
+
- type: url
|
49
|
+
url: "https://my-app.com"
|
50
|
+
text: 'View'
|
51
|
+
webview_height: 'tall'
|
52
|
+
- type: url
|
53
|
+
url: "https://itunes.apple.com/us/app/my-app"
|
54
|
+
text: 'Download iOS App'
|
55
|
+
- reply_type: delay # position 18
|
56
|
+
duration: dynamic
|
57
|
+
- reply_type: list
|
58
|
+
top_element_style: large
|
59
|
+
buttons:
|
60
|
+
- type: payload
|
61
|
+
text: View More
|
62
|
+
payload: view_more
|
63
|
+
elements:
|
64
|
+
- title: Your Daily News Update
|
65
|
+
subtitle: The following stories have been curated just for you.
|
66
|
+
image_url: "https://loremflickr.com/320/240"
|
67
|
+
buttons:
|
68
|
+
- type: url
|
69
|
+
url: "https://news-articles.com/199"
|
70
|
+
text: 'View'
|
71
|
+
webview_height: 'tall'
|
72
|
+
- title: Breakthrough in AI
|
73
|
+
subtitle: Major breakthrough in the AI space.
|
74
|
+
image_url: "https://loremflickr.com/320/320"
|
75
|
+
default_action:
|
76
|
+
- url: "https://news-articles.com/232"
|
77
|
+
webview_height: 'tall'
|
78
|
+
- reply_type: delay # position 20
|
79
|
+
duration: dynamic
|
data/spec/session_spec.rb
CHANGED
@@ -107,4 +107,21 @@ describe "Stealth::Session" do
|
|
107
107
|
expect(new_session.state_string).to eq('error')
|
108
108
|
end
|
109
109
|
end
|
110
|
+
|
111
|
+
describe "self.is_a_session_string?" do
|
112
|
+
it "should return false for state strings" do
|
113
|
+
session_string = 'say_hello'
|
114
|
+
expect(Stealth::Session.is_a_session_string?(session_string)).to be false
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should return false for an incomplete session string" do
|
118
|
+
session_string = 'hello->'
|
119
|
+
expect(Stealth::Session.is_a_session_string?(session_string)).to be false
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should return true for a complete session string" do
|
123
|
+
session_string = 'hello->say_hello'
|
124
|
+
expect(Stealth::Session.is_a_session_string?(session_string)).to be true
|
125
|
+
end
|
126
|
+
end
|
110
127
|
end
|