botium-core 1.13.7 → 1.13.9

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 (27) hide show
  1. package/dist/botium-cjs.js +214 -1497
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +214 -1497
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +24 -24
  6. package/src/scripting/Convo.js +42 -15
  7. package/src/scripting/MatchFunctions.js +3 -4
  8. package/src/scripting/ScriptingProvider.js +11 -15
  9. package/src/scripting/helper.js +61 -2
  10. package/src/scripting/logichook/asserter/JsonPathAsserter.js +7 -3
  11. package/src/scripting/logichook/asserter/WerAsserter.js +3 -2
  12. package/src/scripting/logichook/logichooks/SetScriptingMemoryLogicHook.js +1 -1
  13. package/test/convo/convos/applyscriptingmemoryinbegin.convo.txt +14 -0
  14. package/test/convo/fillAndApplyScriptingMemory.spec.js +20 -0
  15. package/test/scripting/asserters/convos/wer_threshold_wildcard_nok_float.yml +7 -0
  16. package/test/scripting/asserters/convos/wer_threshold_wildcard_nok_percentage.yml +7 -0
  17. package/test/scripting/asserters/convos/wer_threshold_wildcard_ok_float.yml +7 -0
  18. package/test/scripting/asserters/convos/wer_threshold_wildcard_ok_percentage.yml +7 -0
  19. package/test/scripting/asserters/jsonpathAsserter.spec.js +90 -3
  20. package/test/scripting/asserters/werAsserter.spec.js +41 -0
  21. package/test/scripting/matching/matchingmode.spec.js +82 -0
  22. package/test/scripting/scriptingModificator.spec.js +2 -0
  23. package/test/scripting/scriptingmemory/convosPartial/buy.convo.txt +7 -0
  24. package/test/scripting/scriptingmemory/convosPartial/product.scriptingmemory.txt +2 -0
  25. package/test/scripting/scriptingmemory/convosPartial/sub1.pconvo.txt +7 -0
  26. package/test/scripting/scriptingmemory/convosPartial/sub2.pconvo.txt +7 -0
  27. package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +10 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botium-core",
3
- "version": "1.13.7",
3
+ "version": "1.13.9",
4
4
  "description": "The Selenium for Chatbots",
5
5
  "main": "index.js",
6
6
  "module": "dist/botium-es.js",
@@ -19,7 +19,7 @@
19
19
  "test": "cross-env NODE_PATH=\"./test/plugins/plugindir/fromfolder:./test/plugins/plugindir/fromfile:./test/security/resources\" mocha \"./test/**/*.spec.js\"",
20
20
  "coverage:report": "nyc report --reporter=lcov npm test",
21
21
  "license-checker": "license-checker > LICENSES-3RDPARTY.txt",
22
- "update-dependencies": "npm-check-updates --reject globby -u --timeout 120000"
22
+ "update-dependencies": "npm-check-updates --reject globby,rollup -u --timeout 120000"
23
23
  },
24
24
  "repository": {
25
25
  "type": "git",
@@ -32,17 +32,17 @@
32
32
  },
33
33
  "homepage": "https://www.botium.ai",
