botium-core 1.11.14 → 1.12.1

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 (52) hide show
  1. package/dist/botium-cjs.js +853 -579
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +471 -198
  4. package/dist/botium-es.js.map +1 -1
  5. package/index.js +1 -0
  6. package/package.json +29 -29
  7. package/samples/connectors/custom/botium-connector-myapi.js +3 -3
  8. package/samples/extensions/asserterHooks/DummyAsserter.js +3 -3
  9. package/src/Capabilities.js +4 -1
  10. package/src/Defaults.js +1 -0
  11. package/src/Enums.js +6 -0
  12. package/src/containers/plugins/SimpleRestContainer.js +32 -1
  13. package/src/scripting/BotiumError.js +21 -0
  14. package/src/scripting/CompilerCsv.js +1 -1
  15. package/src/scripting/CompilerObjectBase.js +4 -14
  16. package/src/scripting/CompilerTxt.js +4 -15
  17. package/src/scripting/CompilerXlsx.js +81 -25
  18. package/src/scripting/Convo.js +16 -4
  19. package/src/scripting/MatchFunctions.js +21 -0
  20. package/src/scripting/ScriptingProvider.js +55 -40
  21. package/src/scripting/helper.js +57 -4
  22. package/src/scripting/logichook/LogicHookConsts.js +4 -0
  23. package/src/scripting/logichook/LogicHookUtils.js +2 -0
  24. package/src/scripting/logichook/asserter/JsonPathAsserter.js +1 -1
  25. package/src/scripting/logichook/asserter/TextWildcardExactAllAsserter.js +8 -0
  26. package/src/scripting/logichook/asserter/TextWildcardExactAllICAsserter.js +8 -0
  27. package/src/scripting/logichook/asserter/TextWildcardExactAnyAsserter.js +8 -0
  28. package/src/scripting/logichook/asserter/TextWildcardExactAnyICAsserter.js +8 -0
  29. package/src/scripting/logichook/logichooks/ClearQueueLogicHook.js +1 -1
  30. package/src/scripting/logichook/userinput/MediaInput.js +14 -2
  31. package/test/connectors/convos/hello.convo.txt +6 -0
  32. package/test/connectors/simplerest.spec.js +42 -2
  33. package/test/convo/convos/continuefailing.convo.txt +19 -0
  34. package/test/convo/transcript.spec.js +34 -0
  35. package/test/scripting/asserters/convos/text_wildcardexact_all_nok.yml +7 -0
  36. package/test/scripting/asserters/convos/text_wildcardexact_all_ok.yml +7 -0
  37. package/test/scripting/asserters/convos/text_wildcardexact_any_nok.yml +7 -0
  38. package/test/scripting/asserters/convos/text_wildcardexact_any_ok.yml +7 -0
  39. package/test/scripting/asserters/textWildcardExactAllAsserter.spec.js +51 -0
  40. package/test/scripting/asserters/textWildcardExactAnyAsserter.spec.js +51 -0
  41. package/test/scripting/matching/matchingmode.spec.js +43 -0
  42. package/test/scripting/scriptingProvider.spec.js +4 -4
  43. package/test/scripting/scriptingmemory/convosMultiMemorySameCols/buy.convo.txt +6 -0
  44. package/test/scripting/scriptingmemory/convosMultiMemorySameCols/products1.scriptingmemory.txt +2 -0
  45. package/test/scripting/scriptingmemory/convosMultiMemorySameCols/products2.scriptingmemory.txt +2 -0
  46. package/test/scripting/scriptingmemory/convosSimpleCols/buy.convo.txt +8 -0
  47. package/test/scripting/scriptingmemory/convosSimpleCols/product.scriptingmemory.txt +3 -0
  48. package/test/scripting/scriptingmemory/convosTwoTablesCols/buy.convo.txt +6 -0
  49. package/test/scripting/scriptingmemory/convosTwoTablesCols/customer.xlsx +0 -0
  50. package/test/scripting/scriptingmemory/convosTwoTablesCols/product.xlsx +0 -0
  51. package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +45 -0
  52. package/test/scripting/userinputs/mediaInputConvos.spec.js +53 -2
