botium-core 1.14.8 → 1.14.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,10 +13,6 @@
13
13
 
14
14
  **_IF YOU LIKE WHAT YOU SEE, PLEASE CONSIDER GIVING US A STAR ON GITHUB!_**
15
15
 
16
- **UPDATE 2020/11/05:** Botium has a FREE, hosted plan available! The new Botium Box Mini is our ❤️ to the community. [Take it for a test drive 🚗 ...](https://www.botium.ai/pricing/)
17
-
18
- [![](http://img.youtube.com/vi/ciVxojvRfng/0.jpg)](https://www.youtube.com/watch?v=ciVxojvRfng "Botium Box Mini")
19
-
20
16
  ## Getting Help
21
17
 
22
18
  See our [Botium Forum](https://forum.botium.ai/)
@@ -77,7 +77,7 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
77
77
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
78
78
 
79
79
  var name = "botium-core";
80
- var version$1 = "1.14.8";
80
+ var version$1 = "1.14.10";
81
81
  var description = "The Selenium for Chatbots";
82
82
  var main = "index.js";
83
83
  var module$1 = "dist/botium-es.js";
@@ -140,6 +140,7 @@ var dependencies = {
140
140
  "socketio-auth": "^0.1.1",
141
141
  "swagger-jsdoc": "^6.2.8",
142
142
  "swagger-ui-express": "^5.0.0",
143
+ tinyglobby: "^0.2.10",
143
144
  uuid: "^9.0.1",
144
145
  "word-error-rate": "0.0.7",
145
146
  "write-yaml": "^1.0.0",
@@ -1124,9 +1125,9 @@ var LogicHookUtils_1 = class LogicHookUtils {
1124
1125
  caps
1125
1126
  }) {
1126
1127
  this.asserters = {};
1127
- this.globalAsserters = [];
1128
+ this.globalAsserterNames = [];
1128
1129
  this.logicHooks = {};
1129
- this.globalLogicHooks = [];
1130
+ this.globalLogicHookNames = [];
1130
1131
  this.userInputs = {};
1131
1132
  this.buildScriptContext = buildScriptContext;
1132
1133
  this.caps = caps;
@@ -1159,7 +1160,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1159
1160
  }
1160
1161
  this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter');
1161
1162
  if (asserter.global) {
1162
- this.globalAsserters.push(asserter.ref);
1163
+ this.globalAsserterNames.push(asserter.ref);
1163
1164
  }
1164
1165
  });
1165
1166
  }
@@ -1170,7 +1171,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1170
1171
  }
1171
1172
  this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logichook');
1172
1173
  if (logicHook.global) {
1173
- this.globalLogicHooks.push(logicHook.ref);
1174
+ this.globalLogicHookNames.push(logicHook.ref);
1174
1175
  }
1175
1176
  });
1176
1177
  }
@@ -1182,11 +1183,17 @@ var LogicHookUtils_1 = class LogicHookUtils {
1182
1183
  this.userInputs[userInput.ref] = this._loadClass(userInput, 'userinput');
1183
1184
  });
1184
1185
  }
