stealth 1.0.4 → 1.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -4
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +32 -77
  5. data/README.md +1 -0
  6. data/VERSION +1 -1
  7. data/docs/03-basics.md +18 -2
  8. data/docs/04-sessions.md +12 -0
  9. data/docs/05-controllers.md +3 -3
  10. data/docs/07-replies.md +42 -1
  11. data/lib/stealth/base.rb +23 -9
  12. data/lib/stealth/controller/catch_all.rb +1 -1
  13. data/lib/stealth/controller/controller.rb +21 -9
  14. data/lib/stealth/controller/dynamic_delay.rb +64 -0
  15. data/lib/stealth/controller/replies.rb +55 -14
  16. data/lib/stealth/flow/base.rb +1 -1
  17. data/lib/stealth/flow/specification.rb +30 -8
  18. data/lib/stealth/flow/state.rb +10 -5
  19. data/lib/stealth/generators/builder/Gemfile +3 -0
  20. data/lib/stealth/generators/builder/Procfile.dev +1 -1
  21. data/lib/stealth/generators/builder/bot/controllers/catch_alls_controller.rb +3 -6
  22. data/lib/stealth/generators/builder/config/services.yml +9 -10
  23. data/lib/stealth/generators/generate/flow/controllers/controller.tt +0 -19
  24. data/lib/stealth/generators/generate/flow/helpers/helper.tt +2 -1
  25. data/lib/stealth/generators/generate/flow/replies/{ask_reply.tt → ask_example.tt} +0 -0
  26. data/lib/stealth/generators/generate.rb +2 -9
  27. data/lib/stealth/migrations/tasks.rb +2 -0
  28. data/lib/stealth/scheduled_reply.rb +1 -1
  29. data/lib/stealth/server.rb +2 -0
  30. data/lib/stealth/services/jobs/handle_message_job.rb +1 -1
  31. data/lib/stealth/session.rb +44 -16
  32. data/spec/controller/catch_all_spec.rb +2 -1
  33. data/spec/controller/controller_spec.rb +102 -13
  34. data/spec/controller/dynamic_delay_spec.rb +72 -0
  35. data/spec/controller/replies_spec.rb +94 -3
  36. data/spec/flow/state_spec.rb +33 -4
  37. data/spec/replies/messages/say_hola.yml+facebook.erb +6 -0
  38. data/spec/replies/messages/say_hola.yml+twilio.erb +6 -0
  39. data/spec/replies/messages/say_hola.yml.erb +6 -0
  40. data/spec/replies/messages/say_howdy_with_dynamic.yml +79 -0
  41. data/spec/replies/messages/say_offer_with_dynamic.yml +6 -0
  42. data/spec/replies/messages/say_yo.yml +6 -0
  43. data/spec/replies/messages/say_yo.yml+twitter +6 -0
  44. data/spec/session_spec.rb +17 -0
  45. data/spec/support/sample_messages.rb +24 -26
  46. data/stealth.gemspec +1 -3
  47. metadata +25 -41
  48. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
  49. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
  50. data/lib/stealth/generators/generate/flow/models/model.tt +0 -2
  51. data/lib/stealth/generators/generate/flow/replies/say_no_reply.tt +0 -2
  52. 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.current_user_id)
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.current_user_id,
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.current_user_id,
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.current_user_id,
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.current_user_id)
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.current_user_id,
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.current_user_id,
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.current_user_id,
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.current_user_id,
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.current_user_id,
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.current_user_id)
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.current_user_id,
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.current_user_id,
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
@@ -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::Flow::State)
39
- expect(flow_map.current_state.fails_to).to eq :new
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 - 2.states
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 + 5.states
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,6 @@
1
+ - reply_type: text
2
+ text: "Hi, Facebook. Welcome to Stealth bot..."
3
+ - reply_type: delay
4
+ duration: 2
5
+ - reply_type: text
6
+ text: "We offer users an awesome Ruby framework for building chat bots."
@@ -0,0 +1,6 @@
1
+ - reply_type: text
2
+ text: "Hi, Twilio. Welcome to Stealth bot..."
3
+ - reply_type: delay
4
+ duration: 2
5
+ - reply_type: text
6
+ text: "We offer users an awesome Ruby framework for building chat bots."
@@ -0,0 +1,6 @@
1
+ - reply_type: text
2
+ text: "Hi, Morty. Welcome to Stealth bot..."
3
+ - reply_type: delay
4
+ duration: 2
5
+ - reply_type: text
6
+ text: "We offer users an awesome Ruby framework for building chat bots."
@@ -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
@@ -0,0 +1,6 @@
1
+ - reply_type: text
2
+ text: "Hi, Morty. Welcome to Stealth bot..."
3
+ - reply_type: delay
4
+ duration: dynamic
5
+ - reply_type: text
6
+ text: "We offer users an awesome Ruby framework for building chat bots."
@@ -0,0 +1,6 @@
1
+ - reply_type: text
2
+ text: "Yo, Morty! Welcome to Stealth bot..."
3
+ - reply_type: delay
4
+ duration: 2
5
+ - reply_type: text
6
+ text: "We offer users an awesome Ruby framework for building chat bots."
@@ -0,0 +1,6 @@
1
+ - reply_type: text
2
+ text: "Yo, Morty from Twitter! Welcome to Stealth bot..."
3
+ - reply_type: delay
4
+ duration: 2
5
+ - reply_type: text
6
+ text: "We offer users an awesome Ruby framework for building chat bots."
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