botium-core 1.13.16 → 1.13.17

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
@@ -2,7 +2,7 @@ import util from 'util';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import async from 'async';
5
- import rimraf from 'rimraf';
5
+ import rimraf$2 from 'rimraf';
6
6
  import mkdirp from 'mkdirp';
7
7
  import sanitizeFilename from 'sanitize-filename';
8
8
  import moment from 'moment';
@@ -37,7 +37,7 @@ import express from 'express';
37
37
  import bodyParser from 'body-parser';
38
38
 
39
39
  var name = "botium-core";
40
- var version$1 = "1.13.16";
40
+ var version$1 = "1.13.17";
41
41
  var description = "The Selenium for Chatbots";
42
42
  var main = "index.js";
43
43
  var module = "dist/botium-es.js";
@@ -69,66 +69,66 @@ var bugs = {
69
69
  };
70
70
  var homepage = "https://www.botium.ai";
71
71
  var dependencies = {
72
- "@babel/runtime": "^7.20.6",
72
+ "@babel/runtime": "^7.21.5",
73
73
  async: "^3.2.4",
74
- "body-parser": "^1.20.1",
74
+ "body-parser": "^1.20.2",
75
75
  boolean: "^3.2.0",
76
76
  bottleneck: "^2.19.5",
77
- "csv-parse": "^5.3.3",
77
+ "csv-parse": "^5.3.10",
78
78
  debug: "^4.3.4",
79
79
  esprima: "^4.0.1",
80
80
  express: "^4.18.2",
81
81
  globby: "11.0.4",
82
- ioredis: "^5.2.4",
82
+ ioredis: "^5.3.2",
83
83
  "is-class": "^0.0.9",
84
84
  "is-json": "^2.0.1",
85
85
  jsonpath: "^1.1.1",
86
86
  lodash: "^4.17.21",
87
87
  "markdown-it": "^13.0.1",
88
88
  "mime-types": "^2.1.35",
89
- mkdirp: "^1.0.4",
89
+ mkdirp: "^3.0.1",
90
90
  moment: "^2.29.4",
91
91
  mustache: "^4.2.0",
92
92
  "promise-retry": "^2.0.1",
93
93
  "promise.allsettled": "^1.0.6",
94
94
  randomatic: "^3.1.1",
95
95
  request: "^2.88.2",
96
- rimraf: "^3.0.2",
96
+ rimraf: "^5.0.0",
97
97
  "sanitize-filename": "^1.6.3",
98
- slugify: "^1.6.5",
99
- "socket.io": "^4.5.4",
100
- "socket.io-client": "^4.5.4",
98
+ slugify: "^1.6.6",
99
+ "socket.io": "^4.6.1",
100
+ "socket.io-client": "^4.6.1",
101
101
  "socketio-auth": "^0.1.1",
102
- "swagger-jsdoc": "^6.2.5",
103
- "swagger-ui-express": "^4.6.0",
102
+ "swagger-jsdoc": "^6.2.8",
103
+ "swagger-ui-express": "^4.6.3",
104
104
  uuid: "^9.0.0",
105
- vm2: "^3.9.13",
105
+ vm2: "^3.9.17",
106
106
  "word-error-rate": "0.0.7",
107
107
  "write-yaml": "^1.0.0",
108
108
  xlsx: "^0.18.5",
109
109
  xregexp: "^5.1.1",
110
- yaml: "^2.1.3"
110
+ yaml: "^2.2.2"
111
111
  };