1185
- getGlobalAsserter() {
1186
- return this.globalAsserters.map(name => this.asserters[name]);
1186
+ getGlobalAsserters() {
1187
+ return this.globalAsserterNames.reduce((agg, name) => ({
1188
+ ...agg,
1189
+ [name]: this.asserters[name]
1190
+ }), {});
1187
1191
  }
1188
- getGlobalLogicHook() {
1189
- return this.globalLogicHooks.map(name => this.logicHooks[name]);
1192
+ getGlobalLogicHooks() {
1193
+ return this.globalLogicHookNames.reduce((agg, name) => ({
1194
+ ...agg,
1195
+ [name]: this.logicHooks[name]
1196
+ }), {});
1190
1197
  }
1191
1198
  _loadClass({
1192
1199
  src,
@@ -1970,12 +1977,6 @@ const validateConvo$2 = convo => {
1970
1977
  if (optionalSet.size > 1) {
1971
1978
  validationResult.errors.push(new Error(`Step ${i + 1}: Failed to decompile conversation. Mixed optional flag is not allowed inside one step.`));
1972
1979
  }
1973
- if (optionalSet.size === 1 && optionalSet.has(true)) {
1974
- const nextStep = convo.conversation[i + 1];
1975
- if (!nextStep || nextStep.sender !== 'bot') {
1976
- validationResult.errors.push(new Error(`Step ${i + 1}: Optional bot convo step has to be followed by a bot convo step.`));
1977
- }
1978
- }
1979
1980
  }
1980
1981
  if (!validateSender$1(step.sender)) {
1981
1982
  validationResult.errors.push(new Error(`Step ${i + 1}: Sender #${step.sender} is invalid.`));
@@ -2019,6 +2020,10 @@ const convoStepToLines$2 = step => {
2019
2020
  } else {
2020
2021
  if (step.messageText) {
2021
2022
  lines.push((step.optional ? '?' : '') + (step.not ? '!' : '') + step.messageText);
2023
+ } else {
2024
+ if (step.optional) {
2025
+ lines.push('?');
2026
+ }
2022
2027
  }
2023
2028
  if (step.buttons && step.buttons.length > 0) lines.push('BUTTONS' + _formatAppendArgs(step.buttons.filter(b => b.text).map(b => flatString(b.text))));
2024
2029
  if (step.media && step.media.length > 0) lines.push('MEDIA' + _formatAppendArgs(step.media.filter(m => !m.buffer && m.mediaUri).map(m => m.mediaUri)));
@@ -2978,6 +2983,10 @@ class Convo$6 {
2978
2983
  let skipTranscriptStep = false;
2979
2984
  let conditionalGroupId = null;
2980
2985
  let conditionMetInGroup = false;
2986
+ let skipOptionalStep = false;
2987
+ // If there are optional step(s) in the conversation, and the message from the bot fails on each optional bot step(s) and/or mandatory bot step, then we have an unexpected message.
2988
+ // So in this case an unexpected error should be shown instead of the latest assertion error.
2989
+ let optionalStepAssertionError = false;
2981
2990
  let globalConvoStepParameters = container.caps[Capabilities.SCRIPTING_CONVO_STEP_PARAMETERS] || {};
2982
2991
  let retryBotMessageTimeoutEnd = null;
2983
2992
  let retryBotMessageConvoId = null;
@@ -2985,6 +2994,13 @@ class Convo$6 {
2985
2994
  for (let i = 0; i < this.conversation.length; i = retryBotMessageDropBotResponse ? i : i + 1) {
2986
2995
  retryBotMessageDropBotResponse = false;
2987
2996
  const convoStep = this.conversation[i];
2997
+ if (!convoStep.optional) {
2998
+ skipOptionalStep = false;
2999
+ }
3000
+ if (convoStep.optional && skipOptionalStep) {
3001
+ // If there are multiple optional steps, and the previous optional step was timeout, then the next optional step should be skipped to prevent too long convo run with multiple timeout.
3002
+ continue;
3003
+ }
2988
3004
  const rawConvoStepParameters = convoStep.logicHooks.find(lh => lh.name === 'CONVO_STEP_PARAMETERS')?.args;
2989
3005
  let convoStepParameters = {};
2990
3006
  if (rawConvoStepParameters && rawConvoStepParameters.length) {
@@ -3161,7 +3177,7 @@ class Convo$6 {
3161
3177
  });
3162
3178
  transcriptStep.botBegin = new Date();
3163
3179
  if (!botMsg) {
3164
- botMsg = await container.WaitBotSays(convoStep.channel);
3180
+ botMsg = await container.WaitBotSays(convoStep.channel, convoStepParameters?.stepTimeout);
3165
3181
  }
3166
3182
  transcriptStep.botEnd = new Date();
3167
3183
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
@@ -3169,6 +3185,10 @@ class Convo$6 {
3169
3185
  debug$k(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3170
3186
  } catch (err) {
3171
3187
  transcriptStep.botEnd = new Date();
3188
+ if (!(err.message.indexOf('Bot did not respond within') < 0) && convoStep.optional) {
3189
+ skipOptionalStep = true;
3190
+ continue;
3191
+ }
3172
3192
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error waiting for bot - ${err.message}`, err);
3173
3193
  debug$k(failErr);
3174
3194
  try {
@@ -3250,6 +3270,7 @@ class Convo$6 {
3250
3270
  }
3251
3271
  waitForBotSays = false;
3252
3272
  skipTranscriptStep = true;
3273
+ optionalStepAssertionError = true;
3253
3274
  return true;
3254
3275
  } else if (retryOn) {
3255
3276
  if (!retryBotMessageTimeoutEnd || retryBotMessageConvoId !== convoStep.stepTag) {
@@ -3267,9 +3288,18 @@ class Convo$6 {
3267
3288
  }
3268
3289
  }
3269
3290
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
3270
- assertErrors.push(err);
3291
+ if (optionalStepAssertionError) {
3292
+ optionalStepAssertionError = false;
3293
+ assertErrors.push(new BotiumError$2(`${this.header.name}: Unexpected message.`));
3294
+ } else {
3295
+ assertErrors.push(err);
3296
+ }
3271
3297
  return false;
3272
3298
  } else {
3299
+ if (optionalStepAssertionError) {
3300
+ optionalStepAssertionError = false;
3301
+ throw new BotiumError$2(`${this.header.name}: Unexpected message.`);
3302
+ }
3273
3303
  throw err;
3274
3304
  }
3275
3305
  };
@@ -3283,6 +3313,7 @@ class Convo$6 {
3283
3313
  if (convoStep.not) {
3284
3314
  try {
3285
3315
  this.scriptingEvents.assertBotNotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters);
3316
+ optionalStepAssertionError = false;
3286
3317
  } catch (err) {
3287
3318
  if (isErrorHandledWithOptionConvoStep(err)) {
3288
3319
  continue;
@@ -3291,6 +3322,7 @@ class Convo$6 {
3291
3322
  } else {
3292
3323
  try {
3293
3324
  this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters);
3325
+ optionalStepAssertionError = false;
3294
3326
  } catch (err) {
3295
3327
  if (isErrorHandledWithOptionConvoStep(err)) {
3296
3328
  continue;
@@ -3300,6 +3332,7 @@ class Convo$6 {
3300
3332
  } else if (convoStep.sourceData) {
3301
3333
  try {
3302
3334
  this._compareObject(container, scriptingMemory, convoStep, botMsg.sourceData, convoStep.sourceData, botMsg, convoStepParameters);
3335
+ optionalStepAssertionError = false;
3303
3336
  } catch (err) {
3304
3337
  if (isErrorHandledWithOptionConvoStep(err)) {
3305
3338
  continue;
@@ -3326,11 +3359,13 @@ class Convo$6 {
3326
3359
  transcript,
3327
3360
  transcriptStep
3328
3361
  });
3362
+ optionalStepAssertionError = false;
3329
3363
  } catch (err) {
3330
3364
  const nextConvoStep = this.conversation[i + 1];
3331
3365
  if (convoStep.optional && nextConvoStep && nextConvoStep.sender === 'bot') {
3332
3366
  waitForBotSays = false;
3333
3367
  skipTranscriptStep = true;
3368
+ optionalStepAssertionError = true;
3334
3369
  continue;
3335
3370
  }
3336
3371
  const errors = err.toArray ? err.toArray() : [];
@@ -3359,8 +3394,17 @@ class Convo$6 {
3359
3394
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3360
3395
  } catch (failErr) {}
3361
3396
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$2) {
3362
- assertErrors.push(err);
3397
+ if (optionalStepAssertionError) {
3398
+ optionalStepAssertionError = false;
3399
+ assertErrors.push(new BotiumError$2(`${this.header.name}: Unexpected message.`));
3400
+ } else {
3401
+ assertErrors.push(err);
3402
+ }
3363
3403
  } else {
3404
+ if (optionalStepAssertionError) {
3405
+ optionalStepAssertionError = false;
3406
+ throw new BotiumError$2(`${this.header.name}: Unexpected message.`);
3407
+ }
3364
3408
  throw failErr;
3365
3409
  }
3366
3410
  }
@@ -5561,9 +5605,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
5561
5605
  this.utterances = {};
5562
5606
  this.matchFn = null;
5563
5607
  this.asserters = {};
5564
- this.globalAsserter = {};
5608
+ this.globalAsserters = {};
5565
5609
  this.logicHooks = {};
5566
- this.globalLogicHook = {};
5610
+ this.globalLogicHooks = {};
5567
5611
  this.userInputs = {};
5568
5612
  this.partialConvos = {};
5569
5613
  this.scriptingMemories = [];
@@ -5932,7 +5976,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
5932
5976
  return p(this.retryHelperAsserter, () => asserter[asserterType](params));
5933
5977
  }
5934
5978
  };
5935
- const convoAsserter = asserters.filter(a => this.asserters[a.name][asserterType]).map(a => ({
5979
+ const localAsserters = (asserters || []).filter(a => this.asserters[a.name][asserterType]);
5980
+ const convoStepPromises = localAsserters.map(a => ({
5936
5981
  asserter: a,
5937
5982
  promise: callAsserter(a, this.asserters[a.name], {
5938
5983
  convo,
@@ -5947,7 +5992,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
5947
5992
  promise,
5948
5993
  asserter
5949
5994
  }) => updateExceptionContext(promise, asserter));
5950
- const globalAsserter = Object.values(this.globalAsserter).filter(a => a[asserterType]).map(a => ({
5995
+ const globalAsserters = Object.keys(this.globalAsserters).filter(name => localAsserters.map(a => a.name).indexOf(name) < 0).reduce((agg, name) => [...agg, this.globalAsserters[name]], []).filter(a => a[asserterType]);
5996
+ const globalPromises = globalAsserters.map(a => ({
5951
5997
  asserter: a,
5952
5998
  promise: p(this.retryHelperAsserter, () => a[asserterType]({
5953
5999
  convo,
@@ -5962,7 +6008,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5962
6008
  promise,
5963
6009
  asserter
5964
6010
  }) => updateExceptionContext(promise, asserter));
5965
- const allPromises = [...convoAsserter, ...globalAsserter];
6011
+ const allPromises = [...convoStepPromises, ...globalPromises];
5966
6012
  if (this.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
5967
6013
  return Promise.allSettled(allPromises).then(results => {
5968
6014
  const rejected = results.filter(result => result.status === 'rejected').map(result => result.reason);
@@ -5997,7 +6043,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5997
6043
  isGlobal: false,
5998
6044
  ...rest
5999
6045
  })));
6000
- const globalHooks = Object.values(this.globalLogicHook).filter(l => l[hookType]);
6046
+ const globalHooks = Object.keys(this.globalLogicHooks).filter(name => localHooks.map(l => l.name).indexOf(name) < 0).reduce((agg, name) => [...agg, this.globalLogicHooks[name]], []).filter(l => l[hookType]);
6001
6047
  const globalPromises = globalHooks.map(l => p(this.retryHelperLogicHook, () => l[hookType]({
6002
6048
  convo,
6003
6049
  convoStep,
@@ -6117,9 +6163,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
6117
6163
  caps: this.caps
6118
6164
  });
6119
6165
  this.asserters = logicHookUtils.asserters;
6120
- this.globalAsserter = logicHookUtils.getGlobalAsserter();
6166
+ this.globalAsserters = logicHookUtils.getGlobalAsserters();
6121
6167
  this.logicHooks = logicHookUtils.logicHooks;
6122
- this.globalLogicHook = logicHookUtils.getGlobalLogicHook();
6168
+ this.globalLogicHooks = logicHookUtils.getGlobalLogicHooks();
6123
6169
  this.userInputs = logicHookUtils.userInputs;
6124
6170
  }
6125
6171
  IsAsserterValid(name) {