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
66 changes: 65 additions & 1 deletion libraries/botbuilder-core/src/activityHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,38 @@ export class ActivityHandler extends ActivityHandlerBase {
return this.on('Event', handler);
}

/**
* Registers an activity event handler for the _end of conversation_ activity.
*
* @param handler The event handler.
*
* @remarks
* Returns a reference to the [ActivityHandler](xref:botbuilder-core.ActivityHandler) object.
*
* This activity is typically send from a Skill to a Skill caller indicating the end of that particular child conversation.
*
* To handle an End of Conversation, use the
* [onEndOfConversation](xref:botbuilder-core.ActivityHandler.onEndOfConversation) type-specific event handler.
*/
public onEndOfConversation(handler: BotHandler): this {
return this.on('EndOfConversation', handler);
}

/**
* Registers an activity event handler for the _typing_ activity.
*
* @param handler The event handler.
*
* @remarks
* Returns a reference to the [ActivityHandler](xref:botbuilder-core.ActivityHandler) object.
*
* To handle a Typing event, use the
* [onTyping](xref:botbuilder-core.ActivityHandler.onTyping) type-specific event handler.
*/
public onTyping(handler: BotHandler): this {
return this.on('Typing', handler);
}

/**
* Registers an activity event handler for the _tokens-response_ event, emitted for any incoming
* `tokens/response` event activity. These are generated as part of the OAuth authentication flow.
Expand All @@ -270,7 +302,7 @@ export class ActivityHandler extends ActivityHandlerBase {
public onTokenResponseEvent(handler: BotHandler): this {
return this.on('TokenResponseEvent', handler);
}

/**
* Registers an activity event handler for the _unrecognized activity type_ event, emitted for an
* incoming activity with a type for which the [ActivityHandler](xref:botbuilder-core.ActivityHandler)
Expand Down Expand Up @@ -377,6 +409,38 @@ export class ActivityHandler extends ActivityHandlerBase {
await this.handle(context, 'Message', this.defaultNextEvent(context));
}

/**
* Runs all registered _endOfConversation_ handlers and then continues the event emission process.
*
* @param context The context object for the current turn.
*
* @remarks
* Overwrite this method to support channel-specific behavior across multiple channels.
*
* The default logic is to call any handlers registered via
* [onEndOfConversationActivity](xref:botbuilder-core.ActivityHandler.onMessage),
* and then continue by calling [defaultNextEvent](xref:botbuilder-core.ActivityHandler.defaultNextEvent).
*/
protected async onEndOfConversationActivity(context: TurnContext): Promise<void> {
await this.handle(context, 'EndOfConversation', this.defaultNextEvent(context));
}

/**
* Runs all registered _typing_ handlers and then continues the event emission process.
*
* @param context The context object for the current turn.
*
* @remarks
* Overwrite this method to support channel-specific behavior across multiple channels.
*
* The default logic is to call any handlers registered via
* [onTypingActivity](xref:botbuilder-core.ActivityHandler.onTypingActivity),
* and then continue by calling [defaultNextEvent](xref:botbuilder-core.ActivityHandler.defaultNextEvent).
*/
protected async onTypingActivity(context: TurnContext): Promise<void> {
await this.handle(context, 'Typing', this.defaultNextEvent(context));
}

/**
* Runs all registered _unrecognized activity type_ handlers and then continues the event emission process.
*
Expand Down
32 changes: 32 additions & 0 deletions libraries/botbuilder-core/src/activityHandlerBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ export class ActivityHandlerBase {
case ActivityTypes.Event:
await this.onEventActivity(context);
break;
case ActivityTypes.EndOfConversation:
await this.onEndOfConversationActivity(context);
break;
case ActivityTypes.Typing:
await this.onTypingActivity(context);
break;
default:
// handler for unknown or unhandled types
await this.onUnrecognizedActivity(context);
Expand Down Expand Up @@ -143,6 +149,32 @@ export class ActivityHandlerBase {
return;
}

/**
* Provides a hook for emitting the _end of conversation_ event.
*
* @param context The context object for the current turn.
*
* @remarks
* Overwrite this method to run registered _end of conversation_ handlers and then continue the event
* emission process.
*/
protected async onEndOfConversationActivity(context: TurnContext): Promise<void> {
return;
}

