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/dist/botium-es.js CHANGED
@@ -35,7 +35,7 @@ import express from 'express';
35
35
  import bodyParser from 'body-parser';
36
36
 
37
37
  var name = "botium-core";
38
- var version$1 = "1.14.8";
38
+ var version$1 = "1.14.10";
39
39
  var description = "The Selenium for Chatbots";
40
40
  var main = "index.js";
41
41
  var module = "dist/botium-es.js";
@@ -98,6 +98,7 @@ var dependencies = {
98
98
  "socketio-auth": "^0.1.1",
99
99
  "swagger-jsdoc": "^6.2.8",
100
100
  "swagger-ui-express": "^5.0.0",
101
+ tinyglobby: "^0.2.10",
101
102
  uuid: "^9.0.1",
102
103
  "word-error-rate": "0.0.7",
103
104
  "write-yaml": "^1.0.0",
@@ -1082,9 +1083,9 @@ var LogicHookUtils_1 = class LogicHookUtils {
1082
1083
  caps
1083
1084
  }) {
1084
1085
  this.asserters = {};
1085
- this.globalAsserters = [];
1086
+ this.globalAsserterNames = [];
1086
1087
  this.logicHooks = {};
1087
- this.globalLogicHooks = [];
1088
+ this.globalLogicHookNames = [];
1088
1089
  this.userInputs = {};
1089
1090
  this.buildScriptContext = buildScriptContext;
1090
1091
  this.caps = caps;
@@ -1117,7 +1118,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1117
1118
  }
1118
1119
  this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter');
1119
1120
  if (asserter.global) {
1120
- this.globalAsserters.push(asserter.ref);
1121
+ this.globalAsserterNames.push(asserter.ref);
1121
1122
  }
1122
1123
  });
1123
1124
  }
@@ -1128,7 +1129,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1128
1129
  }
1129
1130
  this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logichook');
1130
1131
  if (logicHook.global) {
1131
- this.globalLogicHooks.push(logicHook.ref);
1132
+ this.globalLogicHookNames.push(logicHook.ref);
1132
1133
  }
1133
1134
  });
1134
1135
  }
@@ -1140,11 +1141,17 @@ var LogicHookUtils_1 = class LogicHookUtils {
1140
1141
  this.userInputs[userInput.ref] = this._loadClass(userInput, 'userinput');
1141
1142
  });
1142
1143
  }