@@ -0,0 +1,51 @@
1
+ const assert = require('chai').assert
2
+ const path = require('path')
3
+
4
+ const BotDriver = require('../../..').BotDriver
5
+ const Capabilities = require('../../..').Capabilities
6
+
7
+ const echoConnector = ({ queueBotSays }) => {
8
+ return {
9
+ UserSays (msg) {
10
+ const botMsg = { sender: 'bot', sourceData: msg.sourceData, messageText: msg.messageText }
11
+ queueBotSays(botMsg)
12
+ }
13
+ }
14
+ }
15
+
16
+ describe('scripting.asserters.textWildcardExactAnyAsserter', function () {
17
+ beforeEach(async function () {
18
+ const myCaps = {
19
+ [Capabilities.PROJECTNAME]: 'scripting.asserters.textWildcardExactAnyAsserter',
20
+ [Capabilities.CONTAINERMODE]: echoConnector
21
+ }
22
+ const driver = new BotDriver(myCaps)
23
+ this.compiler = driver.BuildCompiler()
24
+ this.container = await driver.Build()
25
+ })
26
+ afterEach(async function () {
27
+ this.container && await this.container.Clean()
28
+ })
29
+
30
+ it('ok', async function () {
31
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'text_wildcardexact_any_ok.yml'))
32
+
33
+ this.compiler.ExpandScriptingMemoryToConvos()
34
+ assert.equal(this.compiler.convos.length, 1)
35
+ await this.compiler.convos[0].Run(this.container)
36
+ })
37
+
38
+ it('nok', async function () {
39
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'text_wildcardexact_any_nok.yml'))
40
+
41
+ this.compiler.ExpandScriptingMemoryToConvos()
42
+ assert.equal(this.compiler.convos.length, 1)
43
+
44
+ try {
45
+ await this.compiler.convos[0].Run(this.container)
46
+ assert.fail('expected error')
47
+ } catch (err) {
48
+ assert.equal(err.message, 'text_wildcardexact_any_nok/Line 2: assertion error - Line 2: Expected any text in response "Im Joe, my number is 12345, and my ID is id2_*3,Im Joe, my number is 12345, and my ID is id3_*3"')
49
+ }
50
+ })
51
+ })
@@ -206,6 +206,49 @@ describe('matching.matchingmode.wildcardIgnoreCase', function () {
206
206
  })
207
207
  })
208
208
 
