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.
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.15";
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",
@@ -812,6 +812,7 @@ var Events = {
812
812
  CONTAINER_CLEANED: 'CONTAINER_CLEANED',
813
813
  CONTAINER_CLEAN_ERROR: 'CONTAINER_CLEAN_ERROR',
814
814
  BOT_CONNECTED: 'BOT_CONNECTED',
815
+ CONVO_STEP_NEXT: 'CONVO_STEP_NEXT',
815
816
  // Chatbot Events
816
817
  MESSAGE_SENTTOBOT: 'MESSAGE_SENTTOBOT',
817
818
  MESSAGE_SENDTOBOT_ERROR: 'MESSAGE_SENDTOBOT_ERROR',
@@ -835,6 +836,7 @@ Events.CONTAINER_CLEANING;
835
836
  Events.CONTAINER_CLEANED;
836
837
  Events.CONTAINER_CLEAN_ERROR;
837
838
  Events.BOT_CONNECTED;
839
+ Events.CONVO_STEP_NEXT;
838
840
  Events.MESSAGE_SENTTOBOT;
839
841
  Events.MESSAGE_SENDTOBOT_ERROR;
840
842
  Events.MESSAGE_RECEIVEDFROMBOT;
@@ -1722,10 +1724,10 @@ const toString$3 = value => {
1722
1724
  return '' + value;
1723
1725
  };
1724
1726
  const flatString = str => {
1725
- return str ? str.split('\n').map(s => s.trim()).join(' ') : '';
1727
+ return toString$3(str).split('\n').map(s => s.trim()).join(' ') || '';
1726
1728
  };
1727
1729
  const _formatAppendArgs = args => {
1728
- return args ? ` ${args.map(a => lodash.isString(a) ? a.replace(/\|/g, '\\|') : `${a}`).join('|')}` : '';
1730
+ return args && args.length > 0 && lodash.isArray(args) && ` ${args.map(a => lodash.isString(a) ? a.replace(/\|/g, '\\|') : `${a}`).join('|')}` || '';
1729
1731
  };
1730
1732
  const _parseArgs = str => {
1731
1733
  return str && str.length > 0 && str.replace(/\\\|/g, '###ESCAPESPLIT###').split('|').map(s => s.replace(/###ESCAPESPLIT###/g, '|').trim()) || [];
@@ -2178,7 +2180,7 @@ const linesToScriptingMemories$2 = (lines, columnMode = null) => {
2178
2180
  }
2179
2181
  return scriptingMemories;
2180
2182
  };
2181
- const calculateWer$1 = (str, pattern) => {
2183
+ const calculateWer$2 = (str, pattern) => {
2182
2184
  const _prepareString = (str, remWildcard = false) => {
2183
2185
  if (remWildcard) return str.replace(/[.,/#!$%^&;:*{}=\-_`~()]/g, '').toLowerCase();
2184
2186
  return str.replace(/[.,/#!$%^&;:{}=\-_`~()]/g, '').toLowerCase();
@@ -2201,6 +2203,11 @@ const calculateWer$1 = (str, pattern) => {
2201
2203
  const botMessage = _prepareString(str);
2202
2204
  const botMessageWords = botMessage.split(' ').map(bm => bm.trim());
2203
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
2204
2211
  const errors = [];
2205
2212
  for (let wildcardPart of utt.split('*')) {
2206
2213
  let wer = 1;
@@ -2220,7 +2227,7 @@ const calculateWer$1 = (str, pattern) => {
2220
2227
  }
2221
2228
  }
2222
2229
  if (lodash.isNil(subsetPhraseFound)) {
2223
- 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!');
2224
2231
  }
2225
2232
  errors.push(_getErrors(_getWords(wildcardPart), _getWords(subsetPhraseFound)));
2226
2233
  }
@@ -2233,6 +2240,7 @@ const calculateWer$1 = (str, pattern) => {
2233
2240
  debug$l(`Word Error Rate Asserter - Compared Bot Message '${botMessage}' / '${utt}': ${(errCount / allCount).toFixed(2)}`);
2234
2241
  return (errCount / allCount).toFixed(2);
2235
2242
  };
2243
+ const toPercent$1 = s => `${(s * 100).toFixed(0)}%`;
2236
2244
  var helper = {
2237
2245
  normalizeText: normalizeText$1,
2238
2246
  splitStringInNonEmptyLines: splitStringInNonEmptyLines$1,
@@ -2247,7 +2255,8 @@ var helper = {
2247
2255
  validateSender: validateSender$1,
2248
2256
  validateConvo: validateConvo$2,
2249
2257
  linesToScriptingMemories: linesToScriptingMemories$2,
2250
- calculateWer: calculateWer$1
2258
+ calculateWer: calculateWer$2,
2259
+ toPercent: toPercent$1
2251
2260
  };
2252
2261
 
2253
2262
  const debug$k = debug$n('botium-core-ScriptingMemory');
@@ -2587,45 +2596,7 @@ ScriptingMemory.extractVarNames;
2587
2596
  ScriptingMemory.RESERVED_WORDS;
2588
2597
  ScriptingMemory.SCRIPTING_FUNCTIONS;
2589
2598
 
2590
- const debug$j = debug$n('botium-core-RetryHelper');
2591
- var RetryHelper_1 = class RetryHelper {
2592
- constructor(caps, section, options = {}) {
2593
- this.retryErrorPatterns = [];
2594
- const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
2595
- if (onErrorRegexp) {
2596
- if (lodash.isArray(onErrorRegexp)) {
2597
- onErrorRegexp.forEach(r => {
2598
- if (lodash.isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
2599
- });
2600
- } else if (lodash.isString(onErrorRegexp)) {
2601
- this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
2602
- } else {
2603
- this.retryErrorPatterns.push(onErrorRegexp);
2604
- }
2605
- }
2606
-
2607
- // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
2608
- this.retrySettings = {
2609
- retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash.isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
2610
- factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash.isNil(options.factor) ? 1 : options.factor),
2611
- minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash.isNil(options.minTimeout) ? 1000 : options.minTimeout)
2612
- };
2613
- if (this.retrySettings.retries > 0) {
2614
- debug$j(`Retry for ${section} is enabled. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
2615
- }
2616
- }
2617
- shouldRetry(err) {
2618
- if (!err) return false;
2619
- if (this.retryErrorPatterns.length === 0) return true;
2620
- const errString = util.inspect(err);
2621
- for (const re of this.retryErrorPatterns) {
2622
- if (errString.match(re)) return true;
2623
- }
2624
- return false;
2625
- }
2626
- };
2627
-
2628
- const debug$i = debug$n('botium-core-Convo');
2599
+ const debug$j = debug$n('botium-core-Convo');
2629
2600
  const {
2630
2601
  BotiumError: BotiumError$4,
2631
2602
  botiumErrorFromErr: botiumErrorFromErr$1,
@@ -2779,10 +2750,10 @@ class TranscriptError extends Error {
2779
2750
  class Convo$6 {
2780
2751
  constructor(context, fromJson = {}) {
2781
2752
  if (fromJson instanceof Convo$6) {
2782
- 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');
2783
2754
  } else if (fromJson.beginAsserter) {
2784
2755
  // beginAsserter is one of the fields which are lost
2785
- 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');
2786
2757
  }
2787
2758
  this.scriptingEvents = context.scriptingEvents;
2788
2759
  this.context = context;
@@ -2827,23 +2798,6 @@ class Convo$6 {
2827
2798
  return this.header.toString() + (this.sourceTag ? ` (${util.inspect(this.sourceTag)})` : '') + ': ' + this.conversation.map(c => c.toString()).join(' | ');
2828
2799
  }
2829
2800
  async Run(container) {
2830
- const retryHelper = new RetryHelper_1(container.caps, 'CONVO');
2831
- return promiseRetry(async (retry, number) => {
2832
- return this.RunImpl(container).catch(err => {
2833
- const retryRemaining = retryHelper.retrySettings.retries - number + 1;
2834
- if (retryHelper.shouldRetry(err)) {
2835
- debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry ${retryRemaining > 0 ? 'enabled' : 'disabled'} (remaining #${retryRemaining}/${retryHelper.retrySettings.retries}, criterion matches)`);
2836
- retry(err);
2837
- } else {
2838
- if (retryHelper.retryErrorPatterns.length > 0) {
2839
- debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry 'disabled' (remaining (#${retryRemaining}/${retryHelper.retrySettings.retries}), criterion does not match)`);
2840
- }
2841
- throw err;
2842
- }
2843
- });
2844
- }, retryHelper.retrySettings);
2845
- }
2846
- async RunImpl(container) {
2847
2801
  const transcript = new Transcript({
2848
2802
  steps: [],
2849
2803
  attachments: [],
@@ -2949,6 +2903,7 @@ class Convo$6 {
2949
2903
  for (let i = 0; i < this.conversation.length; i++) {
2950
2904
  const convoStep = this.conversation[i];
2951
2905
  const currentStepIndex = i;
2906
+ container.eventEmitter.emit(Events.CONVO_STEP_NEXT, container, convoStep, i);
2952
2907
  skipTranscriptStep = false;
2953
2908
  const transcriptStep = new TranscriptStep({
2954
2909
  expected: new BotiumMockMessage_1(convoStep),
@@ -3008,7 +2963,7 @@ class Convo$6 {
3008
2963
  });
3009
2964
  await this._checkBotRepliesConsumed(container);
3010
2965
  const coreMsg = lodash.omit(removeBuffers(meMsg), ['sourceData']);
3011
- 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)}`);
3012
2967
  await new Promise(resolve => {
3013
2968
  if (container.caps.SIMULATE_WRITING_SPEED && meMsg.messageText && meMsg.messageText.length) {
3014
2969
  setTimeout(() => resolve(), container.caps.SIMULATE_WRITING_SPEED * meMsg.messageText.length);
@@ -3044,7 +2999,7 @@ class Convo$6 {
3044
2999
  });
3045
3000
  continue;
3046
3001
  } else {
3047
- 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)}`);
3048
3003
  transcriptStep.botEnd = new Date();
3049
3004
  await this.scriptingEvents.onMeEnd({
3050
3005
  convo: this,
@@ -3060,7 +3015,7 @@ class Convo$6 {
3060
3015
  } catch (err) {
3061
3016
  transcriptStep.botEnd = new Date();
3062
3017
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error sending to bot - ${err.message || err}`, err);
3063
- debug$i(failErr);
3018
+ debug$j(failErr);
3064
3019
  try {
3065
3020
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3066
3021
  } catch (failErr) {}
@@ -3073,7 +3028,7 @@ class Convo$6 {
3073
3028
  waitForBotSays = true;
3074
3029
  }
3075
3030
  try {
3076
- debug$i(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3031
+ debug$j(`${this.header.name} wait for bot ${convoStep.channel || ''}`);
3077
3032
  await this.scriptingEvents.onBotStart({
3078
3033
  convo: this,
3079
3034
  convoStep,
@@ -3089,11 +3044,11 @@ class Convo$6 {
3089
3044
  transcriptStep.botEnd = new Date();
3090
3045
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3091
3046
  const coreMsg = lodash.omit(removeBuffers(botMsg), ['sourceData']);
3092
- 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)}`);
3093
3048
  } catch (err) {
3094
3049
  transcriptStep.botEnd = new Date();
3095
3050
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: error waiting for bot - ${err.message}`, err);
3096
- debug$i(failErr);
3051
+ debug$j(failErr);
3097
3052
  try {
3098
3053
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3099
3054
  } catch (failErr) {}
@@ -3112,11 +3067,11 @@ class Convo$6 {
3112
3067
  if (prepared) {
3113
3068
  transcriptStep.actual = new BotiumMockMessage_1(botMsg);
3114
3069
  const coreMsg = lodash.omit(removeBuffers(botMsg), ['sourceData']);
3115
- 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)}`);
3116
3071
  }
3117
3072
  } catch (err) {
3118
3073
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: onBotPrepare error - ${err.message || err}`, err);
3119
- debug$i(failErr);
3074
+ debug$j(failErr);
3120
3075
  try {
3121
3076
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3122
3077
  } catch (failErr) {}
@@ -3124,7 +3079,7 @@ class Convo$6 {
3124
3079
  }
3125
3080
  if (!botMsg || !botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp) {
3126
3081
  const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3127
- debug$i(failErr);
3082
+ debug$j(failErr);
3128
3083
  try {
3129
3084
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3130
3085
  } catch (failErr) {}
@@ -3205,7 +3160,7 @@ class Convo$6 {
3205
3160
  continue;
3206
3161
  }
3207
3162
  const failErr = botiumErrorFromErr$1(`${this.header.name}/${convoStep.stepTag}: assertion error - ${err.message || err}`, err);
3208
- debug$i(failErr);
3163
+ debug$j(failErr);
3209
3164
  try {
3210
3165
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3211
3166
  } catch (failErr) {}
@@ -3226,7 +3181,7 @@ class Convo$6 {
3226
3181
  }
3227
3182
  } else {
3228
3183
  const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util.inspect(convoStep.sender)}`);
3229
- debug$i(failErr);
3184
+ debug$j(failErr);
3230
3185
  try {
3231
3186
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
3232
3187
  } catch (failErr) {}
@@ -3432,7 +3387,7 @@ class Convo$6 {
3432
3387
  throw new BotiumError$4(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3433
3388
  }
3434
3389
  _getEffectiveConversationRecursive(partialConvo.conversation, [...parentPConvos, includeLogicHook], result, true);
3435
- debug$i(`Partial convo ${includeLogicHook} included`);
3390
+ debug$j(`Partial convo ${includeLogicHook} included`);
3436
3391
  });
3437
3392
  });
3438
3393
  return result;
@@ -3453,10 +3408,48 @@ var Convo_1 = {
3453
3408
  TranscriptError
3454
3409
  };
3455
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
+
3456
3449
  const {
3457
3450
  toString,
3458
3451
  quoteRegexpString,
3459
- calculateWer
3452
+ calculateWer: calculateWer$1
3460
3453
  } = helper;
3461
3454
  const _normalize = botresponse => {
3462
3455
  if (lodash.isUndefined(botresponse) || lodash.isNil(botresponse)) return '';
@@ -3524,7 +3517,7 @@ const wer = () => (botresponse, utterance, args) => {
3524
3517
  botresponse = _normalize(botresponse || '');
3525
3518
  utterance = toString(utterance || '');
3526
3519
  const threshold = [',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100;
3527
- return calculateWer(botresponse, utterance) <= threshold;
3520
+ return calculateWer$1(botresponse, utterance) <= threshold;
3528
3521
  };
3529
3522
  const getMatchFunction$1 = matchingMode => {
3530
3523
  if (matchingMode === 'regexp' || matchingMode === 'regexpIgnoreCase') {
@@ -5318,6 +5311,10 @@ const {
5318
5311
  const {
5319
5312
  getMatchFunction
5320
5313
  } = MatchFunctions;
5314
+ const {
5315
+ calculateWer,
5316
+ toPercent
5317
+ } = helper;
5321
5318
  const globPattern = '**/+(*.convo.txt|*.utterances.txt|*.pconvo.txt|*.scriptingmemory.txt|*.xlsx|*.xlsm|*.convo.csv|*.pconvo.csv|*.utterances.csv|*.yaml|*.yml|*.json|*.md|*.markdown)';
5322
5319
  const skipPattern = /^skip[.\-_]/i;
5323
5320
  const p = (retryHelper, fn) => {
@@ -5578,29 +5575,51 @@ var ScriptingProvider_1 = class ScriptingProvider {
5578
5575
  const found = lodash.find(tomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5579
5576
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5580
5577
  if (lodash.isNil(found)) {
5581
- let message = `${stepTag}: Bot response `;
5582
- message += meMsg ? `(on ${meMsg}) ` : '';
5583
- message += botresponse ? '"' + botresponse + '"' : '<no response>';
5584
- message += ' expected to match ';
5585
- message += tomatch && tomatch.length > 1 ? 'one of ' : '';
5586
- message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5587
- throw new BotiumError$2(message, {
5588
- type: 'asserter',
5589
- source: asserterType,
5590
- params: {
5591
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5592
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5593
- },
5594
- context: {
5595
- stepTag
5596
- },
5597
- cause: {
5598
- expected: tomatch,
5599
- actual: botresponse,
5600
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5601
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5602
- }
5603
- });
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
+ }
5604
5623
  }
5605
5624
  },
5606
5625
  assertBotNotResponse: (botresponse, nottomatch, stepTag, meMsg) => {
@@ -5611,30 +5630,52 @@ var ScriptingProvider_1 = class ScriptingProvider {
5611
5630
  const found = lodash.find(nottomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
5612
5631
  const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'Word Error Rate Asserter' : 'Text Match Asserter';
5613
5632
  if (!lodash.isNil(found)) {
5614
- let message = `${stepTag}: Bot response `;
5615
- message += meMsg ? `(on ${meMsg}) ` : '';
5616
- message += botresponse ? '"' + botresponse + '"' : '<no response>';
5617
- message += ' expected NOT to match ';
5618
- message += nottomatch && nottomatch.length > 1 ? 'one of ' : '';
5619
- message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5620
- throw new BotiumError$2(message, {
5621
- type: 'asserter',
5622
- source: asserterType,
5623
- params: {
5624
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5625
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5626
- },
5627
- context: {
5628
- stepTag
5629
- },
5630
- cause: {
5631
- not: true,
5632
- expected: nottomatch,
5633
- actual: botresponse,
5634
- matchingMode: this.caps[Capabilities.SCRIPTING_MATCHING_MODE],
5635
- args: this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS] || null
5636
- }
5637
- });
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
+ }
5638
5679
  }
5639
5680
  },
5640
5681
  fail: null
@@ -7105,6 +7146,9 @@ var Queue_1 = class Queue {
7105
7146
  }
7106
7147
  };
7107
7148
 
7149
+ const {
7150
+ rimraf: rimraf$1
7151
+ } = rimraf$2;
7108
7152
  const debug$7 = debug$n('botium-connector-BaseContainer');
7109
7153
  const {
7110
7154
  executeHook: executeHook$1,
@@ -7237,10 +7281,7 @@ var BaseContainer_1 = class BaseContainer {
7237
7281
  }, rimraffed => {
7238
7282
  if (this.caps[Capabilities.CLEANUPTEMPDIR]) {
7239
7283
  debug$7(`Cleanup rimrafing temp dir ${this.tempDirectory}`);
7240
- rimraf(this.tempDirectory, err => {
7241
- if (err) debug$7(`Cleanup temp dir ${this.tempDirectory} failed: ${util.inspect(err)}`);
7242
- rimraffed();
7243
- });
7284
+ rimraf$1(this.tempDirectory).catch(err => debug$7(`Cleanup temp dir ${this.tempDirectory} failed: ${util.inspect(err)}`)).finally(() => rimraffed());
7244
7285
  } else {
7245
7286
  rimraffed();
7246
7287
  }
@@ -8764,15 +8805,21 @@ var PluginConnectorContainer_1 = class PluginConnectorContainer extends BaseCont
8764
8805
  }
8765
8806
  };
8766
8807
 
8767
- var require$$2 = getCjsExportFromNamespace(_package$1);
8808
+ var require$$4 = getCjsExportFromNamespace(_package$1);
8768
8809
 
8810
+ const {
8811
+ rimraf
8812
+ } = rimraf$2;
8813
+ const {
8814
+ mkdirpSync
8815
+ } = mkdirp;
8769
8816
  const {
8770
8817
  boolean
8771
8818
  } = boolean$1;
8772
8819
  const debug$1 = debug$n('botium-core-BotDriver');
8773
8820
  const {
8774
8821
  version
8775
- } = require$$2;
8822
+ } = require$$4;
8776
8823
  var BotDriver_1 = class BotDriver {
8777
8824
  constructor(caps = {}, sources = {}, envs = {}) {
8778
8825
  this.eventEmitter = new events();
@@ -8862,7 +8909,7 @@ var BotDriver_1 = class BotDriver {
8862
8909
  }, tempDirectoryCreated => {
8863
8910
  tempDirectory = path.resolve(process.cwd(), this.caps[Capabilities.TEMPDIR], sanitizeFilename(`${this.caps[Capabilities.PROJECTNAME]} ${moment().format('YYYYMMDD HHmmss')} ${randomatic('Aa0', 5)}`));
8864
8911
  try {
8865
- mkdirp.sync(tempDirectory);
8912
+ mkdirpSync(tempDirectory);
8866
8913
  tempDirectoryCreated();
8867
8914
  } catch (err) {
8868
8915
  tempDirectoryCreated(new Error(`Unable to create temp directory ${tempDirectory}: ${err.message}`));
@@ -8890,9 +8937,7 @@ var BotDriver_1 = class BotDriver {
8890
8937
  debug$1(`BotDriver Build error: ${err}`);
8891
8938
  this.eventEmitter.emit(Events.CONTAINER_BUILD_ERROR, err);
8892
8939
  if (tempDirectory) {
8893
- rimraf(tempDirectory, err => {
8894
- if (err) debug$1(`Cleanup temp dir ${tempDirectory} failed: ${util.inspect(err)}`);
8895
- });
8940
+ rimraf(tempDirectory).catch(err => debug$1(`Cleanup temp dir ${tempDirectory} failed: ${util.inspect(err)}`));
8896
8941
  }
8897
8942
  return reject(err);
8898
8943
  }
@@ -9247,6 +9292,7 @@ var botiumCore = {
9247
9292
  InboundProxy: proxy,
9248
9293
  HookUtils: HookUtils,
9249
9294
  TranscriptUtils: TranscriptUtils,
9295
+ RetryHelper: RetryHelper_1,
9250
9296
  BotiumMockRichMessageTypes: BotiumMockRichMessageTypes,
9251
9297
  BotiumError: BotiumError_1.BotiumError,
9252
9298
  ScriptingConstants: Constants,
@@ -9268,13 +9314,14 @@ var botiumCore_7 = botiumCore.Source;
9268
9314
  var botiumCore_8 = botiumCore.InboundProxy;
9269
9315
  var botiumCore_9 = botiumCore.HookUtils;
9270
9316
  var botiumCore_10 = botiumCore.TranscriptUtils;
9271
- var botiumCore_11 = botiumCore.BotiumMockRichMessageTypes;
9272
- var botiumCore_12 = botiumCore.BotiumError;
9273
- var botiumCore_13 = botiumCore.ScriptingConstants;
9274
- var botiumCore_14 = botiumCore.ScriptingMemory;
9275
- var botiumCore_15 = botiumCore.ScriptingProvider;
9276
- var botiumCore_16 = botiumCore.LogicHookConstants;
9277
- var botiumCore_17 = botiumCore.Lib;
9317
+ var botiumCore_11 = botiumCore.RetryHelper;
9318
+ var botiumCore_12 = botiumCore.BotiumMockRichMessageTypes;
9319
+ var botiumCore_13 = botiumCore.BotiumError;
9320
+ var botiumCore_14 = botiumCore.ScriptingConstants;
9321
+ var botiumCore_15 = botiumCore.ScriptingMemory;
9322
+ var botiumCore_16 = botiumCore.ScriptingProvider;
9323
+ var botiumCore_17 = botiumCore.LogicHookConstants;
9324
+ var botiumCore_18 = botiumCore.Lib;
9278
9325
 
9279
- export { botiumCore_1 as BotDriver, botiumCore_12 as BotiumError, botiumCore_11 as BotiumMockRichMessageTypes, botiumCore_2 as Capabilities, botiumCore_3 as Defaults, botiumCore_4 as Enums, botiumCore_5 as Events, botiumCore_9 as HookUtils, botiumCore_8 as InboundProxy, botiumCore_17 as Lib, botiumCore_16 as LogicHookConstants, botiumCore_6 as Plugins, botiumCore_13 as ScriptingConstants, botiumCore_14 as ScriptingMemory, botiumCore_15 as ScriptingProvider, botiumCore_7 as Source, botiumCore_10 as TranscriptUtils, botiumCore as default };
9326
+ export { botiumCore_1 as BotDriver, botiumCore_13 as BotiumError, botiumCore_12 as BotiumMockRichMessageTypes, botiumCore_2 as Capabilities, botiumCore_3 as Defaults, botiumCore_4 as Enums, botiumCore_5 as Events, botiumCore_9 as HookUtils, botiumCore_8 as InboundProxy, botiumCore_18 as Lib, botiumCore_17 as LogicHookConstants, botiumCore_6 as Plugins, botiumCore_11 as RetryHelper, botiumCore_14 as ScriptingConstants, botiumCore_15 as ScriptingMemory, botiumCore_16 as ScriptingProvider, botiumCore_7 as Source, botiumCore_10 as TranscriptUtils, botiumCore as default };
9280
9327
  //# sourceMappingURL=botium-es.js.map