UNPKG

botbuilder-unit

Version:
171 lines (149 loc) 5.56 kB
"use strict"; const FINISH_TIMEOUT = 20; const DEFAULT_TEST_TIMEOUT = 10000; const SrcBasePath = process.env.BOTBUILDERUNIT_USE_INSTRUMENTED_SOURCE || './src'; const MessageFactory = require(SrcBasePath + '/ScriptStepFactory'); const PlainLogReporter = require(SrcBasePath + '/log-reporters/PlainLogReporter'); const EmptyLogReporter = require(SrcBasePath + '/log-reporters/EmptyLogReporter'); const BeautyLogReporter = require(SrcBasePath + '/log-reporters/BeautyLogReporter'); const BotMessage = require(SrcBasePath + '/messages/BotMessage'); const UserMessage = require(SrcBasePath + '/messages/UserMessage'); const SessionMessage = require(SrcBasePath + '/messages/SessionMessage'); const SetDialogMessage = require(SrcBasePath + '/messages/SetDialogMessage'); const TestConnector = require(SrcBasePath + '/TestConnector'); const detectReporter = require(SrcBasePath + '/detectReporter') const builder = require('botbuilder'); /** * Wraps arrays and functions into instance of UniversalBot * Ensure that given bot has connector, otherwise inject TestConnector * * @param bot * @returns {*} */ function resolveBot(bot) { let isWaterfall = ("function" == typeof bot) || Array.isArray(bot); if (isWaterfall) { let dialog = bot; let connector = new TestConnector(); bot = new builder.UniversalBot(connector); bot.dialog('/', dialog); } else if (bot instanceof builder.UniversalBot) { if ( !bot.connector()) { bot.connector('console', new TestConnector()); } } else { throw new Error(`Unknown type of bot/dialog. Error: ${JSON.stringify(bot)}`); } return bot; } function testBot(bot, messages, options) { function getLogReporter() { return options.reporter; } bot = resolveBot(bot); options = Object.assign({ timeout: module.exports.config.timeout, reporter: module.exports.config.reporter, title: '' }, options); messages = messages.slice(0); return new Promise(function (resolve, reject) { var step = 0; var finished = false; function done() { finished = true; getLogReporter().scriptFinished(); resolve(); } function fail(err) { if (!finished) { getLogReporter().error("Script failed with error:", err); } finished = true; reject(err); } /** * Convert script steps into promises, each step executed after previous * botmessage depends on previous step and bot response * customessage depends on previous step * session message depends on previous step * set dialog message depends on previous step * user message dependes on previos step */ function startTesting() { getLogReporter().newScript(messages, options.title); let startTestingAction = null; let prevStepFinishedPromise = new Promise((resolve, reject) => { startTestingAction = resolve; }); let logReporter = getLogReporter(); messages.forEach((item, i) => { // Where: // i - step // this - is actual config of step let scriptStep = MessageFactory(i, item, bot, logReporter, prevStepFinishedPromise); messages[i] = scriptStep; prevStepFinishedPromise = scriptStep.getStepFinishedPromise() prevStepFinishedPromise.then(() => { step = i; }, fail) }); prevStepFinishedPromise.then(done, fail); startTestingAction(); } function setupTimeout() { if (options.timeout) { setTimeout(() => { if (!finished) { let msg = `Default timeout (${options.timeout}) exceeded`; fail(msg); } }, options.timeout); } } function setupReplyReceiver() { let extraMessageIndex = messages.length; bot.on('send', function (message) { let found = false; messages.some((step) => { // // As bot could send multiple messages sequentially, next code tries to // secure library from the case when two or more replies will be received by // one step let botReplyFunc = step.receiveBotReply; if (botReplyFunc) { step.receiveBotReply = false; botReplyFunc.call(step, message); found = true; return -1; } }) if (!found) { getLogReporter().messageReceived(extraMessageIndex, message) getLogReporter().warning(`Warning at EXTRA STEP ${extraMessageIndex}`, 'Ignoring message (Out of Range)'); extraMessageIndex++; // As more messages could appear, I suppose that is better to track them setTimeout(done, FINISH_TIMEOUT); } }); } setupTimeout(); setupReplyReceiver(); startTesting(); }) } module.exports = testBot; module.exports.config = { timeout: process.env.BOTBUILDERUNIT_TEST_TIMEOUT ? process.env.BOTBUILDERUNIT_TEST_TIMEOUT : DEFAULT_TEST_TIMEOUT, reporter: detectReporter(process.env.BOTBUILDERUNIT_REPORTER) }; module.exports.PlainLogReporter = PlainLogReporter; module.exports.BeautyLogReporter = BeautyLogReporter; module.exports.EmptyLogReporter = EmptyLogReporter; module.exports.ConversationMock = require(SrcBasePath + '/ConversationMock'); module.exports.BotMessage = BotMessage; module.exports.UserMessage = UserMessage; module.exports.SetDialogMessage = SetDialogMessage; module.exports.SessionMessage = SessionMessage; module.exports.TestConnector = TestConnector; module.exports.DEFAULT_ADDRESS = SessionMessage.DEFAULT_ADDRESS;