botium-core 1.13.15 → 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.
@@ -6,7 +6,7 @@ var util = require('util');
6
6
  var fs = require('fs');
7
7
  var path = require('path');
8
8
  var async = require('async');
9
- var rimraf = require('rimraf');
9
+ var rimraf$2 = require('rimraf');
10
10
  var mkdirp = require('mkdirp');
11
11
  var sanitizeFilename = require('sanitize-filename');
12
12
  var moment = require('moment');
@@ -46,7 +46,7 @@ var util__default = /*#__PURE__*/_interopDefaultLegacy(util);
46
46
  var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
47
47
  var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
48
48
  var async__default = /*#__PURE__*/_interopDefaultLegacy(async);
49
- var rimraf__default = /*#__PURE__*/_interopDefaultLegacy(rimraf);
49
+ var rimraf__default = /*#__PURE__*/_interopDefaultLegacy(rimraf$2);
50
50
  var mkdirp__default = /*#__PURE__*/_interopDefaultLegacy(mkdirp);
51
51
  var sanitizeFilename__default = /*#__PURE__*/_interopDefaultLegacy(sanitizeFilename);
52
52
  var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
@@ -81,7 +81,7 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
81
81
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
82
82
 
83
83
  var name = "botium-core";
84
- var version$1 = "1.13.15";
84
+ var version$1 = "1.13.17";
85
85
  var description = "The Selenium for Chatbots";
86
86
  var main = "index.js";
87
87
  var module$1 = "dist/botium-es.js";
@@ -113,66 +113,66 @@ var bugs = {
113
113
  };
114
114
  var homepage = "https://www.botium.ai";
115
115
  var dependencies = {
116
- "@babel/runtime": "^7.20.6",
116
+ "@babel/runtime": "^7.21.5",
117
117
  async: "^3.2.4",
118
- "body-parser": "^1.20.1",
118
+ "body-parser": "^1.20.2",
119
119
  boolean: "^3.2.0",
120
120
  bottleneck: "^2.19.5",
121
- "csv-parse": "^5.3.3",
121
+ "csv-parse": "^5.3.10",
122
122
  debug: "^4.3.4",
123
123
  esprima: "^4.0.1",
124
124
  express: "^4.18.2",
125
125
  globby: "11.0.4",
126
- ioredis: "^5.2.4",
126
+ ioredis: "^5.3.2",
127
127
  "is-class": "^0.0.9",
128
128
  "is-json": "^2.0.1",
129
129
  jsonpath: "^1.1.1",
130
130
  lodash: "^4.17.21",
131
131
  "markdown-it": "^13.0.1",
132
132
  "mime-types": "^2.1.35",
133
- mkdirp: "^1.0.4",
133
+ mkdirp: "^3.0.1",
134
134
  moment: "^2.29.4",
135
135
  mustache: "^4.2.0",
136
136
  "promise-retry": "^2.0.1",
137
137
  "promise.allsettled": "^1.0.6",
138
138
  randomatic: "^3.1.1",
139
139
  request: "^2.88.2",
140
- rimraf: "^3.0.2",
140
+ rimraf: "^5.0.0",
141
141
  "sanitize-filename": "^1.6.3",
142
- slugify: "^1.6.5",
143
- "socket.io": "^4.5.4",
144
- "socket.io-client": "^4.5.4",
142
+ slugify: "^1.6.6",
143
+ "socket.io": "^4.6.1",
144
+ "socket.io-client": "^4.6.1",
145
145
  "socketio-auth": "^0.1.1",
146
- "swagger-jsdoc": "^6.2.5",
147
- "swagger-ui-express": "^4.6.0",
146
+ "swagger-jsdoc": "^6.2.8",
147
+ "swagger-ui-express": "^4.6.3",
148
148
  uuid: "^9.0.0",
149
- vm2: "^3.9.13",
149
+ vm2: "^3.9.17",
150
150
  "word-error-rate": "0.0.7",
151
151
  "write-yaml": "^1.0.0",
152
152
  xlsx: "^0.18.5",
153
153
  xregexp: "^5.1.1",
154
- yaml: "^2.1.3"
154
+ yaml: "^2.2.2"
155
155
  };
