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