botium-core 1.14.9 → 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 +65 -20
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +65 -20
- package/dist/botium-es.js.map +1 -1
- package/package.json +2 -1
- package/src/scripting/Convo.js +39 -3
- package/src/scripting/ScriptingProvider.js +18 -11
- package/src/scripting/logichook/LogicHookUtils.js +8 -10
- package/src/scripting/logichook/userinput/MediaInput.js +2 -2
- package/test/convo/transcript.spec.js +93 -1
- package/test/scripting/logichooks/localvsglobal.spec.js +105 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botium-core",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.10",
|
|
4
4
|
"description": "The Selenium for Chatbots",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/botium-es.js",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"socketio-auth": "^0.1.1",
|
|
64
64
|
"swagger-jsdoc": "^6.2.8",
|
|
65
65
|
"swagger-ui-express": "^5.0.0",
|
|
66
|
+
"tinyglobby": "^0.2.10",
|
|
66
67
|
"uuid": "^9.0.1",
|
|
67
68
|
"word-error-rate": "0.0.7",
|
|
68
69
|
"write-yaml": "^1.0.0",
|
package/src/scripting/Convo.js
CHANGED
|
@@ -277,6 +277,10 @@ class Convo {
|
|
|
277
277
|
let skipTranscriptStep = false
|
|
278
278
|
let conditionalGroupId = null
|
|
279
279
|
let conditionMetInGroup = false
|
|
280
|
+
let skipOptionalStep = false
|
|
281
|
+
// 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.
|
|
282
|
+
// So in this case an unexpected error should be shown instead of the latest assertion error.
|
|
283
|
+
let optionalStepAssertionError = false
|
|
280
284
|
let globalConvoStepParameters = container.caps[Capabilities.SCRIPTING_CONVO_STEP_PARAMETERS] || {}
|
|
281
285
|
let retryBotMessageTimeoutEnd = null
|
|
282
286
|
let retryBotMessageConvoId = null
|
|
@@ -284,6 +288,13 @@ class Convo {
|
|
|
284
288
|
for (let i = 0; i < this.conversation.length; i = (retryBotMessageDropBotResponse ? i : i + 1)) {
|
|
285
289
|
retryBotMessageDropBotResponse = false
|
|
286
290
|
const convoStep = this.conversation[i]
|
|
291
|
+
if (!convoStep.optional) {
|
|
292
|
+
skipOptionalStep = false
|
|
293
|
+
}
|
|
294
|
+
if (convoStep.optional && skipOptionalStep) {
|
|
295
|
+
// 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.
|
|
296
|
+
continue
|
|
297
|
+
}
|
|
287
298
|
const rawConvoStepParameters = convoStep.logicHooks.find(lh => lh.name === 'CONVO_STEP_PARAMETERS')?.args
|
|
288
299
|
let convoStepParameters = {}
|
|
289
300
|
if (rawConvoStepParameters && rawConvoStepParameters.length) {
|
|
@@ -426,7 +437,8 @@ class Convo {
|
|
|
426
437
|
} catch (err) {
|
|
427
438
|
transcriptStep.botEnd = new Date()
|
|
428
439
|
|
|
429
|
-
if (convoStep.optional) {
|
|
440
|
+
if (!(err.message.indexOf('Bot did not respond within') < 0) && convoStep.optional) {
|
|
441
|
+
skipOptionalStep = true
|
|
430
442
|
continue
|
|
431
443
|
}
|
|
432
444
|
|
|
@@ -512,6 +524,7 @@ class Convo {
|
|
|
512
524
|
}
|
|
513
525
|
waitForBotSays = false
|
|
514
526
|
skipTranscriptStep = true
|
|
527
|
+
optionalStepAssertionError = true
|
|
515
528
|
return true
|
|
516
529
|
} else if (retryOn) {
|
|
517
530
|
if (!retryBotMessageTimeoutEnd || retryBotMessageConvoId !== convoStep.stepTag) {
|
|
@@ -531,9 +544,18 @@ class Convo {
|
|
|
531
544
|
}
|
|
532
545
|
|
|
533
546
|
if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
|
|
534
|
-
|
|
547
|
+
if (optionalStepAssertionError) {
|
|
548
|
+
optionalStepAssertionError = false
|
|
549
|
+
assertErrors.push(new BotiumError(`${this.header.name}: Unexpected message.`))
|
|
550
|
+
} else {
|
|
551
|
+
assertErrors.push(err)
|
|
552
|
+
}
|
|
535
553
|
return false
|
|
536
554
|
} else {
|
|
555
|
+
if (optionalStepAssertionError) {
|
|
556
|
+
optionalStepAssertionError = false
|
|
557
|
+
throw new BotiumError(`${this.header.name}: Unexpected message.`)
|
|
558
|
+
}
|
|
537
559
|
throw err
|
|
538
560
|
}
|
|
539
561
|
}
|
|
@@ -547,6 +569,7 @@ class Convo {
|
|
|
547
569
|
if (convoStep.not) {
|
|
548
570
|
try {
|
|
549
571
|
this.scriptingEvents.assertBotNotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters)
|
|
572
|
+
optionalStepAssertionError = false
|
|
550
573
|
} catch (err) {
|
|
551
574
|
if (isErrorHandledWithOptionConvoStep(err)) {
|
|
552
575
|
continue
|
|
@@ -555,6 +578,7 @@ class Convo {
|
|
|
555
578
|
} else {
|
|
556
579
|
try {
|
|
557
580
|
this.scriptingEvents.assertBotResponse(response, tomatch, `${this.header.name}/${convoStep.stepTag}`, lastMeConvoStep, convoStepParameters)
|
|
581
|
+
optionalStepAssertionError = false
|
|
558
582
|
} catch (err) {
|
|
559
583
|
if (isErrorHandledWithOptionConvoStep(err)) {
|
|
560
584
|
continue
|
|
@@ -564,6 +588,7 @@ class Convo {
|
|
|
564
588
|
} else if (convoStep.sourceData) {
|
|
565
589
|
try {
|
|
566
590
|
this._compareObject(container, scriptingMemory, convoStep, botMsg.sourceData, convoStep.sourceData, botMsg, convoStepParameters)
|
|
591
|
+
optionalStepAssertionError = false
|
|
567
592
|
} catch (err) {
|
|
568
593
|
if (isErrorHandledWithOptionConvoStep(err)) {
|
|
569
594
|
continue
|
|
@@ -574,11 +599,13 @@ class Convo {
|
|
|
574
599
|
try {
|
|
575
600
|
await this.scriptingEvents.assertConvoStep({ convo: this, convoStep, container, scriptingMemory, botMsg, transcript, transcriptStep })
|
|
576
601
|
await this.scriptingEvents.onBotEnd({ convo: this, convoStep, container, scriptingMemory, botMsg, transcript, transcriptStep })
|
|
602
|
+
optionalStepAssertionError = false
|
|
577
603
|
} catch (err) {
|
|
578
604
|
const nextConvoStep = this.conversation[i + 1]
|
|
579
605
|
if (convoStep.optional && nextConvoStep && nextConvoStep.sender === 'bot') {
|
|
580
606
|
waitForBotSays = false
|
|
581
607
|
skipTranscriptStep = true
|
|
608
|
+
optionalStepAssertionError = true
|
|
582
609
|
continue
|
|
583
610
|
}
|
|
584
611
|
|
|
@@ -611,8 +638,17 @@ class Convo {
|
|
|
611
638
|
} catch (failErr) {
|
|
612
639
|
}
|
|
613
640
|
if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError) {
|
|
614
|
-
|
|
641
|
+
if (optionalStepAssertionError) {
|
|
642
|
+
optionalStepAssertionError = false
|
|
643
|
+
assertErrors.push(new BotiumError(`${this.header.name}: Unexpected message.`))
|
|
644
|
+
} else {
|
|
645
|
+
assertErrors.push(err)
|
|
646
|
+
}
|
|
615
647
|
} else {
|
|
648
|
+
if (optionalStepAssertionError) {
|
|
649
|
+
optionalStepAssertionError = false
|
|
650
|
+
throw new BotiumError(`${this.header.name}: Unexpected message.`)
|
|
651
|
+
}
|
|
616
652
|
throw failErr
|
|
617
653
|
}
|
|
618
654
|
}
|
|
@@ -83,9 +83,9 @@ module.exports = class ScriptingProvider {
|
|
|
83
83
|
this.utterances = {}
|
|
84
84
|
this.matchFn = null
|
|
85
85
|
this.asserters = {}
|
|
86
|
-
this.
|
|
86
|
+
this.globalAsserters = {}
|
|
87
87
|
this.logicHooks = {}
|
|
88
|
-
this.
|
|
88
|
+
this.globalLogicHooks = {}
|
|
89
89
|
this.userInputs = {}
|
|
90
90
|
this.partialConvos = {}
|
|
91
91
|
this.scriptingMemories = []
|
|
@@ -319,8 +319,9 @@ module.exports = class ScriptingProvider {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
-
const
|
|
323
|
-
|
|
322
|
+
const localAsserters = (asserters || []).filter(a => this.asserters[a.name][asserterType])
|
|
323
|
+
|
|
324
|
+
const convoStepPromises = localAsserters
|
|
324
325
|
.map(a => ({
|
|
325
326
|
asserter: a,
|
|
326
327
|
promise: callAsserter(a, this.asserters[a.name], {
|
|
@@ -335,8 +336,12 @@ module.exports = class ScriptingProvider {
|
|
|
335
336
|
}))
|
|
336
337
|
.map(({ promise, asserter }) => updateExceptionContext(promise, asserter))
|
|
337
338
|
|
|
338
|
-
const
|
|
339
|
+
const globalAsserters = Object.keys(this.globalAsserters)
|
|
340
|
+
.filter(name => localAsserters.map(a => a.name).indexOf(name) < 0)
|
|
341
|
+
.reduce((agg, name) => [...agg, this.globalAsserters[name]], [])
|
|
339
342
|
.filter(a => a[asserterType])
|
|
343
|
+
|
|
344
|
+
const globalPromises = globalAsserters
|
|
340
345
|
.map(a => ({
|
|
341
346
|
asserter: a,
|
|
342
347
|
promise: p(this.retryHelperAsserter, () => a[asserterType]({
|
|
@@ -351,7 +356,7 @@ module.exports = class ScriptingProvider {
|
|
|
351
356
|
}))
|
|
352
357
|
.map(({ promise, asserter }) => updateExceptionContext(promise, asserter))
|
|
353
358
|
|
|
354
|
-
const allPromises = [...
|
|
359
|
+
const allPromises = [...convoStepPromises, ...globalPromises]
|
|
355
360
|
if (this.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
|
|
356
361
|
return Promise.allSettled(allPromises).then((results) => {
|
|
357
362
|
const rejected = results.filter(result => result.status === 'rejected').map(result => result.reason)
|
|
@@ -372,8 +377,7 @@ module.exports = class ScriptingProvider {
|
|
|
372
377
|
throw Error(`Unknown hookType ${hookType}`)
|
|
373
378
|
}
|
|
374
379
|
|
|
375
|
-
const localHooks = (logicHooks || [])
|
|
376
|
-
.filter(l => this.logicHooks[l.name][hookType])
|
|
380
|
+
const localHooks = (logicHooks || []).filter(l => this.logicHooks[l.name][hookType])
|
|
377
381
|
|
|
378
382
|
const convoStepPromises = localHooks
|
|
379
383
|
.map(l => p(this.retryHelperLogicHook, () => this.logicHooks[l.name][hookType]({
|
|
@@ -386,7 +390,10 @@ module.exports = class ScriptingProvider {
|
|
|
386
390
|
...rest
|
|
387
391
|
})))
|
|
388
392
|
|
|
389
|
-
const globalHooks = Object.
|
|
393
|
+
const globalHooks = Object.keys(this.globalLogicHooks)
|
|
394
|
+
.filter(name => localHooks.map(l => l.name).indexOf(name) < 0)
|
|
395
|
+
.reduce((agg, name) => [...agg, this.globalLogicHooks[name]], [])
|
|
396
|
+
.filter(l => l[hookType])
|
|
390
397
|
const globalPromises = globalHooks.map(l => p(this.retryHelperLogicHook, () => l[hookType]({ convo, convoStep, scriptingMemory, container, args: [], isGlobal: true, ...rest })))
|
|
391
398
|
|
|
392
399
|
const allPromises = [...convoStepPromises, ...globalPromises]
|
|
@@ -499,9 +506,9 @@ module.exports = class ScriptingProvider {
|
|
|
499
506
|
|
|
500
507
|
const logicHookUtils = new LogicHookUtils({ buildScriptContext: this._buildScriptContext(), caps: this.caps })
|
|
501
508
|
this.asserters = logicHookUtils.asserters
|
|
502
|
-
this.
|
|
509
|
+
this.globalAsserters = logicHookUtils.getGlobalAsserters()
|
|
503
510
|
this.logicHooks = logicHookUtils.logicHooks
|
|
504
|
-
this.
|
|
511
|
+
this.globalLogicHooks = logicHookUtils.getGlobalLogicHooks()
|
|
505
512
|
this.userInputs = logicHookUtils.userInputs
|
|
506
513
|
}
|
|
507
514
|
|
|
@@ -24,9 +24,9 @@ const _ = require('lodash')
|
|
|
24
24
|
module.exports = class LogicHookUtils {
|
|
25
25
|
constructor ({ buildScriptContext, caps }) {
|
|
26
26
|
this.asserters = {}
|
|
27
|
-
this.
|
|
27
|
+
this.globalAsserterNames = []
|
|
28
28
|
this.logicHooks = {}
|
|
29
|
-
this.
|
|
29
|
+
this.globalLogicHookNames = []
|
|
30
30
|
this.userInputs = {}
|
|
31
31
|
this.buildScriptContext = buildScriptContext
|
|
32
32
|
this.caps = caps
|
|
@@ -64,7 +64,7 @@ module.exports = class LogicHookUtils {
|
|
|
64
64
|
}
|
|
65
65
|
this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter')
|
|
66
66
|
if (asserter.global) {
|
|
67
|
-
this.
|
|
67
|
+
this.globalAsserterNames.push(asserter.ref)
|
|
68
68
|
}
|
|
69
69
|
})
|
|
70
70
|
}
|
|
@@ -77,7 +77,7 @@ module.exports = class LogicHookUtils {
|
|
|
77
77
|
}
|
|
78
78
|
this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logichook')
|
|
79
79
|
if (logicHook.global) {
|
|
80
|
-
this.
|
|
80
|
+
this.globalLogicHookNames.push(logicHook.ref)
|
|
81
81
|
}
|
|
82
82
|
})
|
|
83
83
|
}
|
|
@@ -92,14 +92,12 @@ module.exports = class LogicHookUtils {
|
|
|
92
92
|
})
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
return this.
|
|
97
|
-
.map(name => this.asserters[name])
|
|
95
|
+
getGlobalAsserters () {
|
|
96
|
+
return this.globalAsserterNames.reduce((agg, name) => ({ ...agg, [name]: this.asserters[name] }), {})
|
|
98
97
|
}
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
return this.
|
|
102
|
-
.map(name => this.logicHooks[name])
|
|
99
|
+
getGlobalLogicHooks () {
|
|
100
|
+
return this.globalLogicHookNames.reduce((agg, name) => ({ ...agg, [name]: this.logicHooks[name] }), {})
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
_loadClass ({ src, ref, args }, hookType) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
|
-
const
|
|
3
|
+
const globSync = require('tinyglobby').globSync
|
|
4
4
|
const request = require('request')
|
|
5
5
|
const mime = require('mime-types')
|
|
6
6
|
const url = require('url')
|
|
@@ -161,7 +161,7 @@ module.exports = class MediaInput {
|
|
|
161
161
|
const baseDir = this._getBaseDir(convo)
|
|
162
162
|
return args.reduce((e, arg) => {
|
|
163
163
|
if (this._isWildcard(arg)) {
|
|
164
|
-
const mediaFiles =
|
|
164
|
+
const mediaFiles = globSync(arg, { cwd: baseDir })
|
|
165
165
|
mediaFiles.forEach(mf => {
|
|
166
166
|
e.push({
|
|
167
167
|
name: 'MEDIA',
|
|
@@ -49,6 +49,57 @@ const echoConnectorMultipleBotMessages = ({ queueBotSays }) => {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
const echoConnectorMultipleBotMessagesSkipAnOptional = ({ queueBotSays }) => {
|
|
53
|
+
return {
|
|
54
|
+
UserSays (msg) {
|
|
55
|
+
const botMsg = { sender: 'bot', sourceData: msg.sourceData, messageText: msg.messageText }
|
|
56
|
+
if (msg.messageText === 'Welcome') {
|
|
57
|
+
botMsg.messageText = 'Welcome'
|
|
58
|
+
queueBotSays(botMsg)
|
|
59
|
+
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
botMsg.messageText = ''
|
|
62
|
+
botMsg.buttons = [
|
|
63
|
+
{ text: 'First Button' },
|
|
64
|
+
{ text: 'Second Button' }
|
|
65
|
+
]
|
|
66
|
+
queueBotSays(botMsg)
|
|
67
|
+
}, 200)
|
|
68
|
+
} else {
|
|
69
|
+
queueBotSays(botMsg)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const echoConnectorMultipleBotMessagesAssertionFailOnOptional = ({ queueBotSays }) => {
|
|
76
|
+
return {
|
|
77
|
+
UserSays (msg) {
|
|
78
|
+
const botMsg = { sender: 'bot', sourceData: msg.sourceData, messageText: msg.messageText }
|
|
79
|
+
if (msg.messageText === 'Welcome') {
|
|
80
|
+
botMsg.messageText = 'Welcome'
|
|
81
|
+
queueBotSays(botMsg)
|
|
82
|
+
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
botMsg.messageText = 'Fail on this:'
|
|
85
|
+
queueBotSays(botMsg)
|
|
86
|
+
}, 200)
|
|
87
|
+
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
botMsg.messageText = ''
|
|
90
|
+
botMsg.buttons = [
|
|
91
|
+
{ text: 'First Button' },
|
|
92
|
+
{ text: 'Second Button' }
|
|
93
|
+
]
|
|
94
|
+
queueBotSays(botMsg)
|
|
95
|
+
}, 200)
|
|
96
|
+
} else {
|
|
97
|
+
queueBotSays(botMsg)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
52
103
|
describe('convo.transcript', function () {
|
|
53
104
|
beforeEach(async function () {
|
|
54
105
|
const myCaps = {
|
|
@@ -92,6 +143,26 @@ describe('convo.transcript', function () {
|
|
|
92
143
|
this.compilerMultipleBotmessages = this.driverMultipleBotmessages.BuildCompiler()
|
|
93
144
|
this.containerMultipleBotmessages = await this.driverMultipleBotmessages.Build()
|
|
94
145
|
await this.containerMultipleBotmessages.Start()
|
|
146
|
+
|
|
147
|
+
const myCapsMultipleBotMessagesSkipAnOptional = {
|
|
148
|
+
[Capabilities.PROJECTNAME]: 'convo.transcript',
|
|
149
|
+
[Capabilities.CONTAINERMODE]: echoConnectorMultipleBotMessagesSkipAnOptional,
|
|
150
|
+
[Capabilities.SCRIPTING_FORCE_BOT_CONSUMED]: true
|
|
151
|
+
}
|
|
152
|
+
this.driverMultipleBotmessagesSkipAnOptional = new BotDriver(myCapsMultipleBotMessagesSkipAnOptional)
|
|
153
|
+
this.compilerMultipleBotmessagesSkipAnOptional = this.driverMultipleBotmessagesSkipAnOptional.BuildCompiler()
|
|
154
|
+
this.containerMultipleBotmessagesSkipAnOptional = await this.driverMultipleBotmessagesSkipAnOptional.Build()
|
|
155
|
+
await this.containerMultipleBotmessagesSkipAnOptional.Start()
|
|
156
|
+
|
|
157
|
+
const myCapsMultipleBotMessagesAssertionFailOnOptional = {
|
|
158
|
+
[Capabilities.PROJECTNAME]: 'convo.transcript',
|
|
159
|
+
[Capabilities.CONTAINERMODE]: echoConnectorMultipleBotMessagesAssertionFailOnOptional,
|
|
160
|
+
[Capabilities.SCRIPTING_FORCE_BOT_CONSUMED]: true
|
|
161
|
+
}
|
|
162
|
+
this.driverMultipleBotmessagesAssertionFailOnOptional = new BotDriver(myCapsMultipleBotMessagesAssertionFailOnOptional)
|
|
163
|
+
this.compilerMultipleBotmessagesAssertionFailOnOptional = this.driverMultipleBotmessagesAssertionFailOnOptional.BuildCompiler()
|
|
164
|
+
this.containerMultipleBotmessagesAssertionFailOnOptional = await this.driverMultipleBotmessagesAssertionFailOnOptional.Build()
|
|
165
|
+
await this.containerMultipleBotmessagesAssertionFailOnOptional.Start()
|
|
95
166
|
})
|
|
96
167
|
afterEach(async function () {
|
|
97
168
|
await this.container.Stop()
|
|
@@ -189,13 +260,34 @@ describe('convo.transcript', function () {
|
|
|
189
260
|
assert.isDefined(transcript)
|
|
190
261
|
assert.equal(transcript.steps.length, 6)
|
|
191
262
|
})
|
|
263
|
+
it('should provide transcript optional multiple bot steps on skip an optional bot messages', async function () {
|
|
264
|
+
this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'welcome_multiple_botsteps_opt.convo.txt')
|
|
265
|
+
assert.equal(this.compiler.convos.length, 1)
|
|
266
|
+
|
|
267
|
+
const transcript = await this.compiler.convos[0].Run(this.containerMultipleBotmessagesSkipAnOptional)
|
|
268
|
+
assert.isDefined(transcript)
|
|
269
|
+
assert.equal(transcript.steps.length, 5)
|
|
270
|
+
})
|
|
271
|
+
it('should provide transcript optional multiple bot steps assertion fail on optional bot messages', async function () {
|
|
272
|
+
this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'welcome_multiple_botsteps_opt.convo.txt')
|
|
273
|
+
assert.equal(this.compiler.convos.length, 1)
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
await this.compiler.convos[0].Run(this.containerMultipleBotmessagesAssertionFailOnOptional)
|
|
277
|
+
assert.fail('expected error')
|
|
278
|
+
} catch (err) {
|
|
279
|
+
assert.isDefined(err.transcript)
|
|
280
|
+
assert.equal(err.transcript.steps.length, 3)
|
|
281
|
+
assert.isTrue(err.message.includes('Unexpected message'))
|
|
282
|
+
}
|
|
283
|
+
})
|
|
192
284
|
it('should provide transcript optional multiple bot steps on not getting all bot messages', async function () {
|
|
193
285
|
this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'welcome_multiple_botsteps_opt.convo.txt')
|
|
194
286
|
assert.equal(this.compiler.convos.length, 1)
|
|
195
287
|
|
|
196
288
|
const transcript = await this.compiler.convos[0].Run(this.container)
|
|
197
289
|
assert.isDefined(transcript)
|
|
198
|
-
assert.equal(transcript.steps.length,
|
|
290
|
+
assert.equal(transcript.steps.length, 5)
|
|
199
291
|
})
|
|
200
292
|
it('should include pause in transcript steps', async function () {
|
|
201
293
|
this.compiler.ReadScript(path.resolve(__dirname, 'convos'), '2stepsWithPause.convo.txt')
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const Constants = require('../../../src/scripting/Constants')
|
|
2
|
+
const assert = require('chai').assert
|
|
3
|
+
const BotDriver = require('../../..').BotDriver
|
|
4
|
+
const Capabilities = require('../../..').Capabilities
|
|
5
|
+
|
|
6
|
+
const echoConnector = () => ({ queueBotSays }) => {
|
|
7
|
+
return {
|
|
8
|
+
UserSays (msg) {
|
|
9
|
+
const botMsg = { sender: 'bot', sourceData: msg.sourceData, messageText: msg.messageText }
|
|
10
|
+
queueBotSays(botMsg)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const buildDriver = async (mergeCaps) => {
|
|
16
|
+
const myCaps = Object.assign({
|
|
17
|
+
[Capabilities.PROJECTNAME]: 'convo.localvsglobal',
|
|
18
|
+
[Capabilities.CONTAINERMODE]: echoConnector()
|
|
19
|
+
}, mergeCaps)
|
|
20
|
+
|
|
21
|
+
const result = {}
|
|
22
|
+
result.driver = new BotDriver(myCaps)
|
|
23
|
+
result.compiler = result.driver.BuildCompiler()
|
|
24
|
+
result.container = await result.driver.Build()
|
|
25
|
+
return result
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const convoScriptAsserters = `
|
|
29
|
+
LOCALVSGLOBAL
|
|
30
|
+
|
|
31
|
+
#me
|
|
32
|
+
hello
|
|
33
|
+
|
|
34
|
+
#bot
|
|
35
|
+
|
|
36
|
+
#me
|
|
37
|
+
hello 2
|
|
38
|
+
|
|
39
|
+
#bot
|
|
40
|
+
MYASSERTER
|
|
41
|
+
`
|
|
42
|
+
|
|
43
|
+
const convoScriptHooks = `
|
|
44
|
+
LOCALVSGLOBAL
|
|
45
|
+
|
|
46
|
+
#me
|
|
47
|
+
hello
|
|
48
|
+
|
|
49
|
+
#bot
|
|
50
|
+
|
|
51
|
+
#me
|
|
52
|
+
hello 2
|
|
53
|
+
|
|
54
|
+
#bot
|
|
55
|
+
MYHOOK
|
|
56
|
+
`
|
|
57
|
+
|
|
58
|
+
describe('Using local and global hooks together', function () {
|
|
59
|
+
it('should use local and global asserter', async function () {
|
|
60
|
+
let localAssertionCount = 0
|
|
61
|
+
let globalAssertionCount = 0
|
|
62
|
+
|
|
63
|
+
const { compiler, container } = await buildDriver({
|
|
64
|
+
[Capabilities.ASSERTERS]: [{
|
|
65
|
+
ref: 'MYASSERTER',
|
|
66
|
+
src: {
|
|
67
|
+
assertConvoStep: ({ isGlobal }) => {
|
|
68
|
+
if (isGlobal) globalAssertionCount++
|
|
69
|
+
else localAssertionCount++
|
|
70
|
+
return Promise.resolve()
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
global: true
|
|
74
|
+
}]
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
compiler.ReadScriptFromBuffer(Buffer.from(convoScriptAsserters), Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_CONVO)
|
|
78
|
+
await compiler.convos[0].Run(container)
|
|
79
|
+
assert.equal(localAssertionCount, 1)
|
|
80
|
+
assert.equal(globalAssertionCount, 1)
|
|
81
|
+
})
|
|
82
|
+
it('should use local and global logic hooks', async function () {
|
|
83
|
+
let localHookCount = 0
|
|
84
|
+
let globalHookCount = 0
|
|
85
|
+
|
|
86
|
+
const { compiler, container } = await buildDriver({
|
|
87
|
+
[Capabilities.LOGIC_HOOKS]: [{
|
|
88
|
+
ref: 'MYHOOK',
|
|
89
|
+
src: {
|
|
90
|
+
onBotEnd: ({ isGlobal }) => {
|
|
91
|
+
if (isGlobal) globalHookCount++
|
|
92
|
+
else localHookCount++
|
|
93
|
+
return Promise.resolve()
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
global: true
|
|
97
|
+
}]
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
compiler.ReadScriptFromBuffer(Buffer.from(convoScriptHooks), Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_CONVO)
|
|
101
|
+
await compiler.convos[0].Run(container)
|
|
102
|
+
assert.equal(localHookCount, 1)
|
|
103
|
+
assert.equal(globalHookCount, 1)
|
|
104
|
+
})
|
|
105
|
+
})
|