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.
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