@telefonica/la-bot-testing
TypeScript icon, indicating that this package has built-in type declarations

2.0.1 • Public • Published

la-bot-sdk

Testing Library for Living Apps bots

1. Usage

1.1. Install

Set up the dependencies in package.json as follows:

"devDependencies": {
    "@telefonica/la-bot-testing": "^1.0.0-alpha.1",
    "botbuilder-testing": "~4.6.2"
}

Now run npm install.

1.2. Initialization

The Living App testing library needs to be initialized prior to any test launch. The best way to do this is with a beforeEach hook where the beginTesting function is called. This function takes as parameters:

  • an object with partial LivingApp info, at least having the livingApp name and library name, which are required to correctly initialize the dialogs
  • an optional user object, in case you want to configure specific user data
import * as sdk from '@telefonica/la-bot-testing';

beforeEach(() => {
    sdk.beginTesting({ name: 'your-living-app', libraryName: 'your-living-app' });
});

This will allow your tests to be default-initialized and ready for normal dialog flow.

1.3 Normal Testing

import { Channel } from '@telefonica/la-bot-testing';
import * as sdk from '@telefonica/la-bot-testing';
import { DialogTestClient } from 'botbuilder-testing';

import MyDialog from '../../src/dialogs/dialog';
import { ChoiceOperation, RedirectIntent, Screen, SessionData } from '../../src/models';

