Skip to content

Commit

Permalink
Merge branch 'master' into Zerryth/QnAMakerServiceHostname
Browse files Browse the repository at this point in the history
  • Loading branch information
Zerryth authored Jul 3, 2019
2 parents e33750b + 3dcc4fc commit ece3485
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ root = true

# Tab indentation
[*]
indent_style = tab
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

Expand Down
21 changes: 10 additions & 11 deletions libraries/botbuilder-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Use the DialogTestClient to drive unit tests of your dialogs.

To create a test client:
```javascript
let client = new DialogTestClient(dialog_to_test, dialog_options, OptionalMiddlewares);
const client = new DialogTestClient('test', dialog_to_test, dialog_options, OptionalMiddlewares);
```

To "send messages" through the dialog:
Expand All @@ -28,7 +28,7 @@ let reply = await client.sendActivity('test');

To check for additional messages:
```javascript
reply = await client.getNextReply();
reply = client.getNextReply();
```

Here is a sample unit test using assert:
Expand All @@ -37,21 +37,21 @@ Here is a sample unit test using assert:
const { DialogTestClient, DialogTestLogger } = require('botbuilder-testing');
const assert = require('assert');

let my_dialog = new SomeDialog();
let options = { ... dialog options ... };
const my_dialog = new SomeDialog();
const options = { ... dialog options ... };

// set up a test client with a logger middleware that logs messages in and out
let client = new DialogTestClient(my_dialog, options, [new DialogTestLogger()]);
const client = new DialogTestClient('test', my_dialog, options, [new DialogTestLogger()]);

// send a test message, catch the reply
let reply = await client.sendActivity('hello');
assert(reply.text == 'hello yourself', 'first message was wrong');
assert.strictEqual(reply.text, 'hello yourself', 'first message was wrong');
// expecting 2 messages in a row?
reply = await client.getNextReply();
assert(reply.text == 'second message', 'second message as wrong');
reply = client.getNextReply();
assert.strictEqual(reply.text, 'second message', 'second message as wrong');