34
34
  "dependencies": {
35
- "@babel/runtime": "^7.19.0",
35
+ "@babel/runtime": "^7.20.6",
36
36
  "async": "^3.2.4",
37
- "body-parser": "^1.20.0",
37
+ "body-parser": "^1.20.1",
38
38
  "boolean": "^3.2.0",
39
39
  "bottleneck": "^2.19.5",
40
- "csv-parse": "^5.3.0",
40
+ "csv-parse": "^5.3.3",
41
41
  "debug": "^4.3.4",
42
42
  "esprima": "^4.0.1",
43
- "express": "^4.18.1",
43
+ "express": "^4.18.2",
44
44
  "globby": "11.0.4",
45
- "ioredis": "^5.2.3",
45
+ "ioredis": "^5.2.4",
46
46
  "is-class": "^0.0.9",
47
47
  "is-json": "^2.0.1",
48
48
  "jsonpath": "^1.1.1",
@@ -53,47 +53,47 @@
53
53
  "moment": "^2.29.4",
54
54
  "mustache": "^4.2.0",
55
55
  "promise-retry": "^2.0.1",
56
- "promise.allsettled": "^1.0.5",
56
+ "promise.allsettled": "^1.0.6",
57
57
  "randomatic": "^3.1.1",
58
58
  "request": "^2.88.2",
59
59
  "rimraf": "^3.0.2",
60
60
  "sanitize-filename": "^1.6.3",
61
61
  "slugify": "^1.6.5",
62
- "socket.io": "^4.5.2",
63
- "socket.io-client": "^4.5.2",
62
+ "socket.io": "^4.5.4",
63
+ "socket.io-client": "^4.5.4",
64
64
  "socketio-auth": "^0.1.1",
65
65
  "swagger-jsdoc": "^6.2.5",
66
- "swagger-ui-express": "^4.5.0",
66
+ "swagger-ui-express": "^4.6.0",
67
67
  "uuid": "^9.0.0",
68
- "vm2": "^3.9.11",
68
+ "vm2": "^3.9.13",
69
69
  "word-error-rate": "0.0.7",
70
70
  "write-yaml": "^1.0.0",
71
71
  "xlsx": "^0.18.5",
72
72
  "xregexp": "^5.1.1",
73
- "yaml": "^2.1.1"
73
+ "yaml": "^2.1.3"
74
74
  },
