Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@
}
},
"state": {
"attemptCount": 2
"attemptCount": 1
}
}
}
Expand Down Expand Up @@ -602,7 +602,7 @@
}
},
"state": {
"attemptCount": 2
"attemptCount": 1
}
}
}
Expand Down Expand Up @@ -713,7 +713,7 @@
}
},
"state": {
"attemptCount": 2
"attemptCount": 1
}
}
}
Expand Down Expand Up @@ -828,7 +828,7 @@
}
},
"state": {
"attemptCount": 3
"attemptCount": 2
}
}
}
Expand Down Expand Up @@ -864,7 +864,7 @@
}
},
"state": {
"attemptCount": 3
"attemptCount": 2
}
}
}
Expand Down Expand Up @@ -975,7 +975,7 @@
}
},
"state": {
"attemptCount": 3
"attemptCount": 2
}
}
}
Expand Down Expand Up @@ -1090,7 +1090,7 @@
}
},
"state": {
"attemptCount": 4
"attemptCount": 3
}
}
}
Expand Down Expand Up @@ -1126,7 +1126,7 @@
}
},
"state": {
"attemptCount": 4
"attemptCount": 3
}
}
}
Expand Down Expand Up @@ -1237,7 +1237,7 @@
}
},
"state": {
"attemptCount": 4
"attemptCount": 3
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions libraries/botbuilder-dialogs/src/prompts/activityPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class ActivityPrompt extends Dialog {
const recognized: PromptRecognizerResult<Activity> = await this.onRecognize(dc.context, state.state, state.options);

if (state.state['attemptCount'] === undefined) {
state.state['attemptCount'] = 1;
state.state['attemptCount'] = 0;
}

// Validate the return value
Expand All @@ -67,7 +67,7 @@ export class ActivityPrompt extends Dialog {
recognized: recognized,
state: state.state,
options: state.options,
attemptCount: state.state['attemptCount']
attemptCount: ++state.state['attemptCount']
});

// Return recognized value or re-prompt
Expand Down
4 changes: 2 additions & 2 deletions libraries/botbuilder-dialogs/src/prompts/oauthPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export class OAuthPrompt extends Dialog {
} else {

if (state.state['attemptCount'] === undefined) {
state.state['attemptCount'] = 1;
state.state['attemptCount'] = 0;
}

// Validate the return value
Expand All @@ -169,7 +169,7 @@ export class OAuthPrompt extends Dialog {
recognized: recognized,
state: state.state,
options: state.options,
attemptCount: state.state['attemptCount']
attemptCount: ++state.state['attemptCount']
});
} else if (recognized.succeeded) {
isValid = true;
Expand Down
7 changes: 2 additions & 5 deletions libraries/botbuilder-dialogs/src/prompts/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,18 +209,15 @@ export abstract class Prompt<T> extends Dialog {
let isValid = false;
if (this.validator) {
if (state.state['attemptCount'] === undefined) {
state.state['attemptCount'] = 1;
state.state['attemptCount'] = 0;
}
isValid = await this.validator({
context: dc.context,
recognized: recognized,
state: state.state,
options: state.options,
attemptCount: state.state['attemptCount']
attemptCount: ++state.state['attemptCount']
});
if (state.state['attemptCount'] !== undefined) {
state.state['attemptCount']++;
}
} else if (recognized.succeeded) {
isValid = true;
}
Expand Down
55 changes: 53 additions & 2 deletions libraries/botbuilder-dialogs/tests/activityPrompt.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { ConversationState, MemoryStorage, TestAdapter } = require('botbuilder-core');
const { ActivityTypes, ConversationState, MemoryStorage, TestAdapter } = require('botbuilder-core');
const { ActivityPrompt, DialogReason, DialogSet, DialogTurnStatus } = require('../');
const assert = require('assert');

Expand Down Expand Up @@ -76,7 +76,7 @@ describe('ActivityPrompt', function () {
.assertReply('Please send an activity.');
});

it('should re-prompt with custom retyrPrompt if validator returned false.', async function () {
it('should re-prompt with custom retryPrompt if validator returned false.', async function () {
const adapter = new TestAdapter(async turnContext => {
const dc = await dialogs.createContext(turnContext);

Expand Down Expand Up @@ -105,6 +105,57 @@ describe('ActivityPrompt', function () {
.assertReply('Activity not received.');
});

it('should see attemptCount increment.', async function() {
const convoState = new ConversationState(new MemoryStorage());

const dialogState = convoState.createProperty('dialogState');
const dialogs = new DialogSet(dialogState);

dialogs.add(new SimpleActivityPrompt('prompt', async prompt => {
assert(prompt, `validator missing PromptValidatorContext.`);
assert(typeof prompt.recognized.value === 'object', 'recognized.value was not an object.');
if (prompt.recognized.value.type !== ActivityTypes.Event) {
prompt.context.sendActivity(`attemptCount ${ prompt.attemptCount }`);
return false;
}
return true;
}));

const adapter = new TestAdapter(async turnContext => {
const dc = await dialogs.createContext(turnContext);

const results = await dc.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dc.prompt('prompt', { prompt: 'Please send activity.', retryPrompt: 'Activity not received.' });
} else if (results.status === DialogTurnStatus.complete) {
const reply = results.result.type;
await turnContext.sendActivity(`You sent a(n) ${ reply }`);
}
await convoState.saveChanges(turnContext);
});

await adapter.send('Hello')
.assertReply('Please send activity.')
.send('100')
.assertReply('attemptCount 1')
.send('200')
.assertReply('attemptCount 2')
.send('300')
.assertReply('attemptCount 3')
.send({ type: ActivityTypes.Event })
.assertReply(`You sent a(n) ${ ActivityTypes.Event }`)
.send('Another!')
.assertReply('Please send activity.')
.send('100')
.assertReply('attemptCount 1')
.send('200')
.assertReply('attemptCount 2')
.send('300')
.assertReply('attemptCount 3')
.send({ type: ActivityTypes.Event })
.assertReply(`You sent a(n) ${ ActivityTypes.Event }`);
});

it('should have resumeDialog() prompt user and return Dialog.EndOfTurn.', async function () {
const adapter = new TestAdapter(async turnContext => {
const dc = await dialogs.createContext(turnContext);
Expand Down
89 changes: 83 additions & 6 deletions libraries/botbuilder-dialogs/tests/oauthPrompt.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { ActivityTypes, CardFactory, ConversationState, InputHints, MemoryStorage, TestAdapter } = require('botbuilder-core');
const { ActivityTypes, CardFactory, ConversationState, InputHints, MemoryStorage, TestAdapter, TurnContext } = require('botbuilder-core');
const { OAuthPrompt, OAuthPromptSettings, DialogSet, DialogTurnStatus, ListStyle } = require('../');
const assert = require('assert');

Expand Down Expand Up @@ -31,10 +31,10 @@ describe('OAuthPrompt', function () {
await convoState.saveChanges(turnContext);
});

// Create new ConversationState with MemoryStorage and register the state as middleware.
// Create new ConversationState with MemoryStorage
const convoState = new ConversationState(new MemoryStorage());

// Create a DialogState property, DialogSet and AttachmentPrompt.
// Create a DialogState property, DialogSet and OAuthPrompt
const dialogState = convoState.createProperty('dialogState');
const dialogs = new DialogSet(dialogState);
dialogs.add(new OAuthPrompt('prompt', {
Expand Down Expand Up @@ -92,10 +92,10 @@ describe('OAuthPrompt', function () {
await convoState.saveChanges(turnContext);
});

// Create new ConversationState with MemoryStorage and register the state as middleware.
// Create new ConversationState with MemoryStorage
const convoState = new ConversationState(new MemoryStorage());

// Create a DialogState property, DialogSet and AttachmentPrompt.
// Create a DialogState property, DialogSet and OAuthPrompt
const dialogState = convoState.createProperty('dialogState');
const dialogs = new DialogSet(dialogState);
dialogs.add(new OAuthPrompt('prompt', {
Expand All @@ -109,13 +109,90 @@ describe('OAuthPrompt', function () {
assert(activity.attachments.length === 1);
assert(activity.attachments[0].contentType === CardFactory.contentTypes.oauthCard);

// send a mock EventActivity back to the bot with the token
adapter.addUserToken(connectionName, activity.channelId, activity.recipient.id, token, magicCode);
})
.send(magicCode)
.assertReply('Logged in.');
});

it('should see attemptCount increment', async function() {
var connectionName = 'myConnection';
var token = 'abc123';
var magicCode = '888999';

// Create new ConversationState with MemoryStorage
const convoState = new ConversationState(new MemoryStorage());

// Create a DialogState property, DialogSet and OAuthPrompt
const dialogState = convoState.createProperty('dialogState');
const dialogs = new DialogSet(dialogState);

dialogs.add(new OAuthPrompt('prompt', {
connectionName,
title: 'Login',
timeout: 300000
}, async (prompt) => {
if (prompt.recognized.succeeded) {
return true;
}
prompt.context.sendActivity(`attemptCount ${ prompt.attemptCount }`);
return false;
}));

// Initialize TestAdapter.
const adapter = new TestAdapter(async (turnContext) => {
const dc = await dialogs.createContext(turnContext);

const results = await dc.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dc.prompt('prompt', { retryPrompt: 'Try again' });
} else if (results.status === DialogTurnStatus.complete) {
if (results.result.token) {
await turnContext.sendActivity('Logged in');
}
else {
await turnContext.sendActivity('Failed');
}
}
await convoState.saveChanges(turnContext);
});

await adapter.send('Hello')
.assertReply(activity => {
assert(activity.attachments.length === 1);
assert(activity.attachments[0].contentType === CardFactory.contentTypes.oauthCard);

adapter.addUserToken(connectionName, activity.channelId, activity.recipient.id, token, magicCode);
})
.send('1')
.assertReply('attemptCount 1')
.send('12')
.assertReply('attemptCount 2')
.send('123')
.assertReply('attemptCount 3')
.send(magicCode)
.assertReply(activity => {
assert(activity.text === 'Logged in');

adapter.signOutUser(new TurnContext(adapter, { channelId: activity.channelId, from: activity.recipient }), connectionName);
})
.send('Another!')
.assertReply(activity => {
assert(activity.attachments.length === 1);
assert(activity.attachments[0].contentType === CardFactory.contentTypes.oauthCard);

adapter.addUserToken(connectionName, activity.channelId, activity.recipient.id, token, magicCode);
})
.send('1234')
.assertReply('attemptCount 1')
.send('12345')
.assertReply('attemptCount 2')
.send('123456')
.assertReply('attemptCount 3')
.send(magicCode)
.assertReply('Logged in');
});

it('should call OAuthPrompt for streaming connection', async function () {
var connectionName = "myConnection";
var token = "abc123";
Expand Down