describe('MyDialog dialog', () => {
    test('MyDialog - no entity & no persistence', async (done) => {
        // Load the dialog with env vars from settings/.env; This can be overrided
        // with specific config entries:
        // { ...sdk.loadConfig('settings/.env), MY_LIVING_APP_CONFIG_ENTRY: "mock://host" }
        const dialog = new MyDialog(sdk.loadConfig('settings/.env'));
        const client = new DialogTestClient('test', dialog, {});
        let messages;

        // We set the intent and entities (if any) that should lead to this dialog
        sdk.setIntent({
            intent: RedirectIntent.HOME,
            entities: [],
        });

        // We set the active channel, the one that would have initialized the request
        sdk.setActiveChannel(Channel.STBH);
        await client.sendActivity('');

        // The dialog has been executed until the first prompt, we can process the
        // messages per channel and assert anything we want
        messages = sdk.getChannelMessages(Channel.STBH);
        expect(messages).toHaveLength(1);
        messages = sdk.getChannelMessages(Channel.MH);
        expect(messages).toHaveLength(1);

        // We can do the same with the SessionData contents
        const sessionData = sdk.getSessionData() as SessionData;
        expect(sessionData.currentOffer).toBe(0);
        expect(sessionData.origin).toBeUndefined();

        // And with the cross-session persistence too
        const persistence = sdk.getPersistenceData();
        expect(persistence.origin).toBeUndefined();

        done();
    });
}

1.4 Advanced Features

There are several advanced features available in case normal flow is not enough.

Channel Configuration

  • function setActiveChannel(channel: Channel): void;
    • As we have seen in the normal example, this sets the requesting channel
  • function resetChannels(): void;
    • This clears the channels from the session, so there are no active channels joined
  • function joinChannel(channel: Channel, state: State = State.STABLE): void;
    • This sets an active channel in one of three possible states: JOINING (useful when testing a start dialog), JOINED (useful when testing what happens when a channel has just joined), STABLE (useful when you do not want to test joining of channels). Remember that a JOINED channel only sends the first message after joining to itself, since this is the joining dispatcher behaviour.
  • function removeChannel(channel: Channel): void;
    • Removes a specific channel from the session.
  • function getChannelActivities(name: Channel): Partial[];
    • Allows you to get the full activities instead of the la-data attachment

Logging configuration

  • function setLoggingOutput(state: boolean): void;
    • Activates logging output to console (default offline)
  • function getBotLogs(): string[];
    • Gives you any log generated by the dialog

Session handling

  • function getSession(): DeepPartial;
    • This will allow you to modify the session object, which usually is not a good idea.

Persistence and SessionData reset

  • function clearSessionData(): void;
  • function clearPersistenceData(): void

Example: Start Dialog testing

import { Channel, State } from '@telefonica/la-bot-testing';
import * as sdk from '@telefonica/la-bot-testing';
import { DialogTestClient } from 'botbuilder-testing';

import MyLivingAppStartDialog from '../../src/dialogs/dialog-la-start';

beforeEach(() => {
    sdk.beginTesting({ name: 'your-living-app', libraryName: 'your-living-app' });
});

describe('Start dialogs', () => {
    test('stbh => mh', async (done) => {
        const dialog = new MyLivingAppStartDialog({});
        const client = new DialogTestClient('test', dialog, {});
        let messages, activity;

        sdk.resetChannels();
        sdk.setIntent({
            intent: 'intent.internal.living-app.start',
            entities: [{ type: 'ent.living_app_name', entity: 'your-living-app' }],
        });

        // First channel to join will be STBH
        sdk.setActiveChannel(Channel.STBH);
        sdk.joinChannel(Channel.STBH, State.JOINING);
        await client.sendActivity('');

        // Only STBH should have message
        messages = sdk.getChannelMessages(Channel.STBH);
        expect(messages).toHaveLength(1);
        expect(messages[0]).toHaveProperty('activeChannels', [Channel.STBH]);
        messages = sdk.getChannelMessages(Channel.MH);
        expect(messages).toHaveLength(0);

        // Only STBH should have activity and no text/html attachment
        activity = sdk.getChannelActivities(Channel.STBH)[0];
        expect(activity.attachments.find((att) => att.contentType === 'text/html')).toBeUndefined();
        activity = sdk.getChannelActivities(Channel.MH)[0];
        expect(activity).toBeUndefined();

        // We clear the messages so we don't have complexity when asserting them
        sdk.clearMessages();

        // Now MH joins the session
        sdk.setActiveChannel(Channel.MH);
        sdk.joinChannel(Channel.MH, State.JOINING);
        await client.sendActivity('');

        // Only MH should have message
        messages = sdk.getChannelMessages(Channel.MH);
        expect(messages).toHaveLength(1);
        expect(messages[0]).toHaveProperty('activeChannels', [Channel.STBH, Channel.MH]);
        messages = sdk.getChannelMessages(Channel.STBH);
        expect(messages).toHaveLength(0);

        // Only MH shoudl have activity, but with no text/html attachment, since STBH is already joined
        activity = sdk.getChannelActivities(Channel.MH)[0];
        expect(activity.attachments.find((att) => att.contentType === 'text/html')).toBeUndefined();
        activity = sdk.getChannelActivities(Channel.STBH)[0];
        expect(activity).toBeUndefined();

        done();
    });

    test('mh => stbh', async (done) => {
        const dialog = new MyLivingAppStartDialog({});
        const client = new DialogTestClient('test', dialog, {});
        let messages, activity;

        sdk.resetChannels();
        sdk.setIntent({
            intent: 'intent.internal.living-app.start',
            entities: [{ type: 'ent.living_app_name', entity: 'your-living-app' }],
        });

        sdk.setActiveChannel(Channel.MH);
        sdk.joinChannel(Channel.MH, State.JOINING);
        await client.sendActivity('');

        messages = sdk.getChannelMessages(Channel.MH);
        expect(messages).toHaveLength(1);
        expect(messages[0]).toHaveProperty('activeChannels', [Channel.MH]);
        messages = sdk.getChannelMessages(Channel.STBH);
        expect(messages).toHaveLength(0);

        // In this case, since MH joins first, the text/html attachment IS defined
        activity = sdk.getChannelActivities(Channel.MH)[0];
        expect(activity.attachments.find((att) => att.contentType === 'text/html')).toHaveProperty('contentUrl');
        activity = sdk.getChannelActivities(Channel.STBH)[0];
        expect(activity).toBeUndefined();

        sdk.clearMessages();

        sdk.setActiveChannel(Channel.STBH);
        sdk.joinChannel(Channel.STBH, State.JOINING);
        await client.sendActivity('');

        messages = sdk.getChannelMessages(Channel.STBH);
        expect(messages).toHaveLength(1);
        expect(messages[0]).toHaveProperty('activeChannels', [Channel.MH, Channel.STBH]);
        messages = sdk.getChannelMessages(Channel.MH);
        expect(messages).toHaveLength(0);

        activity = sdk.getChannelActivities(Channel.MH)[0];
        expect(activity).toBeUndefined();
        activity = sdk.getChannelActivities(Channel.STBH)[0];
        expect(activity.attachments.find((att) => att.contentType === 'text/html')).toBeUndefined();

        done();
    });
});

Readme

Keywords

none

Package Sidebar

Install

npm i @telefonica/la-bot-testing

Weekly Downloads

1

Version

2.0.1

License

ISC

Unpacked Size

48.3 kB

Total Files

5

Last publish

Collaborators

  • tdaf
  • aura
  • living-apps
  • lifecyle-novum