botium-core 1.11.13 → 1.12.0

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 (31) hide show
  1. package/dist/botium-cjs.js +692 -524
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +323 -155
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +30 -29
  6. package/samples/connectors/custom/botium-connector-myapi.js +3 -3
  7. package/samples/extensions/asserterHooks/DummyAsserter.js +3 -3
  8. package/src/Capabilities.js +7 -1
  9. package/src/Defaults.js +1 -0
  10. package/src/containers/plugins/SimpleRestContainer.js +129 -52
  11. package/src/scripting/CompilerCsv.js +1 -1
  12. package/src/scripting/MatchFunctions.js +21 -0
  13. package/src/scripting/ScriptingProvider.js +49 -40
  14. package/src/scripting/helper.js +3 -3
  15. package/src/scripting/logichook/LogicHookConsts.js +4 -0
  16. package/src/scripting/logichook/LogicHookUtils.js +2 -0
  17. package/src/scripting/logichook/asserter/JsonPathAsserter.js +1 -1
  18. package/src/scripting/logichook/asserter/TextWildcardExactAllAsserter.js +8 -0
  19. package/src/scripting/logichook/asserter/TextWildcardExactAllICAsserter.js +8 -0
  20. package/src/scripting/logichook/asserter/TextWildcardExactAnyAsserter.js +8 -0
  21. package/src/scripting/logichook/asserter/TextWildcardExactAnyICAsserter.js +8 -0
  22. package/src/scripting/logichook/logichooks/UpdateCustomLogicHook.js +3 -4
  23. package/test/connectors/convos/hello.convo.txt +6 -0
  24. package/test/connectors/simplerest.spec.js +129 -2
  25. package/test/scripting/asserters/convos/text_wildcardexact_all_nok.yml +7 -0
  26. package/test/scripting/asserters/convos/text_wildcardexact_all_ok.yml +7 -0
  27. package/test/scripting/asserters/convos/text_wildcardexact_any_nok.yml +7 -0
  28. package/test/scripting/asserters/convos/text_wildcardexact_any_ok.yml +7 -0
  29. package/test/scripting/asserters/textWildcardExactAllAsserter.spec.js +51 -0
  30. package/test/scripting/asserters/textWildcardExactAnyAsserter.spec.js +51 -0
  31. package/test/scripting/matching/matchingmode.spec.js +43 -0
@@ -464,11 +464,33 @@ module.exports = class ScriptingProvider {
464
464
  return { convos: dirConvos, utterances: dirUtterances, pconvos: dirPartialConvos, scriptingMemories: dirScriptingMemories }
465
465
  }
466
466
 