// test end state
assert(client.dialogTurnResult.status == 'empty', 'dialog is not empty');
assert.strictEqual(client.dialogTurnResult.status, 'empty', 'dialog is not empty');
```

[Additional examples are available here](tests/)
Expand All @@ -63,6 +63,5 @@ By default, the transcript will be logged with the `mocha-logger` package. You m
your own logger:

```javascript
let testlogger = new DialogTestLogger(console);
const testlogger = new DialogTestLogger(console);
```

44 changes: 27 additions & 17 deletions libraries/botbuilder-testing/src/dialogTestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,51 @@ export class DialogTestClient {
private readonly _callback: (turnContext: TurnContext) => Promise<void>;
private readonly _testAdapter: TestAdapter;
public dialogTurnResult: DialogTurnResult;
public conversationState: ConversationState;

/**
* Create a DialogTestClient to test a dialog without having to create a full-fledged adapter.
*
*
* ```javascript
* let client = new DialogTestClient(MY_DIALOG, MY_OPTIONS);
* let reply = client.sendActivity('first message');
* assert(reply.text == 'first reply','reply failed');
* let client = new DialogTestClient('test', MY_DIALOG, MY_OPTIONS);
* let reply = await client.sendActivity('first message');
* assert.strictEqual(reply.text, 'first reply', 'reply failed');
* ```
*
*
* @param channelId The channelId to be used for the test.
* Use 'emulator' or 'test' if you are uncertain of the channel you are targeting.
* Otherwise, it is recommended that you use the id for the channel(s) your bot will be using and write a test case for each channel.
* @param testAdapter A list of middlewares to be added to the test adapter.
* @param targetDialog The dialog to be tested. This will be the root dialog for the test client.
* @param initialDialogOptions (Optional) additional argument(s) to pass to the dialog being started.
* @param middlewares (Optional) The test adapter to use. If this parameter is not provided, the test client will use a default TestAdapter
* @param testAdapter (Optional) A list of middlewares to be added to the test adapter.
* @param callback (Optional) The bot turn processing logic for the test. If this value is not provided, the test client will create a default BotCallbackHandler
* @param adapterOptions (Optional) Options passed to TestAdapter that allow customizing behavior such as the channelId. eg {channelId: 'custom'}
* @param conversationState (Optional) A ConversationState instance to use in the test client
*/
public constructor(targetDialog: Dialog, initialDialogOptions?: any, middlewares?: Middleware[], testAdapter?: TestAdapter, callback?: (turnContext: TurnContext) => Promise<void>, adapterOptions?: Partial<Activity>) {
let convoState = new ConversationState(new MemoryStorage());
public constructor(channelId: string, targetDialog: Dialog, initialDialogOptions?: any, middlewares?: Middleware[], conversationState?: ConversationState);
public constructor(testAdapter: TestAdapter, targetDialog: Dialog, initialDialogOptions?: any, middlewares?: Middleware[], conversationState?: ConversationState)
constructor(channelOrAdapter: string|TestAdapter, targetDialog: Dialog, initialDialogOptions?: any, middlewares?: Middleware[], conversationState?: ConversationState) {
this.conversationState = conversationState || new ConversationState(new MemoryStorage());

let dialogState = convoState.createProperty('DialogState');
let dialogState = this.conversationState.createProperty('DialogState');

this._callback = callback || this.getDefaultCallback(targetDialog, initialDialogOptions || null, dialogState);
this._callback = this.getDefaultCallback(targetDialog, initialDialogOptions || null, dialogState);

this._testAdapter = testAdapter || new TestAdapter(this._callback,adapterOptions).use(new AutoSaveStateMiddleware(convoState));
if (typeof channelOrAdapter == 'string') {
const channelIdToUse: string = channelOrAdapter;
this._testAdapter = new TestAdapter(this._callback, {channelId: channelIdToUse}).use(new AutoSaveStateMiddleware(this.conversationState));
} else {
const testAdapterToUse: TestAdapter = channelOrAdapter;
this._testAdapter = testAdapterToUse;
}

this.addUserMiddlewares(middlewares);

}

/**
* Send an activity into the dialog.
* @returns a TestFlow that can be used to assert replies etc
* @param activity an activity potentially with text
*
*
* ```javascript
* DialogTest.send('hello').assertReply('hello yourself').then(done);
* ```
Expand All @@ -65,7 +75,7 @@ export class DialogTestClient {
/**
* Get the next reply waiting to be delivered (if one exists)
*/
public async getNextReply(): Promise<any> {
public getNextReply() {
return this._testAdapter.activityBuffer.shift();
}

Expand All @@ -91,5 +101,5 @@ export class DialogTestClient {
});
}
}

}
28 changes: 10 additions & 18 deletions libraries/botbuilder-testing/tests/dialogTestClient.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ const assert = require('assert');
describe('DialogTestClient', function() {

it('should create a DialogTestClient', async function() {
let client = new DialogTestClient();
let client = new DialogTestClient('test', null);
assert(client instanceof DialogTestClient, 'Created an invalid object');
});

it('should create a DialogTestClient with a custom channelId', async function() {
let client = new DialogTestClient(null, null, null, null, null, {channelId: 'custom'});
let client = new DialogTestClient('custom', null);
assert(client._testAdapter.template.channelId == 'custom', 'Created with wrong channel id');
});


it('should process a single turn waterfall dialog', async function() {

let dialog = new WaterfallDialog('waterfall', [
Expand All @@ -30,16 +29,13 @@ describe('DialogTestClient', function() {
}
]);

let client = new DialogTestClient(dialog, null, null, null, null, {channelId: 'custom'});
let client = new DialogTestClient('test', dialog);
let reply = await client.sendActivity('hello');
assert(reply.text == 'hello', 'dialog responded with incorrect message');
assert(reply.channelId == 'custom', 'custom channel id didnt get set');
assert(reply.channelId == 'test', 'test channel id didnt get set');
assert(client.dialogTurnResult.status == DialogTurnStatus.complete, 'dialog did not end properly');

});



it('should process a 2 turn waterfall dialog', async function() {

let dialog = new WaterfallDialog('waterfall', [
Expand All @@ -54,18 +50,17 @@ describe('DialogTestClient', function() {
},
]);

let client = new DialogTestClient(dialog, null, [new DialogTestLogger()], null, null, {channelId: 'custom'});
let client = new DialogTestClient('test', dialog, null, [new DialogTestLogger()], null, null);
let reply = await client.sendActivity('hello');
assert(reply.text == 'hello', 'dialog responded with incorrect message');
// get typing
reply = await client.getNextReply();
reply = client.getNextReply();
assert(reply.type == 'typing', 'dialog responded with incorrect message');
reply = await client.getNextReply();
reply = client.getNextReply();
assert(reply.text == 'hello 2', 'dialog responded with incorrect 2nd message');
assert(client.dialogTurnResult.status == DialogTurnStatus.complete, 'dialog did not end properly');
});


it('should process a component dialog', async function() {

class MainDialog extends ComponentDialog {
Expand All @@ -81,15 +76,15 @@ describe('DialogTestClient', function() {
return step.next();
},
]);

this.addDialog(dialog);
this.addDialog(new TextPrompt('textPrompt'));
}

async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);

const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
Expand All @@ -98,15 +93,12 @@ describe('DialogTestClient', function() {
}
}


let component = new MainDialog('component');

let client = new DialogTestClient(component,null, [new DialogTestLogger()]);
let client = new DialogTestClient('test', component, null, [new DialogTestLogger()]);
let reply = await client.sendActivity('hello');
assert(reply.text == 'Tell me something','dialog responded with incorrect message');
reply = await client.sendActivity('foo');
assert(reply.text == 'you said: foo', 'dialog responded with incorrect 2nd message');
assert(client.dialogTurnResult.status == DialogTurnStatus.complete, 'dialog did not end properly');
});

});
2 changes: 2 additions & 0 deletions libraries/testbot/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MicrosoftAppId=
MicrosoftAppPassword=
7 changes: 6 additions & 1 deletion libraries/testbot/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
// Licensed under the MIT License.

const restify = require('restify');
const path = require('path');

const { BotFrameworkAdapter, MemoryStorage, UserState, ConversationState, InspectionState, InspectionMiddleware } = require('botbuilder');
const { MicrosoftAppCredentials } = require('botframework-connector');
const { MyBot } = require('./bots/myBot')

const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });

const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
Expand All @@ -17,7 +22,7 @@ var inspectionState = new InspectionState(memoryStorage);
var userState = new UserState(memoryStorage);
var conversationState = new ConversationState(memoryStorage);

adapter.use(new InspectionMiddleware(inspectionState, userState, conversationState));
adapter.use(new InspectionMiddleware(inspectionState, userState, conversationState, new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword)));

adapter.onTurnError = async (context, error) => {
console.error(`\n [onTurnError]: ${ error }`);
Expand Down
5 changes: 5 additions & 0 deletions libraries/testbot/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion libraries/testbot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"license": "MIT",
"dependencies": {
"botbuilder": "^4.1.6",
"restify": "^8.3.0"
"restify": "^8.3.0",
"dotenv": "^6.1.0"
}
}

0 comments on commit ece3485

Please sign in to comment.