112
112
  var devDependencies = {
113
- "@babel/core": "^7.20.5",
114
- "@babel/node": "^7.20.5",
115
- "@babel/plugin-transform-runtime": "^7.19.6",
116
- "@babel/preset-env": "^7.20.2",
113
+ "@babel/core": "^7.21.8",
114
+ "@babel/node": "^7.20.7",
115
+ "@babel/plugin-transform-runtime": "^7.21.4",
116
+ "@babel/preset-env": "^7.21.5",
117
117
  chai: "^4.3.7",
118
118
  "chai-as-promised": "^7.1.1",
119
119
  "cross-env": "^7.0.3",
120
- eslint: "^8.29.0",
120
+ eslint: "^8.40.0",
121
121
  "eslint-config-standard": "^17.0.0",
122
- "eslint-plugin-import": "^2.26.0",
122
+ "eslint-plugin-import": "^2.27.5",
123
123
  "eslint-plugin-mocha": "^10.1.0",
124
- "eslint-plugin-n": "^15.6.0",
124
+ "eslint-plugin-n": "^15.7.0",
125
125
  "eslint-plugin-promise": "^6.1.1",
126
126
  "eslint-plugin-standard": "^4.1.0",
127
127
  "license-checker": "^25.0.1",
128
128
  "license-compatibility-checker": "^0.3.5",
129
129
  mocha: "^10.2.0",
130
- nock: "^13.2.9",
131
- "npm-check-updates": "^16.5.6",
130
+ nock: "^13.3.1",
131
+ "npm-check-updates": "^16.10.12",
132
132
  nyc: "^15.1.0",
133
133
  rollup: "2.79.1",
134
134
  "rollup-plugin-babel": "^4.4.0",
@@ -339,9 +339,7 @@ var Capabilities = {
339
339
  RATELIMIT_USERSAYS_MINTIME: 'RATELIMIT_USERSAYS_MINTIME',
340
340
  RATELIMIT_BOTTLENECK_FN: 'RATELIMIT_BOTTLENECK_FN',
341
341
  SECURITY_ALLOW_UNSAFE: 'SECURITY_ALLOW_UNSAFE',
342
- PRECOMPILERS: 'PRECOMPILERS',
343
- // RETRY
344
- RETRY_CONVO_ASYNC: 'RETRY_CONVO_ASYNC'
342
+ PRECOMPILERS: 'PRECOMPILERS'
345
343
  };
346
344
  Capabilities.PROJECTNAME;
347
345
  Capabilities.TESTSESSIONNAME;
@@ -494,7 +492,6 @@ Capabilities.RATELIMIT_USERSAYS_MINTIME;
494
492
  Capabilities.RATELIMIT_BOTTLENECK_FN;
495
493
  Capabilities.SECURITY_ALLOW_UNSAFE;
496
494
  Capabilities.PRECOMPILERS;
497
- Capabilities.RETRY_CONVO_ASYNC;
498
495
 
499
496
  var Source = {
500
497
  LOCALPATH: 'LOCALPATH',
@@ -815,6 +812,7 @@ var Events = {
815
812
  CONTAINER_CLEANED: 'CONTAINER_CLEANED',
816
813
  CONTAINER_CLEAN_ERROR: 'CONTAINER_CLEAN_ERROR',
817
814
  BOT_CONNECTED: 'BOT_CONNECTED',
815
+ CONVO_STEP_NEXT: 'CONVO_STEP_NEXT',
818
816
  // Chatbot Events
819
817
  MESSAGE_SENTTOBOT: 'MESSAGE_SENTTOBOT',
820
818
  MESSAGE_SENDTOBOT_ERROR: 'MESSAGE_SENDTOBOT_ERROR',
@@ -838,6 +836,7 @@ Events.CONTAINER_CLEANING;
838
836
  Events.CONTAINER_CLEANED;
839
837
  Events.CONTAINER_CLEAN_ERROR;
840
838
  Events.BOT_CONNECTED;
839
+ Events.CONVO_STEP_NEXT;
841
840
  Events.MESSAGE_SENTTOBOT;
842
841
  Events.MESSAGE_SENDTOBOT_ERROR;
843
842
  Events.MESSAGE_RECEIVEDFROMBOT;
@@ -2181,7 +2180,7 @@ const linesToScriptingMemories$2 = (lines, columnMode = null) => {
2181
2180
  }
2182
2181
  return scriptingMemories;
2183
2182
  };
2184
- const calculateWer$1 = (str, pattern) => {
2183
+ const calculateWer$2 = (str, pattern) => {
2185
2184
  const _prepareString = (str, remWildcard = false) => {
2186
2185
  if (remWildcard) return str.replace(/[.,/#!$%^&;:*{}=\-_`~()]/g, '').toLowerCase();
2187
2186
  return str.replace(/[.,/#!$%^&;:{}=\-_`~()]/g, '').toLowerCase();
@@ -2204,6 +2203,11 @@ const calculateWer$1 = (str, pattern) => {
2204
2203
  const botMessage = _prepareString(str);
2205
2204
  const botMessageWords = botMessage.split(' ').map(bm => bm.trim());
2206
2205
  const utt = _prepareString(utterance);
2206
+
2207
+ // if no wildcards, just calculate WER
2208
+ if (utt.indexOf('*') === -1) return wordErrorRate.wordErrorRate(botMessage, utt).toFixed(2);
2209
+
2210
+ // if there are wildcards, calculate WER for each wildcard part
2207
2211
  const errors = [];
2208
2212
  for (let wildcardPart of utt.split('*')) {
2209
2213
  let wer = 1;
@@ -2223,7 +2227,7 @@ const calculateWer$1 = (str, pattern) => {
2223
2227
  }
2224
2228
  }
2225
2229
  if (lodash.isNil(subsetPhraseFound)) {
2226
- throw new Error('Word Error Asserter: Something went wrong here, please try to modify your assertion!');
2230
+ throw new Error('Word Error Asserter: When using wild cards, please make sure that the length of the asserter text is smaller than the bot message!');
2227
2231
  }
2228
2232
  errors.push(_getErrors(_getWords(wildcardPart), _getWords(subsetPhraseFound)));
2229
2233
  }
@@ -2236,6 +2240,7 @@ const calculateWer$1 = (str, pattern) => {
2236
2240
  debug$l(`Word Error Rate Asserter - Compared Bot Message '${botMessage}' / '${utt}': ${(errCount / allCount).toFixed(2)}`);
2237
2241
  return (errCount / allCount).toFixed(2);
2238
2242
  };
2243
+ const toPercent$1 = s => `${(s * 100).toFixed(0)}%`;
2239
2244
  var helper = {
2240
2245
  normalizeText: normalizeText$1,
2241
2246
  splitStringInNonEmptyLines: splitStringInNonEmptyLines$1,
@@ -2250,7 +2255,8 @@ var helper = {
2250
2255
  validateSender: validateSender$1,
2251
2256
  validateConvo: validateConvo$2,
2252
2257
  linesToScriptingMemories: linesToScriptingMemories$2,
2253
- calculateWer: calculateWer$1
2258
+ calculateWer: calculateWer$2,
2259
+ toPercent: toPercent$1
2254
2260
  };
2255
2261
 
2256
2262
  const debug$k = debug$n('botium-core-ScriptingMemory');
@@ -2590,45 +2596,7 @@ ScriptingMemory.extractVarNames;
2590
2596
  ScriptingMemory.RESERVED_WORDS;
2591
2597
  ScriptingMemory.SCRIPTING_FUNCTIONS;
2592
2598
 
2593
- const debug$j = debug$n('botium-core-RetryHelper');
2594
- var RetryHelper_1 = class RetryHelper {
2595
- constructor(caps, section, options = {}) {
2596
- this.retryErrorPatterns = [];
2597
- const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
2598
- if (onErrorRegexp) {
2599
- if (lodash.isArray(onErrorRegexp)) {
2600
- onErrorRegexp.forEach(r => {
2601
- if (lodash.isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
2602
- });
2603
- } else if (lodash.isString(onErrorRegexp)) {
2604
- this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
2605
- } else {
2606
- this.retryErrorPatterns.push(onErrorRegexp);
2607
- }
2608
- }
2609
-
2610
- // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
2611
- this.retrySettings = {
2612
- retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash.isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
2613
- factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash.isNil(options.factor) ? 1 : options.factor),
2614
- minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash.isNil(options.minTimeout) ? 1000 : options.minTimeout)
2615
- };
2616
- if (this.retrySettings.retries > 0) {
2617
- debug$j(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
2618
- }
2619
- }
2620
- shouldRetry(err) {
2621
- if (!err) return false;
2622
- if (this.retryErrorPatterns.length === 0) return true;
2623
- const errString = util.inspect(err);
2624
- for (const re of this.retryErrorPatterns) {
2625
- if (errString.match(re)) return true;
2626
- }
2627
- return false;
2628
- }
2629
- };
2630
-
2631
- const debug$i = debug$n('botium-core-Convo');
2599
+ const debug$j = debug$n('botium-core-Convo');
2632
2600
  const {
2633
2601
  BotiumError: BotiumError$4,
2634
2602
  botiumErrorFromErr: botiumErrorFromErr$1,
@@ -2782,10 +2750,10 @@ class TranscriptError extends Error {
2782
2750
  class Convo$6 {
2783
2751
  constructor(context, fromJson = {}) {
2784
2752
  if (fromJson instanceof Convo$6) {
2785
- debug$i('Illegal state!!! Parameter should be a JSON, but it is a Convo');
2753
+ debug$j('Illegal state!!! Parameter should be a JSON, but it is a Convo');
2786
2754
  } else if (fromJson.beginAsserter) {
2787
2755
  // beginAsserter is one of the fields which are lost
2788
- debug$i('Illegal state!!! Parameter should be a native JSON, but looks as a Convo converted to JSON');
2756
+ debug$j('Illegal state!!! Parameter should be a native JSON, but looks as a Convo converted to JSON');
2789
2757
  }
2790
2758
  this.scriptingEvents = context.scriptingEvents;
2791
2759
  this.context = context;
@@ -2830,30 +2798,6 @@ class Convo$6 {
2830
2798
  return this.header.toString() + (this.sourceTag ? ` (${util.inspect(this.sourceTag)})` : '') + ': ' + this.conversation.map(c => c.toString()).join(' | ');
2831
2799
  }
2832
2800
  async Run(container) {
2833
- if (container.caps.RETRY_CONVO_ASYNC) {
2834
- return this.RunImpl(container).catch(err => {
2835
- debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}".`);
2836
- throw err;
2837
- });
2838
- } else {
2839
- const retryHelper = new RetryHelper_1(container.caps, 'CONVO');
2840
- return promiseRetry(async (retry, number) => {
2841
- const retryRemaining = retryHelper.retrySettings.retries - number + 1;
2842
- return this.RunImpl(container).catch(err => {
2843
- if (retryHelper.shouldRetry(err)) {
2844
- debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry ${retryRemaining > 0 ? 'enabled' : 'disabled'} (remaining #${retryRemaining}/${retryHelper.retrySettings.retries}, criterion matches)`);
2845
- retry(err);
2846
- } else {
2847
- if (retryHelper.retryErrorPatterns.length > 0) {
2848
- debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry 'disabled' (remaining (#${retryRemaining}/${retryHelper.retrySettings.retries}), criterion does not match)`);
2849
- }
2850
- throw err;
2851
- }
2852
- });
2853
- }, retryHelper.retrySettings);
2854
- }
2855
- }
2856
- async RunImpl(container) {
2857
2801
  const transcript = new Transcript({
2858
2802
  steps: [],
2859
2803
  attachments: [],
@@ -2959,6 +2903,7 @@ class Convo$6 {
2959
2903
  for (let i = 0; i < this.conversation.length; i++) {
2960
2904
  const convoStep = this.conversation[i];
2961
2905
  const currentStepIndex = i;
2906
+ container.eventEmitter.emit(Events.CONVO_STEP_NEXT, container, convoStep, i);
2962
2907
  skipTranscriptStep = false;
2963
2908
  const transcriptStep = new TranscriptStep({
2964
2909
  expected: new BotiumMockMessage_1(convoStep),
@@ -3018,7 +2963,7 @@ class Convo$6 {
3018
2963
  });
3019
2964
  await this._checkBotRepliesConsumed(container);
3020
2965
  const coreMsg = lodash.omit(removeBuffers(meMsg), ['sourceData']);
3021
- debug$i(`${this.header.name}/${convoStep.stepTag}: user says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
2966
+ debug$j(`${this.header.name}/${convoStep.stepTag}: user says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3022
2967
  await new Promise(resolve => {
3023
2968
  if (container.caps.SIMULATE_WRITING_SPEED && meMsg.messageText && meMsg.messageText.length) {
3024
2969
  setTimeout(() => resolve(), container.caps.SIMULATE_WRITING_SPEED * meMsg.messageText.length);
@@ -3054,7 +2999,7 @@ class Convo$6 {
3054
2999
  });
3055
3000
  continue;
3056
3001
  } else {
3057
- debug$i(`${this.header.name}/${convoStep.stepTag}: message not found in #me section, message not sent to container ${util.inspect(convoStep)}`);
3002
+ debug$j(`${this.header.name}/${convoStep.stepTag}: message not found in #me section, message not sent to container ${util.inspect(convoStep)}`);
3058
3003
  transcriptStep.botEnd = new Date();
3059
3004
  await this.scriptingEvents.onMeEnd({
3060
3005
  convo: this,
@@ -3070,7 +3015,7 @@ class Convo$6 {
3070
3015
  } catch (err) {
3071
3016
  transcriptStep.botEnd = new Date();
3072
3017
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error sending to bot - ${err.message || err}`, err);
3073
- debug$i(failErr);
3018
+ debug$j(failErr);
3074
3019
  try {
3075
3020
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3076
3021
  } catch (failErr) {}
@@ -3083,7 +3028,7 @@ class Convo$6 {
3083
3028
  waitForBotSays = true;
3084
3029
  }
3085
3030
  try {
3086
- debug$i(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3031
+ debug$j(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3087
3032
  await this.scriptingEvents.onBotStart({
3088
3033
  convo: this,
3089
3034
  convoStep,
@@ -3099,11 +3044,11 @@ class Convo$6 {
3099
3044
  transcriptStep.botEnd = new Date();
3100
3045
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3101
3046
  const coreMsg = lodash.omit(removeBuffers(botMsg), ['sourceData']);
3102
- debug$i(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3047
+ debug$j(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3103
3048
  } catch (err) {
3104
3049
  transcriptStep.botEnd = new Date();
3105
3050
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error waiting for bot - ${err.message}`, err);
3106
- debug$i(failErr);
3051
+ debug$j(failErr);
3107
3052
  try {
3108
3053
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3109
3054
  } catch (failErr) {}
@@ -3122,11 +3067,11 @@ class Convo$6 {
3122
3067
  if (prepared) {
3123
3068
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3124
3069
  const coreMsg = lodash.omit(removeBuffers(botMsg), ['sourceData']);
3125
- debug$i(`${this.header.name}: onBotPrepare (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3070
+ debug$j(`${this.header.name}: onBotPrepare (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3126
3071
  }
3127
3072
  } catch (err) {
3128
3073
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: onBotPrepare error - ${err.message || err}`, err);
3129
- debug$i(failErr);
3074
+ debug$j(failErr);
3130
3075
  try {
3131
3076
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3132
3077
  } catch (failErr) {}
@@ -3134,7 +3079,7 @@ class Convo$6 {
3134
3079
  }
3135
3080
  if (!botMsg || !botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp) {
3136
3081
  const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3137
- debug$i(failErr);
3082
+ debug$j(failErr);
3138
3083
  try {
3139
3084
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3140
3085
  } catch (failErr) {}
@@ -3215,7 +3160,7 @@ class Convo$6 {
3215
3160
  continue;
3216
3161
  }
3217
3162
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: assertion error - ${err.message || err}`, err);
3218
- debug$i(failErr);
3163
+ debug$j(failErr);
3219
3164
  try {
3220
3165
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3221
3166
  } catch (failErr) {}
@@ -3236,7 +3181,7 @@ class Convo$6 {
3236
3181
  }
3237
3182
  } else {
3238
3183
  const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util.inspect(convoStep.sender)}`);
3239
- debug$i(failErr);
3184
+ debug$j(failErr);
3240
3185
  try {
3241
3186
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3242
3187
  } catch (failErr) {}
@@ -3442,7 +3387,7 @@ class Convo$6 {
3442
3387
  throw new BotiumError$4(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3443
3388
  }
3444
3389
  _getEffectiveConversationRecursive(partialConvo.conversation, [...parentPConvos, includeLogicHook], result, true);
3445
- debug$i(`Partial convo ${includeLogicHook} included`);
3390
+ debug$j(`Partial convo ${includeLogicHook} included`);
3446
3391
  });
3447
3392
  });
3448
3393
  return result;
@@ -3463,10 +3408,48 @@ var Convo_1 = {
3463
3408
  TranscriptError
3464
3409
  };
3465
3410
 
3411
+ const debug$i = debug$n('botium-core-RetryHelper');
3412
+ var RetryHelper_1 = class RetryHelper {
3413
+ constructor(caps, section, options = {}) {
3414
+ this.retryErrorPatterns = [];
3415
+ const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
3416
+ if (onErrorRegexp) {
3417
+ if (lodash.isArray(onErrorRegexp)) {
3418
+ onErrorRegexp.forEach(r => {
3419
+ if (lodash.isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
3420
+ });
3421
+ } else if (lodash.isString(onErrorRegexp)) {
3422
+ this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
3423
+ } else {
3424
+ this.retryErrorPatterns.push(onErrorRegexp);
3425
+ }
3426
+ }
3427
+
3428
+ // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
3429
+ this.retrySettings = {
3430
+ retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash.isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
3431
+ factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash.isNil(options.factor) ? 1 : options.factor),
3432
+ minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash.isNil(options.minTimeout) ? 1000 : options.minTimeout)
3433
+ };
3434
+ if (this.retrySettings.retries > 0) {
3435
+ debug$i(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
3436
+ }
3437
+ }
3438
+ shouldRetry(err) {
3439
+ if (!err) return false;
3440
+ if (this.retryErrorPatterns.length === 0) return true;
3441
+ const errString = util.inspect(err);
3442
+ for (const re of this.retryErrorPatterns) {
3443
+ if (errString.match(re)) return true;
3444
+ }
3445
+ return false;
3446
+ }
3447
+ };
3448
+
3466
3449
  const {
3467
3450
  toString,
3468
3451
  quoteRegexpString,
3469
- calculateWer
3452
+ calculateWer: calculateWer$1
3470
3453
  } = helper;
3471
3454
  const _normalize = botresponse => {
3472
3455
  if (lodash.isUndefined(botresponse) || lodash.isNil(botresponse)) return '';
@@ -3534,7 +3517,7 @@ const wer = () => (botresponse, utterance, args) => {
3534
3517
  botresponse = _normalize(botresponse || '');
3535
3518
  utterance = toString(utterance || '');
3536
3519
  const threshold = [',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100;
3537
- return calculateWer(botresponse, utterance) <= threshold;
3520
+ return calculateWer$1(botresponse, utterance) <= threshold;
3538
3521
  };
3539
3522
  const getMatchFunction$1 = matchingMode => {
3540
3523
  if (matchingMode === 'regexp' || matchingMode === 'regexpIgnoreCase') {
@@ -5328,6 +5311,10 @@ const {
5328
5311
  const {
5329
5312
  getMatchFunction
5330
5313
  } = MatchFunctions;
5314
+ const {
5315
+ calculateWer,
5316
+ toPercent
5317
+ } = helper;
5331
5318
  const globPattern = '**/+(*.convo.txt|*.utterances.txt|*.pconvo.txt|*.scriptingmemory.txt|*.xlsx|*.xlsm|*.convo.csv|*.pconvo.csv|*.utterances.csv|*.yaml|*.yml|*.json|*.md|*.markdown)';
5332
5319
  const skipPattern = /^skip[.\-_]/i;
5333
5320
  const p = (retryHelper, fn) => {
@@ -5588,29 +5575,51 @@ var ScriptingProvider_1 = class ScriptingProvider {
5588
5575
  const found = lodash.find(tomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5589
5576
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5590
5577
  if (lodash.isNil(found)) {
5591
- let message = `${stepTag}: Bot response `;
5592
- message += meMsg ? `(on ${meMsg}) ` : '';
5593
- message += botresponse ? '"' + botresponse + '"' : '<no response>';
5594
- message += ' expected to match ';
5595
- message += tomatch && tomatch.length > 1 ? 'one of ' : '';
5596
- message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5597
- throw new BotiumError$2(message, {
5598
- type: 'asserter',
5599
- source: asserterType,
5600
- params: {
5601
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5602
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5603
- },
5604
- context: {
5605
- stepTag
5606
- },
5607
- cause: {
5608
- expected: tomatch,
5609
- actual: botresponse,
5610
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5611
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5612
- }
5613
- });
5578
+ if (this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer') {
5579
+ const wer = calculateWer(botresponse, tomatch[0]);
5580
+ const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5581
+ const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5582
+ const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) higher than accepted (${toPercent(threshold)})`;
5583
+ throw new BotiumError$2(message, {
5584
+ type: 'asserter',
5585
+ source: asserterType,
5586
+ params: {
5587
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5588
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5589
+ },
5590
+ context: {
5591
+ stepTag
5592
+ },
5593
+ cause: {
5594
+ expected: `<=${toPercent(threshold)} (${tomatch})`,
5595
+ actual: `${toPercent(wer)} (${botresponse})`
5596
+ }
5597
+ });
5598
+ } else {
5599
+ let message = `${stepTag}: Bot response `;
5600
+ message += meMsg ? `(on ${meMsg}) ` : '';
5601
+ message += botresponse ? '"' + botresponse + '"' : '<no response>';
5602
+ message += ' expected to match ';
5603
+ message += tomatch && tomatch.length > 1 ? 'one of ' : '';
5604
+ message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5605
+ throw new BotiumError$2(message, {
5606
+ type: 'asserter',
5607
+ source: asserterType,
5608
+ params: {
5609
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5610
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5611
+ },
5612
+ context: {
5613
+ stepTag
5614
+ },
5615
+ cause: {
5616
+ expected: tomatch,
5617
+ actual: botresponse,
5618
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5619
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5620
+ }
5621
+ });
5622
+ }
5614
5623
  }
5615
5624
  },
5616
5625
  assertBotNotResponse: (botresponse, nottomatch, stepTag, meMsg) => {
@@ -5621,30 +5630,52 @@ var ScriptingProvider_1 = class ScriptingProvider {
5621
5630
  const found = lodash.find(nottomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5622
5631
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5623
5632
  if (!lodash.isNil(found)) {
5624
- let message = `${stepTag}: Bot response `;
5625
- message += meMsg ? `(on ${meMsg}) ` : '';
5626
- message += botresponse ? '"' + botresponse + '"' : '<no response>';
5627
- message += ' expected NOT to match ';
5628
- message += nottomatch && nottomatch.length > 1 ? 'one of ' : '';
5629
- message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5630
- throw new BotiumError$2(message, {
5631
- type: 'asserter',
5632
- source: asserterType,
5633
- params: {
5634
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5635
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5636
- },
5637
- context: {
5638
- stepTag
5639
- },
5640
- cause: {
5641
- not: true,
5642
- expected: nottomatch,
5643
- actual: botresponse,
5644
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5645
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5646
- }
5647
- });
5633
+ if (this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer') {
5634
+ const wer = calculateWer(botresponse, nottomatch[0]);
5635
+ const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5636
+ const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5637
+ const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) lower than accepted (${toPercent(threshold)})`;
5638
+ throw new BotiumError$2(message, {
5639
+ type: 'asserter',
5640
+ source: asserterType,
5641
+ params: {
5642
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5643
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5644
+ },
5645
+ context: {
5646
+ stepTag
5647
+ },
5648
+ cause: {
5649
+ expected: `>=${toPercent(threshold)} (${nottomatch})`,
5650
+ actual: `${toPercent(wer)} (${botresponse})`
5651
+ }
5652
+ });
5653
+ } else {
5654
+ let message = `${stepTag}: Bot response `;
5655
+ message += meMsg ? `(on ${meMsg}) ` : '';
5656
+ message += botresponse ? '"' + botresponse + '"' : '<no response>';
5657
+ message += ' expected NOT to match ';
5658
+ message += nottomatch && nottomatch.length > 1 ? 'one of ' : '';
5659
+ message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5660
+ throw new BotiumError$2(message, {
5661
+ type: 'asserter',
5662
+ source: asserterType,
5663
+ params: {
5664
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5665
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5666
+ },
5667
+ context: {
5668
+ stepTag
5669
+ },
5670
+ cause: {
5671
+ not: true,
5672
+ expected: nottomatch,
5673
+ actual: botresponse,
5674
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5675
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5676
+ }
5677
+ });
5678
+ }
5648
5679
  }
5649
5680
  },
5650
5681
  fail: null
@@ -7115,6 +7146,9 @@ var Queue_1 = class Queue {
7115
7146
  }
7116
7147
  };
7117
7148
 
7149
+ const {
7150
+ rimraf: rimraf$1
7151
+ } = rimraf$2;
7118
7152
  const debug$7 = debug$n('botium-connector-BaseContainer');
7119
7153
  const {
7120
7154
  executeHook: executeHook$1,
@@ -7247,10 +7281,7 @@ var BaseContainer_1 = class BaseContainer {
7247
7281
  }, rimraffed => {
7248
7282
  if (this.caps[Capabilities.CLEANUPTEMPDIR]) {
7249
7283
  debug$7(`Cleanup rimrafing temp dir ${this.tempDirectory}`);
7250
- rimraf(this.tempDirectory, err => {
7251
- if (err) debug$7(`Cleanup temp dir ${this.tempDirectory} failed: ${util.inspect(err)}`);
7252
- rimraffed();
7253
- });
7284
+ rimraf$1(this.tempDirectory).catch(err => debug$7(`Cleanup temp dir ${this.tempDirectory} failed: ${util.inspect(err)}`)).finally(() => rimraffed());
7254
7285
  } else {
7255
7286
  rimraffed();
7256
7287
  }
@@ -8641,13 +8672,9 @@ const {
8641
8672
  var PluginConnectorContainer_1 = class PluginConnectorContainer extends BaseContainer_1 {
8642
8673
  async Validate() {
8643
8674
  await super.Validate();
8644
- const setAsync = isAsync => {
8645
- this.caps.RETRY_CONVO_ASYNC = isAsync;
8646
- };
8647
8675
  this.pluginInstance = tryLoadPlugin(this.caps[Capabilities.CONTAINERMODE], this.caps[Capabilities.PLUGINMODULEPATH], {
8648
8676
  container: this,
8649
8677
  queueBotSays: msg => this._QueueBotSays(msg),
8650
- setAsync: isAsync => setAsync(isAsync),
8651
8678
  bottleneck: this.bottleneck,
8652
8679
  eventEmitter: this.eventEmitter,
8653
8680
  caps: this.caps,
@@ -8778,15 +8805,21 @@ var PluginConnectorContainer_1 = class PluginConnectorContainer extends BaseCont
8778
8805
  }
8779
8806
  };
8780
8807
 
8781
- var require$$2 = getCjsExportFromNamespace(_package$1);
8808
+ var require$$4 = getCjsExportFromNamespace(_package$1);
8782
8809
 
8810
+ const {
8811
+ rimraf
8812
+ } = rimraf$2;
8813
+ const {
8814
+ mkdirpSync
8815
+ } = mkdirp;
8783
8816
  const {
8784
8817
  boolean
8785
8818
  } = boolean$1;
8786
8819
  const debug$1 = debug$n('botium-core-BotDriver');
8787
8820
  const {
8788
8821
  version
8789
- } = require$$2;
8822
+ } = require$$4;
8790
8823
  var BotDriver_1 = class BotDriver {
8791
8824
  constructor(caps = {}, sources = {}, envs = {}) {
8792
8825
  this.eventEmitter = new events();
@@ -8876,7 +8909,7 @@ var BotDriver_1 = class BotDriver {
8876
8909
  }, tempDirectoryCreated => {
8877
8910
  tempDirectory = path.resolve(process.cwd(), this.caps[Capabilities.TEMPDIR], sanitizeFilename(`${this.caps[Capabilities.PROJECTNAME]} ${moment().format('YYYYMMDD HHmmss')} ${randomatic('Aa0', 5)}`));
8878
8911
  try {
8879
- mkdirp.sync(tempDirectory);
8912
+ mkdirpSync(tempDirectory);
8880
8913
  tempDirectoryCreated();
8881
8914
  } catch (err) {
8882
8915
  tempDirectoryCreated(new Error(`Unable to create temp directory ${tempDirectory}: ${err.message}`));
@@ -8904,9 +8937,7 @@ var BotDriver_1 = class BotDriver {
8904
8937
  debug$1(`BotDriver Build error: ${err}`);
8905
8938
  this.eventEmitter.emit(Events.CONTAINER_BUILD_ERROR, err);
8906
8939
  if (tempDirectory) {
8907
- rimraf(tempDirectory, err => {
8908
- if (err) debug$1(`Cleanup temp dir ${tempDirectory} failed: ${util.inspect(err)}`);
8909
- });
8940
+ rimraf(tempDirectory).catch(err => debug$1(`Cleanup temp dir ${tempDirectory} failed: ${util.inspect(err)}`));
8910
8941
  }
8911
8942
  return reject(err);
8912
8943
  }