467
+ ReadScriptFromBuffer (scriptBuffer, scriptingFormat, scriptingTypes = null) {
468
+ if (_.isString(scriptingTypes)) scriptingTypes = [scriptingTypes]
469
+ if (_.isArray(scriptingTypes) && scriptingTypes.length === 0) scriptingTypes = null
470
+
471
+ const result = {
472
+ convos: [],
473
+ utterances: [],
474
+ pconvos: [],
475
+ scriptingMemories: []
476
+ }
477
+ if (!scriptingTypes || scriptingTypes.includes(Constants.SCRIPTING_TYPE_UTTERANCES)) {
478
+ result.utterances = this.Compile(scriptBuffer, scriptingFormat, Constants.SCRIPTING_TYPE_UTTERANCES)
479
+ }
480
+ if (!scriptingTypes || scriptingTypes.includes(Constants.SCRIPTING_TYPE_PCONVO)) {
481
+ result.pconvos = this.Compile(scriptBuffer, scriptingFormat, Constants.SCRIPTING_TYPE_PCONVO)
482
+ }
483
+ if (!scriptingTypes || scriptingTypes.includes(Constants.SCRIPTING_TYPE_CONVO)) {
484
+ result.convos = this.Compile(scriptBuffer, scriptingFormat, Constants.SCRIPTING_TYPE_CONVO)
485
+ }
486
+ if (!scriptingTypes || scriptingTypes.includes(Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY)) {
487
+ result.scriptingMemories = this.Compile(scriptBuffer, scriptingFormat, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY)
488
+ }
489
+ return result
490
+ }
491
+
467
492
  ReadScript (convoDir, filename) {
468
- let fileConvos = []
469
- let fileUtterances = []
470
- let filePartialConvos = []
471
- let fileScriptingMemories = []
493
+ let result = {}
472
494
 
473
495
  try {
474
496
  let scriptBuffer = fs.readFileSync(path.resolve(convoDir, filename))
@@ -487,36 +509,25 @@ module.exports = class ScriptingProvider {
487
509
  }
488
510
 
489
511
  if (filename.endsWith('.xlsx') || filename.endsWith('.xlsm')) {
490
- fileUtterances = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_XSLX, Constants.SCRIPTING_TYPE_UTTERANCES)
491
- filePartialConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_XSLX, Constants.SCRIPTING_TYPE_PCONVO)
492
- fileConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_XSLX, Constants.SCRIPTING_TYPE_CONVO)
493
- fileScriptingMemories = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_XSLX, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY)
512
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_XSLX, [Constants.SCRIPTING_TYPE_UTTERANCES, Constants.SCRIPTING_TYPE_PCONVO, Constants.SCRIPTING_TYPE_CONVO, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY])
494
513
  } else if (filename.endsWith('.convo.txt')) {
495
- fileConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_CONVO)
514
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_CONVO)
496
515
  } else if (filename.endsWith('.pconvo.txt')) {
497
- filePartialConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_PCONVO)
516
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_PCONVO)
498
517
  } else if (filename.endsWith('.utterances.txt')) {
499
- fileUtterances = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_UTTERANCES)
518
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_UTTERANCES)
500
519
  } else if (filename.endsWith('.scriptingmemory.txt')) {
501
- fileScriptingMemories = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY)
520
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_TXT, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY)
502
521
  } else if (filename.endsWith('.convo.csv')) {
503
- fileConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_CONVO)
522
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_CONVO)
504
523
  } else if (filename.endsWith('.pconvo.csv')) {
505
- filePartialConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_PCONVO)
524
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_CSV, Constants.SCRIPTING_TYPE_PCONVO)
506
525
  } else if (filename.endsWith('.yaml') || filename.endsWith('.yml')) {
507
- fileUtterances = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_YAML, Constants.SCRIPTING_TYPE_UTTERANCES)
508
- filePartialConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_YAML, Constants.SCRIPTING_TYPE_PCONVO)
509
- fileConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_YAML, Constants.SCRIPTING_TYPE_CONVO)
510
- fileScriptingMemories = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_YAML, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY)
526
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_YAML, [Constants.SCRIPTING_TYPE_UTTERANCES, Constants.SCRIPTING_TYPE_PCONVO, Constants.SCRIPTING_TYPE_CONVO, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY])
511
527
  } else if (filename.endsWith('.json')) {
512
- fileUtterances = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_JSON, Constants.SCRIPTING_TYPE_UTTERANCES)
513
- filePartialConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_JSON, Constants.SCRIPTING_TYPE_PCONVO)
514
- fileConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_JSON, Constants.SCRIPTING_TYPE_CONVO)
515
- fileScriptingMemories = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_JSON, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY)
528
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_JSON, [Constants.SCRIPTING_TYPE_UTTERANCES, Constants.SCRIPTING_TYPE_PCONVO, Constants.SCRIPTING_TYPE_CONVO, Constants.SCRIPTING_TYPE_SCRIPTING_MEMORY])
516
529
  } else if (filename.endsWith('.markdown') || filename.endsWith('.md')) {
517
- fileUtterances = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_MARKDOWN, Constants.SCRIPTING_TYPE_UTTERANCES)
518
- fileConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_MARKDOWN, Constants.SCRIPTING_TYPE_CONVO)
519
- filePartialConvos = this.Compile(scriptBuffer, Constants.SCRIPTING_FORMAT_MARKDOWN, Constants.SCRIPTING_TYPE_PCONVO)
530
+ result = this.ReadScriptFromBuffer(scriptBuffer, Constants.SCRIPTING_FORMAT_MARKDOWN, [Constants.SCRIPTING_TYPE_UTTERANCES, Constants.SCRIPTING_TYPE_PCONVO, Constants.SCRIPTING_TYPE_CONVO])
520
531
  } else {
521
532
  debug(`ReadScript - dropped file: ${filename}, filename not supported`)
522
533
  }
@@ -526,42 +537,40 @@ module.exports = class ScriptingProvider {
526
537
  }
527
538
 
