botium-core 1.11.15 → 1.12.2

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 (41) hide show
  1. package/dist/botium-cjs.js +420 -172
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +411 -164
  4. package/dist/botium-es.js.map +1 -1
  5. package/index.js +1 -0
  6. package/package.json +27 -27
  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 -0
  10. package/src/Defaults.js +1 -0
  11. package/src/Enums.js +6 -0
  12. package/src/containers/BaseContainer.js +20 -10
  13. package/src/containers/PluginConnectorContainer.js +1 -0
  14. package/src/containers/plugins/SimpleRestContainer.js +36 -4
  15. package/src/scripting/BotiumError.js +21 -0
  16. package/src/scripting/CompilerCsv.js +1 -1
  17. package/src/scripting/CompilerObjectBase.js +4 -14
  18. package/src/scripting/CompilerTxt.js +4 -15
  19. package/src/scripting/CompilerXlsx.js +81 -25
  20. package/src/scripting/Convo.js +16 -4
  21. package/src/scripting/ScriptingProvider.js +6 -0
  22. package/src/scripting/helper.js +54 -1
  23. package/src/scripting/logichook/LogicHookUtils.js +2 -0
  24. package/src/scripting/logichook/asserter/JsonPathAsserter.js +1 -1
  25. package/src/scripting/logichook/logichooks/ClearQueueLogicHook.js +1 -1
  26. package/src/scripting/logichook/userinput/MediaInput.js +14 -2
  27. package/test/connectors/convos/hello.convo.txt +6 -0
  28. package/test/connectors/simplerest.spec.js +42 -2
  29. package/test/convo/convos/continuefailing.convo.txt +19 -0
  30. package/test/convo/transcript.spec.js +34 -0
  31. package/test/scripting/scriptingProvider.spec.js +4 -4
  32. package/test/scripting/scriptingmemory/convosMultiMemorySameCols/buy.convo.txt +6 -0
  33. package/test/scripting/scriptingmemory/convosMultiMemorySameCols/products1.scriptingmemory.txt +2 -0
  34. package/test/scripting/scriptingmemory/convosMultiMemorySameCols/products2.scriptingmemory.txt +2 -0
  35. package/test/scripting/scriptingmemory/convosSimpleCols/buy.convo.txt +8 -0
  36. package/test/scripting/scriptingmemory/convosSimpleCols/product.scriptingmemory.txt +3 -0
  37. package/test/scripting/scriptingmemory/convosTwoTablesCols/buy.convo.txt +6 -0
  38. package/test/scripting/scriptingmemory/convosTwoTablesCols/customer.xlsx +0 -0
  39. package/test/scripting/scriptingmemory/convosTwoTablesCols/product.xlsx +0 -0
  40. package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +45 -0
  41. package/test/scripting/userinputs/mediaInputConvos.spec.js +53 -2
@@ -761,6 +761,7 @@ module.exports = class ScriptingProvider {
761
761
 
762
762
  debug(`ExpandScriptingMemoryToConvos - ${convosExpandedAll.length} convo expanded, added to convos (${this.convos.length}). Result ${convosExpandedAll.length + this.convos.length} convo`)
763
763
  this.convos = this.convos.concat(convosExpandedAll)
764
+ this._sortConvos()
764
765
  }
765
766
 
