umbot
    Preparing search index...

    Testing your project

    This page is machine-translated from the Russian original. If something reads oddly, the Russian version is the source of truth — open an issue.

    Go to the developer console and open the testing tab. This applies to Alice. For other platforms, the link is entered in the corresponding developer console.

    You do not need to deploy a server to debug!

    Testing uses the same code as running the application. The only difference is that you use the BotTest class instead of Bot.

    import { BotTest } from 'umbot/test';
    import { fullPlatforms } from 'umbot/plugins';

    const bot = new BotTest();
    bot.use(fullPlatforms); // register platforms — without them test() does not know which format to use
    await bot.test(); // starts the interactive console

    You start it like this:

    npm run build && npm run start
    # or run the built file directly (a standard CLI project puts the code into dist/)
    node ./dist/index.js

    A console with your application opens. To exit the testing mode:

    1. If the skill sets isEnd = true at some point (ending the dialog), reach that point in the scenario.
    2. Enter the exit command.
    • When bot.test() starts, it automatically sends the first message 'Привет' (simulating a session start with messageId === 0).
    • After that you type text manually, and the bot replies the same way it would on the real platform.
    • To exit, type exit or close the terminal. The session also ends automatically if the bot sets isEnd = true.
    • appMode is forced to 'dev' (unless strict_prod is set explicitly).
    • Processing is the same as in production — you test the real logic.

    By default BotTest works with the "auto" platform: when test() and simulate() are called without an explicit platform, the first registered one is used (with fullPlatforms this is Alice). A platform passed to the constructor takes priority for test()/simulate() — but the adapter itself still has to be registered with bot.use(...). run() behaves differently: without an explicit appType it always uses 'alisa', even if the constructor specifies another platform, so pass appType explicitly: bot.run('telegram', ...).

    import { BotTest } from 'umbot/test';
    import { fullPlatforms } from 'umbot/plugins';

    // The priority platform is Telegram
    const bot = new BotTest('telegram');
    bot.use(fullPlatforms);
    import { BotTest } from 'umbot/test';
    import { fullPlatforms } from 'umbot/plugins';

    // The priority platform is Alice
    const bot = new BotTest('alisa');
    bot.use(fullPlatforms);

    The platform you test must be registered with bot.use(...) — otherwise BotTest will not find its adapter.

    An IBotTestParams object with display settings is passed to test():

    Parameter Type Default Description
    isShowResult boolean false Show the full platform response as JSON
    isShowStorage boolean false Show the storage data (userData and state)
    isShowTime boolean true Show the request processing time in ms
    const bot = new BotTest();

    // Extended testing with all data shown
    await bot.test({
    isShowResult: true, // Show the platform's JSON response
    isShowStorage: true, // Show user and storage data
    isShowTime: true, // Show the processing time
    });
    import { BotTest } from 'umbot/test';
    import { TelegramAdapter } from 'umbot/plugins';

    const bot = new BotTest('telegram');

    bot.use(new TelegramAdapter('your-token'));
    bot.setPlatformParams({
    intents: [
    {
    name: 'greeting',
    slots: ['hello', 'hi'],
    },
    ],
    });

    bot.initBotController(MyController);

    await bot.test({
    isShowResult: true,
    isShowStorage: true,
    });

    BotTest can be used in unit tests to check the logic:

    import { BotTest } from 'umbot/test';
    import { fullPlatforms } from 'umbot/plugins';
    import { MyController } from './MyController';

    describe('MyController', () => {
    it('should greet user', async () => {
    const bot = new BotTest();
    bot.use(fullPlatforms); // without a registered platform run() throws an error
    bot.initBotController(MyController);

    // Run request handling. Important: the payload must be valid for the platform —
    // the adapter checks the structure (for example, Alice requires session + request),
    // otherwise setQueryData() returns false and the request is rejected
    const result = await bot.run(
    'alisa',
    JSON.stringify({
    version: '1.0',
    session: { message_id: 0, user_id: 'test-user' },
    request: { command: 'hello', original_utterance: 'Hello' },
    }),
    );

    // Check the result — check the content rather than just its presence
    expect(result).toBeDefined();
    expect(JSON.stringify(result)).toContain('Hello');
    });
    });

    Instead of building a platform JSON request by hand, you can use simulate() — it generates a valid payload for the given platform and calls run():

    import { BotTest } from 'umbot/test';
    import { AlisaAdapter, T_ALISA } from 'umbot/plugins';

    const bot = new BotTest();
    bot.use(new AlisaAdapter());
    bot.addCommand('start', ['hello'], (_, ctx) => {
    ctx.text = 'Hello!';
    });

    // Voice platform: the result is the ready platform JSON response
    const res = (await bot.simulate('hello', { platform: T_ALISA })) as {
    response: { text: string };
    };
    console.log(res.response.text); // 'Hello!'

    For chat platforms (Telegram, VK, Viber, Max), simulate() enables skipAutoReply, so no message is actually sent to the platform API — even if no token is set:

    import { BotTest } from 'umbot/test';
    import { TelegramAdapter, T_TELEGRAM } from 'umbot/plugins';

    const bot = new BotTest();
    bot.use(new TelegramAdapter('your-token'));
    bot.addCommand('start', ['hello'], (_, ctx) => {
    ctx.text = 'Hello!';
    });

    // For chat platforms the result is 'ok' (sending is skipped),
    // and the response text stays in the controller
    await bot.simulate('hello', { platform: T_TELEGRAM });
    console.log(bot.getBotController()?.text); // 'Hello!'

    simulate(query, options) parameters:

    Parameter Type Default Description
    query string — User text
    options.platform TAppType the constructor's platform or the first registered The platform to generate the request for
    options.userId string 'test_user' User ID
    options.count number 0 Message number (0 — a new user/session)
    options.state object | string {} Prefilled session state

    The method returns the same result as run(): a JSON response for voice platforms, and the string 'ok' for chat platforms, since sending to the API is skipped in simulation mode.

    A more detailed example with platform setup and response checks:

    import { BotTest } from 'umbot/test';
    import { fullPlatforms, T_ALISA } from 'umbot/plugins';
    import { MyController } from '../../src/controller/MyController';

    describe('MyController', () => {
    let bot: BotTest;

    beforeAll(() => {
    bot = new BotTest();
    bot.use(fullPlatforms);
    bot.setAppConfig({ isLocalStorage: true });
    bot.setPlatformParams({
    welcome_text: 'Hello!',
    intents: [{ name: 'help', slots: ['help'] }],
    });
    bot.initBotController(MyController);
    });

    it('handles welcome', async () => {
    const result = await bot.run(
    T_ALISA,
    JSON.stringify({
    version: '1.0',
    session: { message_id: 0, user_id: 'test-user' },
    request: { command: 'hello', original_utterance: 'Hello' },
    }),
    );
    expect(result).toBeDefined();
    });

    it('handles help command', async () => {
    const result = await bot.run(
    T_ALISA,
    JSON.stringify({
    version: '1.0',
    session: { message_id: 1, user_id: 'test-user' },
    request: { command: 'help', original_utterance: 'Help' },
    }),
    );
    expect(result).toBeDefined();
    });
    });

    To keep tests off the network and the disk, replace the context's HTTP client and FileAdapter file reading:

    import { BotTest } from 'umbot/test';
    import { fullPlatforms, FileAdapter } from 'umbot/plugins';

    const bot = new BotTest();
    bot.use(fullPlatforms);

    // HTTP client mock: requests to platform APIs and external services do not go to the network
    bot.getAppContext().httpClient = (): Promise<Response> =>
    Promise.resolve(new Response(JSON.stringify({ ok: true, result: {} }), { status: 200 }));

    // File database mock: tables are read from memory, not from disk
    const tables: Record<string, Record<string, Record<string, unknown>>> = { UsersData: {} };
    const adapter = new FileAdapter();
    adapter.getFileData = (tableName) => {
    const data = (tables[tableName] ??= {});
    adapter.setCachedFileData(tableName, { data, version: Date.now(), isFileRead: true });
    return data;
    };
    bot.use(adapter);
    Approach When to use What you get
    bot.test() Interactive debugging in the console A real-time dialog, you type the text yourself
    bot.run(appType, content) Automated tests (Jest) Programmatic access to the result, you can write assertions
    bot.setContent() + bot.run() Testing with preset content Convenient for repeated tests

    Recommendation: use bot.run() for Jest tests — it gives you full control over the input and lets you check the result.

    You can exit the testing mode in two ways:

    1. Type exit in the console
    2. If the controller set this.isEnd = true, the dialog ends automatically

    Depending on the options, BotTest prints:

    • Response: the application's text response (response.text for voice platforms, text for chatbots)
    • Platform-format response (with isShowResult: true): the full JSON response
    • Database data (with isShowStorage: true): the contents of userData and state
    • Processing time (with isShowTime: true): request processing time in milliseconds
    • Debugging logic
    • Measuring speed
    • Automated unit tests