/**
* Provides a hook for emitting the _typing_ event.
*
* @param context The context object for the current turn.
*
* @remarks
* Overwrite this method to run registered _typing_ handlers and then continue the event
* emission process.
*/
protected async onTypingActivity(context: TurnContext): Promise<void> {
return;
}

/**
* Provides a hook for emitting the _unrecognized_ event.
*
Expand Down
95 changes: 60 additions & 35 deletions libraries/botbuilder-core/tests/ActivityHandler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ describe('ActivityHandler', function() {
await bot.run(context).catch(error => done(error));
}

it(`should fire onTurn for any inbound activity`, async function (done) {
it(`should fire onTurn for any inbound activity`, async function(done) {

const bot = new ActivityHandler();

bot.onTurn(async(context, next) => {
bot.onTurn(async (context, next) => {
assert(true, 'onTurn not called');
done();
await next();
Expand All @@ -35,66 +35,66 @@ describe('ActivityHandler', function() {
processActivity({type: 'any'}, bot, done);
});

it(`should fire onMessage for any message activities`, async function (done) {
it(`should fire onMessage for any message activities`, async function(done) {

const bot = new ActivityHandler();

bot.onMessage(async(context, next) => {
bot.onMessage(async (context, next) => {
assert(true, 'onMessage not called');
done();
await next();
});

processActivity({type: 'message'}, bot, done);
processActivity({type: ActivityTypes.Message}, bot, done);
});

it(`calling next allows following events to firing`, async function (done) {
it(`calling next allows following events to firing`, async function(done) {

const bot = new ActivityHandler();

bot.onTurn(async(context, next) => {
bot.onTurn(async (context, next) => {
assert(true, 'onTurn not called');
await next();
});

bot.onMessage(async(context, next) => {
bot.onMessage(async (context, next) => {
assert(true, 'onMessage not called');
done();
await next();
});

processActivity({type: 'message'}, bot, done);
processActivity({type: ActivityTypes.Message}, bot, done);
});

it(`omitting call to next prevents following events from firing`, async function (done) {
it(`omitting call to next prevents following events from firing`, async function(done) {

const bot = new ActivityHandler();

bot.onTurn(async(context, next) => {
bot.onTurn(async (context, next) => {
assert(true, 'onTurn not called');
done();
});

bot.onMessage(async(context, next) => {
bot.onMessage(async (context, next) => {
assert(false, 'onMessage called improperly!');
await next();
});

processActivity({type: 'message'}, bot, done);
processActivity({type: ActivityTypes.Message}, bot, done);
});

it(`binding 2 methods to the same event both fire`, async function (done) {
it(`binding 2 methods to the same event both fire`, async function(done) {

const bot = new ActivityHandler();
let count = 0;

bot.onMessage(async(context, next) => {
bot.onMessage(async (context, next) => {
assert(true, 'event 1 did not fire');
count++;
await next();
});

bot.onMessage(async(context, next) => {
bot.onMessage(async (context, next) => {
assert(true, 'event 2 did not fire');
count++;

Expand All @@ -103,14 +103,14 @@ describe('ActivityHandler', function() {
await next();
});

processActivity({type: 'message'}, bot, done);
processActivity({type: ActivityTypes.Message}, bot, done);
});

it(`should fire onConversationUpdate`, async function (done) {
it(`should fire onConversationUpdate`, async function(done) {

const bot = new ActivityHandler();

bot.onConversationUpdate(async(context, next) => {
bot.onConversationUpdate(async (context, next) => {
assert(true, 'onConversationUpdate not called');
done();
await next();
Expand All @@ -119,11 +119,11 @@ describe('ActivityHandler', function() {
processActivity({type: ActivityTypes.ConversationUpdate}, bot, done);
});

it(`should fire onMembersAdded`, async function (done) {
it(`should fire onMembersAdded`, async function(done) {

const bot = new ActivityHandler();

bot.onMembersAdded(async(context, next) => {
bot.onMembersAdded(async (context, next) => {
assert(true, 'onConversationUpdate not called');
done();
await next();
Expand All @@ -132,11 +132,11 @@ describe('ActivityHandler', function() {
processActivity({type: ActivityTypes.ConversationUpdate, membersAdded: [{id: 1}]}, bot, done);
});

it(`should fire onMembersRemoved`, async function (done) {
it(`should fire onMembersRemoved`, async function(done) {

const bot = new ActivityHandler();

bot.onMembersRemoved(async(context, next) => {
bot.onMembersRemoved(async (context, next) => {
assert(true, 'onMembersRemoved not called');
done();
await next();
Expand All @@ -145,11 +145,11 @@ describe('ActivityHandler', function() {
processActivity({type: ActivityTypes.ConversationUpdate, membersRemoved: [{id: 1}]}, bot, done);
});

it(`should fire onMessageReaction`, async function (done) {
it(`should fire onMessageReaction`, async function(done) {

const bot = new ActivityHandler();

bot.onMessageReaction(async(context, next) => {
bot.onMessageReaction(async (context, next) => {
assert(true, 'onMessageReaction not called');
done();
await next();
Expand All @@ -158,11 +158,11 @@ describe('ActivityHandler', function() {
processActivity({type: ActivityTypes.MessageReaction}, bot, done);
});

it(`should fire onReactionsAdded`, async function (done) {
it(`should fire onReactionsAdded`, async function(done) {

const bot = new ActivityHandler();

bot.onReactionsAdded(async(context, next) => {
bot.onReactionsAdded(async (context, next) => {
assert(true, 'onReactionsAdded not called');
done();
await next();
Expand All @@ -171,11 +171,11 @@ describe('ActivityHandler', function() {
processActivity({type: ActivityTypes.MessageReaction, reactionsAdded: [{type: 'like'}]}, bot, done);
});

it(`should fire onReactionsRemoved`, async function (done) {
it(`should fire onReactionsRemoved`, async function(done) {

const bot = new ActivityHandler();

bot.onReactionsRemoved(async(context, next) => {
bot.onReactionsRemoved(async (context, next) => {
assert(true, 'onReactionsRemoved not called');
done();
await next();
Expand All @@ -184,11 +184,11 @@ describe('ActivityHandler', function() {
processActivity({type: ActivityTypes.MessageReaction, reactionsRemoved: [{type: 'like'}]}, bot, done);
});

it(`should fire onEvent`, async function (done) {
it(`should fire onEvent`, async function(done) {

const bot = new ActivityHandler();

bot.onEvent(async(context, next) => {
bot.onEvent(async (context, next) => {
assert(true, 'onEvent not called');
done();
await next();
Expand All @@ -197,12 +197,37 @@ describe('ActivityHandler', function() {
processActivity({type: ActivityTypes.Event}, bot, done);
});

it(`should fire onEndOfConversation`, async function(done) {

it(`should fire onUnrecognizedActivityType`, async function (done) {
const bot = new ActivityHandler();

bot.onEndOfConversation(async (context, next) => {
assert(true, 'onEndOfConversation not called');
done();
await next();
});

processActivity({type: ActivityTypes.EndOfConversation}, bot, done);
});

it(`should fire onTyping`, async function(done) {

const bot = new ActivityHandler();

bot.onTyping(async (context, next) => {
assert(true, 'onTyping not called');
done();
await next();
});

processActivity({type: ActivityTypes.Typing}, bot, done);
});

it(`should fire onUnrecognizedActivityType`, async function(done) {

const bot = new ActivityHandler();

bot.onUnrecognizedActivityType(async(context, next) => {
bot.onUnrecognizedActivityType(async (context, next) => {
assert(true, 'onUnrecognizedActivityType not called');
done();
await next();
Expand All @@ -211,11 +236,11 @@ describe('ActivityHandler', function() {
processActivity({type: 'foo'}, bot, done);
});

it(`should fire onDialog`, async function (done) {
it(`should fire onDialog`, async function(done) {

const bot = new ActivityHandler();

bot.onDialog(async(context, next) => {
bot.onDialog(async (context, next) => {
assert(true, 'onDialog not called');
done();
await next();
Expand Down
Loading