766
767
  ExpandUtterancesToConvos ({ useNameAsIntent, incomprehensionUtt } = {}) {
@@ -796,6 +797,11 @@ module.exports = class ScriptingProvider {
796
797
  conversation: [
797
798
  {
798
799
  sender: 'me',
800
+ logicHooks: [
801
+ {
802
+ name: 'SKIP_BOT_UNCONSUMED'
803
+ }
804
+ ],
799
805
  messageText: utt.name,
800
806
  stepTag: 'Step 1 - tell utterance'
801
807
  },
@@ -1,6 +1,8 @@
1
1
  const _ = require('lodash')
2
2
  const isJSON = require('is-json')
3
3
 
4
+ const { E_SCRIPTING_MEMORY_COLUMN_MODE } = require('../Enums')
5
+
4
6
  const normalizeText = (str, doCleanup) => {
5
7
  if (str && _.isArray(str)) {
6
8
  str = str.join(' ')
@@ -463,6 +465,56 @@ const convoStepToLines = (step) => {
463
465
  return lines.map(l => l.trim())
464
466
  }
465
467
 
468
+ const linesToScriptingMemories = (lines, columnMode = null) => {
469
+ const guessScriptingMemoryColumnMode = (lines) => {
470
+ if (lines && lines.length > 1) {
471
+ if (lines[1].trim().startsWith('$')) return E_SCRIPTING_MEMORY_COLUMN_MODE.TESTCASENAMES
472
+ }
473
+ return E_SCRIPTING_MEMORY_COLUMN_MODE.VARNAMES
474
+ }
475
+ columnMode = columnMode || guessScriptingMemoryColumnMode(lines)
476
+
477
+ const scriptingMemories = []
478
+
479
+ if (columnMode === E_SCRIPTING_MEMORY_COLUMN_MODE.TESTCASENAMES) {
480
+ const caseNames = lines[0].split('|').map((name) => name.trim()).slice(1)
481
+
482
+ const varNames = []
483
+ const varValues = []
484
+ for (let row = 1; row < lines.length; row++) {
485
+ if (!lines[row] || lines[row].length === 0) continue
486
+ const rawRow = lines[row].split('|').map((name) => name.trim())
487
+ varNames.push(rawRow[0])
488
+ varValues.push(rawRow.slice(1))
489
+ }
490
+ for (let caseIndex = 0; caseIndex < caseNames.length; caseIndex++) {
491
+ const caseName = caseNames[caseIndex]
492
+
493
+ const values = varNames.reduce((agg, varName, varIndex) => {
494
+ agg[varName] = varValues[varIndex][caseIndex] || null
495
+ return agg
496
+ }, {})
497
+ const scriptingMemory = { header: { name: caseName }, values: values }
498
+ scriptingMemories.push(scriptingMemory)
499
+ }
500
+ } else {
501
+ const varNames = lines[0].split('|').map((name) => name.trim()).slice(1)
502
+ for (let row = 1; row < lines.length; row++) {
503
+ if (!lines[row] || lines[row].length === 0) continue
504
+ const rawRow = lines[row].split('|').map((name) => name.trim())
505
+ const caseName = rawRow[0]
506
+ const values = rawRow.slice(1)
507
+ const varValues = {}
508
+ for (let varIndex = 0; varIndex < varNames.length; varIndex++) {
509
+ varValues[varNames[varIndex]] = values[varIndex]
510
+ }
511
+ const scriptingMemory = { header: { name: caseName }, values: varValues }
512
+ scriptingMemories.push(scriptingMemory)
513
+ }
514
+ }
515
+ return scriptingMemories
516
+ }
517
+
466
518
  module.exports = {
467
519
  normalizeText,
468
520
  splitStringInNonEmptyLines,
@@ -475,5 +527,6 @@ module.exports = {
475
527
  convoStepToObject,
476
528
  validSenders,
477
529
  validateSender,
478
- validateConvo
530
+ validateConvo,
531
+ linesToScriptingMemories
479
532
  }
@@ -240,6 +240,8 @@ module.exports = class LogicHookUtils {
240
240
  return CheckClass({ ref, ...this.buildScriptContext }, this.caps, args)
241
241
  } else if (isClass(CheckClass.PluginClass)) {
242
242
  return new CheckClass.PluginClass({ ref, ...this.buildScriptContext }, this.caps, args)
243
+ } else if (_.isFunction(CheckClass.PluginClass)) {
244
+ return CheckClass.PluginClass({ ref, ...this.buildScriptContext }, this.caps, args)
243
245
  } else {
244
246
  throw new Error(`${src} class or function expected`)
245
247
  }
@@ -118,7 +118,7 @@ module.exports = class JsonPathAsserter {
118
118
  }
119
119
  },
120
120
  cause: {
121
- expected: assert || (args && `any element for ${args.join('|')}`) || (!args && `any element in ${path}`),
121
+ expected: assert || ((args && args.length > 0) && `any element for ${args.join('|')}`) || ((!args || args.length === 0) && `any element in ${path}`),
122
122
  actual: null,
123
123
  path
124
124
  }
@@ -9,7 +9,7 @@ module.exports = class ClearQueueLogicHook {
9
9
  container._EmptyQueue()
10
10
  }
11
11
 
12
- onMeEnd ({ container }) {
12
+ onMeStart ({ container }) {
13
13
  container._EmptyQueue()
14
14
  }
15
15
 
@@ -20,6 +20,9 @@ module.exports = class MediaInput {
20
20
  }
21
21
 
22
22
  _getResolvedUri (uri, convo) {
23
+ if (uri.startsWith('data:')) {
24
+ return new url.URL(uri)
25
+ }
23
26
  if (this.globalArgs && this.globalArgs.baseUris) {
24
27
  const baseUrisSelector = _.get(convo, this.globalArgs.baseSelector || DEFAULT_BASE_SELECTOR)
25
28
  if (baseUrisSelector && this.globalArgs.baseUris[baseUrisSelector]) {
@@ -134,6 +137,8 @@ module.exports = class MediaInput {
134
137
  }
135
138
  })
136
139
  })
140
+ } else if (uri.protocol === 'data:') {
141
+ return Buffer.from(uri.href.split(',')[1], 'base64')
137
142
  }
138
143
  }
139
144
  }
@@ -142,6 +147,13 @@ module.exports = class MediaInput {
142
147
  return arg.indexOf('*') >= 0
143
148
  }
144
149
 
150
+ _mime (arg) {
151
+ if (arg.startsWith('data:')) {
152
+ return arg.substring(arg.indexOf(':') + 1, arg.indexOf(';'))
153
+ }
154
+ return mime.lookup(arg)
155
+ }
156
+
145
157
  expandConvo ({ convo, convoStep, args }) {
146
158
  const hasWildcard = args.findIndex(a => this._isWildcard(a)) >= 0
147
159
 
@@ -187,14 +199,14 @@ module.exports = class MediaInput {
187
199
  meMsg.media.push(new BotiumMockMedia({
188
200
  mediaUri: args[0],
189
201
  downloadUri: uri.toString(),
190
- mimeType: mime.lookup(args[0]),
202
+ mimeType: this._mime(args[0]),
191
203
  buffer
192
204
  }))
193
205
  }
194
206
  } else if (args.length === 2) {
195
207
  meMsg.media.push(new BotiumMockMedia({
196
208
  mediaUri: args[0],
197
- mimeType: mime.lookup(args[0]),
209
+ mimeType: this._mime(args[0]),
198
210
  buffer: args[1]
199
211
  }))
200
212
  }
@@ -0,0 +1,6 @@
1
+ hello
2
+
3
+ #me
4
+ hello
5
+
6
+ #bot
@@ -22,6 +22,12 @@ const myCapsPost = {
22
22
  [Capabilities.SIMPLEREST_BODY_TEMPLATE]: { BODY1: 'BODY1VALUE', BODY2: '{{msg.messageText}}' },
23
23
  [Capabilities.SIMPLEREST_RESPONSE_JSONPATH]: ['$']
24
24
  }
25
+ const myCapsFormPost = {
26
+ [Capabilities.CONTAINERMODE]: 'simplerest',
27
+ [Capabilities.SIMPLEREST_URL]: 'http://my-host.com/api/endpoint/{{msg.messageText}}',
28
+ [Capabilities.SIMPLEREST_METHOD]: 'POST',
29
+ [Capabilities.SIMPLEREST_RESPONSE_JSONPATH]: ['$']
30
+ }
25
31
 
26
32
  const myCapsScriptingMemory = {
27
33
  [Capabilities.CONTAINERMODE]: 'simplerest',
@@ -448,7 +454,7 @@ describe('connectors.simplerest.build', function () {
448
454
  assert.isTrue(err.message.includes('Cant load hook, syntax is not valid'))
449
455
  }
450
456
  })
451
- it('should query params from UPDATE_CUSTOM (without "?")', async function () {
457
+ it('should add query params from UPDATE_CUSTOM (without "?")', async function () {
452
458
  const myCaps = Object.assign({}, myCapsGet)
453
459
  const myMsg = Object.assign({}, msg)
454
460
  myMsg.ADD_QUERY_PARAM = {
@@ -467,7 +473,7 @@ describe('connectors.simplerest.build', function () {
467
473
 
468
474
  await container.Clean()
469
475
  })
470
- it('should query params from UPDATE_CUSTOM (with "?")', async function () {
476
+ it('should add query params from UPDATE_CUSTOM (with "?")', async function () {
471
477
  const myCaps = Object.assign({}, myCapsGet)
472
478
  myCaps.SIMPLEREST_URL = 'http://my-host.com/api/endpoint/messageText?const1=const1'
473
479
  const myMsg = Object.assign({}, msg)
@@ -510,6 +516,26 @@ describe('connectors.simplerest.build', function () {
510
516
 
511
517
  await container.Clean()
512
518
  })
519
+ it('should add form params from UPDATE_CUSTOM (without "?")', async function () {
520
+ const myCaps = Object.assign({}, myCapsFormPost)
521
+ const myMsg = Object.assign({}, msg)
522
+ myMsg.ADD_FORM_PARAM = {
523
+ formparam1: 'valueparam1',
524
+ formparam2: '{{msg.messageText}}'
525
+ }
526
+
527
+ const driver = new BotDriver(myCaps)
528
+ const container = await driver.Build()
529
+ assert.equal(container.pluginInstance.constructor.name, 'SimpleRestContainer')
530
+
531
+ await container.Start()
532
+ const request = await container.pluginInstance._buildRequest(myMsg)
533
+ assert.isObject(request.form)
534
+ assert.equal(request.form.formparam1, 'valueparam1')
535
+ assert.equal(request.form.formparam2, 'messageText')
536
+
537
+ await container.Clean()
538
+ })
513
539
  it('should add header from UPDATE_CUSTOM', async function () {
514
540
  const myCaps = Object.assign({}, myCapsGet)
515
541
  const myMsg = Object.assign({}, msg)
@@ -789,6 +815,7 @@ describe('connectors.simplerest.useresponse', function () {
789
815
  .get('/startencoded').reply(200, { text: JSON.stringify({ prop: 'response from start' }) })
790
816
  .get('/startstring').reply(200, 'response from start')
791
817
  .get('/msg').reply(200, { text: 'response from msg' })
818
+ .get('/msgfail').reply(400, { error: 'failure text' })
792
819
  .persist()
793
820
 
794
821
  const myCaps = Object.assign({
@@ -914,6 +941,19 @@ describe('connectors.simplerest.useresponse', function () {
914
941
  assert.equal(transcript.steps.length, 1)
915
942
  assert.equal(transcript.steps[0].actual.messageText, 'response from start')
916
943
  })
944
+
945
+ it('should use error body content', async function () {
946
+ await this.init({
947
+ [Capabilities.SIMPLEREST_URL]: 'https://mock.com/msgfail'
948
+ })
949
+
950
+ this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'hello.convo.txt')
951
+ try {
952
+ await this.compiler.convos[0].Run(this.container)
953
+ } catch (err) {
954
+ assert.isTrue(err.message.indexOf('failure text') >= 0)
955
+ }
956
+ })
917
957
  })
918
958
 
919
959
  describe('connectors.simplerest.inbound', function () {
@@ -0,0 +1,19 @@
1
+ continuefailing
2
+
3
+ #me
4
+ Hello
5
+
6
+ #bot
7
+ Hello
8
+
9
+ #me
10
+ Hello again!
11
+
12
+ #bot
13
+ Hello again FAILING!
14
+
15
+ #me
16
+ working again
17
+
18
+ #bot
19
+ working again
@@ -42,12 +42,25 @@ describe('convo.transcript', function () {
42
42
  this.compilerMultipleAssertErrors = this.driverMultipleAssertErrors.BuildCompiler()
43
43
  this.containerMultipleAssertErrors = await this.driverMultipleAssertErrors.Build()
44
44
  await this.containerMultipleAssertErrors.Start()
45
+
46
+ const myCapsSkipAssertErrors = {
47
+ [Capabilities.PROJECTNAME]: 'convo.transcript',
48
+ [Capabilities.CONTAINERMODE]: echoConnector,
49
+ [Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]: true,
50
+ [Capabilities.SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS]: true
51
+ }
52
+ this.driverSkipAssertErrors = new BotDriver(myCapsSkipAssertErrors)
53
+ this.compilerSkipAssertErrors = this.driverSkipAssertErrors.BuildCompiler()
54
+ this.containerSkipAssertErrors = await this.driverSkipAssertErrors.Build()
55
+ await this.containerSkipAssertErrors.Start()
45
56
  })
46
57
  afterEach(async function () {
47
58
  await this.container.Stop()
48
59
  await this.container.Clean()
49
60
  await this.containerMultipleAssertErrors.Stop()
50
61
  await this.containerMultipleAssertErrors.Clean()
62
+ await this.containerSkipAssertErrors.Stop()
63
+ await this.containerSkipAssertErrors.Clean()
51
64
  })
52
65
  it('should provide transcript steps on success', async function () {
53
66
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), '2steps.convo.txt')
@@ -347,4 +360,25 @@ describe('convo.transcript', function () {
347
360
  assert.equal(this.compilerMultipleAssertErrors.convos.length, 1)
348
361
  await this.compilerMultipleAssertErrors.convos[0].Run(this.containerMultipleAssertErrors)
349
362
  })
363
+ it('should continue on failing assertion', async function () {
364
+ this.compilerSkipAssertErrors.ReadScript(path.resolve(__dirname, 'convos'), 'continuefailing.convo.txt')
365
+ assert.equal(this.compilerSkipAssertErrors.convos.length, 1)
366
+
367
+ try {
368
+ await this.compilerSkipAssertErrors.convos[0].Run(this.containerSkipAssertErrors)
369
+ assert.fail('expected error')
370
+ } catch (err) {
371
+ assert.isDefined(err.transcript)
372
+ assert.equal(err.transcript.steps.length, 6)
373
+ assert.equal(err.transcript.steps[0].actual.messageText, this.compilerSkipAssertErrors.convos[0].conversation[0].messageText)
374
+ assert.equal(err.transcript.steps[1].actual.messageText, this.compilerSkipAssertErrors.convos[0].conversation[1].messageText)
375
+ assert.equal(err.transcript.steps[2].actual.messageText, this.compilerSkipAssertErrors.convos[0].conversation[2].messageText)
376
+ assert.equal(err.transcript.steps[3].expected.messageText, this.compilerSkipAssertErrors.convos[0].conversation[3].messageText)
377
+ assert.notEqual(err.transcript.steps[3].actual.messageText, this.compilerSkipAssertErrors.convos[0].conversation[3].messageText)
378
+ assert.isDefined(err.transcript.steps[3].err)
379
+ assert.equal(err.transcript.steps[4].expected.messageText, this.compilerSkipAssertErrors.convos[0].conversation[4].messageText)
380
+ assert.equal(err.transcript.steps[5].expected.messageText, this.compilerSkipAssertErrors.convos[0].conversation[5].messageText)
381
+ assert.isNull(err.transcript.steps[5].err)
382
+ }
383
+ })
350
384
  })
@@ -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
  })