528
539
  // Compilers saved the convos, and we alter here the saved version too
529
- if (fileConvos) {
530
- fileConvos.forEach((fileConvo) => {
540
+ if (result.convos && result.convos.length > 0) {
541
+ result.convos.forEach((fileConvo) => {
531
542
  fileConvo.sourceTag = { convoDir, filename }
532
543
  if (!fileConvo.header.name) {
533
544
  fileConvo.header.name = filename
534
545
  }
535
546
  })
536
547
  const isSkip = (c) => c.header.name && skipPattern.test(c.header.name.toLowerCase())
537
- fileConvos.filter(c => isSkip(c)).forEach(c => debug(`ReadScript - skipping convo '${c.header.name}'`))
538
- fileConvos = fileConvos.filter(c => !isSkip(c))
548
+ result.convos.filter(c => isSkip(c)).forEach(c => debug(`ReadScript - skipping convo '${c.header.name}'`))
549
+ result.convos = result.convos.filter(c => !isSkip(c))
539
550
  }
540
- if (filePartialConvos) {
541
- filePartialConvos.forEach((filePartialConvo) => {
551
+ if (result.pconvos && result.pconvos.length > 0) {
552
+ result.pconvos.forEach((filePartialConvo) => {
542
553
  filePartialConvo.sourceTag = { convoDir, filename }
543
554
  if (!filePartialConvo.header.name) {
544
555
  filePartialConvo.header.name = filename
545
556
  }
546
557
  })
547
558
  }
548
- if (fileScriptingMemories && fileScriptingMemories.length) {
549
- fileScriptingMemories.forEach((scriptingMemory) => {
559
+ if (result.scriptingMemories && result.scriptingMemories.length > 0) {
560
+ result.scriptingMemories.forEach((scriptingMemory) => {
550
561
  scriptingMemory.sourceTag = { filename }
551
562
  })
552
563
  }
553
-
554
- if (fileUtterances) {
555
- this.fileUtterances = this._tagAndCleanupUtterances(fileUtterances, convoDir, filename)
564
+ if (result.utterances) {
565
+ result.utterances = this._tagAndCleanupUtterances(result.utterances, convoDir, filename)
556
566
  }
557
- return { convos: fileConvos, utterances: fileUtterances, pconvos: filePartialConvos, scriptingMemories: fileScriptingMemories }
567
+ return { convos: result.convos || [], utterances: result.utterances || [], pconvos: result.pconvos || [], scriptingMemories: result.scriptingMemories || [] }
558
568
  }
559
569
 
560
570
  _tagAndCleanupUtterances (utteranceFiles, convoDir, filename) {
561
571
  return utteranceFiles.map((fileUtt) => {
562
572
  fileUtt.sourceTag = { convoDir, filename }
563
- fileUtt.utterances = fileUtt.utterances
564
- .filter(u => u)
573
+ fileUtt.utterances = fileUtt.utterances.filter(u => u)
565
574
  return fileUtt
566
575
  })
567
576
  }
@@ -944,7 +953,7 @@ module.exports = class ScriptingProvider {
944
953
  }
945
954
  }
946
955
  } else {
947
- expandedConvos.push(Object.assign(_.cloneDeep(currentConvo), { conversation: convoStepsStack }))
956
+ expandedConvos.push(Object.assign(_.cloneDeep(currentConvo), { conversation: _.cloneDeep(convoStepsStack) }))
948
957
  }
949
958
  }
950
959
 
@@ -72,7 +72,7 @@ const toString = (value) => {
72
72
  }
73
73
 
74
74
  const flatString = (str) => {
75
- return str.split('\n').map(s => s.trim()).join(' ')
75
+ return str ? str.split('\n').map(s => s.trim()).join(' ') : ''
76
76
  }
77
77
 
78
78
  const linesToConvoStep = (lines, sender, context, eol, singleLineMode = false) => {
@@ -439,7 +439,7 @@ const convoStepToLines = (step) => {
439
439
  if (step.messageText) {
440
440
  lines.push((step.optional ? '?' : '') + (step.not ? '!' : '') + step.messageText)
441
441
  }
442
- if (step.buttons && step.buttons.length > 0) lines.push('BUTTONS ' + step.buttons.map(b => flatString(b.text)).join('|'))
442
+ if (step.buttons && step.buttons.length > 0) lines.push('BUTTONS ' + step.buttons.filter(b => b.text).map(b => flatString(b.text)).join('|'))
443
443
  if (step.media && step.media.length > 0) lines.push('MEDIA ' + step.media.filter(m => !m.buffer && m.mediaUri).map(m => m.mediaUri).join('|'))
444
444
  if (step.cards && step.cards.length > 0) {
445
445
  step.cards.forEach(c => {
@@ -449,7 +449,7 @@ const convoStepToLines = (step) => {
449
449
  if (c.content) cardTexts = cardTexts.concat(_.isArray(c.content) ? c.content : [c.content])
450
450
  if (cardTexts.length > 0) lines.push('CARDS ' + cardTexts.map(c => flatString(c)).join('|'))
451
451
 
452
- if (c.buttons && c.buttons.length > 0) lines.push('BUTTONS ' + c.buttons.map(b => flatString(b.text)).join('|'))
452
+ if (c.buttons && c.buttons.length > 0) lines.push('BUTTONS ' + c.buttons.filter(b => b.text).map(b => flatString(b.text)).join('|'))
453
453
  if (c.image && !c.image.buffer && c.image.mediaUri) lines.push('MEDIA ' + c.image.mediaUri)
454
454
  })
455
455
  }
@@ -33,6 +33,10 @@ module.exports = {
33
33
  { name: 'TEXT_WILDCARD_ANY_IC', className: 'TextWildcardAnyICAsserter' },
34
34
  { name: 'TEXT_WILDCARD_ALL', className: 'TextWildcardAllAsserter' },
35
35
  { name: 'TEXT_WILDCARD_ALL_IC', className: 'TextWildcardAllICAsserter' },
36
+ { name: 'TEXT_WILDCARDEXACT_ANY', className: 'TextWildcardExactAnyAsserter' },
37
+ { name: 'TEXT_WILDCARDEXACT_ANY_IC', className: 'TextWildcardExactAnyICAsserter' },
38
+ { name: 'TEXT_WILDCARDEXACT_ALL', className: 'TextWildcardExactAllAsserter' },
39
+ { name: 'TEXT_WILDCARDEXACT_ALL_IC', className: 'TextWildcardExactAllICAsserter' },
36
40
  { name: 'TEXT_REGEXP_ANY', className: 'TextRegexpAnyAsserter' },
37
41
  { name: 'TEXT_REGEXP_ANY_IC', className: 'TextRegexpAnyICAsserter' },
38
42
  { name: 'TEXT_REGEXP_ALL', className: 'TextRegexpAllAsserter' },
@@ -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
  }
@@ -0,0 +1,8 @@
1
+ const BaseTextAsserter = require('./BaseTextAsserter')
2
+ const MatchFunctions = require('../../MatchFunctions')
3
+
4
+ module.exports = class TextWildcardExactAnyAsserter extends BaseTextAsserter {
5
+ constructor (context, caps = {}) {
6
+ super(context, caps, MatchFunctions.wildcardExact(false), 'all')
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ const BaseTextAsserter = require('./BaseTextAsserter')
2
+ const MatchFunctions = require('../../MatchFunctions')
3
+
4
+ module.exports = class TextWildcardExactAnyAsserter extends BaseTextAsserter {
5
+ constructor (context, caps = {}) {
6
+ super(context, caps, MatchFunctions.wildcardExact(true), 'all')
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ const BaseTextAsserter = require('./BaseTextAsserter')
2
+ const MatchFunctions = require('../../MatchFunctions')
3
+
4
+ module.exports = class TextWildcardExactAnyAsserter extends BaseTextAsserter {
5
+ constructor (context, caps = {}) {
6
+ super(context, caps, MatchFunctions.wildcardExact(false), 'any')
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ const BaseTextAsserter = require('./BaseTextAsserter')
2
+ const MatchFunctions = require('../../MatchFunctions')
3
+
4
+ module.exports = class TextWildcardExactAnyAsserter extends BaseTextAsserter {
5
+ constructor (context, caps = {}) {
6
+ super(context, caps, MatchFunctions.wildcardExact(true), 'any')
7
+ }
8
+ }
@@ -1,8 +1,6 @@
1
1
  const util = require('util')
2
2
  const _ = require('lodash')
3
3
 
4
- const { isStringJson } = require('../../../helpers/Utils')
5
-
6
4
  module.exports = class UpdateCustomLogicHook {
7
5
  constructor (context, caps = {}, globalArgs = {}) {
8
6
  this.context = context
@@ -58,10 +56,11 @@ module.exports = class UpdateCustomLogicHook {
58
56
  }
59
57
 
60
58
  _getValue (raw) {
61
- if (isStringJson(raw)) {
59
+ try {
62
60
  return JSON.parse(raw)
61
+ } catch (e) {
62
+ return raw
63
63
  }
64
- return raw
65
64
  }
66
65
 
67
66
  _update (args, meMsg) {
@@ -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)
@@ -782,9 +808,14 @@ describe('connectors.simplerest.useresponse', function () {
782
808
  this.scope = nock('https://mock.com')
783
809
  .get('/ping').reply(200, { text: 'response from ping' })
784
810
  .get('/pingtrash').reply(200, 'asdfasdfasdfasdf')
811
+ .get('/pingencoded').reply(200, { text: JSON.stringify({ prop: 'response from ping' }) })
812
+ .get('/pingstring').reply(200, 'response from ping')
785
813
  .get('/start').reply(200, { text: 'response from start' })
786
814
  .get('/starttrash').reply(200, 'asdfasdfasdfasdf')
815
+ .get('/startencoded').reply(200, { text: JSON.stringify({ prop: 'response from start' }) })
816
+ .get('/startstring').reply(200, 'response from start')
787
817
  .get('/msg').reply(200, { text: 'response from msg' })
818
+ .get('/msgfail').reply(400, { error: 'failure text' })
788
819
  .persist()
789
820
 
790
821
  const myCaps = Object.assign({
@@ -832,6 +863,32 @@ describe('connectors.simplerest.useresponse', function () {
832
863
  }
833
864
  })
834
865
 
866
+ it('should use parser to parse response from ping', async function () {
867
+ await this.init({
868
+ [Capabilities.SIMPLEREST_PING_URL]: 'https://mock.com/pingencoded',
869
+ [Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE]: true,
870
+ [Capabilities.SIMPLEREST_PARSER_HOOK]: 'body.text = JSON.parse(body.text).prop'
871
+ })
872
+
873
+ this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'responsefromping.convo.txt')
874
+ const transcript = await this.compiler.convos[0].Run(this.container)
875
+ assert.equal(transcript.steps.length, 1)
876
+ assert.equal(transcript.steps[0].actual.messageText, 'response from ping')
877
+ })
878
+
879
+ it('should use parser to parse string from ping', async function () {
880
+ await this.init({
881
+ [Capabilities.SIMPLEREST_PING_URL]: 'https://mock.com/pingstring',
882
+ [Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE]: true,
883
+ [Capabilities.SIMPLEREST_PARSER_HOOK]: 'changeBody({ text: body })'
884
+ })
885
+
886
+ this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'responsefromping.convo.txt')
887
+ const transcript = await this.compiler.convos[0].Run(this.container)
888
+ assert.equal(transcript.steps.length, 1)
889
+ assert.equal(transcript.steps[0].actual.messageText, 'response from ping')
890
+ })
891
+
835
892
  it('should use response from start', async function () {
836
893
  await this.init({
837
894
  [Capabilities.SIMPLEREST_START_URL]: 'https://mock.com/start',
@@ -858,6 +915,45 @@ describe('connectors.simplerest.useresponse', function () {
858
915
  assert.isTrue(err.message.indexOf('Bot did not respond within') >= 0)
859
916
  }
860
917
  })
918
+
919
+ it('should use parser to parse response from ping', async function () {
920
+ await this.init({
921
+ [Capabilities.SIMPLEREST_START_URL]: 'https://mock.com/startencoded',
922
+ [Capabilities.SIMPLEREST_START_PROCESS_RESPONSE]: true,
923
+ [Capabilities.SIMPLEREST_PARSER_HOOK]: 'body.text = JSON.parse(body.text).prop'
924
+ })
925
+
926
+ this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'responsefromstart.convo.txt')
927
+ const transcript = await this.compiler.convos[0].Run(this.container)
928
+ assert.equal(transcript.steps.length, 1)
929
+ assert.equal(transcript.steps[0].actual.messageText, 'response from start')
930
+ })
931
+
932
+ it('should use parser to parse string from ping', async function () {
933
+ await this.init({
934
+ [Capabilities.SIMPLEREST_START_URL]: 'https://mock.com/startstring',
935
+ [Capabilities.SIMPLEREST_START_PROCESS_RESPONSE]: true,
936
+ [Capabilities.SIMPLEREST_PARSER_HOOK]: 'changeBody({ text: body })'
937
+ })
938
+
939
+ this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'responsefromstart.convo.txt')
940
+ const transcript = await this.compiler.convos[0].Run(this.container)
941
+ assert.equal(transcript.steps.length, 1)
942
+ assert.equal(transcript.steps[0].actual.messageText, 'response from start')
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
+ })
861
957
  })
862
958
 
863
959
  describe('connectors.simplerest.inbound', function () {
@@ -985,6 +1081,37 @@ describe('connectors.simplerest.polling', function () {
985
1081
  await container.WaitBotSays()
986
1082
  await container.WaitBotSays()
987
1083
 
1084
+ await container.Stop()
1085
+ await container.Clean()
1086
+ scope.persist(false)
1087
+ }).timeout(5000)
1088
+ it('should use request hook for polling', async () => {
1089
+ const caps = {
1090
+ [Capabilities.CONTAINERMODE]: 'simplerest',
1091
+ [Capabilities.SIMPLEREST_URL]: () => 'https://mock.com/endpoint',
1092
+ [Capabilities.SIMPLEREST_RESPONSE_JSONPATH]: () => ['$.text'],
1093
+ [Capabilities.SIMPLEREST_POLL_URL]: () => 'https://mock.com/poll',
1094
+ [Capabilities.SIMPLEREST_POLL_REQUEST_HOOK]: 'requestOptions.uri = "https://mock.com/_from_hook"'
1095
+ }
1096
+ const scope = nock('https://mock.com')
1097
+ .get('/endpoint')
1098
+ .reply(200, {
1099
+ text: 'you called me'
1100
+ })
1101
+ .get('/_from_hook')
1102
+ .reply(200, {
1103
+ text: 'you called me'
1104
+ })
1105
+ .persist()
1106
+
1107
+ const driver = new BotDriver(caps)
1108
+ const container = await driver.Build()
1109
+ await container.Start()
1110
+
1111
+ await container.UserSays({ text: 'hallo' })
1112
+ await container.WaitBotSays()
1113
+ await container.WaitBotSays()
1114
+
988
1115
  await container.Stop()
989
1116
  await container.Clean()
990
1117
  scope.persist(false)
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: text_wildcardexact_all_nok
3
+ steps:
4
+ - me:
5
+ - Im Joe, my number is 12345, and my ID is id1_123
6
+ - bot:
7
+ - TEXT_WILDCARDEXACT_ALL Im Joe, my number is 12345, and my ID is id2_*3|Im Joe, my number is 1*5, and my ID is id1_123
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: text_wildcardexact_all_nok
3
+ steps:
4
+ - me:
5
+ - Im Joe, my number is 12345, and my ID is id1_123
6
+ - bot:
7
+ - TEXT_WILDCARDEXACT_ALL Im Joe, my number is 12345, and my ID is id1_*3|Im Joe, my number is 1*5, and my ID is id1_123
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: text_wildcardexact_any_nok
3
+ steps:
4
+ - me:
5
+ - Im Joe, my number is 12345, and my ID is id1_123
6
+ - bot:
7
+ - TEXT_WILDCARDEXACT_ANY Im Joe, my number is 12345, and my ID is id2_*3|Im Joe, my number is 12345, and my ID is id3_*3
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: text_wildcardexact_any_ok
3
+ steps:
4
+ - me:
5
+ - Im Joe, my number is 12345, and my ID is id1_123
6
+ - bot:
7
+ - TEXT_WILDCARDEXACT_ANY Im Joe, my number is 12345, and my ID is id1_*3|Im Joe, my number is 12345, and my ID is id2_*3
@@ -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.textWildcardExactAllAsserter', function () {
17
+ beforeEach(async function () {
18
+ const myCaps = {
19
+ [Capabilities.PROJECTNAME]: 'scripting.asserters.textWildcardExactAllAsserter',
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_all_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_all_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_all_nok/Line 2: assertion error - Line 2: Expected text(s) in response "Im Joe, my number is 12345, and my ID is id2_*3"')
49
+ }
50
+ })
51
+ })
@@ -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 = {