Skip to content

Commit 39bcb74

Browse files
authored
attachment_prompt tests (#230)
1 parent 76ba270 commit 39bcb74

File tree

3 files changed

+252
-9
lines changed

3 files changed

+252
-9
lines changed

libraries/botbuilder-core/botbuilder/core/adapters/test_adapter.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ async def receive_activity(self, activity):
112112
context = TurnContext(self, request)
113113
return await self.run_pipeline(context, self.logic)
114114

115+
def get_next_activity(self) -> Activity:
116+
return self.activity_buffer.pop(0)
117+
115118
async def send(self, user_says) -> object:
116119
"""
117120
Sends something to the bot. This returns a new `TestFlow` instance which can be used to add

libraries/botbuilder-dialogs/botbuilder/dialogs/prompts/attachment_prompt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ class AttachmentPrompt(Prompt):
1818
By default the prompt will return to the calling dialog an `[Attachment]`
1919
"""
2020

21-
def __init__(self, dialog_id: str, validator: Callable[[Attachment], bool]):
21+
def __init__(self, dialog_id: str, validator: Callable[[Attachment], bool] = None):
2222
super().__init__(dialog_id, validator)
2323

2424
async def on_prompt(
2525
self,
2626
context: TurnContext,
2727
state: Dict[str, object],
2828
options: PromptOptions,
29-
isRetry: bool
29+
is_retry: bool
3030
):
3131
if not context:
3232
raise TypeError('AttachmentPrompt.on_prompt(): TurnContext cannot be None.')
3333

3434
if not isinstance(options, PromptOptions):
3535
raise TypeError('AttachmentPrompt.on_prompt(): PromptOptions are required for Attachment Prompt dialogs.')
3636

37-
if isRetry and options.retry_prompt:
37+
if is_retry and options.retry_prompt:
3838
options.retry_prompt.input_hint = InputHints.expecting_input
3939
await context.send_activity(options.retry_prompt)
4040
elif options.prompt:

libraries/botbuilder-dialogs/tests/test_attachment_prompt.py

Lines changed: 246 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
# Licensed under the MIT License.
33

44
import aiounittest
5-
from botbuilder.dialogs.prompts import AttachmentPrompt, PromptOptions, PromptRecognizerResult
6-
from botbuilder.schema import Activity, InputHints
5+
from botbuilder.dialogs.prompts import AttachmentPrompt, PromptOptions, PromptRecognizerResult, PromptValidatorContext
6+
from botbuilder.schema import Activity, ActivityTypes, Attachment, InputHints
77

8-
from botbuilder.core import TurnContext, ConversationState
8+
from botbuilder.core import TurnContext, ConversationState, MemoryStorage, MessageFactory
99
from botbuilder.core.adapters import TestAdapter
10+
from botbuilder.dialogs import DialogSet, DialogTurnStatus
1011

1112
class AttachmentPromptTests(aiounittest.AsyncTestCase):
1213
def test_attachment_prompt_with_empty_id_should_fail(self):
@@ -18,6 +19,245 @@ def test_attachment_prompt_with_empty_id_should_fail(self):
1819
def test_attachment_prompt_with_none_id_should_fail(self):
1920
with self.assertRaises(TypeError):
2021
AttachmentPrompt(None)
21-
22-
# TODO other tests require TestFlow
23-
22+
23+
async def test_basic_attachment_prompt(self):
24+
async def exec_test(turn_context: TurnContext):
25+
dc = await dialogs.create_context(turn_context)
26+
27+
results = await dc.continue_dialog()
28+
if results.status == DialogTurnStatus.Empty:
29+
options = PromptOptions(prompt=Activity(type=ActivityTypes.message, text='please add an attachment.'))
30+
await dc.prompt('AttachmentPrompt', options)
31+
elif results.status == DialogTurnStatus.Complete:
32+
attachment = results.result[0]
33+
content = MessageFactory.text(attachment.content)
34+
await turn_context.send_activity(content)
35+
36+
await convo_state.save_changes(turn_context)
37+
38+
# Initialize TestAdapter.
39+
adapter = TestAdapter(exec_test)
40+
41+
# Create ConversationState with MemoryStorage and register the state as middleware.
42+
convo_state = ConversationState(MemoryStorage())
43+
44+
# Create a DialogState property, DialogSet and AttachmentPrompt.
45+
dialog_state = convo_state.create_property('dialog_state')
46+
dialogs = DialogSet(dialog_state)
47+
dialogs.add(AttachmentPrompt('AttachmentPrompt'))
48+
49+
# Create incoming activity with attachment.
50+
attachment = Attachment(content='some content', content_type='text/plain')
51+
attachment_activity = Activity(type=ActivityTypes.message, attachments=[attachment])
52+
53+
step1 = await adapter.send('hello')
54+
step2 = await step1.assert_reply('please add an attachment.')
55+
step3 = await step2.send(attachment_activity)
56+
await step3.assert_reply('some content')
57+
58+
async def test_attachment_prompt_with_validator(self):
59+
async def exec_test(turn_context: TurnContext):
60+
dc = await dialogs.create_context(turn_context)
61+
62+
results = await dc.continue_dialog()
63+
if results.status == DialogTurnStatus.Empty:
64+
options = PromptOptions(prompt=Activity(type=ActivityTypes.message, text='please add an attachment.'))
65+
await dc.prompt('AttachmentPrompt', options)
66+
elif results.status == DialogTurnStatus.Complete:
67+
attachment = results.result[0]
68+
content = MessageFactory.text(attachment.content)
69+
await turn_context.send_activity(content)
70+
71+
await convo_state.save_changes(turn_context)
72+
73+
# Initialize TestAdapter.
74+
adapter = TestAdapter(exec_test)
75+
76+
# Create ConversationState with MemoryStorage and register the state as middleware.
77+
convo_state = ConversationState(MemoryStorage())
78+
79+
# Create a DialogState property, DialogSet and AttachmentPrompt.
80+
dialog_state = convo_state.create_property('dialog_state')
81+
dialogs = DialogSet(dialog_state)
82+
83+
async def aux_validator(prompt_context: PromptValidatorContext):
84+
assert prompt_context, 'Validator missing prompt_context'
85+
return prompt_context.recognized.succeeded
86+
87+
dialogs.add(AttachmentPrompt('AttachmentPrompt', aux_validator))
88+
89+
# Create incoming activity with attachment.
90+
attachment = Attachment(content='some content', content_type='text/plain')
91+
attachment_activity = Activity(type=ActivityTypes.message, attachments=[attachment])
92+
93+
step1 = await adapter.send('hello')
94+
step2 = await step1.assert_reply('please add an attachment.')
95+
step3 = await step2.send(attachment_activity)
96+
await step3.assert_reply('some content')
97+
98+
async def test_retry_attachment_prompt(self):
99+
async def exec_test(turn_context: TurnContext):
100+
dc = await dialogs.create_context(turn_context)
101+
102+
results = await dc.continue_dialog()
103+
if results.status == DialogTurnStatus.Empty:
104+
options = PromptOptions(prompt=Activity(type=ActivityTypes.message, text='please add an attachment.'))
105+
await dc.prompt('AttachmentPrompt', options)
106+
elif results.status == DialogTurnStatus.Complete:
107+
attachment = results.result[0]
108+
content = MessageFactory.text(attachment.content)
109+
await turn_context.send_activity(content)
110+
111+
await convo_state.save_changes(turn_context)
112+
113+
# Initialize TestAdapter.
114+
adapter = TestAdapter(exec_test)
115+
116+
# Create ConversationState with MemoryStorage and register the state as middleware.
117+
convo_state = ConversationState(MemoryStorage())
118+
119+
# Create a DialogState property, DialogSet and AttachmentPrompt.
120+
dialog_state = convo_state.create_property('dialog_state')
121+
dialogs = DialogSet(dialog_state)
122+
dialogs.add(AttachmentPrompt('AttachmentPrompt'))
123+
124+
# Create incoming activity with attachment.
125+
attachment = Attachment(content='some content', content_type='text/plain')
126+
attachment_activity = Activity(type=ActivityTypes.message, attachments=[attachment])
127+
128+
step1 = await adapter.send('hello')
129+
step2 = await step1.assert_reply('please add an attachment.')
130+
step3 = await step2.send('hello again')
131+
step4 = await step3.assert_reply('please add an attachment.')
132+
step5 = await step4.send(attachment_activity)
133+
await step5.assert_reply('some content')
134+
135+
async def test_attachment_prompt_with_custom_retry(self):
136+
async def exec_test(turn_context: TurnContext):
137+
dc = await dialogs.create_context(turn_context)
138+
139+
results = await dc.continue_dialog()
140+
if results.status == DialogTurnStatus.Empty:
141+
options = PromptOptions(
142+
prompt=Activity(type=ActivityTypes.message, text='please add an attachment.'),
143+
retry_prompt=Activity(type=ActivityTypes.message, text='please try again.')
144+
)
145+
await dc.prompt('AttachmentPrompt', options)
146+
elif results.status == DialogTurnStatus.Complete:
147+
attachment = results.result[0]
148+
content = MessageFactory.text(attachment.content)
149+
await turn_context.send_activity(content)
150+
151+
await convo_state.save_changes(turn_context)
152+
153+
# Initialize TestAdapter.
154+
adapter = TestAdapter(exec_test)
155+
156+
# Create ConversationState with MemoryStorage and register the state as middleware.
157+
convo_state = ConversationState(MemoryStorage())
158+
159+
# Create a DialogState property, DialogSet and AttachmentPrompt.
160+
dialog_state = convo_state.create_property('dialog_state')
161+
dialogs = DialogSet(dialog_state)
162+
163+
async def aux_validator(prompt_context: PromptValidatorContext):
164+
assert prompt_context, 'Validator missing prompt_context'
165+
return prompt_context.recognized.succeeded
166+
167+
dialogs.add(AttachmentPrompt('AttachmentPrompt', aux_validator))
168+
169+
# Create incoming activity with attachment.
170+
attachment = Attachment(content='some content', content_type='text/plain')
171+
attachment_activity = Activity(type=ActivityTypes.message, attachments=[attachment])
172+
invalid_activty = Activity(type=ActivityTypes.message, text='invalid')
173+
174+
step1 = await adapter.send('hello')
175+
step2 = await step1.assert_reply('please add an attachment.')
176+
step3 = await step2.send(invalid_activty)
177+
step4 = await step3.assert_reply('please try again.')
178+
step5 = await step4.send(attachment_activity)
179+
await step5.assert_reply('some content')
180+
181+
async def test_should_send_ignore_retry_rompt_if_validator_replies(self):
182+
async def exec_test(turn_context: TurnContext):
183+
dc = await dialogs.create_context(turn_context)
184+
185+
results = await dc.continue_dialog()
186+
if results.status == DialogTurnStatus.Empty:
187+
options = PromptOptions(
188+
prompt=Activity(type=ActivityTypes.message, text='please add an attachment.'),
189+
retry_prompt=Activity(type=ActivityTypes.message, text='please try again.')
190+
)
191+
await dc.prompt('AttachmentPrompt', options)
192+
elif results.status == DialogTurnStatus.Complete:
193+
attachment = results.result[0]
194+
content = MessageFactory.text(attachment.content)
195+
await turn_context.send_activity(content)
196+
197+
await convo_state.save_changes(turn_context)
198+
199+
# Initialize TestAdapter.
200+
adapter = TestAdapter(exec_test)
201+
202+
# Create ConversationState with MemoryStorage and register the state as middleware.
203+
convo_state = ConversationState(MemoryStorage())
204+
205+
# Create a DialogState property, DialogSet and AttachmentPrompt.
206+
dialog_state = convo_state.create_property('dialog_state')
207+
dialogs = DialogSet(dialog_state)
208+
209+
async def aux_validator(prompt_context: PromptValidatorContext):
210+
assert prompt_context, 'Validator missing prompt_context'
211+
212+
if not prompt_context.recognized.succeeded:
213+
await prompt_context.context.send_activity('Bad input.')
214+
215+
return prompt_context.recognized.succeeded
216+
217+
dialogs.add(AttachmentPrompt('AttachmentPrompt', aux_validator))
218+
219+
# Create incoming activity with attachment.
220+
attachment = Attachment(content='some content', content_type='text/plain')
221+
attachment_activity = Activity(type=ActivityTypes.message, attachments=[attachment])
222+
invalid_activty = Activity(type=ActivityTypes.message, text='invalid')
223+
224+
step1 = await adapter.send('hello')
225+
step2 = await step1.assert_reply('please add an attachment.')
226+
step3 = await step2.send(invalid_activty)
227+
step4 = await step3.assert_reply('Bad input.')
228+
step5 = await step4.send(attachment_activity)
229+
await step5.assert_reply('some content')
230+
231+
async def test_should_not_send_retry_if_not_specified(self):
232+
async def exec_test(turn_context: TurnContext):
233+
dc = await dialogs.create_context(turn_context)
234+
235+
results = await dc.continue_dialog()
236+
if results.status == DialogTurnStatus.Empty:
237+
await dc.begin_dialog('AttachmentPrompt', PromptOptions())
238+
elif results.status == DialogTurnStatus.Complete:
239+
attachment = results.result[0]
240+
content = MessageFactory.text(attachment.content)
241+
await turn_context.send_activity(content)
242+
243+
await convo_state.save_changes(turn_context)
244+
245+
# Initialize TestAdapter.
246+
adapter = TestAdapter(exec_test)
247+
248+
# Create ConversationState with MemoryStorage and register the state as middleware.
249+
convo_state = ConversationState(MemoryStorage())
250+
251+
# Create a DialogState property, DialogSet and AttachmentPrompt.
252+
dialog_state = convo_state.create_property('dialog_state')
253+
dialogs = DialogSet(dialog_state)
254+
dialogs.add(AttachmentPrompt('AttachmentPrompt'))
255+
256+
# Create incoming activity with attachment.
257+
attachment = Attachment(content='some content', content_type='text/plain')
258+
attachment_activity = Activity(type=ActivityTypes.message, attachments=[attachment])
259+
260+
step1 = await adapter.send('hello')
261+
step2 = await step1.send('what?')
262+
step3 = await step2.send(attachment_activity)
263+
await step3.assert_reply('some content')

0 commit comments

Comments
 (0)