botium-core 1.13.0 → 1.13.3

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.
Files changed (57) hide show
  1. package/.eslintrc.js +6 -3
  2. package/dist/botium-cjs.js +305 -123
  3. package/dist/botium-cjs.js.map +1 -1
  4. package/dist/botium-es.js +323 -142
  5. package/dist/botium-es.js.map +1 -1
  6. package/package.json +17 -15
  7. package/src/Capabilities.js +2 -1
  8. package/src/containers/plugins/SimpleRestContainer.js +23 -16
  9. package/src/grid/inbound/proxy.js +2 -1
  10. package/src/helpers/RetryHelper.js +13 -7
  11. package/src/scripting/Convo.js +36 -10
  12. package/src/scripting/MatchFunctions.js +10 -0
  13. package/src/scripting/ScriptingProvider.js +106 -37
  14. package/src/scripting/logichook/LogicHookConsts.js +1 -1
  15. package/src/scripting/logichook/LogicHookUtils.js +1 -1
  16. package/src/scripting/logichook/asserter/WerAsserter.js +59 -0
  17. package/src/scripting/logichook/logichooks/UpdateCustomLogicHook.js +3 -2
  18. package/test/compiler/compilercsv.spec.js +104 -3
  19. package/test/compiler/compilerjson.spec.js +0 -2
  20. package/test/compiler/compilerxlsx.spec.js +1 -1
  21. package/test/compiler/convos/csv/utterances_liveperson2.csv +12 -0
  22. package/test/connectors/simplerest.spec.js +1012 -969
  23. package/test/convo/fillAndApplyScriptingMemory.spec.js +804 -785
  24. package/test/convo/partialconvo.spec.js +345 -339
  25. package/test/convo/retryconvo.spec.js +134 -0
  26. package/test/driver/capabilities.spec.js +156 -151
  27. package/test/logichooks/hookfromsrc.spec.js +79 -73
  28. package/test/plugins/plugins.spec.js +44 -42
  29. package/test/scripting/asserters/buttonsAsserter.spec.js +257 -240
  30. package/test/scripting/asserters/cardsAsserter.spec.js +214 -212
  31. package/test/scripting/asserters/convos/wer_threshold_nok.yml +7 -0
  32. package/test/scripting/asserters/convos/wer_threshold_ok.yml +7 -0
  33. package/test/scripting/asserters/intentConfidenceAsserter.spec.js +34 -35
  34. package/test/scripting/asserters/jsonpathAsserter.spec.js +307 -308
  35. package/test/scripting/asserters/mediaAsserter.spec.js +236 -234
  36. package/test/scripting/asserters/werAsserter.spec.js +51 -0
  37. package/test/scripting/logichooks/setClearScriptingMemory.spec.js +202 -192
  38. package/test/scripting/matching/matchingmode.spec.js +306 -258
  39. package/test/scripting/scriptingProvider.spec.js +666 -633
  40. package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +299 -281
  41. package/test/scripting/scriptingmemory/useScriptingMemoryForAssertion.spec.js +94 -80
  42. package/test/scripting/userinputs/defaultUserInputs.spec.js +233 -127
  43. package/test/scripting/userinputs/mediaInputConvos.spec.js +409 -403
  44. package/test/scripting/utteranceexpansion/associateByIndex.spec.js +259 -0
  45. package/test/scripting/utteranceexpansion/convos/associate_utterances_by_index.json +33 -0
  46. package/test/scripting/utteranceexpansion/convos/media.convo.txt +19 -0
  47. package/test/scripting/utteranceexpansion/files/step0voice0.wav +0 -0
  48. package/test/scripting/utteranceexpansion/files/step0voice1.wav +0 -0
  49. package/test/scripting/utteranceexpansion/files/step0voice2.wav +0 -0
  50. package/test/scripting/utteranceexpansion/files/step1voice0.wav +0 -0
  51. package/test/scripting/utteranceexpansion/files/step2voice0.wav +0 -0
  52. package/test/scripting/utteranceexpansion/files/step2voice1.wav +0 -0
  53. package/test/scripting/utteranceexpansion/files/step2voice2.wav +0 -0
  54. package/test/scripting/utteranceexpansion/files/step2voice4.wav +0 -0
  55. package/test/scripting/utteranceexpansion/files/step2voice5.wav +0 -0
  56. package/test/security/allowUnsafe.spec.js +274 -268
  57. package/test/utils.spec.js +40 -38
package/dist/botium-es.js CHANGED
@@ -10,7 +10,7 @@ import randomatic from 'randomatic';
10
10
  import lodash from 'lodash';
11
11
  import boolean$1 from 'boolean';
12
12
  import events from 'events';
13
- import debug$l from 'debug';
13
+ import debug$m from 'debug';
14
14
  import vm2 from 'vm2';
15
15
  import isClass from 'is-class';
16
16
  import crypto from 'crypto';
@@ -20,6 +20,7 @@ import promise from 'promise.allsettled';
20
20
  import uuid from 'uuid';
21
21
  import jsonpath from 'jsonpath';
22
22
  import isJson$1 from 'is-json';
23
+ import wordErrorRate from 'word-error-rate';
23
24
  import esprima from 'esprima';
24
25
  import markdownIt from 'markdown-it';
25
26
  import xlsx from 'xlsx';
@@ -36,7 +37,7 @@ import express from 'express';
36
37
  import bodyParser from 'body-parser';
37
38
 
38
39
  var name = "botium-core";
39
- var version$1 = "1.13.0";
40
+ var version$1 = "1.13.3";
40
41
  var description = "The Selenium for Chatbots";
41
42
  var main = "index.js";
42
43
  var module = "dist/botium-es.js";
@@ -68,17 +69,17 @@ var bugs = {
68
69
  };
69
70
  var homepage = "https://www.botium.ai";