75
75
  "devDependencies": {
76
- "@babel/core": "^7.19.3",
77
- "@babel/node": "^7.19.1",
78
- "@babel/plugin-transform-runtime": "^7.19.1",
79
- "@babel/preset-env": "^7.19.3",
80
- "chai": "^4.3.6",
76
+ "@babel/core": "^7.20.5",
77
+ "@babel/node": "^7.20.5",
78
+ "@babel/plugin-transform-runtime": "^7.19.6",
79
+ "@babel/preset-env": "^7.20.2",
80
+ "chai": "^4.3.7",
81
81
  "chai-as-promised": "^7.1.1",
82
82
  "cross-env": "^7.0.3",
83
- "eslint": "^8.24.0",
83
+ "eslint": "^8.29.0",
84
84
  "eslint-config-standard": "^17.0.0",
85
85
  "eslint-plugin-import": "^2.26.0",
86
86
  "eslint-plugin-mocha": "^10.1.0",
87
- "eslint-plugin-n": "^15.3.0",
88
- "eslint-plugin-promise": "^6.0.1",
87
+ "eslint-plugin-n": "^15.6.0",
88
+ "eslint-plugin-promise": "^6.1.1",
89
89
  "eslint-plugin-standard": "^4.1.0",
90
90
  "license-checker": "^25.0.1",
91
91
  "license-compatibility-checker": "^0.3.5",
92
- "mocha": "^10.0.0",
92
+ "mocha": "^10.2.0",
93
93
  "nock": "^13.2.9",
94
- "npm-check-updates": "^16.3.4",
94
+ "npm-check-updates": "^16.5.6",
95
95
  "nyc": "^15.1.0",
96
- "rollup": "^2.79.1",
96
+ "rollup": "2.79.1",
97
97
  "rollup-plugin-babel": "^4.4.0",
98
98
  "rollup-plugin-commonjs": "^10.1.0",
99
99
  "rollup-plugin-json": "^4.0.0",
@@ -591,26 +591,53 @@ class Convo {
591
591
  }
592
592
 
593
593
  GetScriptingMemoryAllVariables (container) {
594
- const resultOuter = this.conversation.reduce((acc, convoStep) => {
595
- let result = acc
596
- result = result.concat(this.GetScriptingMemoryVariables(container, convoStep.messageText))
597
- const extractFromArgs = (convoStepItems) => {
598
- let resultInner = []
599
- for (const item of (convoStepItems || [])) {
600
- for (const arg of (item.args || [])) {
601
- resultInner = resultInner.concat(this.GetScriptingMemoryVariables(container, arg))
594
+ const partialConvos = this.context.GetPartialConvos()
595
+
596
+ const variableNames = this.conversation.reduce((acc, convoStep) => {
597
+ if (convoStep.sender === 'include') {
598
+ if (convoStep.channel) {
599
+ const partialConvo = partialConvos[convoStep.channel]
600
+ if (partialConvo) {
601
+ acc = [...acc, ...partialConvo.GetScriptingMemoryAllVariables(container)]
602
602
  }
603
603
  }
604
- return resultInner
605
- }
606
- result = result.concat(extractFromArgs(convoStep.asserters))
607
- result = result.concat(extractFromArgs(convoStep.logicHooks))
608
- result = result.concat(extractFromArgs(convoStep.userInputs))
604
+ if (convoStep.messageText) {
605
+ for (const partialConvoName of splitStringInNonEmptyLines(convoStep.messageText)) {
606
+ const partialConvo = partialConvos[partialConvoName]
607
+ if (partialConvo) {
608
+ acc = [...acc, ...partialConvo.GetScriptingMemoryAllVariables(container)]
609
+ }
610
+ }
611
+ }
612
+ } else {
613
+ acc = [...acc, ...this.GetScriptingMemoryVariables(container, convoStep.messageText)]
609
614
 
610
- return result
615
+ const __extractFromArgs = (convoStepItems) => {
616
+ let resultInner = []
617
+ for (const item of (convoStepItems || [])) {
618
+ for (const arg of (item.args || [])) {
619
+ resultInner = resultInner.concat(this.GetScriptingMemoryVariables(container, arg))
620
+ }
621
+ }
622
+ return resultInner
623
+ }
624
+ acc = [...acc, ...__extractFromArgs(convoStep.asserters)]
625
+ acc = [...acc, ...__extractFromArgs(convoStep.logicHooks)]
626
+ acc = [...acc, ...__extractFromArgs(convoStep.userInputs)]
627
+
628
+ convoStep.logicHooks.forEach((logicHook) => {
629
+ if (logicHook.name === LOGIC_HOOK_INCLUDE) {
630
+ const partialConvo = partialConvos[logicHook.args[0]]
631
+ if (partialConvo) {
632
+ acc = [...acc, ...partialConvo.GetScriptingMemoryAllVariables(container)]
633
+ }
634
+ }
635
+ })
636
+ }
637
+ return acc
611
638
  }, [])
612
639
 
613
- return [...new Set(resultOuter)]
640
+ return _.uniq(variableNames)
614
641
  }
615
642
 
616
643
  GetScriptingMemoryVariables (container, utterance) {
@@ -1,10 +1,9 @@
1
1
  const _ = require('lodash')
2
- const speechScorer = require('word-error-rate')
3
2
 
4
- const { toString, quoteRegexpString } = require('./helper')
3
+ const { toString, quoteRegexpString, calculateWer } = require('./helper')
5
4
 
6
5
  const _normalize = (botresponse) => {
7
- if (_.isUndefined(botresponse)) return ''
6
+ if (_.isUndefined(botresponse) || _.isNil(botresponse)) return ''
8
7
  if (_.isObject(botresponse) && _.has(botresponse, 'messageText')) {
9
8
  return toString(botresponse.messageText) || ''
10
9
  }
@@ -85,7 +84,7 @@ const wer = () => (botresponse, utterance, args) => {
85
84
  utterance = toString(utterance || '')
86
85
 
87
86
  const threshold = ([',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100)
88
- return speechScorer.wordErrorRate(botresponse, utterance) <= threshold
87
+ return calculateWer(botresponse, utterance) <= threshold
89
88
  }
90
89
 
91
90
  const getMatchFunction = (matchingMode) => {
@@ -209,7 +209,7 @@ module.exports = class ScriptingProvider {
209
209
  this.retryHelperUserInput = new RetryHelper(this.caps, 'USERINPUT')
210
210
  }
211
211
 
212
- _createAsserterPromises ({ asserterType, asserters, convo, convoStep, scriptingMemory, ...rest }) {
212
+ _createAsserterPromises ({ asserterType, asserters, convo, convoStep, scriptingMemory, container, ...rest }) {
213
213
  if (!this._isValidAsserterType(asserterType)) {
214
214
  throw Error(`Unknown asserterType ${asserterType}`)
215
215
  }
@@ -254,7 +254,8 @@ module.exports = class ScriptingProvider {
254
254
  convo,
255
255
  convoStep,
256
256
  scriptingMemory,
257
- args: ScriptingMemory.applyToArgs(a.args, scriptingMemory, this.caps, rest.botMsg),
257
+ container,
258
+ args: ScriptingMemory.applyToArgs(a.args, scriptingMemory, container.caps, rest.botMsg),
258
259
  isGlobal: false,
259
260
  ...rest
260
261
  }))
@@ -276,7 +277,7 @@ module.exports = class ScriptingProvider {
276
277
  return Promise.resolve(false)
277
278
  }
278
279
 
279
- _createLogicHookPromises ({ hookType, logicHooks, convo, convoStep, scriptingMemory, ...rest }) {
280
+ _createLogicHookPromises ({ hookType, logicHooks, convo, convoStep, scriptingMemory, container, ...rest }) {
280
281
  if (hookType !== 'onMeStart' && hookType !== 'onMePrepare' && hookType !== 'onMeEnd' && hookType !== 'onBotStart' && hookType !== 'onBotPrepare' && hookType !== 'onBotEnd' &&
281
282
  hookType !== 'onConvoBegin' && hookType !== 'onConvoEnd'
282
283
  ) {
@@ -289,7 +290,8 @@ module.exports = class ScriptingProvider {
289
290
  convo,
290
291
  convoStep,
291
292
  scriptingMemory,
292
- args: ScriptingMemory.applyToArgs(l.args, scriptingMemory, this.caps, rest.botMsg),
293
+ container,
294
+ args: ScriptingMemory.applyToArgs(l.args, scriptingMemory, container.caps, rest.botMsg),
293
295
  isGlobal: false,
294
296
  ...rest
295
297
  })))
@@ -303,14 +305,15 @@ module.exports = class ScriptingProvider {
303
305
  return Promise.resolve(false)
304
306
  }
305
307
 
306
- _createUserInputPromises ({ convo, convoStep, scriptingMemory, ...rest }) {
308
+ _createUserInputPromises ({ convo, convoStep, scriptingMemory, container, ...rest }) {
307
309
  const convoStepPromises = (convoStep.userInputs || [])
308
310
  .filter(ui => this.userInputs[ui.name])
309
311
  .map(ui => p(this.retryHelperUserInput, () => this.userInputs[ui.name].setUserInput({
310
312
  convo,
311
313
  convoStep,
312
314
  scriptingMemory,
313
- args: ScriptingMemory.applyToArgs(ui.args, scriptingMemory, this.caps, rest.meMsg),
315
+ container,
316
+ args: ScriptingMemory.applyToArgs(ui.args, scriptingMemory, container.caps, rest.meMsg),
314
317
  ...rest
315
318
  })))
316
319
 
@@ -885,12 +888,11 @@ module.exports = class ScriptingProvider {
885
888
  // drop unwanted convos
886
889
  convoFilter: null
887
890
  }, options)
888
- const context = { count: 0 }
889
891
  const expandedConvos = []
890
892
  debug(`ExpandConvos - Using utterances expansion mode: ${this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE]}`)
891
893
  this.convos.forEach((convo) => {
892
894
  convo.expandPartialConvos()
893
- for (const expanded of this._expandConvo(convo, options, context)) {
895
+ for (const expanded of this._expandConvo(convo, options, {})) {
894
896
  expanded.header.assertionCount = this.GetAssertionCount(expanded)
895
897
  if (options.justHeader) {
896
898
  const ConvoWithOnlyHeader = {
@@ -922,10 +924,9 @@ module.exports = class ScriptingProvider {
922
924
  // creating a nested generator, calling the other.
923
925
  // We hope this.convos does not changes while this iterator is used
924
926
  const _convosIterable = function * (options) {
925
- const context = { count: 0 }
926
927
  for (const convo of this.convos) {
927
928
  convo.expandPartialConvos()
928
- yield * this._expandConvo(convo, options, context)
929
+ yield * this._expandConvo(convo, options, {})
929
930
  }
930
931
  }.bind(this)
931
932
 
@@ -1122,11 +1123,6 @@ module.exports = class ScriptingProvider {
1122
1123
  } else {
1123
1124
  const expanded = Object.assign(_.cloneDeep(currentConvo), { conversation: _.cloneDeep(convoStepsStack) })
1124
1125
  if (!options.convoFilter || options.convoFilter(expanded)) {
1125
- context.count++
1126
- const logPerEntry = context.count < 10 ? 1 : context.count < 100 ? 10 : context.count < 1000 ? 100 : context.count < 10000 ? 1000 : 10000
1127
- if (context.count % logPerEntry === 0) {
1128
- debug(`Convo #${context.count} expanded (${expanded.header.name})`)
1129
- }
1130
1126
  yield expanded
1131
1127
  }
1132
1128
  }
@@ -1,5 +1,6 @@
1
1
  const _ = require('lodash')
2
2
  const isJSON = require('is-json')
3
+ const speechScorer = require('word-error-rate')
3
4
 
4
5
  const { E_SCRIPTING_MEMORY_COLUMN_MODE } = require('../Enums')
5
6
 
@@ -61,7 +62,7 @@ const removeBuffers = obj => {
61
62
  }
62
63
 
63
64
  const toString = (value) => {
64
- if (_.isUndefined(value)) return undefined
65
+ if (_.isUndefined(value) || _.isNil(value)) return ''
65
66
  if (_.isString(value)) return value
66
67
  if (_.isNumber(value)) return value.toString()
67
68
  if (_.isArray(value)) return value.map(v => toString(v)).join(',')
@@ -524,6 +525,63 @@ const linesToScriptingMemories = (lines, columnMode = null) => {
524
525
  return scriptingMemories
525
526
  }
526
527
 
528
+ const calculateWer = (str, pattern) => {
529
+ const _prepareString = (str, remWildcard = false) => {
530
+ if (remWildcard) return str.replace(/[.,/#!$%^&;:*{}=\-_`~()]/g, '').toLowerCase()
531
+ return str.replace(/[.,/#!$%^&;:{}=\-_`~()]/g, '').toLowerCase()
532
+ }
533
+
534
+ const _getSubsets = (array, size) => {
535
+ const subsets = []
536
+ for (const index in array) {
537
+ const end = parseInt(index) + size
538
+ if (end <= array.length) { subsets.push(array.slice(index, end)) }
539
+ }
540
+ return subsets
541
+ }
542
+
543
+ const _getWords = str => str.split(' ').map(w => w.trim())
544
+
545
+ const _getErrors = (words1, words2) => words1.map((w, i) => {
546
+ return w !== words2[i]
547
+ })
548
+
549
+ const utterance = pattern
550
+
551
+ const botMessage = _prepareString(str)
552
+ const botMessageWords = botMessage.split(' ').map(bm => bm.trim())
553
+ const utt = _prepareString(utterance)
554
+
555
+ const errors = []
556
+ for (let wildcardPart of utt.split('*')) {
557
+ let wer = 1
558
+ wildcardPart = wildcardPart.trim()
559
+ if (wildcardPart.length === 0) {
560
+ errors.push([false])
561
+ continue
562
+ }
563
+ const wordCount = wildcardPart.split(' ').length
564
+ const subsetPhrases = _getSubsets(botMessageWords, wordCount).map(subset => subset.join(' ')) // botMessageWordsSubsets.filter(subset => subset.length === wordCount).map(subset => subset.reverse().join(' '))
565
+ let subsetPhraseFound = null
566
+ for (const subsetPhrase of subsetPhrases) {
567
+ const localWer = speechScorer.wordErrorRate(subsetPhrase, wildcardPart).toFixed(2)
568
+ if (localWer <= wer) {
569
+ subsetPhraseFound = subsetPhrase
570
+ wer = localWer
571
+ }
572
+ }
573
+ console.log('lala', subsetPhraseFound)
574
+ errors.push(_getErrors(_getWords(wildcardPart), _getWords(subsetPhraseFound)))
575
+ }
576
+ let errCount = 0
577
+ let allCount = 0
578
+ for (const err of errors) {
579
+ errCount += err.filter(err => err === true).length
580
+ allCount += err.length
581
+ }
582
+ return (errCount / allCount).toFixed(2)
583
+ }
584
+
527
585
  module.exports = {
528
586
  normalizeText,
529
587
  splitStringInNonEmptyLines,
@@ -537,5 +595,6 @@ module.exports = {
537
595
  validSenders,
538
596
  validateSender,
539
597
  validateConvo,
540
- linesToScriptingMemories
598
+ linesToScriptingMemories,
599
+ calculateWer
541
600
  }
@@ -127,6 +127,10 @@ module.exports = class JsonPathAsserter {
127
127
  }
128
128
  }
129
129
 
130
+ if (this.globalArgs && this.globalArgs.checkExistanceOnEmptyAssert) {
131
+ if (!assert) return Promise.resolve()
132
+ }
133
+
130
134
  if (!_.isNil(assert)) {
131
135
  const actual = (_.isArray(jsonPathValues) && jsonPathValues.length === 1) ? jsonPathValues[0] : jsonPathValues
132
136
 
@@ -135,10 +139,10 @@ module.exports = class JsonPathAsserter {
135
139
  matchFn = getMatchFunction(this.globalArgs.matchingMode)
136
140
  }
137
141
 
138
- const match = jsonPathValues.find(a => matchFn(a, assert))
142
+ const match = jsonPathValues.findIndex(a => matchFn(a, assert)) >= 0
139
143
 
140
144
  if (not && match) {
141
- return Promise.reject(new BotiumError(`${convoStep.stepTag}: Not expected: "${toString(actual)}" in jsonPath ${path}"`,
145
+ return Promise.reject(new BotiumError(`${convoStep.stepTag}: Not expected: "${actual === '' ? '<empty>' : toString(actual)}" in jsonPath ${path}"`,
142
146
  {
143
147
  type: 'asserter',
144
148
  source: this.name,
@@ -159,7 +163,7 @@ module.exports = class JsonPathAsserter {
159
163
  ))
160
164
  }
161
165
  if (!not && !match) {
162
- return Promise.reject(new BotiumError(`${convoStep.stepTag}: Expected: "${assert}" in jsonPath ${path}, actual: ${toString(actual)}`,
166
+ return Promise.reject(new BotiumError(`${convoStep.stepTag}: Expected: "${assert === '' ? '<empty>' : assert}" in jsonPath ${path}, actual: ${actual === '' ? '<empty>' : toString(actual)}`,
163
167
  {
164
168
  type: 'asserter',
165
169
  source: this.name,
@@ -1,6 +1,6 @@
1
1
  // const _ = require('lodash')
2
- const speechScorer = require('word-error-rate')
3
2
  const { BotiumError } = require('../../BotiumError')
3
+ const { calculateWer } = require('../../helper')
4
4
 
5
5
  module.exports = class WerAsserter {
6
6
  constructor (context, caps = {}) {
@@ -34,7 +34,8 @@ module.exports = class WerAsserter {
34
34
  const utterance = args[0]
35
35
  const threshold = ([',', '.'].find(p => `${args[1]}`.includes(p)) ? parseFloat(args[1]) : parseInt(args[1]) / 100).toFixed(2)
36
36
 
37
- const wer = speechScorer.wordErrorRate(botMsg.messageText, utterance).toFixed(2)
37
+ const wer = calculateWer(botMsg.messageText, utterance)
38
+
38
39
  if (wer > threshold) {
39
40
  const _toPercent = (s) => `${(s * 100).toFixed(0)}%`
40
41
 
@@ -44,7 +44,7 @@ module.exports = class SetScriptingMemoryLogicHook {
44
44
  // args[0] cant have the whole name of the variable, because the variable names are replaced
45
45
  const name = '$' + params.name
46
46
  const value = params.value
47
- debug(`Set scripting memory variable "${name}" from "${scriptingMemory[name]}" to "${value}, isGlobal: ${isGlobal}, type: ${type}"`)
47
+ debug(`Set scripting memory variable "${name}" from "${scriptingMemory[name]}" to "${value}", isGlobal: ${isGlobal}, type: ${type}"`)
48
48
  scriptingMemory[name] = value
49
49
 
50
50
  return Promise.resolve()
@@ -0,0 +1,14 @@
1
+ applyscriptingmemoryinbegin
2
+
3
+ #begin
4
+ SET_SCRIPTING_MEMORY access_token|$cap(MYTOKEN)
5
+
6
+ #me
7
+ access token: $cap(MYTOKEN)
8
+
9
+ #bot
10
+
11
+ #me
12
+ access token: $access_token
13
+
14
+ #bot
@@ -163,6 +163,26 @@ describe('convo.fillAndApplyScriptingMemory', function () {
163
163
  const transcript = await compiler.convos[0].Run(container)
164
164
  assert.isObject(transcript.scriptingMemory)
165
165
  })
166
+ it('should apply scripting memory in begin args', async function () {
167
+ const myCaps = {
168
+ [Capabilities.PROJECTNAME]: 'convo.scriptingmemory',
169
+ [Capabilities.CONTAINERMODE]: echoConnector,
170
+ [Capabilities.SCRIPTING_ENABLE_MEMORY]: true,
171
+ [Capabilities.CUSTOMHOOK_ONBUILD]: 'module.exports = ({ container }) => { console.log("customhooks called"); container.caps.MYTOKEN = "test1234" }'
172
+ }
173
+ const driver = new BotDriver(myCaps)
174
+ const compiler = driver.BuildCompiler()
175
+ const container = await driver.Build()
176
+
177
+ compiler.ReadScript(path.resolve(__dirname, 'convos'), 'applyscriptingmemoryinbegin.convo.txt')
178
+ assert.equal(compiler.convos.length, 1)
179
+
180
+ const transcript = await compiler.convos[0].Run(container)
181
+ assert.isObject(transcript.scriptingMemory)
182
+ assert.equal(transcript.scriptingMemory.$access_token, 'test1234')
183
+ assert.equal(transcript.steps[0].actual.messageText, 'access token: test1234')
184
+ assert.equal(transcript.steps[2].actual.messageText, 'access token: test1234')
185
+ })
166
186
  })
167
187
 
168
188
  describe('api', function () {
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: wer_threshold_wildcard_nok
3
+ steps:
4
+ - me:
5
+ - This is an example
6
+ - bot:
7
+ - TEXT_WER * that are * hot|0.4
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: wer_threshold_wildcard_nok
3
+ steps:
4
+ - me:
5
+ - This is an example
6
+ - bot:
7
+ - TEXT_WER * is * hot|1
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: wer_threshold_wildcard_ok
3
+ steps:
4
+ - me:
5
+ - This is an example
6
+ - bot:
7
+ - TEXT_WER this is * sample|0.4
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: wer_threshold_wildcard_ok
3
+ steps:
4
+ - me:
5
+ - This is an example
6
+ - bot:
7
+ - TEXT_WER this is another *|30
@@ -7,16 +7,89 @@ describe('scripting.asserters.jsonPathAsserter', function () {
7
7
  describe('jsonPathAsserter', function () {
8
8
  beforeEach(async function () {
9
9
  this.jsonPathAsserter = new JsonPathAsserter({
10
- Match: (botresponse, utterance) => botresponse.toLowerCase().indexOf(utterance.toLowerCase()) >= 0
10
+ Match: (botresponse, utterance) => {
11
+ return botresponse.toLowerCase().indexOf(utterance.toLowerCase()) >= 0
12
+ }
11
13
  }, {})
12
14
  this.jsonPathAsserterWildcard = new JsonPathAsserter({
13
15
  Match: getMatchFunction('wildcardIgnoreCase')
14
16
  }, {})
17
+ this.jsonPathAsserterEquals = new JsonPathAsserter({
18
+ Match: getMatchFunction('equals')
19
+ }, {})
15
20
  this.jsonPathAsserterGlobalArgs = new JsonPathAsserter({
16
21
  Match: (botresponse, utterance) => botresponse.toLowerCase().indexOf(utterance.toLowerCase()) >= 0
17
22
  }, {}, { path: '$.test' })
18
23
  })
19
24
 
25
+ describe('empty string', function () {
26
+ it('should succeed if both is empty', async function () {
27
+ await this.jsonPathAsserterWildcard.assertConvoStep({
28
+ convoStep: { stepTag: 'test' },
29
+ args: ['$.test', ''],
30
+ botMsg: {
31
+ sourceData: {
32
+ test: ''
33
+ }
34
+ }
35
+ })
36
+ })
37
+ it('should succeed if null', async function () {
38
+ await this.jsonPathAsserterEquals.assertConvoStep({
39
+ convoStep: { stepTag: 'test' },
40
+ args: ['$.test', ''],
41
+ botMsg: {
42
+ sourceData: {
43
+ test: null
44
+ }
45
+ }
46
+ })
47
+ })
48
+ it('should succeed if expected is empty, and asserter is negated', async function () {
49
+ await this.jsonPathAsserterEquals.assertNotConvoStep({
50
+ convoStep: { stepTag: 'test' },
51
+ args: ['$.test', ''],
52
+ botMsg: {
53
+ sourceData: {
54
+ test: 'something but not empty string'
55
+ }
56
+ }
57
+ })
58
+ })
59
+ it('should fail if expected is not empty', async function () {
60
+ try {
61
+ await this.jsonPathAsserterWildcard.assertConvoStep({
62
+ convoStep: { stepTag: 'test' },
63
+ args: ['$.test', 'something but not empty string'],
64
+ botMsg: {
65
+ sourceData: {
66
+ test: ''
67
+ }
68
+ }
69
+ })
70
+ assert.fail('expected jsonPathAsserter to fail')
71
+ } catch (err) {
72
+ assert.isTrue(err.message.includes('Expected: "something but not empty string" in jsonPath $.test, actual: <empty>'))
73
+ }
74
+ })
75
+ it('should fail if real is not empty', async function () {
76
+ try {
77
+ await this.jsonPathAsserterEquals.assertConvoStep({
78
+ convoStep: { stepTag: 'test' },
79
+ args: ['$.test', ''],
80
+ botMsg: {
81
+ sourceData: {
82
+ test: 'something but not empty string'
83
+ }
84
+ }
85
+ })
86
+ assert.fail('expected jsonPathAsserter to fail')
87
+ } catch (err) {
88
+ assert.isTrue(err.message.includes('Expected: "<empty>" in jsonPath $.test, actual: something but not empty string'))
89
+ }
90
+ })
91
+ })
92
+
20
93
  it('should do nothing on no arg', async function () {
21
94
  await this.jsonPathAsserter.assertConvoStep({})
22
95
  })
@@ -62,7 +135,6 @@ describe('scripting.asserters.jsonPathAsserter', function () {
62
135
  }
63
136
  })
64
137
  } catch (err) {
65
- console.log(err.message)
66
138
  assert.isTrue(err.message.includes('Expected: "message4" in jsonPath $.messages[*].label, actual: message1,message2,message3'))
67
139
  }
68
140
  })
@@ -216,7 +288,7 @@ describe('scripting.asserters.jsonPathAsserter', function () {
216
288
  })
217
289
  })
218
290
  it('should succeed on matching jsonpath from globalArgs', async function () {
219
- await this.jsonPathAsserter.assertConvoStep({
291
+ await this.jsonPathAsserterGlobalArgs.assertConvoStep({
220
292
  convoStep: { stepTag: 'test' },
221
293
  args: ['test'],
222
294
  botMsg: {
@@ -376,6 +448,21 @@ describe('scripting.asserters.jsonPathAsserter', function () {
376
448
  assert.isTrue(err.message.indexOf('Expected: "value1" in jsonPath $.test') > 0)
377
449
  }
378
450
  })
451
+
452
+ it('should succeed on empty string if checkExistanceOnEmptyAssert is on in globalArgs', async function () {
453
+ this.jsonPathAsserterEquals.globalArgs = {
454
+ checkExistanceOnEmptyAssert: true
455
+ }
456
+ await this.jsonPathAsserterEquals.assertConvoStep({
457
+ convoStep: { stepTag: 'test' },
458
+ args: ['test', ''],
459
+ botMsg: {
460
+ sourceData: {
461
+ test: 'asdf'
462
+ }
463
+ }
464
+ })
465
+ })
379
466
  })
380
467
 
381
468
  describe('jsonPathCountAsserter', function () {