209
+ describe('matching.matchingmode.wildcardExact', function () {
210
+ beforeEach(async function () {
211
+ const myCaps = {
212
+ [Capabilities.PROJECTNAME]: 'matching.matchingmode',
213
+ [Capabilities.CONTAINERMODE]: echoConnector,
214
+ [Capabilities.SCRIPTING_MATCHING_MODE]: 'wildcardExact'
215
+ }
216
+ const driver = new BotDriver(myCaps)
217
+ this.compiler = driver.BuildCompiler()
218
+ this.container = await driver.Build()
219
+ })
220
+ afterEach(async function () {
221
+ this.container && await this.container.Clean()
222
+ })
223
+
224
+ it('should not match response with substring', async function () {
225
+ assert.isFalse(this.compiler.Match('Interesting...', 'Interesting'))
226
+ })
227
+ it('should match long response with wildcard', async function () {
228
+ assert.isTrue(this.compiler.Match('this is a long text', 'this is a * text'))
229
+ })
230
+ it('should match very long response with wildcard', async function () {
231
+ assert.isTrue(this.compiler.Match('this is a long text this is a long text this is a long text this is a long text', 'this is a * text this is a * text this is a * text this is a * text'))
232
+ })
233
+ it('should not match long uppcercase response with wildcard', async function () {
234
+ assert.isFalse(this.compiler.Match('THIS IS A LONG TEXT', 'this is a * text'))
235
+ })
236
+ it('should match very long response with very long wildcard', async function () {
237
+ assert.isTrue(this.compiler.Match('begin this is a long text this is a long text this is a long text this is a long text end', 'begin * end'))
238
+ })
239
+ it('should not allow more than 10 wildcards in a string', async function () {
240
+ try {
241
+ this.compiler.Match('some text', 'begin * * * * * * * * * * * end')
242
+ assert.fail('should have failed')
243
+ } catch (err) {
244
+ assert.equal(err.message, 'Maximum number of 10 wildcards supported.')
245
+ }
246
+ })
247
+ it('should not match if pattern is not matching', async function () {
248
+ assert.isFalse(this.compiler.Match('This is a long text', '*notthere*'))
249
+ })
250
+ })
251
+
209
252
  describe('matching.matchingmode.equals', function () {
210
253
  beforeEach(async function () {
211
254
  const myCaps = {
@@ -508,11 +508,11 @@ describe('scriptingProvider.ExpandUtterancesToConvos', function () {
508
508
  assert.equal(scriptingProvider.convos[0].conversation.length, 2)
509
509
  assert.equal(scriptingProvider.convos[0].header.name, 'utt1/utt1-L1')
510
510
  assert.equal(scriptingProvider.convos[0].conversation[0].messageText, 'TEXT1')
511
- assert.equal(scriptingProvider.convos[0].toString(), '1 utt1/utt1-L1 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT1 | Step 2 - check bot response: #bot - ')
511
+ assert.equal(scriptingProvider.convos[0].toString(), '1 utt1/utt1-L1 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT1 SKIP_BOT_UNCONSUMED(no args) | Step 2 - check bot response: #bot - ')
512
512
  assert.equal(scriptingProvider.convos[1].conversation.length, 2)
513
513
  assert.equal(scriptingProvider.convos[1].header.name, 'utt1/utt1-L2')
514
514
  assert.equal(scriptingProvider.convos[1].conversation[0].messageText, 'TEXT2')
515
- assert.equal(scriptingProvider.convos[1].toString(), '2 utt1/utt1-L2 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT2 | Step 2 - check bot response: #bot - ')
515
+ assert.equal(scriptingProvider.convos[1].toString(), '2 utt1/utt1-L2 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT2 SKIP_BOT_UNCONSUMED(no args) | Step 2 - check bot response: #bot - ')
516
516
  })
517
517
  it('should add leading zeros for utterance tags', async function () {
518
518
  const scriptingProvider = new ScriptingProvider(DefaultCapabilities)
@@ -529,11 +529,11 @@ describe('scriptingProvider.ExpandUtterancesToConvos', function () {
529
529
  assert.equal(scriptingProvider.convos[0].conversation.length, 2)
530
530
  assert.equal(scriptingProvider.convos[0].header.name, 'utt1/utt1-L00001')
531
531
  assert.equal(scriptingProvider.convos[0].conversation[0].messageText, 'TEXT1')
532
- assert.equal(scriptingProvider.convos[0].toString(), '1 utt1/utt1-L00001 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT1 | Step 2 - check bot response: #bot - ')
532
+ assert.equal(scriptingProvider.convos[0].toString(), '1 utt1/utt1-L00001 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT1 SKIP_BOT_UNCONSUMED(no args) | Step 2 - check bot response: #bot - ')
533
533
  assert.equal(scriptingProvider.convos[1].conversation.length, 2)
534
534
  assert.equal(scriptingProvider.convos[1].header.name, 'utt1/utt1-L00002')
535
535
  assert.equal(scriptingProvider.convos[1].conversation[0].messageText, 'TEXT2')
536
- assert.equal(scriptingProvider.convos[1].toString(), '2 utt1/utt1-L00002 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT2 | Step 2 - check bot response: #bot - ')
536
+ assert.equal(scriptingProvider.convos[1].toString(), '2 utt1/utt1-L00002 (Expanded Utterances - utt1) ({ origUttName: \'utt1\', origConvoName: \'utt1\' }): Step 1 - tell utterance: #me - TEXT2 SKIP_BOT_UNCONSUMED(no args) | Step 2 - check bot response: #bot - ')
537
537
  })
538
538
  it('should build incomprehension convos for utterance', async function () {
539
539
  const scriptingProvider = new ScriptingProvider(Object.assign({}, DefaultCapabilities, { SCRIPTING_UTTEXPANSION_INCOMPREHENSION: 'INCOMPREHENSION' }))
@@ -0,0 +1,6 @@
1
+ buy
2
+
3
+ #me
4
+ Ok, then send me some $productName
5
+
6
+ #bot
@@ -0,0 +1,2 @@
1
+ | productBread | productBeer | productEE
2
+ $productName | Bread | Beer | Everything Else
@@ -0,0 +1,2 @@
1
+ | productHamburger
2
+ $productName | Hamburger
@@ -0,0 +1,8 @@
1
+ simple text
2
+
3
+ #begin
4
+
5
+ #me
6
+ $productName $customer
7
+
8
+ #bot
@@ -0,0 +1,3 @@
1
+ |product1
2
+ $productName |Wiener Schnitzel
3
+ $customer |Joe
@@ -0,0 +1,6 @@
1
+ two table
2
+
3
+ #me
4
+ buy $productName as $customerName
5
+
6
+ #bot
@@ -71,6 +71,27 @@ describe('scripting.fillingScriptingMemoryFromFile.memoryenabled.originaldeleted
71
71
  }
72
72
  })
73
73
 
74
+ it('two scripting memory file, one colum each, column mode testcasenames', async function () {
75
+ // all variations are generated
76
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convosTwoTablesCols'))
77
+ this.compiler.ExpandScriptingMemoryToConvos()
78
+ assert.equal(this.compiler.convos.length, 4)
79
+
80
+ const assertScriptingMemory = [
81
+ { $productName: 'Wiener Schnitzel', $customerName: 'GoodCustomer' },
82
+ { $productName: 'Pfannkuchen', $customerName: 'GoodCustomer' },
83
+ { $productName: 'Wiener Schnitzel', $customerName: 'BadCustomer' },
84
+ { $productName: 'Pfannkuchen', $customerName: 'BadCustomer' }
85
+ ]
86
+
87
+ for (const [i, convo] of this.compiler.convos.entries()) {
88
+ const transcript = await convo.Run(this.container)
89
+ assert.isObject(transcript.scriptingMemory)
90
+ assert.equal(transcript.scriptingMemory.$productName, assertScriptingMemory[i].$productName)
91
+ assert.equal(transcript.scriptingMemory.$customerName, assertScriptingMemory[i].$customerName)
92
+ }
93
+ })
94
+
74
95
  it('Value is optional in the scripting memory file', async function () {
75
96
  // all variations are generated
76
97
  this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convosValueOptional'))
@@ -96,6 +117,19 @@ describe('scripting.fillingScriptingMemoryFromFile.memoryenabled.originaldeleted
96
117
  assert.equal(transcript.scriptingMemory.$customer, 'Joe')
97
118
  })
98
119
 
120
+ it('Using text file in column mode testcasenames', async function () {
121
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convosSimpleCols'))
122
+ this.compiler.ExpandScriptingMemoryToConvos()
123
+ assert.equal(this.compiler.convos.length, 1)
124
+
125
+ const transcript = await this.compiler.convos[0].Run(this.container)
126
+ assert.isObject(transcript.scriptingMemory)
127
+ assert.isDefined(transcript.scriptingMemory.$productName)
128
+ assert.equal(transcript.scriptingMemory.$productName, 'Wiener Schnitzel')
129
+ assert.isDefined(transcript.scriptingMemory.$customer)
130
+ assert.equal(transcript.scriptingMemory.$customer, 'Joe')
131
+ })
132
+
99
133
  it('should throw exception if name is not set', async function () {
100
134
  try {
101
135
  this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convosMultiMemoryNoName'))
@@ -178,6 +212,17 @@ describe('scripting.fillingScriptingMemoryFromFile.memoryenabled.originaldeleted
178
212
  assert.equal(transcript.scriptingMemory.$productName, 'Hamburger')
179
213
  })
180
214
 
215
+ it('should work with same variable names in column mode testcasenames', async function () {
216
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convosMultiMemorySameCols'))
217
+ this.compiler.ExpandScriptingMemoryToConvos()
218
+ assert.equal(this.compiler.convos.length, 4)
219
+
220
+ const transcript = await this.compiler.convos[3].Run(this.container)
221
+ assert.isObject(transcript.scriptingMemory)
222
+ assert.isDefined(transcript.scriptingMemory.$productName)
223
+ assert.equal(transcript.scriptingMemory.$productName, 'Hamburger')
224
+ })
225
+
181
226
  it('should throw exception if there is intersection in convosMultiMemoryCaseNameCollisionvariable names', async function () {
182
227
  try {
183
228
  this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convosMultiMemoryIntersection'))
@@ -1,4 +1,5 @@
1
1
  const path = require('path')
2
+ const fs = require('fs')
2
3
  const assert = require('chai').assert
3
4
  const nock = require('nock')
4
5
  const BotDriver = require('../../../').BotDriver
@@ -96,6 +97,30 @@ describe('scripting.userinputs.mediaInputConvos.relative', function () {
96
97
  assert.equal(this.compiler.convos[1].conversation[0].userInputs[0].args[0], 'files/botium1.png')
97
98
  assert.equal(this.compiler.convos[2].conversation[0].userInputs[0].args[0], 'files/botium2.png')
98
99
  })
100
+
101
+ it('should use dataUri as media in user message', async function () {
102
+ const mediaData = fs.readFileSync(path.resolve(__dirname, 'convos', 'files', 'botium0.png'))
103
+ const mediaUri = `data:image/png;base64,${mediaData.toString('base64')}`
104
+ const script = `should use dataUri as media in user message
105
+
106
+ #me
107
+ MEDIA ${mediaUri}
108
+ `
109
+
110
+ this.compiler.Compile(script, 'SCRIPTING_FORMAT_TXT', 'SCRIPTING_TYPE_CONVO')
111
+ assert.equal(this.compiler.convos.length, 1)
112
+ assert.equal(this.compiler.convos[0].conversation.length, 1)
113
+ assert.equal(this.compiler.convos[0].conversation[0].userInputs.length, 1)
114
+ assert.equal(this.compiler.convos[0].conversation[0].userInputs[0].name, 'MEDIA')
115
+ assert.equal(this.compiler.convos[0].conversation[0].userInputs[0].args.length, 1)
116
+ assert.isTrue(this.compiler.convos[0].conversation[0].userInputs[0].args[0].startsWith('data:image/png'))
117
+
118
+ const transcript = await this.compiler.convos[0].Run(this.container)
119
+ assert.equal(transcript.steps.length, 1)
120
+ assert.equal(transcript.steps[0].actual.media.length, 1)
121
+ assert.isTrue(transcript.steps[0].actual.media[0].downloadUri.startsWith('data:image/png'))
122
+ assert.equal(transcript.steps[0].actual.media[0].mimeType, 'image/png')
123
+ })
99
124
  })
100
125
 
101
126
  describe('scripting.userinputs.mediaInputConvos.baseUri', function () {
@@ -257,6 +282,7 @@ describe('scripting.userinputs.mediaInputConvos.baseDir', function () {
257
282
  ref: 'MEDIA',
258
283
  src: 'MediaInput',
259
284
  args: {
285
+ downloadMedia: true,
260
286
  baseDir: path.join(__dirname, 'convos', 'files')
261
287
  }
262
288
  }
@@ -315,6 +341,31 @@ describe('scripting.userinputs.mediaInputConvos.baseDir', function () {
315
341
  assert.isTrue(err.message.startsWith('mediaoutofbasedir/Line 3: error sending to bot - The uri \'../*.png\' is pointing out of the base directory'))
316
342
  }
317
343
  })
344
+
345
+ it('should use dataUri as media in user message', async function () {
346
+ const mediaData = fs.readFileSync(path.resolve(__dirname, 'convos', 'files', 'botium0.png'))
347
+ const mediaUri = `data:image/png;base64,${mediaData.toString('base64')}`
348
+ const script = `should use dataUri as media in user message
349
+
350
+ #me
351
+ MEDIA ${mediaUri}
352
+ `
353
+
354
+ this.compiler.Compile(script, 'SCRIPTING_FORMAT_TXT', 'SCRIPTING_TYPE_CONVO')
355
+ assert.equal(this.compiler.convos.length, 1)
356
+ assert.equal(this.compiler.convos[0].conversation.length, 1)
357
+ assert.equal(this.compiler.convos[0].conversation[0].userInputs.length, 1)
358
+ assert.equal(this.compiler.convos[0].conversation[0].userInputs[0].name, 'MEDIA')
359
+ assert.equal(this.compiler.convos[0].conversation[0].userInputs[0].args.length, 1)
360
+ assert.isTrue(this.compiler.convos[0].conversation[0].userInputs[0].args[0].startsWith('data:image/png'))
361
+
362
+ const transcript = await this.compiler.convos[0].Run(this.container)
363
+ assert.equal(transcript.steps.length, 1)
364
+ assert.equal(transcript.steps[0].actual.media.length, 1)
365
+ assert.isTrue(transcript.steps[0].actual.media[0].downloadUri.startsWith('data:image/png'))
366
+ assert.equal(transcript.steps[0].actual.media[0].mimeType, 'image/png')
367
+ assert.isTrue(Buffer.isBuffer(transcript.steps[0].actual.media[0].buffer))
368
+ })
318
369
  })
319
370
 
320
371
  describe('scripting.userinputs.mediaInputDownloadConvos.relative', function () {
@@ -349,7 +400,7 @@ describe('scripting.userinputs.mediaInputDownloadConvos.relative', function () {
349
400
  assert.equal(transcript.steps[0].actual.media.length, 1)
350
401
  assert.isTrue(transcript.steps[0].actual.media[0].downloadUri.endsWith('test/scripting/userinputs/convos/botium.png'))
351
402
  assert.equal(transcript.steps[0].actual.media[0].mimeType, 'image/png')
352
- assert.isNotNull(transcript.steps[0].actual.media[0].buffer)
403
+ assert.isTrue(Buffer.isBuffer(transcript.steps[0].actual.media[0].buffer))
353
404
  })
354
405
  })
355
406
 
@@ -391,7 +442,7 @@ describe('scripting.userinputs.mediaInputDownloadConvos.baseUri', function () {
391
442
  assert.equal(transcript.steps[0].actual.media.length, 1)
392
443
  assert.equal(transcript.steps[0].actual.media[0].downloadUri, 'https://www.botium.at/botium.png')
393
444
  assert.equal(transcript.steps[0].actual.media[0].mimeType, 'image/png')
394
- assert.isNotNull(transcript.steps[0].actual.media[0].buffer)
445
+ assert.isTrue(Buffer.isBuffer(transcript.steps[0].actual.media[0].buffer))
395
446
 
396
447
  scope.persist(false)
397
448
  })