70
71
  var dependencies = {
71
- "@babel/runtime": "^7.18.3",
72
+ "@babel/runtime": "^7.18.6",
72
73
  async: "^3.2.4",
73
74
  "body-parser": "^1.20.0",
74
75
  boolean: "^3.2.0",
75
76
  bottleneck: "^2.19.5",
76
- "csv-parse": "^5.2.0",
77
+ "csv-parse": "^5.3.0",
77
78
  debug: "^4.3.4",
78
79
  esprima: "^4.0.1",
79
80
  express: "^4.18.1",
80
81
  globby: "11.0.4",
81
- ioredis: "^5.0.6",
82
+ ioredis: "^5.1.0",
82
83
  "is-class": "^0.0.9",
83
84
  "is-json": "^2.0.1",
84
85
  jsonpath: "^1.1.1",
@@ -86,7 +87,7 @@ var dependencies = {
86
87
  "markdown-it": "^13.0.1",
87
88
  "mime-types": "^2.1.35",
88
89
  mkdirp: "^1.0.4",
89
- moment: "^2.29.3",
90
+ moment: "^2.29.4",
90
91
  mustache: "^4.2.0",
91
92
  "promise-retry": "^2.0.1",
92
93
  "promise.allsettled": "^1.0.5",
@@ -101,33 +102,35 @@ var dependencies = {
101
102
  "swagger-jsdoc": "^6.2.1",
102
103
  "swagger-ui-express": "^4.4.0",
103
104
  uuid: "^8.3.2",
104
- vm2: "^3.9.9",
105
+ vm2: "^3.9.10",
106
+ "word-error-rate": "0.0.7",
105
107
  "write-yaml": "^1.0.0",
106
108
  xlsx: "^0.18.5",
107
109
  xregexp: "^5.1.1",
108
110
  yaml: "^2.1.1"
109
111
  };
110
112
  var devDependencies = {
111
- "@babel/core": "^7.18.5",
112
- "@babel/node": "^7.18.5",
113
- "@babel/plugin-transform-runtime": "^7.18.5",
114
- "@babel/preset-env": "^7.18.2",
113
+ "@babel/core": "^7.18.6",
114
+ "@babel/node": "^7.18.6",
115
+ "@babel/plugin-transform-runtime": "^7.18.6",
116
+ "@babel/preset-env": "^7.18.6",
115
117
  chai: "^4.3.6",
116
118
  "chai-as-promised": "^7.1.1",
117
119
  "cross-env": "^7.0.3",
118
- eslint: "^8.18.0",
120
+ eslint: "^8.19.0",
119
121
  "eslint-config-standard": "^17.0.0",
120
122
  "eslint-plugin-import": "^2.26.0",
121
- "eslint-plugin-n": "^15.2.3",
123
+ "eslint-plugin-mocha": "^10.1.0",
124
+ "eslint-plugin-n": "^15.2.4",
122
125
  "eslint-plugin-promise": "^6.0.0",
123
126
  "eslint-plugin-standard": "^4.1.0",
124
127
  "license-checker": "^25.0.1",
125
128
  "license-compatibility-checker": "^0.3.5",
126
129
  mocha: "^10.0.0",
127
- nock: "^13.2.7",
128
- "npm-check-updates": "^14.0.1",
130
+ nock: "^13.2.8",
131
+ "npm-check-updates": "^15.2.6",
129
132
  nyc: "^15.1.0",
130
- rollup: "^2.75.6",
133
+ rollup: "^2.76.0",
131
134
  "rollup-plugin-babel": "^4.4.0",
132
135
  "rollup-plugin-commonjs": "^10.1.0",
133
136
  "rollup-plugin-json": "^4.0.0",
@@ -297,8 +300,9 @@ var Capabilities = {
297
300
  SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS: 'SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS',
298
301
  SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS: 'SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS',
299
302
  SCRIPTING_FORCE_BOT_CONSUMED: 'SCRIPTING_FORCE_BOT_CONSUMED',
300
- // regexp, regexpIgnoreCase, wildcard, wildcardIgnoreCase, wildcardExact, wildcardExactIgnoreCase, include, includeIgnoreCase, equals, equalsIgnoreCase
303
+ // regexp, regexpIgnoreCase, wildcard, wildcardIgnoreCase, wildcardExact, wildcardExactIgnoreCase, include, includeIgnoreCase, equals, equalsIgnoreCase, wer
301
304
  SCRIPTING_MATCHING_MODE: 'SCRIPTING_MATCHING_MODE',
305
+ SCRIPTING_MATCHING_MODE_ARGS: 'SCRIPTING_MATCHING_MODE_ARGS',
302
306
  // all, first, random
303
307
  SCRIPTING_UTTEXPANSION_MODE: 'SCRIPTING_UTTEXPANSION_MODE',
304
308
  SCRIPTING_UTTEXPANSION_RANDOM_COUNT: 'SCRIPTING_UTTEXPANSION_RANDOM_COUNT',
@@ -452,6 +456,7 @@ Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS;
452
456
  Capabilities.SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS;
453
457
  Capabilities.SCRIPTING_FORCE_BOT_CONSUMED;
454
458
  Capabilities.SCRIPTING_MATCHING_MODE;
459
+ Capabilities.SCRIPTING_MATCHING_MODE_ARGS;
455
460
  Capabilities.SCRIPTING_UTTEXPANSION_MODE;
456
461
  Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT;
457
462
  Capabilities.SCRIPTING_UTTEXPANSION_INCOMPREHENSION;
@@ -1137,6 +1142,9 @@ var LogicHookConsts = {
1137
1142
  }, {
1138
1143
  name: 'TEXT_IC',
1139
1144
  className: 'TextEqualsAnyICAsserter'
1145
+ }, {
1146
+ name: 'TEXT_WER',
1147
+ className: 'WerAsserter'
1140
1148
  }, {
1141
1149
  name: 'BOT_CONSUMED',
1142
1150
  className: 'BotRepliesConsumedAsserter'
@@ -1188,7 +1196,7 @@ LogicHookConsts.DEFAULT_USER_INPUTS;
1188
1196
  const {
1189
1197
  NodeVM: NodeVM$2
1190
1198
  } = vm2;
1191
- const debug$k = debug$l('botium-core-asserterUtils');
1199
+ const debug$l = debug$m('botium-core-asserterUtils');
1192
1200
  const {
1193
1201
  BotiumError: BotiumError$6
1194
1202
  } = BotiumError_1;
@@ -1253,7 +1261,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1253
1261
  _fetchAsserters() {
1254
1262
  this.caps[Capabilities.ASSERTERS].forEach(asserter => {
1255
1263
  if (this.asserters[asserter.ref]) {
1256
- debug$k(`${asserter.ref} asserter already exists, overwriting.`);
1264
+ debug$l(`${asserter.ref} asserter already exists, overwriting.`);
1257
1265
  }
1258
1266
 
1259
1267
  this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter');
@@ -1267,7 +1275,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1267
1275
  _fetchLogicHooks() {
1268
1276
  this.caps[Capabilities.LOGIC_HOOKS].forEach(logicHook => {
1269
1277
  if (this.logicHooks[logicHook.ref]) {
1270
- debug$k(`${logicHook.ref} logic hook already exists, overwriting.`);
1278
+ debug$l(`${logicHook.ref} logic hook already exists, overwriting.`);
1271
1279
  }
1272
1280
 
1273
1281
  this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logichook');
@@ -1281,7 +1289,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1281
1289
  _fetchUserInputs() {
1282
1290
  this.caps[Capabilities.USER_INPUTS].forEach(userInput => {
1283
1291
  if (this.userInputs[userInput.ref]) {
1284
- debug$k(`${userInput.ref} userinput already exists, overwriting.`);
1292
+ debug$l(`${userInput.ref} userinput already exists, overwriting.`);
1285
1293
  }
1286
1294
 
1287
1295
  this.userInputs[userInput.ref] = this._loadClass(userInput, 'userinput');
@@ -1424,7 +1432,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1424
1432
  });
1425
1433
  return vm.run(script);
1426
1434
  } catch (err) {
1427
- throw new Error(`${err.message || err}`);
1435
+ throw new Error(`Script ${key} is not valid - ${err.message || err}`);
1428
1436
  }
1429
1437
  } else {
1430
1438
  throw new Error(`Script "${key}" is not valid - only functions and javascript code accepted`);
@@ -1515,7 +1523,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1515
1523
  }
1516
1524
  }
1517
1525
 
1518
- loadErr.forEach(debug$k);
1526
+ loadErr.forEach(debug$l);
1519
1527
  }
1520
1528
 
1521
1529
  throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`);
@@ -2374,7 +2382,7 @@ var helper = {
2374
2382
  linesToScriptingMemories: linesToScriptingMemories$2
2375
2383
  };
2376
2384
 
2377
- const debug$j = debug$l('botium-core-ScriptingMemory');
2385
+ const debug$k = debug$m('botium-core-ScriptingMemory');
2378
2386
  const {
2379
2387
  v1: uuidv1
2380
2388
  } = uuid;
@@ -2632,7 +2640,7 @@ const extractVarNames = text => {
2632
2640
  };
2633
2641
 
2634
2642
  const fill = (container, scriptingMemory, result, utterance, scriptingEvents) => {
2635
- debug$j(`fill start: ${util.inspect(scriptingMemory)}`);
2643
+ debug$k(`fill start: ${util.inspect(scriptingMemory)}`);
2636
2644
  let varRegex;
2637
2645
 
2638
2646
  switch (container.caps[Capabilities.SCRIPTING_MEMORY_MATCHING_MODE]) {
@@ -2676,14 +2684,14 @@ const fill = (container, scriptingMemory, result, utterance, scriptingEvents) =>
2676
2684
  const varName = varMatches[i - 1];
2677
2685
 
2678
2686
  if (RESERVED_WORDS.indexOf(varName) >= 0) {
2679
- debug$j(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2687
+ debug$k(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2680
2688
  } else {
2681
2689
  scriptingMemory[varName] = resultMatches[i];
2682
2690
  }
2683
2691
  }
2684
2692
  }
2685
2693
  });
2686
- debug$j(`fill end: ${util.inspect(scriptingMemory)}`);
2694
+ debug$k(`fill end: ${util.inspect(scriptingMemory)}`);
2687
2695
  }
2688
2696
  };
2689
2697
 
@@ -2702,7 +2710,48 @@ ScriptingMemory.extractVarNames;
2702
2710
  ScriptingMemory.RESERVED_WORDS;
2703
2711
  ScriptingMemory.SCRIPTING_FUNCTIONS;
2704
2712
 
2705
- const debug$i = debug$l('botium-core-Convo');
2713
+ const debug$j = debug$m('botium-core-RetryHelper');
2714
+ var RetryHelper_1 = class RetryHelper {
2715
+ constructor(caps, section, options = {}) {
2716
+ this.retryErrorPatterns = [];
2717
+ const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
2718
+
2719
+ if (onErrorRegexp) {
2720
+ if (lodash.isArray(onErrorRegexp)) {
2721
+ onErrorRegexp.forEach(r => {
2722
+ if (lodash.isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
2723
+ });
2724
+ } else if (lodash.isString(onErrorRegexp)) {
2725
+ this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
2726
+ } else {
2727
+ this.retryErrorPatterns.push(onErrorRegexp);
2728
+ }
2729
+ } // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
2730
+
2731
+
2732
+ this.retrySettings = {
2733
+ retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash.isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
2734
+ factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash.isNil(options.factor) ? 1 : options.factor),
2735
+ minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash.isNil(options.minTimeout) ? 1000 : options.minTimeout)
2736
+ };
2737
+ debug$j(`Retry for ${section} is ${this.retrySettings.retries > 0 ? 'enabled' : 'disabled'}. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
2738
+ }
2739
+
2740
+ shouldRetry(err) {
2741
+ if (!err) return false;
2742
+ if (this.retryErrorPatterns.length === 0) return true;
2743
+ const errString = util.inspect(err);
2744
+
2745
+ for (const re of this.retryErrorPatterns) {
2746
+ if (errString.match(re)) return true;
2747
+ }
2748
+
2749
+ return false;
2750
+ }
2751
+
2752
+ };
2753
+
2754
+ const debug$i = debug$m('botium-core-Convo');
2706
2755
  const {
2707
2756
  BotiumError: BotiumError$4,
2708
2757
  botiumErrorFromErr: botiumErrorFromErr$1,
@@ -2798,7 +2847,7 @@ class ConvoStep$1 {
2798
2847
  }
2799
2848
 
2800
2849
  toString() {
2801
- return (this.stepTag ? this.stepTag + ': ' : '') + '#' + this.sender + ' - ' + (this.optional ? '?' : '') + (this.not ? '!' : '') + (this.messageText || '') + (this.asserters && this.asserters.length > 0 ? ' ' + this.asserters.map(a => a.toString()).join(' ASS: ') : '') + (this.logicHooks && this.logicHooks.length > 0 ? ' ' + this.logicHooks.map(l => l.toString()).join(' LH: ') : '') + (this.userInputs && this.userInputs.length > 0 ? ' ' + this.userInputs.map(u => u.toString()).join(' UI: ') : '');
2850
+ return (this.stepTag ? this.stepTag + ': ' : '') + '#' + this.sender + ' - ' + (this.optional ? '?' : '') + (this.not ? '!' : '') + (this.messageText || '') + (this.asserters && this.asserters.length > 0 ? ' ' + this.asserters.map(a => a.toString()).join(' ') : '') + (this.logicHooks && this.logicHooks.length > 0 ? ' ' + this.logicHooks.map(l => l.toString()).join(' ') : '') + (this.userInputs && this.userInputs.length > 0 ? ' ' + this.userInputs.map(u => u.toString()).join(' ') : '');
2802
2851
  }
2803
2852
 
2804
2853
  }
@@ -2833,6 +2882,16 @@ class Transcript {
2833
2882
 
2834
2883
  }
2835
2884
 
2885
+ class TranscriptAttachment {
2886
+ constructor(fromJson = {}) {
2887
+ this.name = fromJson.name;
2888
+ this.mimeType = fromJson.mimeType;
2889
+ this.base64 = fromJson.base64;
2890
+ this.href = fromJson.href;
2891
+ }
2892
+
2893
+ }
2894
+
2836
2895
  class TranscriptStep {
2837
2896
  constructor({
2838
2897
  expected,
@@ -2927,6 +2986,26 @@ class Convo$6 {
2927
2986
  }
2928
2987
 
2929
2988
  async Run(container) {
2989
+ const retryHelper = new RetryHelper_1(container.caps, 'CONVO');
2990
+ return promiseRetry(async (retry, number) => {
2991
+ return this.RunImpl(container).catch(err => {
2992
+ const retryRemaining = retryHelper.retrySettings.retries - number + 1;
2993
+
2994
+ if (retryHelper.shouldRetry(err)) {
2995
+ debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry ${retryRemaining > 0 ? 'enabled' : 'disabled'} (remaining #${retryRemaining}/${retryHelper.retrySettings.retries}, criterion matches)`);
2996
+ retry(err);
2997
+ } else {
2998
+ if (retryHelper.retryErrorPatterns.length > 0) {
2999
+ debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry 'disabled' (remaining (#${retryRemaining}/${retryHelper.retrySettings.retries}), criterion does not match)`);
3000
+ }
3001
+
3002
+ throw err;
3003
+ }
3004
+ });
3005
+ }, retryHelper.retrySettings);
3006
+ }
3007
+
3008
+ async RunImpl(container) {
2930
3009
  const transcript = new Transcript({
2931
3010
  steps: [],
2932
3011
  attachments: [],
@@ -3593,45 +3672,16 @@ class Convo$6 {
3593
3672
  }
3594
3673
 
3595
3674
  var Convo_1 = {
3596
- ConvoHeader: ConvoHeader$1,
3597
3675
  Convo: Convo$6,
3598
- ConvoStep: ConvoStep$1
3599
- };
3600
-
3601
- var RetryHelper_1 = class RetryHelper {
3602
- constructor(caps, section) {
3603
- this.retrySettings = {
3604
- retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || 1,
3605
- factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || 1,
3606
- minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || 1000
3607
- };
3608
- this.retryErrorPatterns = [];
3609
- const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
3610
-
3611
- if (onErrorRegexp) {
3612
- if (lodash.isArray(onErrorRegexp)) {
3613
- onErrorRegexp.forEach(r => {
3614
- if (lodash.isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
3615
- });
3616
- } else if (lodash.isString(onErrorRegexp)) {
3617
- this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
3618
- } else {
3619
- this.retryErrorPatterns.push(onErrorRegexp);
3620
- }
3621
- }
3622
- }
3623
-
3624
- shouldRetry(err) {
3625
- if (!err || this.retryErrorPatterns.length === 0) return false;
3626
- const errString = util.inspect(err);
3627
-
3628
- for (const re of this.retryErrorPatterns) {
3629
- if (errString.match(re)) return true;
3630
- }
3631
-
3632
- return false;
3633
- }
3634
-
3676
+ ConvoHeader: ConvoHeader$1,
3677
+ ConvoStep: ConvoStep$1,
3678
+ ConvoStepAssert,
3679
+ ConvoStepLogicHook,
3680
+ ConvoStepUserInput,
3681
+ Transcript,
3682
+ TranscriptAttachment,
3683
+ TranscriptStep,
3684
+ TranscriptError
3635
3685
  };
3636
3686
 
3637
3687
  const {
@@ -3719,6 +3769,12 @@ const equals = ignoreCase => (botresponse, utterance) => {
3719
3769
  return botresponse === utterance;
3720
3770
  };
3721
3771
 
3772
+ const wer = () => (botresponse, utterance, args) => {
3773
+ botresponse = _normalize(botresponse || '');
3774
+ utterance = toString(utterance || '');
3775
+ return wordErrorRate.wordErrorRate(botresponse, utterance) <= args[0];
3776
+ };
3777
+
3722
3778
  const getMatchFunction$1 = matchingMode => {
3723
3779
  if (matchingMode === 'regexp' || matchingMode === 'regexpIgnoreCase') {
3724
3780
  return regexp(matchingMode === 'regexpIgnoreCase');
@@ -3730,6 +3786,8 @@ const getMatchFunction$1 = matchingMode => {
3730
3786
  return include(matchingMode === 'includeIgnoreCase' || matchingMode === 'includeLowerCase');
3731
3787
  } else if (matchingMode === 'equals' || matchingMode === 'equalsIgnoreCase') {
3732
3788
  return equals(matchingMode === 'equalsIgnoreCase');
3789
+ } else if (matchingMode === 'wer') {
3790
+ return wer();
3733
3791
  } else {
3734
3792
  return equals(false);
3735
3793
  }
@@ -3741,6 +3799,7 @@ var MatchFunctions = {
3741
3799
  wildcardExact,
3742
3800
  include,
3743
3801
  equals,
3802
+ wer,
3744
3803
  getMatchFunction: getMatchFunction$1
3745
3804
  };
3746
3805
 
@@ -3956,7 +4015,7 @@ var JsonToJson = {
3956
4015
  const {
3957
4016
  NodeVM
3958
4017
  } = vm2;
3959
- const debug$h = debug$l('botium-core-HookUtils');
4018
+ const debug$h = debug$m('botium-core-HookUtils');
3960
4019
  const {
3961
4020
  BotiumError: BotiumError$3
3962
4021
  } = BotiumError_1;
@@ -4106,7 +4165,7 @@ var Script = {
4106
4165
  precompile: precompile$1
4107
4166
  };
4108
4167
 
4109
- const debug$g = debug$l('botium-core-PrecompilerMarkdownRasa');
4168
+ const debug$g = debug$m('botium-core-PrecompilerMarkdownRasa');
4110
4169
  const htmlCommentRegexp = /(<!--.*?-->)/g;
4111
4170
 
4112
4171
  var precompile = (caps, scriptBuffer, options, filename) => {
@@ -4222,7 +4281,7 @@ var MarkdownRasa = {
4222
4281
  precompile: precompile
4223
4282
  };
4224
4283
 
4225
- const debug$f = debug$l('botium-core-CapabilitiesUtils');
4284
+ const debug$f = debug$m('botium-core-CapabilitiesUtils');
4226
4285
  const {
4227
4286
  toJsonWeak
4228
4287
  } = Utils;
@@ -4334,7 +4393,7 @@ var CapabilitiesUtils = {
4334
4393
  flatCababilities: flatCababilities$1
4335
4394
  };
4336
4395
 
4337
- const debug$e = debug$l('botium-core-Precompilers');
4396
+ const debug$e = debug$m('botium-core-Precompilers');
4338
4397
  const {
4339
4398
  isJsonObject
4340
4399
  } = Utils;
@@ -4484,7 +4543,7 @@ var Utterance_1 = class Utterance {
4484
4543
 
4485
4544
  };
4486
4545
 
4487
- const debug$d = debug$l('botium-core-CompilerXlsx');
4546
+ const debug$d = debug$m('botium-core-CompilerXlsx');
4488
4547
  const {
4489
4548
  E_SCRIPTING_MEMORY_COLUMN_MODE
4490
4549
  } = Enums;
@@ -5257,7 +5316,7 @@ var CompilerTxt_1 = class CompilerTxt extends CompilerBase_1 {
5257
5316
  const {
5258
5317
  parse
5259
5318
  } = sync;
5260
- const debug$c = debug$l('botium-core-CompilerCsv');
5319
+ const debug$c = debug$m('botium-core-CompilerCsv');
5261
5320
  const {
5262
5321
  Convo: Convo$3
5263
5322
  } = Convo_1;
@@ -5520,7 +5579,7 @@ var CompilerCsv_1 = class CompilerCsv extends CompilerBase_1 {
5520
5579
 
5521
5580
  };
5522
5581
 
5523
- const debug$b = debug$l('botium-core-CompilerObject');
5582
+ const debug$b = debug$m('botium-core-CompilerObject');
5524
5583
  const {
5525
5584
  Convo: Convo$2
5526
5585
  } = Convo_1;
@@ -5697,7 +5756,7 @@ var CompilerJson_1 = class CompilerJson extends CompilerObjectBase_1 {
5697
5756
 
5698
5757
  };
5699
5758
 
5700
- const debug$a = debug$l('botium-core-CompilerMarkdown');
5759
+ const debug$a = debug$m('botium-core-CompilerMarkdown');
5701
5760
  const md = new markdownIt();
5702
5761
  const {
5703
5762
  Convo: Convo$1
@@ -5828,7 +5887,7 @@ var CompilerMarkdown_1 = class CompilerMarkdown extends CompilerBase_1 {
5828
5887
  };
5829
5888
 
5830
5889
  promise.shim();
5831
- const debug$9 = debug$l('botium-core-ScriptingProvider');
5890
+ const debug$9 = debug$m('botium-core-ScriptingProvider');
5832
5891
  const {
5833
5892
  Convo,
5834
5893
  ConvoStep
@@ -6105,7 +6164,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
6105
6164
 
6106
6165
  debug$9(`assertBotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} = ${tomatch} ...`);
6107
6166
 
6108
- const found = lodash.find(tomatch, utt => this.matchFn(botresponse, utt));
6167
+ const found = lodash.find(tomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
6168
+
6169
+ const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'WerAsserter' : 'TextMatchAsserter';
6109
6170
 
6110
6171
  if (lodash.isNil(found)) {
6111
6172
  let message = `${stepTag}: Bot response `;
@@ -6116,7 +6177,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6116
6177
  message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
6117
6178
  throw new BotiumError$2(message, {
6118
6179
  type: 'asserter',
6119
- source: 'TextMatchAsserter',
6180
+ source: asserterType,
6120
6181
  context: {
6121
6182
  stepTag
6122
6183
  },
@@ -6135,7 +6196,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
6135
6196
 
6136
6197
  debug$9(`assertBotNotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} != ${nottomatch} ...`);
6137
6198
 
6138
- const found = lodash.find(nottomatch, utt => this.matchFn(botresponse, utt));
6199
+ const found = lodash.find(nottomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
6200
+
6201
+ const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'WerAsserter' : 'TextMatchAsserter';
6139
6202
 
6140
6203
  if (!lodash.isNil(found)) {
6141
6204
  let message = `${stepTag}: Bot response `;
@@ -6146,7 +6209,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6146
6209
  message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
6147
6210
  throw new BotiumError$2(message, {
6148
6211
  type: 'asserter',
6149
- source: 'TextMatchAsserter',
6212
+ source: asserterType,
6150
6213
  context: {
6151
6214
  stepTag
6152
6215
  },
@@ -6393,7 +6456,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6393
6456
  }
6394
6457
 
6395
6458
  Match(botresponse, utterance) {
6396
- return this.matchFn(botresponse, utterance);
6459
+ return this.matchFn(botresponse, utterance, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]);
6397
6460
  }
6398
6461
 
6399
6462
  Compile(scriptBuffer, scriptFormat, scriptType) {
@@ -6913,11 +6976,12 @@ var ScriptingProvider_1 = class ScriptingProvider {
6913
6976
  * @param currentConvo
6914
6977
  * @param convoStepIndex
6915
6978
  * @param convoStepsStack list of ConvoSteps
6979
+ * @param context {width: }
6916
6980
  * @private
6917
6981
  */
6918
6982
 
6919
6983
 
6920
- _expandConvo(expandedConvos, currentConvo, convoStepIndex = 0, convoStepsStack = []) {
6984
+ _expandConvo(expandedConvos, currentConvo, convoStepIndex = 0, convoStepsStack = [], context = {}) {
6921
6985
  const utterancePostfix = (lineTag, uttOrUserInput) => {
6922
6986
  const naming = this.caps[Capabilities.SCRIPTING_UTTEXPANSION_NAMING_MODE] || Defaults$1.capabilities[Capabilities.SCRIPTING_UTTEXPANSION_NAMING_MODE];
6923
6987
 
@@ -6944,7 +7008,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6944
7008
  const currentStepsStack = convoStepsStack.slice();
6945
7009
  currentStepsStack.push(lodash.cloneDeep(currentStep));
6946
7010
 
6947
- this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack);
7011
+ this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack, context);
6948
7012
  } else if (currentStep.sender === 'me') {
6949
7013
  let useUnexpanded = true;
6950
7014
 
@@ -6965,39 +7029,87 @@ var ScriptingProvider_1 = class ScriptingProvider {
6965
7029
 
6966
7030
  if (this.utterances[uttName]) {
6967
7031
  const allutterances = this.utterances[uttName].utterances;
6968
- let sampleutterances = allutterances;
6969
-
6970
- if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
6971
- sampleutterances = [allutterances[0]];
6972
- } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
6973
- sampleutterances = allutterances.map(x => ({
6974
- x,
6975
- r: Math.random()
6976
- })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]);
6977
- }
6978
7032
 
6979
- sampleutterances.forEach((utt, index) => {
6980
- const lineTag = `${index + 1}`.padStart(`${sampleutterances.length}`.length, '0');
7033
+ const processSampleUtterances = (sampleutterances, myContext) => {
7034
+ sampleutterances.forEach((utt, index) => {
7035
+ processSampleUtterance(utt, sampleutterances.length, index, Object.assign({
7036
+ indexExpansionModeIndex: index
7037
+ }, myContext || context));
7038
+ });
7039
+ };
7040
+
7041
+ const processSampleUtterance = (sampleutterance, length, index, myContext) => {
7042
+ const lineTag = `${index + 1}`.padStart(`${length}`.length, '0');
6981
7043
  const currentStepsStack = convoStepsStack.slice();
6982
7044
 
6983
7045
  if (uttArgs) {
6984
- utt = util.format(utt, ...uttArgs);
7046
+ sampleutterance = util.format(sampleutterance, ...uttArgs);
6985
7047
  }
6986
7048
 
6987
7049
  currentStepsStack.push(Object.assign(lodash.cloneDeep(currentStep), {
6988
- messageText: utt
7050
+ messageText: sampleutterance
6989
7051
  }));
6990
7052
 
6991
7053
  const currentConvoLabeled = lodash.cloneDeep(currentConvo);
6992
7054
 
6993
7055
  Object.assign(currentConvoLabeled.header, {
6994
- name: `${currentConvo.header.name}/${uttName}-${utterancePostfix(lineTag, utt)}`
7056
+ name: `${currentConvo.header.name}/${uttName}-${utterancePostfix(lineTag, sampleutterance)}`
6995
7057
  });
6996
7058
  if (!currentConvoLabeled.sourceTag) currentConvoLabeled.sourceTag = {};
6997
7059
  if (!currentConvoLabeled.sourceTag.origConvoName) currentConvoLabeled.sourceTag.origConvoName = currentConvo.header.name;
6998
7060
 
6999
- this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack);
7000
- });
7061
+ this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack, myContext || context);
7062
+ };
7063
+
7064
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'index') {
7065
+ if (lodash.isNil(context.indexExpansionModeWidth)) {
7066
+ // executed for the first found utterance
7067
+ processSampleUtterances(allutterances, Object.assign({}, context, {
7068
+ indexExpansionModeWidth: allutterances.length
7069
+ }));
7070
+ } else {
7071
+ if (lodash.isNil(context.indexExpansionModeIndex)) {
7072
+ throw new Error('indexExpansionModeIndex must be set!');
7073
+ } // executing the current 'thread', if current utterance has no example to current index, fallback to the last one
7074
+
7075
+
7076
+ const localIndex = Math.min(context.indexExpansionModeIndex, allutterances.length - 1);
7077
+
7078
+ if (localIndex < context.indexExpansionModeIndex && context.indexExpansionModeIndex === context.indexExpansionModeWidth - 1) {
7079
+ debug$9(`While expanding convos by index found in utterance "${uttName}" less examples (${allutterances.length}) as expected (${context.indexExpansionModeWidth})`);
7080
+ }
7081
+
7082
+ const myContext = Object.assign({}, context, {
7083
+ indexExpansionModeWidth: Math.max(allutterances.length, context.indexExpansionModeWidth)
7084
+ });
7085
+ processSampleUtterance(allutterances[localIndex], allutterances.length, localIndex, myContext);
7086
+
7087
+ if (allutterances.length > context.indexExpansionModeWidth && context.indexExpansionModeIndex + 1 === context.indexExpansionModeWidth) {
7088
+ debug$9(`While expanding convos by index found in utterance "${uttName}" more examples (${allutterances.length}) as expected (${context.indexExpansionModeWidth})`);
7089
+
7090
+ for (let i = context.indexExpansionModeWidth; i < allutterances.length; i++) {
7091
+ // if we found a utterance with more examples as any utterances before, we have to start new 'thread'
7092
+ const myContext = Object.assign({}, context, {
7093
+ indexExpansionModeWidth: allutterances.length,
7094
+ indexExpansionModeIndex: i
7095
+ });
7096
+ processSampleUtterance(allutterances[i], allutterances.length, i, myContext);
7097
+ }
7098
+ }
7099
+ }
7100
+ } else {
7101
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
7102
+ processSampleUtterances([allutterances[0]]);
7103
+ } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
7104
+ processSampleUtterances(allutterances.map(x => ({
7105
+ x,
7106
+ r: Math.random()
7107
+ })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]));
7108
+ } else {
7109
+ processSampleUtterances(allutterances);
7110
+ }
7111
+ }
7112
+
7001
7113
  useUnexpanded = false;
7002
7114
  }
7003
7115
  }
@@ -7014,19 +7126,17 @@ var ScriptingProvider_1 = class ScriptingProvider {
7014
7126
  });
7015
7127
 
7016
7128
  if (expandedUserInputs && expandedUserInputs.length > 0) {
7017
- let sampleinputs = expandedUserInputs;
7018
-
7019
- if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
7020
- sampleinputs = [expandedUserInputs[0]];
7021
- } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
7022
- sampleinputs = expandedUserInputs.map(x => ({
7023
- x,
7024
- r: Math.random()
7025
- })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]);
7026
- }
7129
+ // let sampleinputs = expandedUserInputs
7130
+ const processSampleInputs = (sampleinputs, myContext, uiIndex) => {
7131
+ sampleinputs.forEach((input, index) => {
7132
+ processSampleInput(input, sampleinputs.length, index, Object.assign({
7133
+ indexExpansionModeIndex: index
7134
+ }, myContext || context), uiIndex);
7135
+ });
7136
+ };
7027
7137
 
7028
- sampleinputs.forEach((sampleinput, index) => {
7029
- const lineTag = `${index + 1}`.padStart(`${sampleinputs.length}`.length, '0');
7138
+ const processSampleInput = (sampleinput, length, index, myContext, uiIndex) => {
7139
+ const lineTag = `${index + 1}`.padStart(`${length}`.length, '0');
7030
7140
  const currentStepsStack = convoStepsStack.slice();
7031
7141
 
7032
7142
  const currentStepMod = lodash.cloneDeep(currentStep);
@@ -7040,8 +7150,56 @@ var ScriptingProvider_1 = class ScriptingProvider {
7040
7150
  name: `${currentConvo.header.name}/${ui.name}-${utterancePostfix(lineTag, sampleinput.args && sampleinput.args.length ? sampleinput.args.join(', ') : 'no-args')}`
7041
7151
  });
7042
7152
 
7043
- this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack);
7044
- });
7153
+ this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack, myContext || context);
7154
+ };
7155
+
7156
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'index') {
7157
+ if (lodash.isNil(context.indexExpansionModeWidth)) {
7158
+ processSampleInputs(expandedUserInputs, Object.assign({}, context, {
7159
+ indexExpansionModeWidth: expandedUserInputs.length
7160
+ }), uiIndex);
7161
+ } else {
7162
+ if (lodash.isNil(context.indexExpansionModeIndex)) {
7163
+ throw new Error('indexExpansionModeIndex must be set!');
7164
+ } // executing the current 'thread', if current utterance has no example to current index, fallback to the last one
7165
+
7166
+
7167
+ const localIndex = Math.min(context.indexExpansionModeIndex, expandedUserInputs.length - 1);
7168
+
7169
+ if (localIndex < context.indexExpansionModeIndex && context.indexExpansionModeIndex === context.indexExpansionModeWidth - 1) {
7170
+ debug$9(`While expanding convos by index found user input "${ui.name}, ${ui.args}" less examples (${expandedUserInputs.length}) as expected (${context.indexExpansionModeWidth})`);
7171
+ }
7172
+
7173
+ const myContext = Object.assign({}, context, {
7174
+ indexExpansionModeWidth: Math.max(expandedUserInputs.length, context.indexExpansionModeWidth)
7175
+ });
7176
+ processSampleInput(expandedUserInputs[localIndex], expandedUserInputs.length, localIndex, myContext, uiIndex);
7177
+
7178
+ if (expandedUserInputs.length > context.indexExpansionModeWidth && context.indexExpansionModeIndex + 1 === context.indexExpansionModeWidth) {
7179
+ debug$9(`While expanding convos by index found user input "${ui.name}, ${ui.args}" more examples (${expandedUserInputs.length}) as expected (${context.indexExpansionModeWidth})`);
7180
+
7181
+ for (let i = context.indexExpansionModeWidth; i < expandedUserInputs.length; i++) {
7182
+ const myContext = Object.assign({}, context, {
7183
+ indexExpansionModeWidth: expandedUserInputs.length,
7184
+ indexExpansionModeIndex: i
7185
+ });
7186
+ processSampleInput(expandedUserInputs[i], expandedUserInputs.length, i, myContext, uiIndex);
7187
+ }
7188
+ }
7189
+ }
7190
+ } else {
7191
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
7192
+ processSampleInputs([expandedUserInputs[0]], context, uiIndex);
7193
+ } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
7194
+ processSampleInputs(expandedUserInputs.map(x => ({
7195
+ x,
7196
+ r: Math.random()
7197
+ })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]), context, uiIndex);
7198
+ } else {
7199
+ processSampleInputs(expandedUserInputs, context, uiIndex);
7200
+ }
7201
+ }
7202
+
7045
7203
  useUnexpanded = false;
7046
7204
  }
7047
7205
  }
@@ -7052,7 +7210,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
7052
7210
  const currentStepsStack = convoStepsStack.slice();
7053
7211
  currentStepsStack.push(lodash.cloneDeep(currentStep));
7054
7212
 
7055
- this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack);
7213
+ this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack, context);
7056
7214
  }
7057
7215
  }
7058
7216
  } else {
@@ -7398,7 +7556,7 @@ var NoRepo_1 = class NoRepo extends BaseRepo_1 {
7398
7556
  };
7399
7557
 
7400
7558
  var ProcessUtils = createCommonjsModule(function (module) {
7401
- const debug = debug$l('botium-core-ProcessUtils');
7559
+ const debug = debug$m('botium-core-ProcessUtils');
7402
7560
  module.exports = {
7403
7561
  childCommandLineRun: (cmd, ignoreErrors = false, processOptions = {}) => {
7404
7562
  const cmdOptions = cmd.split(' ');
@@ -7450,7 +7608,7 @@ var ProcessUtils = createCommonjsModule(function (module) {
7450
7608
  ProcessUtils.childCommandLineRun;
7451
7609
  ProcessUtils.childProcessRun;
7452
7610
 
7453
- const debug$8 = debug$l('botium-core-GitRepo');
7611
+ const debug$8 = debug$m('botium-core-GitRepo');
7454
7612
  var GitRepo_1 = class GitRepo extends BaseRepo_1 {
7455
7613
  Validate() {
7456
7614
  return super.Validate().then(() => {
@@ -7621,7 +7779,7 @@ var Queue_1 = class Queue {
7621
7779
 
7622
7780
  };
7623
7781
 
7624
- const debug$7 = debug$l('botium-connector-BaseContainer');
7782
+ const debug$7 = debug$m('botium-connector-BaseContainer');
7625
7783
  const {
7626
7784
  executeHook: executeHook$1,
7627
7785
  getHook: getHook$1
@@ -7852,7 +8010,7 @@ var BaseContainer_1 = class BaseContainer {
7852
8010
 
7853
8011
  };
7854
8012
 
7855
- const debug$6 = debug$l('botium-connector-GridContainer');
8013
+ const debug$6 = debug$m('botium-connector-GridContainer');
7856
8014
  var GridContainer_1 = class GridContainer extends BaseContainer_1 {
7857
8015
  Validate() {
7858
8016
  return super.Validate().then(() => {
@@ -8076,7 +8234,7 @@ var InProcessContainer_1 = class InProcessContainer extends BaseContainer_1 {
8076
8234
 
8077
8235
  };
8078
8236
 
8079
- const debug$5 = debug$l('botium-core-inbound-proxy');
8237
+ const debug$5 = debug$m('botium-core-inbound-proxy');
8080
8238
 
8081
8239
  const buildRedisHandler = (redisurl, topic) => {
8082
8240
  const redis = new ioredis(redisurl);
@@ -8108,7 +8266,8 @@ const setupEndpoints = ({
8108
8266
  processEvent({
8109
8267
  originalUrl: req.originalUrl,
8110
8268
  originalMethod: req.method,
8111
- body: req.body
8269
+ body: req.body,
8270
+ headers: req.headers
8112
8271
  });
8113
8272
  res.status(200).json({}).end();
8114
8273
  } else {
@@ -8159,7 +8318,7 @@ proxy.startProxy;
8159
8318
  const {
8160
8319
  v4: uuidv4
8161
8320
  } = uuid;
8162
- const debug$4 = debug$l('botium-connector-simplerest');
8321
+ const debug$4 = debug$m('botium-connector-simplerest');
8163
8322
  const {
8164
8323
  startProxy
8165
8324
  } = proxy;
@@ -8213,7 +8372,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8213
8372
  });
8214
8373
 
8215
8374
  for (const event of sortedEvents) {
8216
- setTimeout(() => this._processBodyAsync(event.body, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
8375
+ setTimeout(() => this._processBodyAsync(event.body, event.headers, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
8217
8376
  }
8218
8377
  }, debounceTimeout);
8219
8378
  }
@@ -8308,12 +8467,15 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8308
8467
  this._startPolling().then(() => startPollingComplete()).catch(startPollingComplete);
8309
8468
  }, pingComplete => {
8310
8469
  if (this.caps[Capabilities.SIMPLEREST_PING_URL]) {
8311
- this._makeCall('SIMPLEREST_PING').then(body => {
8470
+ this._makeCall('SIMPLEREST_PING').then(({
8471
+ body,
8472
+ headers
8473
+ }) => {
8312
8474
  if (this.caps[Capabilities.SIMPLEREST_PING_UPDATE_CONTEXT] || this.caps[Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE]) {
8313
8475
  return this._parseResponseBody(body).then(body => {
8314
8476
  if (body) {
8315
8477
  debug$4(`Ping Uri ${this.caps[Capabilities.SIMPLEREST_PING_URL]} returned JSON response: ${Utils.shortenJsonString(body)}`);
8316
- return this._processBodyAsync(body, !!this.caps[Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_PING_UPDATE_CONTEXT]);
8478
+ return this._processBodyAsync(body, headers, !!this.caps[Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_PING_UPDATE_CONTEXT]);
8317
8479
  } else {
8318
8480
  debug$4(`Ping Uri ${this.caps[Capabilities.SIMPLEREST_PING_URL]} didn't return JSON response, ignoring it.`);
8319
8481
  }
@@ -8341,12 +8503,15 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8341
8503
  this.processInbound = true;
8342
8504
 
8343
8505
  if (this.caps[Capabilities.SIMPLEREST_START_URL]) {
8344
- this._makeCall('SIMPLEREST_START').then(body => {
8506
+ this._makeCall('SIMPLEREST_START').then(({
8507
+ body,
8508
+ headers
8509
+ }) => {
8345
8510
  if (this.caps[Capabilities.SIMPLEREST_START_UPDATE_CONTEXT] || this.caps[Capabilities.SIMPLEREST_START_PROCESS_RESPONSE]) {
8346
8511
  return this._parseResponseBody(body).then(body => {
8347
8512
  if (body) {
8348
8513
  debug$4(`Start Uri ${this.caps[Capabilities.SIMPLEREST_START_URL]} returned JSON response: ${Utils.shortenJsonString(body)}`);
8349
- return this._processBodyAsync(body, !!this.caps[Capabilities.SIMPLEREST_START_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_START_UPDATE_CONTEXT]);
8514
+ return this._processBodyAsync(body, headers, !!this.caps[Capabilities.SIMPLEREST_START_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_START_UPDATE_CONTEXT]);
8350
8515
  } else {
8351
8516
  debug$4(`Start Uri ${this.caps[Capabilities.SIMPLEREST_START_URL]} didn't return JSON response, ignoring it.`);
8352
8517
  }
@@ -8398,10 +8563,10 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8398
8563
  } // Separated just for better module testing
8399
8564
 
8400
8565
 
8401
- async _processBodyAsync(body, isFromUser, updateContext) {
8566
+ async _processBodyAsync(body, headers, isFromUser, updateContext) {
8402
8567
  const p = async () => {
8403
8568
  try {
8404
- const results = await this._processBodyAsyncImpl(body, isFromUser, updateContext);
8569
+ const results = await this._processBodyAsyncImpl(body, headers, isFromUser, updateContext);
8405
8570
 
8406
8571
  if (results) {
8407
8572
  for (const result of results) {
@@ -8432,7 +8597,12 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8432
8597
  } // Separated just for better module testing
8433
8598
 
8434
8599
 
8435
- async _processBodyAsyncImpl(body, isFromUser, updateContext) {
8600
+ async _processBodyAsyncImpl(body, headers, isFromUser, updateContext) {
8601
+ this.view.response = {
8602
+ body,
8603
+ headers
8604
+ };
8605
+
8436
8606
  if (updateContext) {
8437
8607
  const mergeMode = this.caps[Capabilities.SIMPLEREST_CONTEXT_MERGE_OR_REPLACE];
8438
8608
  const jsonPathsContext = getAllCapValues(Capabilities.SIMPLEREST_CONTEXT_JSONPATH, this.caps);
@@ -8642,7 +8812,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8642
8812
  }
8643
8813
 
8644
8814
  if (body) {
8645
- debug$4(`got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}`);
8815
+ debug$4(`got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}, headers: ${Utils.shortenJsonString(response.headers)}`);
8646
8816
 
8647
8817
  this._storeCookiesFromResponse(response);
8648
8818
 
@@ -8658,7 +8828,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8658
8828
  }
8659
8829
 
8660
8830
  if (body) {
8661
- this._processBodyAsync(body, isFromUser, updateContext).then(() => resolve(this)).then(() => this._emptyWaitProcessQueue());
8831
+ this._processBodyAsync(body, response.headers, isFromUser, updateContext).then(() => resolve(this)).then(() => this._emptyWaitProcessQueue());
8662
8832
  } else {
8663
8833
  debug$4('ignoring response body (no string and no JSON object)');
8664
8834
  resolve(this);
@@ -8720,6 +8890,10 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8720
8890
  try {
8721
8891
  requestOptions.body = this._getMustachedCap(Capabilities.SIMPLEREST_BODY_TEMPLATE, !bodyRaw);
8722
8892
  requestOptions.json = !bodyRaw;
8893
+
8894
+ if (requestOptions.json && (!requestOptions.body || Object.keys(requestOptions.body).length === 0)) {
8895
+ debug$4(`warning: requestOptions.body content seems to be empty - ${requestOptions.body} - capability: "${this.caps[Capabilities.SIMPLEREST_BODY_TEMPLATE]}"`);
8896
+ }
8723
8897
  } catch (err) {
8724
8898
  throw new Error(`composing body from SIMPLEREST_BODY_TEMPLATE failed (${err.message})`);
8725
8899
  }
@@ -8818,10 +8992,13 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8818
8992
  this._storeCookiesFromResponse(response);
8819
8993
 
8820
8994
  if (debug$4.enabled && body) {
8821
- debug$4(Utils.shortenJsonString(body));
8995
+ debug$4(`body: ${Utils.shortenJsonString(body)}, headers: ${Utils.shortenJsonString(response.headers)}`);
8822
8996
  }
8823
8997
 
8824
- return body;
8998
+ return {
8999
+ body,
9000
+ headers: response.headers
9001
+ };
8825
9002
  }
8826
9003
  }
8827
9004
  }
@@ -8865,7 +9042,11 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8865
9042
  try {
8866
9043
  return JSON.parse(raw);
8867
9044
  } catch (err) {
8868
- return new Error(`JSON parsing failed - try to use {{#fnc.jsonify}}{{xxx}}{{/fnc.jsonify}} to escape JSON special characters (ERR: ${err.message})`);
9045
+ if (debug$4.enabled) {
9046
+ debug$4(`JSON parsing failed (${err.message}) for: ${Utils.shortenJsonString(raw)}`);
9047
+ }
9048
+
9049
+ throw new Error(`JSON parsing failed - try to use {{#fnc.jsonify}}{{xxx}}{{/fnc.jsonify}} to escape JSON special characters (ERR: ${err.message})`);
8869
9050
  }
8870
9051
  } else {
8871
9052
  return raw;
@@ -8910,7 +9091,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8910
9091
 
8911
9092
  this._processOrderedInboundEventsArrayAsync();
8912
9093
  } else {
8913
- setTimeout(() => this._processBodyAsync(event.body, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
9094
+ setTimeout(() => this._processBodyAsync(event.body, event.headers, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
8914
9095
  }
8915
9096
  }
8916
9097
 
@@ -9051,7 +9232,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
9051
9232
  debug$4(Utils.shortenJsonString(body));
9052
9233
  }
9053
9234
  } else if (body) {
9054
- debug$4(`_runPolling: got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}`);
9235
+ debug$4(`_runPolling: got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}, headers: ${Utils.shortenJsonString(response.headers)}`);
9055
9236
 
9056
9237
  this._storeCookiesFromResponse(response);
9057
9238
 
@@ -9063,7 +9244,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
9063
9244
  }
9064
9245
 
9065
9246
  if (body) {
9066
- setTimeout(() => this._processBodyAsync(body, true, !!this.caps[Capabilities.SIMPLEREST_POLL_UPDATE_CONTEXT]), 0);
9247
+ setTimeout(() => this._processBodyAsync(body, response.headers, true, !!this.caps[Capabilities.SIMPLEREST_POLL_UPDATE_CONTEXT]), 0);
9067
9248
  } else {
9068
9249
  debug$4('_runPolling: ignoring response body (no string and no JSON object)');
9069
9250
  }
@@ -9189,7 +9370,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
9189
9370
 
9190
9371
  };
9191
9372
 
9192
- const debug$3 = debug$l('botium-connector-PluginConnectorContainer-helper');
9373
+ const debug$3 = debug$m('botium-connector-PluginConnectorContainer-helper');
9193
9374
  const {
9194
9375
  BotiumError
9195
9376
  } = BotiumError_1;
@@ -9358,7 +9539,7 @@ var plugins = {
9358
9539
  tryLoadPlugin: tryLoadPlugin$1
9359
9540
  };
9360
9541
 
9361
- const debug$2 = debug$l('botium-connector-PluginConnectorContainer');
9542
+ const debug$2 = debug$m('botium-connector-PluginConnectorContainer');
9362
9543
  const {
9363
9544
  tryLoadPlugin
9364
9545
  } = plugins;
@@ -9516,7 +9697,7 @@ var require$$2 = getCjsExportFromNamespace(_package$1);
9516
9697
  const {
9517
9698
  boolean
9518
9699
  } = boolean$1;
9519
- const debug$1 = debug$l('botium-core-BotDriver');
9700
+ const debug$1 = debug$m('botium-core-BotDriver');
9520
9701
  const {
9521
9702
  version
9522
9703
  } = require$$2;
@@ -9885,7 +10066,7 @@ var BotDriver_1 = class BotDriver {
9885
10066
 
9886
10067
  };
9887
10068
 
9888
- const debug = debug$l('botium-core-Plugins');
10069
+ const debug = debug$m('botium-core-Plugins');
9889
10070
  const PLUGIN_TYPE_CONNECTOR = 'PLUGIN_TYPE_CONNECTOR';
9890
10071
  const PLUGIN_TYPE_ASSERTER = 'PLUGIN_TYPE_ASSERTER';
9891
10072
  const PLUGIN_TYPE_LOGICHOOK = 'PLUGIN_TYPE_LOGICHOOK';