[botbuilder-dialogs] Dialog does not prompt on continue dialog if any activity is sent on the turn
See original GitHub issueGithub issues should be used for bugs and feature requests. Use Stack Overflow for general “how-to” questions.
Versions
What package version of the SDK are you using: 4.14.1 What nodejs version are you using: node14 What browser version are you using: NA What os are you using: MacOS
Describe the bug
On continueDialog a prompt checks first if the context.responded is false before showing the prompt. This behavior is incorrect in most cases. I show here an example with a typing activity (Which is very common)
/* eslint-disable no-console */
import { ActivityTypes, ConversationState, MemoryStorage, TestAdapter } from 'botbuilder';
import { ChoicePrompt, DialogSet, DialogTurnStatus, ListStyle, WaterfallDialog } from 'botbuilder-dialogs';
const STATEMENT = 'Hello, I will ask you a question.';
const QUESTION = 'Do you like me?';
const prompt = new ChoicePrompt('choices', async (p) => {
if (!p.recognized && p.attemptCount < 2) {
return false;
}
return true;
});
const dialog = new WaterfallDialog('testDialog', [
async (step) => {
await step.context.sendActivity(STATEMENT);
return step.prompt('choices', { prompt: QUESTION, choices: ['Yes', 'Of course'], style: ListStyle.list });
},
]);
const memory = new MemoryStorage();
const dialogMemory = new ConversationState(memory);
const dialogSet = new DialogSet(dialogMemory.createProperty('dialogs'));
dialogSet.add(prompt);
dialogSet.add(dialog);
const testAdapter = new TestAdapter(async (ctx) => {
const dc = await dialogSet.createContext(ctx);
// Comment out the typing activity to see how it changes the behavior of the script.
await ctx.sendActivity({ type: ActivityTypes.Typing });
const result = await dc.continueDialog();
if (result.status === DialogTurnStatus.empty) {
await dc.beginDialog('testDialog');
}
await dialogMemory.saveChanges(ctx);
});
(async () => {
await testAdapter.send('hi');
testAdapter.activeQueue.splice(0, Infinity);
await testAdapter.send('sorry, what?');
const texts = testAdapter.activeQueue.map((a) => a.text);
if (!texts.some((t) => t?.includes(QUESTION))) {
throw new Error('Question not included in replies');
}
})()
.then(() => console.log('Well done'))
.catch((err) => console.error(err));
// (async () => {
// await testAdapter
// .send('hi')
// .assertReply({ type: ActivityTypes.Typing })
// .assertReply(STATEMENT)
// .assertReply((r) => {
// r.text?.includes(QUESTION);
// });
// await testAdapter
// .send('sorry, what')
// .assertReply({ type: ActivityTypes.Typing })
// .assertReply((r) => {
// r.text?.includes(QUESTION);
// });
// })()
// .then(() => console.log('Well done'))
// .catch((err) => console.error(err));
Expected behavior
On continueDialog, the question should be shown, regardless of whether the application sends message before the prompt continueDialog is called
If backwards compatibility for this is necessary, I would recommend to add an option parameter that specifies whether to reply on continue or not. And if this parameter is empty, continue doing the current behavior
PS: TestAdapter is broken
Also, note that if you run the test with the assertReply, the test adapter throws a unhandledpromiserejection. I believe currently the test adapter throws unhandled exceptions whenever
- there is a failed assertion,
- If the test adapter handler itself throws an error.
That makes it really hard to use the TestAdapter on tests to test error throwing
Issue Analytics
- State:
- Created 2 years ago
- Comments:12 (12 by maintainers)
Good afternoon, I modified #3981 to address the backwards compatibility issues we were discussing.
Pushing a change like that (or similar to that if that is considered too intrusive) would minimize the harm of using the “responded” flag.
In essence, it understands the intention to check only if it responded within the validator.
@Stevenic do you have any feedback on this discussion regarding the context.responded flag?