Categories:
Debug with mocha and Typescript
How to test an Aura Bot dialog after its development: debug with mocha and Typescript
Introduction
When developing a use case, and once the use case dialog is built, it is required to test the dialog in order to verify its proper performance in terms of the conversational flow between the user and aura-bot.
The current section includes the guidelines to debug with mocha and Typescript for the execution of the unit tests. This corresponds to the stage Test an Aura Bot dialog within the use case development process over aura-bot.
For this purpose, Bot Framework v4 provides a Test Adapter that allows launching unit tests for the validation of a component performance (mainly a dialog, but it can also be used for other components such as middlewares).
The Test Adapter simulates sending messages from the user to the bot, therefore it requires to mock certain data required by the dialog logic (i.e., Kernel data). With this data, the Test Adapter checks that the conversational flow of the dialog is correct. Tests are executed during each Pull Request and must be passed in order to merge the PR.
Requisites
Add the following dependencies (or check that they are declared) in the package.json file, within the use case library.
An extract is shown below as an example.
"devDependencies": {
"@types/mocha": "^6.2.0",
"@types/chai": "^4.2.3",
"@types/jest": "^24.0.20",
"ts-node": "^8.4.1",
"mocha": "^6.2.1",
📌 Find a complete example for the common library in the following Github link.
Debug configuration
The debug configuration is carried out using Visual Studio Code.
📄 For this purpose, read the Visual Studio Code documentation regarding launch configurations.
Debugging information is kept in the file launch.json, included in the folder .vscode of the developer’s workspace. The launch.json file must be included in the same root repository as the corresponding dialog to be tested.
Within this file, the field configuration must be filled with the following content:
{
"type": "node",
"request": "launch",
"name": "Mocha All",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"-r",
"ts-node/register",
"--timeout",
"999999",
"--colors",
"${workspaceFolder}/src/**/*.spec.ts",
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"protocol": "inspector"
}
Execute tests in the Test Adapter
The Test adapter from Bot Framework 4 is used for executing unit tests. This adapter can be used to simulate sending messages from the user to aura-bot.
The following example sets up the test adapter and then executes a simple test:
const { TestAdapter } = require('botbuilder');
const adapter = new TestAdapter(async (context) => {
await context.sendActivity(`Hello World`);
});
adapter.test(`hi`, `Hello World`)
.then(() => done());
Adapter Test Method
At this stage, you can send something to the bot and check the response provided by it.
This is simply a wrapper around calls to send() and assertReply() methods.
adapter.test('hi', 'Hello World')
.then(() => done());
@param userSays: text or activity simulating user’s input.@param expected: expected text or activity sent by the bot as a reply to the user’s input.@param description: (optional) description of the test case. If not provided, one is generated.@param timeout: (optional) number of milliseconds to wait for the bot response. Default value:3000.
public test(
userSays: string | Partial<Activity>,
expected: string | Partial<Activity> | ((activity: Partial<Activity>, description?: string) => void),
description?: string,
timeout?: number
): TestFlow {
return this.send(userSays)
.assertReply(expected, description);
}
An example is shown below:
const { TestAdapter } = require('botbuilder');
const adapter = new TestAdapter(async (context) => {
if (context.text === 'hi') {
await context.sendActivity(`Hello World`);
} else if (context.text === 'bye') {
await context.sendActivity(`Goodbye`);
}
});
adapter.test(`hi`, `Hello World`)
.test(`bye`, `Goodbye`)
.then(() => done())
.catch(e) => done(e));
Adapter Send and AssertReply methods
Send
This method sends something to aura-bot. It returns a new TestFlow instance which can be used to add additional steps for inspecting the bot reply and then sending additional activities.
📄 For further details, please check the corresponding the TestAdapter class documentation.
-
@param userSays: text or activity simulating user input.public send(userSays: string | Partial<Activity>): TestFlow
assertReply
This method generates an assertion if the aura-bot response does not match the expected text/activity.
@param expected: expected text or activity from the bot. It can be a callback to inspect the response using custom logic.@param description: (optional) description of the test case. If not provided, one is generated.@param timeout: (optional) number of milliseconds to wait for a bot response. The default value is3000.
public assertReply(expected: string | Partial<Activity> | estActivityInspector, description?: string, timeout?: number): TestFlow
An example is shown below:
const { TestAdapter } = require('botbuilder');
const adapter = new TestAdapter(async (context) => {
if (context.text === 'hi') {
await context.sendActivity(`Hello World`);
} else if (context.text === 'bye') {
await context.sendActivity(`Goodbye`);
}
});
adapter.send(`hi`,
.assertReply(`Hello World`)
.send(`bye`)
.assertReply(`Goodbye`)
.then(() => done())
.catch(e) => done(e));
Check values in the current activity
Execute the following command:
.assertReply(activity => assert.equal(activity.type, ActivityTypes.Message))
An example is shown below:
await adapter.send('Hello')
.assertReply(activity => {
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);
let eventActivity = createReply(activity);
eventActivity.type = ActivityTypes.Event;
let from = eventActivity.from;
eventActivity.from = eventActivity.recipient;
eventActivity.recipient = from;
eventActivity.name = "tokens/response";
eventActivity.value = {
connectionName,
token
};
adapter.send(eventActivity);
})
.assertReply('Logged in.');