156
156
  var devDependencies = {
157
- "@babel/core": "^7.20.5",
158
- "@babel/node": "^7.20.5",
159
- "@babel/plugin-transform-runtime": "^7.19.6",
160
- "@babel/preset-env": "^7.20.2",
157
+ "@babel/core": "^7.21.8",
158
+ "@babel/node": "^7.20.7",
159
+ "@babel/plugin-transform-runtime": "^7.21.4",
160
+ "@babel/preset-env": "^7.21.5",
161
161
  chai: "^4.3.7",
162
162
  "chai-as-promised": "^7.1.1",
163
163
  "cross-env": "^7.0.3",
164
- eslint: "^8.29.0",
164
+ eslint: "^8.40.0",
165
165
  "eslint-config-standard": "^17.0.0",
166
- "eslint-plugin-import": "^2.26.0",
166
+ "eslint-plugin-import": "^2.27.5",
167
167
  "eslint-plugin-mocha": "^10.1.0",
168
- "eslint-plugin-n": "^15.6.0",
168
+ "eslint-plugin-n": "^15.7.0",
169
169
  "eslint-plugin-promise": "^6.1.1",
170
170
  "eslint-plugin-standard": "^4.1.0",
171
171
  "license-checker": "^25.0.1",
172
172
  "license-compatibility-checker": "^0.3.5",
173
173
  mocha: "^10.2.0",
174
- nock: "^13.2.9",
175
- "npm-check-updates": "^16.5.6",
174
+ nock: "^13.3.1",
175
+ "npm-check-updates": "^16.10.12",
176
176
  nyc: "^15.1.0",
177
177
  rollup: "2.79.1",
178
178
  "rollup-plugin-babel": "^4.4.0",
@@ -856,6 +856,7 @@ var Events = {
856
856
  CONTAINER_CLEANED: 'CONTAINER_CLEANED',
857
857
  CONTAINER_CLEAN_ERROR: 'CONTAINER_CLEAN_ERROR',
858
858
  BOT_CONNECTED: 'BOT_CONNECTED',
859
+ CONVO_STEP_NEXT: 'CONVO_STEP_NEXT',
859
860
  // Chatbot Events
860
861
  MESSAGE_SENTTOBOT: 'MESSAGE_SENTTOBOT',
861
862
  MESSAGE_SENDTOBOT_ERROR: 'MESSAGE_SENDTOBOT_ERROR',
@@ -879,6 +880,7 @@ Events.CONTAINER_CLEANING;
879
880
  Events.CONTAINER_CLEANED;
880
881
  Events.CONTAINER_CLEAN_ERROR;
881
882
  Events.BOT_CONNECTED;
883
+ Events.CONVO_STEP_NEXT;
882
884
  Events.MESSAGE_SENTTOBOT;
883
885
  Events.MESSAGE_SENDTOBOT_ERROR;
884
886
  Events.MESSAGE_RECEIVEDFROMBOT;
@@ -1766,10 +1768,10 @@ const toString$3 = value => {
1766
1768
  return '' + value;
1767
1769
  };
1768
1770
  const flatString = str => {
1769
- return str ? str.split('\n').map(s => s.trim()).join(' ') : '';
1771
+ return toString$3(str).split('\n').map(s => s.trim()).join(' ') || '';
1770
1772
  };
1771
1773
  const _formatAppendArgs = args => {
1772
- return args ? ` ${args.map(a => lodash__default["default"].isString(a) ? a.replace(/\|/g, '\\|') : `${a}`).join('|')}` : '';
1774
+ return args && args.length > 0 && lodash__default["default"].isArray(args) && ` ${args.map(a => lodash__default["default"].isString(a) ? a.replace(/\|/g, '\\|') : `${a}`).join('|')}` || '';
1773
1775
  };
1774
1776
  const _parseArgs = str => {
1775
1777
  return str && str.length > 0 && str.replace(/\\\|/g, '###ESCAPESPLIT###').split('|').map(s => s.replace(/###ESCAPESPLIT###/g, '|').trim()) || [];
@@ -2222,7 +2224,7 @@ const linesToScriptingMemories$2 = (lines, columnMode = null) => {
2222
2224
  }
2223
2225
  return scriptingMemories;
2224
2226
  };
2225
- const calculateWer$1 = (str, pattern) => {
2227
+ const calculateWer$2 = (str, pattern) => {
2226
2228
  const _prepareString = (str, remWildcard = false) => {
2227
2229
  if (remWildcard) return str.replace(/[.,/#!$%^&;:*{}=\-_`~()]/g, '').toLowerCase();
2228
2230
  return str.replace(/[.,/#!$%^&;:{}=\-_`~()]/g, '').toLowerCase();
@@ -2245,6 +2247,11 @@ const calculateWer$1 = (str, pattern) => {
2245
2247
  const botMessage = _prepareString(str);
2246
2248
  const botMessageWords = botMessage.split(' ').map(bm => bm.trim());
2247
2249
  const utt = _prepareString(utterance);
2250
+
2251
+ // if no wildcards, just calculate WER
2252
+ if (utt.indexOf('*') === -1) return wordErrorRate__default["default"].wordErrorRate(botMessage, utt).toFixed(2);
2253
+
2254
+ // if there are wildcards, calculate WER for each wildcard part
2248
2255
  const errors = [];
2249
2256
  for (let wildcardPart of utt.split('*')) {
2250
2257
  let wer = 1;
@@ -2264,7 +2271,7 @@ const calculateWer$1 = (str, pattern) => {
2264
2271
  }
2265
2272
  }
2266
2273
  if (lodash__default["default"].isNil(subsetPhraseFound)) {
2267
- throw new Error('Word Error Asserter: Something went wrong here, please try to modify your assertion!');
2274
+ 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!');
2268
2275
  }
2269
2276
  errors.push(_getErrors(_getWords(wildcardPart), _getWords(subsetPhraseFound)));
2270
2277
  }
@@ -2277,6 +2284,7 @@ const calculateWer$1 = (str, pattern) => {
2277
2284
  debug$l(`Word Error Rate Asserter - Compared Bot Message '${botMessage}' / '${utt}': ${(errCount / allCount).toFixed(2)}`);
2278
2285
  return (errCount / allCount).toFixed(2);
2279
2286
  };
2287
+ const toPercent$1 = s => `${(s * 100).toFixed(0)}%`;
2280
2288
  var helper = {
2281
2289
  normalizeText: normalizeText$1,
2282
2290
  splitStringInNonEmptyLines: splitStringInNonEmptyLines$1,
@@ -2291,7 +2299,8 @@ var helper = {
2291
2299
  validateSender: validateSender$1,
2292
2300
  validateConvo: validateConvo$2,
2293
2301
  linesToScriptingMemories: linesToScriptingMemories$2,
2294
- calculateWer: calculateWer$1
2302
+ calculateWer: calculateWer$2,
2303
+ toPercent: toPercent$1
2295
2304
  };
2296
2305
 
2297
2306
  const debug$k = debug__default["default"]('botium-core-ScriptingMemory');
@@ -2631,45 +2640,7 @@ ScriptingMemory.extractVarNames;
2631
2640
  ScriptingMemory.RESERVED_WORDS;
2632
2641
  ScriptingMemory.SCRIPTING_FUNCTIONS;
2633
2642
 
2634
- const debug$j = debug__default["default"]('botium-core-RetryHelper');
2635
- var RetryHelper_1 = class RetryHelper {
2636
- constructor(caps, section, options = {}) {
2637
- this.retryErrorPatterns = [];
2638
- const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
2639
- if (onErrorRegexp) {
2640
- if (lodash__default["default"].isArray(onErrorRegexp)) {
2641
- onErrorRegexp.forEach(r => {
2642
- if (lodash__default["default"].isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
2643
- });
2644
- } else if (lodash__default["default"].isString(onErrorRegexp)) {
2645
- this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
2646
- } else {
2647
- this.retryErrorPatterns.push(onErrorRegexp);
2648
- }
2649
- }
2650
-
2651
- // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
2652
- this.retrySettings = {
2653
- retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash__default["default"].isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
2654
- factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash__default["default"].isNil(options.factor) ? 1 : options.factor),
2655
- minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash__default["default"].isNil(options.minTimeout) ? 1000 : options.minTimeout)
2656
- };
2657
- if (this.retrySettings.retries > 0) {
2658
- debug$j(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
2659
- }
2660
- }
2661
- shouldRetry(err) {
2662
- if (!err) return false;
2663
- if (this.retryErrorPatterns.length === 0) return true;
2664
- const errString = util__default["default"].inspect(err);
2665
- for (const re of this.retryErrorPatterns) {
2666
- if (errString.match(re)) return true;
2667
- }
2668
- return false;
2669
- }
2670
- };
2671
-
2672
- const debug$i = debug__default["default"]('botium-core-Convo');
2643
+ const debug$j = debug__default["default"]('botium-core-Convo');
2673
2644
  const {
2674
2645
  BotiumError: BotiumError$4,
2675
2646
  botiumErrorFromErr: botiumErrorFromErr$1,
@@ -2823,10 +2794,10 @@ class TranscriptError extends Error {
2823
2794
  class Convo$6 {
2824
2795
  constructor(context, fromJson = {}) {
2825
2796
  if (fromJson instanceof Convo$6) {
2826
- debug$i('Illegal state!!! Parameter should be a JSON, but it is a Convo');
2797
+ debug$j('Illegal state!!! Parameter should be a JSON, but it is a Convo');
2827
2798
  } else if (fromJson.beginAsserter) {
2828
2799
  // beginAsserter is one of the fields which are lost
2829
- debug$i('Illegal state!!! Parameter should be a native JSON, but looks as a Convo converted to JSON');
2800
+ debug$j('Illegal state!!! Parameter should be a native JSON, but looks as a Convo converted to JSON');
2830
2801
  }
2831
2802
  this.scriptingEvents = context.scriptingEvents;
2832
2803
  this.context = context;
@@ -2871,23 +2842,6 @@ class Convo$6 {
2871
2842
  return this.header.toString() + (this.sourceTag ? ` (${util__default["default"].inspect(this.sourceTag)})` : '') + ': ' + this.conversation.map(c => c.toString()).join(' | ');
2872
2843
  }
2873
2844
  async Run(container) {
2874
- const retryHelper = new RetryHelper_1(container.caps, 'CONVO');
2875
- return promiseRetry__default["default"](async (retry, number) => {
2876
- return this.RunImpl(container).catch(err => {
2877
- const retryRemaining = retryHelper.retrySettings.retries - number + 1;
2878
- if (retryHelper.shouldRetry(err)) {
2879
- debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry ${retryRemaining > 0 ? 'enabled' : 'disabled'} (remaining #${retryRemaining}/${retryHelper.retrySettings.retries}, criterion matches)`);
2880
- retry(err);
2881
- } else {
2882
- if (retryHelper.retryErrorPatterns.length > 0) {
2883
- debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry 'disabled' (remaining (#${retryRemaining}/${retryHelper.retrySettings.retries}), criterion does not match)`);
2884
- }
2885
- throw err;
2886
- }
2887
- });
2888
- }, retryHelper.retrySettings);
2889
- }
2890
- async RunImpl(container) {
2891
2845
  const transcript = new Transcript({
2892
2846
  steps: [],
2893
2847
  attachments: [],
@@ -2993,6 +2947,7 @@ class Convo$6 {
2993
2947
  for (let i = 0; i < this.conversation.length; i++) {
2994
2948
  const convoStep = this.conversation[i];
2995
2949
  const currentStepIndex = i;
2950
+ container.eventEmitter.emit(Events.CONVO_STEP_NEXT, container, convoStep, i);
2996
2951
  skipTranscriptStep = false;
2997
2952
  const transcriptStep = new TranscriptStep({
2998
2953
  expected: new BotiumMockMessage_1(convoStep),
@@ -3052,7 +3007,7 @@ class Convo$6 {
3052
3007
  });
3053
3008
  await this._checkBotRepliesConsumed(container);
3054
3009
  const coreMsg = lodash__default["default"].omit(removeBuffers(meMsg), ['sourceData']);
3055
- debug$i(`${this.header.name}/${convoStep.stepTag}: user says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3010
+ debug$j(`${this.header.name}/${convoStep.stepTag}: user says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3056
3011
  await new Promise(resolve => {
3057
3012
  if (container.caps.SIMULATE_WRITING_SPEED && meMsg.messageText && meMsg.messageText.length) {
3058
3013
  setTimeout(() => resolve(), container.caps.SIMULATE_WRITING_SPEED * meMsg.messageText.length);
@@ -3088,7 +3043,7 @@ class Convo$6 {
3088
3043
  });
3089
3044
  continue;
3090
3045
  } else {
3091
- debug$i(`${this.header.name}/${convoStep.stepTag}: message not found in #me section, message not sent to container ${util__default["default"].inspect(convoStep)}`);
3046
+ debug$j(`${this.header.name}/${convoStep.stepTag}: message not found in #me section, message not sent to container ${util__default["default"].inspect(convoStep)}`);
3092
3047
  transcriptStep.botEnd = new Date();
3093
3048
  await this.scriptingEvents.onMeEnd({
3094
3049
  convo: this,
@@ -3104,7 +3059,7 @@ class Convo$6 {
3104
3059
  } catch (err) {
3105
3060
  transcriptStep.botEnd = new Date();
3106
3061
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error sending to bot - ${err.message || err}`, err);
3107
- debug$i(failErr);
3062
+ debug$j(failErr);
3108
3063
  try {
3109
3064
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3110
3065
  } catch (failErr) {}
@@ -3117,7 +3072,7 @@ class Convo$6 {
3117
3072
  waitForBotSays = true;
3118
3073
  }
3119
3074
  try {
3120
- debug$i(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3075
+ debug$j(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3121
3076
  await this.scriptingEvents.onBotStart({
3122
3077
  convo: this,
3123
3078
  convoStep,
@@ -3133,11 +3088,11 @@ class Convo$6 {
3133
3088
  transcriptStep.botEnd = new Date();
3134
3089
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3135
3090
  const coreMsg = lodash__default["default"].omit(removeBuffers(botMsg), ['sourceData']);
3136
- debug$i(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3091
+ debug$j(`${this.header.name}: bot says (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3137
3092
  } catch (err) {
3138
3093
  transcriptStep.botEnd = new Date();
3139
3094
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error waiting for bot - ${err.message}`, err);
3140
- debug$i(failErr);
3095
+ debug$j(failErr);
3141
3096
  try {
3142
3097
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3143
3098
  } catch (failErr) {}
@@ -3156,11 +3111,11 @@ class Convo$6 {
3156
3111
  if (prepared) {
3157
3112
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3158
3113
  const coreMsg = lodash__default["default"].omit(removeBuffers(botMsg), ['sourceData']);
3159
- debug$i(`${this.header.name}: onBotPrepare (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3114
+ debug$j(`${this.header.name}: onBotPrepare (cleaned by binary and base64 data and sourceData) ${JSON.stringify(coreMsg, null, 2)}`);
3160
3115
  }
3161
3116
  } catch (err) {
3162
3117
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: onBotPrepare error - ${err.message || err}`, err);
3163
- debug$i(failErr);
3118
+ debug$j(failErr);
3164
3119
  try {
3165
3120
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3166
3121
  } catch (failErr) {}
@@ -3168,7 +3123,7 @@ class Convo$6 {
3168
3123
  }
3169
3124
  if (!botMsg || !botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp) {
3170
3125
  const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3171
- debug$i(failErr);
3126
+ debug$j(failErr);
3172
3127
  try {
3173
3128
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3174
3129
  } catch (failErr) {}
@@ -3249,7 +3204,7 @@ class Convo$6 {
3249
3204
  continue;
3250
3205
  }
3251
3206
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: assertion error - ${err.message || err}`, err);
3252
- debug$i(failErr);
3207
+ debug$j(failErr);
3253
3208
  try {
3254
3209
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3255
3210
  } catch (failErr) {}
@@ -3270,7 +3225,7 @@ class Convo$6 {
3270
3225
  }
3271
3226
  } else {
3272
3227
  const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util__default["default"].inspect(convoStep.sender)}`);
3273
- debug$i(failErr);
3228
+ debug$j(failErr);
3274
3229
  try {
3275
3230
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3276
3231
  } catch (failErr) {}
@@ -3476,7 +3431,7 @@ class Convo$6 {
3476
3431
  throw new BotiumError$4(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3477
3432
  }
3478
3433
  _getEffectiveConversationRecursive(partialConvo.conversation, [...parentPConvos, includeLogicHook], result, true);
3479
- debug$i(`Partial convo ${includeLogicHook} included`);
3434
+ debug$j(`Partial convo ${includeLogicHook} included`);
3480
3435
  });
3481
3436
  });
3482
3437
  return result;
@@ -3497,10 +3452,48 @@ var Convo_1 = {
3497
3452
  TranscriptError
3498
3453
  };
3499
3454
 
3455
+ const debug$i = debug__default["default"]('botium-core-RetryHelper');
3456
+ var RetryHelper_1 = class RetryHelper {
3457
+ constructor(caps, section, options = {}) {
3458
+ this.retryErrorPatterns = [];
3459
+ const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
3460
+ if (onErrorRegexp) {
3461
+ if (lodash__default["default"].isArray(onErrorRegexp)) {
3462
+ onErrorRegexp.forEach(r => {
3463
+ if (lodash__default["default"].isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
3464
+ });
3465
+ } else if (lodash__default["default"].isString(onErrorRegexp)) {
3466
+ this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
3467
+ } else {
3468
+ this.retryErrorPatterns.push(onErrorRegexp);
3469
+ }
3470
+ }
3471
+
3472
+ // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
3473
+ this.retrySettings = {
3474
+ retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash__default["default"].isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
3475
+ factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash__default["default"].isNil(options.factor) ? 1 : options.factor),
3476
+ minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash__default["default"].isNil(options.minTimeout) ? 1000 : options.minTimeout)
3477
+ };
3478
+ if (this.retrySettings.retries > 0) {
3479
+ debug$i(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
3480
+ }
3481
+ }
3482
+ shouldRetry(err) {
3483
+ if (!err) return false;
3484
+ if (this.retryErrorPatterns.length === 0) return true;
3485
+ const errString = util__default["default"].inspect(err);
3486
+ for (const re of this.retryErrorPatterns) {
3487
+ if (errString.match(re)) return true;
3488
+ }
3489
+ return false;
3490
+ }
3491
+ };
3492
+
3500
3493
  const {
3501
3494
  toString,
3502
3495
  quoteRegexpString,
3503
- calculateWer
3496
+ calculateWer: calculateWer$1
3504
3497
  } = helper;
3505
3498
  const _normalize = botresponse => {
3506
3499
  if (lodash__default["default"].isUndefined(botresponse) || lodash__default["default"].isNil(botresponse)) return '';
@@ -3568,7 +3561,7 @@ const wer = () => (botresponse, utterance, args) => {
3568
3561
  botresponse = _normalize(botresponse || '');
3569
3562
  utterance = toString(utterance || '');
3570
3563
  const threshold = [',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100;
3571
- return calculateWer(botresponse, utterance) <= threshold;
3564
+ return calculateWer$1(botresponse, utterance) <= threshold;
3572
3565
  };
3573
3566
  const getMatchFunction$1 = matchingMode => {
3574
3567
  if (matchingMode === 'regexp' || matchingMode === 'regexpIgnoreCase') {
@@ -5362,6 +5355,10 @@ const {
5362
5355
  const {
5363
5356
  getMatchFunction
5364
5357
  } = MatchFunctions;
5358
+ const {
5359
+ calculateWer,
5360
+ toPercent
5361
+ } = helper;
5365
5362
  const globPattern = '**/+(*.convo.txt|*.utterances.txt|*.pconvo.txt|*.scriptingmemory.txt|*.xlsx|*.xlsm|*.convo.csv|*.pconvo.csv|*.utterances.csv|*.yaml|*.yml|*.json|*.md|*.markdown)';
5366
5363
  const skipPattern = /^skip[.\-_]/i;
5367
5364
  const p = (retryHelper, fn) => {
@@ -5622,29 +5619,51 @@ var ScriptingProvider_1 = class ScriptingProvider {
5622
5619
  const found = lodash__default["default"].find(tomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5623
5620
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5624
5621
  if (lodash__default["default"].isNil(found)) {
5625
- let message = `${stepTag}: Bot response `;
5626
- message += meMsg ? `(on ${meMsg}) ` : '';
5627
- message += botresponse ? '"' + botresponse + '"' : '<no response>';
5628
- message += ' expected to match ';
5629
- message += tomatch && tomatch.length > 1 ? 'one of ' : '';
5630
- message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5631
- throw new BotiumError$2(message, {
5632
- type: 'asserter',
5633
- source: asserterType,
5634
- params: {
5635
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5636
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5637
- },
5638
- context: {
5639
- stepTag
5640
- },
5641
- cause: {
5642
- expected: tomatch,
5643
- actual: botresponse,
5644
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5645
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5646
- }
5647
- });
5622
+ if (this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer') {
5623
+ const wer = calculateWer(botresponse, tomatch[0]);
5624
+ const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5625
+ const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5626
+ const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) higher than accepted (${toPercent(threshold)})`;
5627
+ throw new BotiumError$2(message, {
5628
+ type: 'asserter',
5629
+ source: asserterType,
5630
+ params: {
5631
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5632
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5633
+ },
5634
+ context: {
5635
+ stepTag
5636
+ },
5637
+ cause: {
5638
+ expected: `<=${toPercent(threshold)} (${tomatch})`,
5639
+ actual: `${toPercent(wer)} (${botresponse})`
5640
+ }
5641
+ });
5642
+ } else {
5643
+ let message = `${stepTag}: Bot response `;
5644
+ message += meMsg ? `(on ${meMsg}) ` : '';
5645
+ message += botresponse ? '"' + botresponse + '"' : '<no response>';
5646
+ message += ' expected to match ';
5647
+ message += tomatch && tomatch.length > 1 ? 'one of ' : '';
5648
+ message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5649
+ throw new BotiumError$2(message, {
5650
+ type: 'asserter',
5651
+ source: asserterType,
5652
+ params: {
5653
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5654
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5655
+ },
5656
+ context: {
5657
+ stepTag
5658
+ },
5659
+ cause: {
5660
+ expected: tomatch,
5661
+ actual: botresponse,
5662
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5663
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5664
+ }
5665
+ });
5666
+ }
5648
5667
  }
5649
5668
  },
5650
5669
  assertBotNotResponse: (botresponse, nottomatch, stepTag, meMsg) => {
@@ -5655,30 +5674,52 @@ var ScriptingProvider_1 = class ScriptingProvider {
5655
5674
  const found = lodash__default["default"].find(nottomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5656
5675
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5657
5676
  if (!lodash__default["default"].isNil(found)) {
5658
- let message = `${stepTag}: Bot response `;
5659
- message += meMsg ? `(on ${meMsg}) ` : '';
5660
- message += botresponse ? '"' + botresponse + '"' : '<no response>';
5661
- message += ' expected NOT to match ';
5662
- message += nottomatch && nottomatch.length > 1 ? 'one of ' : '';
5663
- message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5664
- throw new BotiumError$2(message, {
5665
- type: 'asserter',
5666
- source: asserterType,
5667
- params: {
5668
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5669
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5670
- },
5671
- context: {
5672
- stepTag
5673
- },
5674
- cause: {
5675
- not: true,
5676
- expected: nottomatch,
5677
- actual: botresponse,
5678
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5679
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5680
- }
5681
- });
5677
+ if (this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer') {
5678
+ const wer = calculateWer(botresponse, nottomatch[0]);
5679
+ const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5680
+ const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5681
+ const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) lower than accepted (${toPercent(threshold)})`;
5682
+ throw new BotiumError$2(message, {
5683
+ type: 'asserter',
5684
+ source: asserterType,
5685
+ params: {
5686
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5687
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5688
+ },
5689
+ context: {
5690
+ stepTag
5691
+ },
5692
+ cause: {
5693
+ expected: `>=${toPercent(threshold)} (${nottomatch})`,
5694
+ actual: `${toPercent(wer)} (${botresponse})`
5695
+ }
5696
+ });
5697
+ } else {
5698
+ let message = `${stepTag}: Bot response `;
5699
+ message += meMsg ? `(on ${meMsg}) ` : '';
5700
+ message += botresponse ? '"' + botresponse + '"' : '<no response>';
5701
+ message += ' expected NOT to match ';
5702
+ message += nottomatch && nottomatch.length > 1 ? 'one of ' : '';
5703
+ message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5704
+ throw new BotiumError$2(message, {
5705
+ type: 'asserter',
5706
+ source: asserterType,
5707
+ params: {
5708
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5709
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5710
+ },
5711
+ context: {
5712
+ stepTag
5713
+ },
5714
+ cause: {
5715
+ not: true,
5716
+ expected: nottomatch,
5717
+ actual: botresponse,
5718
+ matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5719
+ args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5720
+ }
5721
+ });
5722
+ }
5682
5723
  }
5683
5724
  },
5684
5725
  fail: null
@@ -7149,6 +7190,9 @@ var Queue_1 = class Queue {
7149
7190
  }
7150
7191
  };
7151
7192
 
7193
+ const {
7194
+ rimraf: rimraf$1
7195
+ } = rimraf__default["default"];
7152
7196
  const debug$7 = debug__default["default"]('botium-connector-BaseContainer');
7153
7197
  const {
7154
7198
  executeHook: executeHook$1,
@@ -7281,10 +7325,7 @@ var BaseContainer_1 = class BaseContainer {
7281
7325
  }, rimraffed => {
7282
7326
  if (this.caps[Capabilities.CLEANUPTEMPDIR]) {
7283
7327
  debug$7(`Cleanup rimrafing temp dir ${this.tempDirectory}`);
7284
- rimraf__default["default"](this.tempDirectory, err => {
7285
- if (err) debug$7(`Cleanup temp dir ${this.tempDirectory} failed: ${util__default["default"].inspect(err)}`);
7286
- rimraffed();
7287
- });
7328
+ rimraf$1(this.tempDirectory).catch(err => debug$7(`Cleanup temp dir ${this.tempDirectory} failed: ${util__default["default"].inspect(err)}`)).finally(() => rimraffed());
7288
7329
  } else {
7289
7330
  rimraffed();
7290
7331
  }
@@ -8808,15 +8849,21 @@ var PluginConnectorContainer_1 = class PluginConnectorContainer extends BaseCont
8808
8849
  }
8809
8850
  };
8810
8851
 
8811
- var require$$2 = getCjsExportFromNamespace(_package$1);
8852
+ var require$$4 = getCjsExportFromNamespace(_package$1);
8812
8853
 
8854
+ const {
8855
+ rimraf
8856
+ } = rimraf__default["default"];
8857
+ const {
8858
+ mkdirpSync
8859
+ } = mkdirp__default["default"];
8813
8860
  const {
8814
8861
  boolean
8815
8862
  } = boolean__default["default"];
8816
8863
  const debug$1 = debug__default["default"]('botium-core-BotDriver');
8817
8864
  const {
8818
8865
  version
8819
- } = require$$2;
8866
+ } = require$$4;
8820
8867
  var BotDriver_1 = class BotDriver {
8821
8868
  constructor(caps = {}, sources = {}, envs = {}) {
8822
8869
  this.eventEmitter = new events__default["default"]();
@@ -8906,7 +8953,7 @@ var BotDriver_1 = class BotDriver {
8906
8953
  }, tempDirectoryCreated => {
8907
8954
  tempDirectory = path__default["default"].resolve(process.cwd(), this.caps[Capabilities.TEMPDIR], sanitizeFilename__default["default"](`${this.caps[Capabilities.PROJECTNAME]} ${moment__default["default"]().format('YYYYMMDD HHmmss')} ${randomatic__default["default"]('Aa0', 5)}`));
8908
8955
  try {
8909
- mkdirp__default["default"].sync(tempDirectory);
8956
+ mkdirpSync(tempDirectory);
8910
8957
  tempDirectoryCreated();
8911
8958
  } catch (err) {
8912
8959
  tempDirectoryCreated(new Error(`Unable to create temp directory ${tempDirectory}: ${err.message}`));
@@ -8934,9 +8981,7 @@ var BotDriver_1 = class BotDriver {
8934
8981
  debug$1(`BotDriver Build error: ${err}`);
8935
8982
  this.eventEmitter.emit(Events.CONTAINER_BUILD_ERROR, err);
8936
8983
  if (tempDirectory) {
8937
- rimraf__default["default"](tempDirectory, err => {
8938
- if (err) debug$1(`Cleanup temp dir ${tempDirectory} failed: ${util__default["default"].inspect(err)}`);
8939
- });
8984
+ rimraf(tempDirectory).catch(err => debug$1(`Cleanup temp dir ${tempDirectory} failed: ${util__default["default"].inspect(err)}`));
8940
8985
  }
8941
8986
  return reject(err);
8942
8987
  }
@@ -9291,6 +9336,7 @@ var botiumCore = {
9291
9336
  InboundProxy: proxy,
9292
9337
  HookUtils: HookUtils,
9293
9338
  TranscriptUtils: TranscriptUtils,
9339
+ RetryHelper: RetryHelper_1,
9294
9340
  BotiumMockRichMessageTypes: BotiumMockRichMessageTypes,
9295
9341
  BotiumError: BotiumError_1.BotiumError,
9296
9342
  ScriptingConstants: Constants,
@@ -9312,29 +9358,31 @@ var botiumCore_7 = botiumCore.Source;
9312
9358
  var botiumCore_8 = botiumCore.InboundProxy;
9313
9359
  var botiumCore_9 = botiumCore.HookUtils;
9314
9360
  var botiumCore_10 = botiumCore.TranscriptUtils;
9315
- var botiumCore_11 = botiumCore.BotiumMockRichMessageTypes;
9316
- var botiumCore_12 = botiumCore.BotiumError;
9317
- var botiumCore_13 = botiumCore.ScriptingConstants;
9318
- var botiumCore_14 = botiumCore.ScriptingMemory;
9319
- var botiumCore_15 = botiumCore.ScriptingProvider;
9320
- var botiumCore_16 = botiumCore.LogicHookConstants;
9321
- var botiumCore_17 = botiumCore.Lib;
9361
+ var botiumCore_11 = botiumCore.RetryHelper;
9362
+ var botiumCore_12 = botiumCore.BotiumMockRichMessageTypes;
9363
+ var botiumCore_13 = botiumCore.BotiumError;
9364
+ var botiumCore_14 = botiumCore.ScriptingConstants;
9365
+ var botiumCore_15 = botiumCore.ScriptingMemory;
9366
+ var botiumCore_16 = botiumCore.ScriptingProvider;
9367
+ var botiumCore_17 = botiumCore.LogicHookConstants;
9368
+ var botiumCore_18 = botiumCore.Lib;
9322
9369
 
9323
9370
  exports.BotDriver = botiumCore_1;
9324
- exports.BotiumError = botiumCore_12;
9325
- exports.BotiumMockRichMessageTypes = botiumCore_11;
9371
+ exports.BotiumError = botiumCore_13;
9372
+ exports.BotiumMockRichMessageTypes = botiumCore_12;
9326
9373
  exports.Capabilities = botiumCore_2;
9327
9374
  exports.Defaults = botiumCore_3;
9328
9375
  exports.Enums = botiumCore_4;
9329
9376
  exports.Events = botiumCore_5;
9330
9377
  exports.HookUtils = botiumCore_9;
9331
9378
  exports.InboundProxy = botiumCore_8;
9332
- exports.Lib = botiumCore_17;
9333
- exports.LogicHookConstants = botiumCore_16;
9379
+ exports.Lib = botiumCore_18;
9380
+ exports.LogicHookConstants = botiumCore_17;
9334
9381
  exports.Plugins = botiumCore_6;
9335
- exports.ScriptingConstants = botiumCore_13;
9336
- exports.ScriptingMemory = botiumCore_14;
9337
- exports.ScriptingProvider = botiumCore_15;
9382
+ exports.RetryHelper = botiumCore_11;
9383
+ exports.ScriptingConstants = botiumCore_14;
9384
+ exports.ScriptingMemory = botiumCore_15;
9385
+ exports.ScriptingProvider = botiumCore_16;
9338
9386
  exports.Source = botiumCore_7;
9339
9387
  exports.TranscriptUtils = botiumCore_10;
9340
9388
  exports["default"] = botiumCore;