1143
- getGlobalAsserter() {
1144
- return this.globalAsserters.map(name => this.asserters[name]);
1144
+ getGlobalAsserters() {
1145
+ return this.globalAsserterNames.reduce((agg, name) => ({
1146
+ ...agg,
1147
+ [name]: this.asserters[name]
1148
+ }), {});
1145
1149
  }
1146
- getGlobalLogicHook() {
1147
- return this.globalLogicHooks.map(name => this.logicHooks[name]);
1150
+ getGlobalLogicHooks() {
1151
+ return this.globalLogicHookNames.reduce((agg, name) => ({
1152
+ ...agg,
1153
+ [name]: this.logicHooks[name]
1154
+ }), {});
1148
1155
  }
1149
1156
  _loadClass({
1150
1157
  src,
@@ -1928,12 +1935,6 @@ const validateConvo$2 = convo => {
1928
1935
  if (optionalSet.size > 1) {
1929
1936
  validationResult.errors.push(new Error(`Step ${i + 1}: Failed to decompile conversation. Mixed optional flag is not allowed inside one step.`));
1930
1937
  }
1931
- if (optionalSet.size === 1 && optionalSet.has(true)) {
1932
- const nextStep = convo.conversation[i + 1];
1933
- if (!nextStep || nextStep.sender !== 'bot') {
1934
- validationResult.errors.push(new Error(`Step ${i + 1}: Optional bot convo step has to be followed by a bot convo step.`));
1935
- }
1936
- }
1937
1938
  }
1938
1939
  if (!validateSender$1(step.sender)) {
1939
1940
  validationResult.errors.push(new Error(`Step ${i + 1}: Sender #${step.sender} is invalid.`));
@@ -1977,6 +1978,10 @@ const convoStepToLines$2 = step => {
1977
1978
  } else {
1978
1979
  if (step.messageText) {
1979
1980
  lines.push((step.optional ? '?' : '') + (step.not ? '!' : '') + step.messageText);
1981
+ } else {
1982
+ if (step.optional) {
1983
+ lines.push('?');
1984
+ }
1980
1985
  }
1981
1986
  if (step.buttons && step.buttons.length > 0) lines.push('BUTTONS' + _formatAppendArgs(step.buttons.filter(b => b.text).map(b => flatString(b.text))));
1982
1987
  if (step.media && step.media.length > 0) lines.push('MEDIA' + _formatAppendArgs(step.media.filter(m => !m.buffer && m.mediaUri).map(m => m.mediaUri)));
@@ -2936,6 +2941,10 @@ class Convo$6 {
2936
2941
  let skipTranscriptStep = false;
2937
2942
  let conditionalGroupId = null;
2938
2943
  let conditionMetInGroup = false;
2944
+ let skipOptionalStep = false;
2945
+ // 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.
2946
+ // So in this case an unexpected error should be shown instead of the latest assertion error.
2947
+ let optionalStepAssertionError = false;
2939
2948
  let globalConvoStepParameters = container.caps[Capabilities.SCRIPTING_CONVO_STEP_PARAMETERS] || {};
2940
2949
  let retryBotMessageTimeoutEnd = null;
2941
2950
  let retryBotMessageConvoId = null;
@@ -2943,6 +2952,13 @@ class Convo$6 {
2943
2952
  for (let i = 0; i < this.conversation.length; i = retryBotMessageDropBotResponse ? i : i + 1) {
2944
2953
  retryBotMessageDropBotResponse = false;
2945
2954
  const convoStep = this.conversation[i];
2955
+ if (!convoStep.optional) {
2956
+ skipOptionalStep = false;
2957
+ }
2958
+ if (convoStep.optional && skipOptionalStep) {
2959
+ // 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.
2960
+ continue;
2961
+ }
2946
2962
  const rawConvoStepParameters = convoStep.logicHooks.find(lh => lh.name === 'CONVO_STEP_PARAMETERS')?.args;
2947
2963
  let convoStepParameters = {};
2948
2964
  if (rawConvoStepParameters && rawConvoStepParameters.length) {
@@ -3119,7 +3135,7 @@ class Convo$6 {
3119
3135
  });
3120
3136
  transcriptStep.botBegin = new Date();
3121
3137
  if (!botMsg) {
3122
- botMsg = await container.WaitBotSays(convoStep.channel);
3138
+ botMsg = await container.WaitBotSays(convoStep.channel, convoStepParameters?.stepTimeout);
3123
3139
  }
3124
3140
  transcriptStep.botEnd = new Date();
3125
3141
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
@@ -3127,6 +3143,10 @@ class Convo$6 {
3127
3143
  debug$k(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3128
3144
  } catch (err) {
3129
3145
  transcriptStep.botEnd = new Date();
3146
+ if (!(err.message.indexOf('Bot did not respond within') < 0) && convoStep.optional) {
3147
+ skipOptionalStep = true;
3148
+ continue;
3149
+ }
3130
3150
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error waiting for bot - ${err.message}`, err);
3131
3151
  debug$k(failErr);
3132
3152
  try {
@@ -3208,6 +3228,7 @@ class Convo$6 {
3208
3228
  }
3209
3229
  waitForBotSays = false;
3210
3230
  skipTranscriptStep = true;
3231
+ optionalStepAssertionError = true;
3211
3232
  return true;
3212
3233
  } else if (retryOn) {
3213
3234
  if (!retryBotMessageTimeoutEnd || retryBotMessageConvoId !== convoStep.stepTag) {
@@ -3225,9 +3246,18 @@ class Convo$6 {
3225
3246
  }
3226
3247
  }
3227
3248
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
3228
- assertErrors.push(err);
3249
+ if (optionalStepAssertionError) {
3250
+ optionalStepAssertionError = false;
3251
+ assertErrors.push(new BotiumError$2(`${this.header.name}: Unexpected message.`));
3252
+ } else {
3253
+ assertErrors.push(err);
3254
+ }
3229
3255
  return false;
3230
3256
  } else {
3257
+ if (optionalStepAssertionError) {
3258
+ optionalStepAssertionError = false;
3259
+ throw new BotiumError$2(`${this.header.name}: Unexpected message.`);
3260
+ }
3231
3261
  throw err;
3232
3262
  }
3233
3263
  };
@@ -3241,6 +3271,7 @@ class Convo$6 {
3241
3271
  if (convoStep.not) {
3242
3272
  try {
3243
3273
  this.scriptingEvents.assertBotNotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters);
3274
+ optionalStepAssertionError = false;
3244
3275
  } catch (err) {
3245
3276
  if (isErrorHandledWithOptionConvoStep(err)) {
3246
3277
  continue;
@@ -3249,6 +3280,7 @@ class Convo$6 {
3249
3280
  } else {
3250
3281
  try {
3251
3282
  this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters);
3283
+ optionalStepAssertionError = false;
3252
3284
  } catch (err) {
3253
3285
  if (isErrorHandledWithOptionConvoStep(err)) {
3254
3286
  continue;
@@ -3258,6 +3290,7 @@ class Convo$6 {
3258
3290
  } else if (convoStep.sourceData) {
3259
3291
  try {
3260
3292
  this._compareObject(container, scriptingMemory, convoStep, botMsg.sourceData, convoStep.sourceData, botMsg, convoStepParameters);
3293
+ optionalStepAssertionError = false;
3261
3294
  } catch (err) {
3262
3295
  if (isErrorHandledWithOptionConvoStep(err)) {
3263
3296
  continue;
@@ -3284,11 +3317,13 @@ class Convo$6 {
3284
3317
  transcript,
3285
3318
  transcriptStep
3286
3319
  });
3320
+ optionalStepAssertionError = false;
3287
3321
  } catch (err) {
3288
3322
  const nextConvoStep = this.conversation[i + 1];
3289
3323
  if (convoStep.optional && nextConvoStep && nextConvoStep.sender === 'bot') {
3290
3324
  waitForBotSays = false;
3291
3325
  skipTranscriptStep = true;
3326
+ optionalStepAssertionError = true;
3292
3327
  continue;
3293
3328
  }
3294
3329
  const errors = err.toArray ? err.toArray() : [];
@@ -3317,8 +3352,17 @@ class Convo$6 {
3317
3352
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3318
3353
  } catch (failErr) {}
3319
3354
  if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$2) {
3320
- assertErrors.push(err);
3355
+ if (optionalStepAssertionError) {
3356
+ optionalStepAssertionError = false;
3357
+ assertErrors.push(new BotiumError$2(`${this.header.name}: Unexpected message.`));
3358
+ } else {
3359
+ assertErrors.push(err);
3360
+ }
3321
3361
  } else {
3362
+ if (optionalStepAssertionError) {
3363
+ optionalStepAssertionError = false;
3364
+ throw new BotiumError$2(`${this.header.name}: Unexpected message.`);
3365
+ }
3322
3366
  throw failErr;
3323
3367
  }
3324
3368
  }
@@ -5519,9 +5563,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
5519
5563
  this.utterances = {};
5520
5564
  this.matchFn = null;
5521
5565
  this.asserters = {};
5522
- this.globalAsserter = {};
5566
+ this.globalAsserters = {};
5523
5567
  this.logicHooks = {};
5524
- this.globalLogicHook = {};
5568
+ this.globalLogicHooks = {};
5525
5569
  this.userInputs = {};
5526
5570
  this.partialConvos = {};
5527
5571
  this.scriptingMemories = [];
@@ -5890,7 +5934,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
5890
5934
  return p(this.retryHelperAsserter, () => asserter[asserterType](params));
5891
5935
  }
5892
5936
  };
5893
- const convoAsserter = asserters.filter(a => this.asserters[a.name][asserterType]).map(a => ({
5937
+ const localAsserters = (asserters || []).filter(a => this.asserters[a.name][asserterType]);
5938
+ const convoStepPromises = localAsserters.map(a => ({
5894
5939
  asserter: a,
5895
5940
  promise: callAsserter(a, this.asserters[a.name], {
5896
5941
  convo,
@@ -5905,7 +5950,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
5905
5950
  promise,
5906
5951
  asserter
5907
5952
  }) => updateExceptionContext(promise, asserter));
5908
- const globalAsserter = Object.values(this.globalAsserter).filter(a => a[asserterType]).map(a => ({
5953
+ 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]);
5954
+ const globalPromises = globalAsserters.map(a => ({
5909
5955
  asserter: a,
5910
5956
  promise: p(this.retryHelperAsserter, () => a[asserterType]({
5911
5957
  convo,
@@ -5920,7 +5966,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5920
5966
  promise,
5921
5967
  asserter
5922
5968
  }) => updateExceptionContext(promise, asserter));
5923
- const allPromises = [...convoAsserter, ...globalAsserter];
5969
+ const allPromises = [...convoStepPromises, ...globalPromises];
5924
5970
  if (this.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
5925
5971
  return Promise.allSettled(allPromises).then(results => {
5926
5972
  const rejected = results.filter(result => result.status === 'rejected').map(result => result.reason);
@@ -5955,7 +6001,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5955
6001
  isGlobal: false,
5956
6002
  ...rest
5957
6003
  })));
5958
- const globalHooks = Object.values(this.globalLogicHook).filter(l => l[hookType]);
6004
+ 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]);
5959
6005
  const globalPromises = globalHooks.map(l => p(this.retryHelperLogicHook, () => l[hookType]({
5960
6006
  convo,
5961
6007
  convoStep,
@@ -6075,9 +6121,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
6075
6121
  caps: this.caps
6076
6122
  });
6077
6123
  this.asserters = logicHookUtils.asserters;
6078
- this.globalAsserter = logicHookUtils.getGlobalAsserter();
6124
+ this.globalAsserters = logicHookUtils.getGlobalAsserters();
6079
6125
  this.logicHooks = logicHookUtils.logicHooks;
6080
- this.globalLogicHook = logicHookUtils.getGlobalLogicHook();
6126
+ this.globalLogicHooks = logicHookUtils.getGlobalLogicHooks();
6081
6127
  this.userInputs = logicHookUtils.userInputs;
6082
6128
  }
6083
6129
  IsAsserterValid(name) {