botium-core 1.13.8 → 1.13.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/botium-cjs.js +214 -1481
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +214 -1481
  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 -8
  9. package/src/scripting/helper.js +61 -2
  10. package/src/scripting/logichook/asserter/JsonPathAsserter.js +1 -1
  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 +11 -0
  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.8",
3
+ "version": "1.13.10",
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,13 +254,14 @@ 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
  }))
261
262
  const globalAsserter = Object.values(this.globalAsserter)
262
263
  .filter(a => a[asserterType])
263
- .map(a => p(this.retryHelperAsserter, () => a[asserterType]({ convo, convoStep, scriptingMemory, args: [], isGlobal: true, ...rest })))
264
+ .map(a => p(this.retryHelperAsserter, () => a[asserterType]({ convo, convoStep, scriptingMemory, container, args: [], isGlobal: true, ...rest })))
264
265
 
265
266
  const allPromises = [...convoAsserter, ...globalAsserter]
266
267
  if (this.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]) {
@@ -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,28 +290,30 @@ 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
  })))
296
298
 
297
299
  const globalPromises = Object.values(this.globalLogicHook)
298
300
  .filter(l => l[hookType])
299
- .map(l => p(this.retryHelperLogicHook, () => l[hookType]({ convo, convoStep, scriptingMemory, args: [], isGlobal: true, ...rest })))
301
+ .map(l => p(this.retryHelperLogicHook, () => l[hookType]({ convo, convoStep, scriptingMemory, container, args: [], isGlobal: true, ...rest })))
300
302
 
301
303
  const allPromises = [...convoStepPromises, ...globalPromises]
302
304
  if (allPromises.length > 0) return Promise.all(allPromises).then(() => true)
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
 
@@ -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
  }
@@ -139,7 +139,7 @@ module.exports = class JsonPathAsserter {
139
139
  matchFn = getMatchFunction(this.globalArgs.matchingMode)
140
140
  }
141
141
 
142
- const match = !_.isNil(jsonPathValues.find(a => matchFn(a, assert)))
142
+ const match = jsonPathValues.findIndex(a => matchFn(a, assert)) >= 0
143
143
 
144
144
  if (not && match) {
145
145
  return Promise.reject(new BotiumError(`${convoStep.stepTag}: Not expected: "${actual === '' ? '<empty>' : toString(actual)}" in jsonPath ${path}"`,
@@ -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
@@ -34,6 +34,17 @@ describe('scripting.asserters.jsonPathAsserter', function () {
34
34
  }
35
35
  })
36
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
+ })
37
48
  it('should succeed if expected is empty, and asserter is negated', async function () {
38
49
  await this.jsonPathAsserterEquals.assertNotConvoStep({
39
50
  convoStep: { stepTag: 'test' },
@@ -68,4 +68,45 @@ describe('scripting.asserters.werAsserter', function () {
68
68
  assert.equal(err.message, 'wer_threshold_nok/Line 2: assertion error - Line 2: Word Error Rate (50%) higher than accepted (10%)')
69
69
  }
70
70
  })
71
+
72
+ it('ok wildcard (percentage)', async function () {
73
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_wildcard_ok_percentage.yml'))
74
+
75
+ this.compiler.ExpandScriptingMemoryToConvos()
76
+ assert.equal(this.compiler.convos.length, 1)
77
+ await this.compiler.convos[0].Run(this.container)
78
+ })
79
+ it('ok wildcard (float)', async function () {
80
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_wildcard_ok_float.yml'))
81
+
82
+ this.compiler.ExpandScriptingMemoryToConvos()
83
+ assert.equal(this.compiler.convos.length, 1)
84
+ await this.compiler.convos[0].Run(this.container)
85
+ })
86
+ it('nok wildcard (percentage)', async function () {
87
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_wildcard_nok_percentage.yml'))
88
+
89
+ this.compiler.ExpandScriptingMemoryToConvos()
90
+ assert.equal(this.compiler.convos.length, 1)
91
+
92
+ try {
93
+ await this.compiler.convos[0].Run(this.container)
94
+ assert.fail('expected error')
95
+ } catch (err) {
96
+ assert.equal(err.message, 'wer_threshold_wildcard_nok/Line 2: assertion error - Line 2: Word Error Rate (33%) higher than accepted (1%)')
97
+ }
98
+ })
99
+ it('nok wildcard (float)', async function () {
100
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_wildcard_nok_float.yml'))
101
+
102
+ this.compiler.ExpandScriptingMemoryToConvos()
103
+ assert.equal(this.compiler.convos.length, 1)
104
+
105
+ try {
106
+ await this.compiler.convos[0].Run(this.container)
107
+ assert.fail('expected error')
108
+ } catch (err) {
109
+ assert.equal(err.message, 'wer_threshold_wildcard_nok/Line 2: assertion error - Line 2: Word Error Rate (75%) higher than accepted (40%)')
110
+ }
111
+ })
71
112
  })
@@ -387,4 +387,86 @@ describe('scripting.matching.matchingmode', function () {
387
387
  assert.isTrue(this.compiler.Match('test 123', 'tast 123'))
388
388
  })
389
389
  })
390
+
391
+ describe('wer.lowthreshold.wildcard (float)', function () {
392
+ beforeEach(async function () {
393
+ const myCaps = {
394
+ [Capabilities.PROJECTNAME]: 'matching.matchingmode',
395
+ [Capabilities.CONTAINERMODE]: echoConnector,
396
+ [Capabilities.SCRIPTING_MATCHING_MODE]: 'wer',
397
+ [Capabilities.SCRIPTING_MATCHING_MODE_ARGS]: [0.4]
398
+ }
399
+ const driver = new BotDriver(myCaps)
400
+ this.compiler = driver.BuildCompiler()
401
+ this.container = await driver.Build()
402
+ })
403
+ afterEach(async function () {
404
+ this.container && await this.container.Clean()
405
+ })
406
+
407
+ it('should not match because of low threshold', async function () {
408
+ assert.isFalse(this.compiler.Match('This is an example', '* that are * hot'))
409
+ })
410
+ })
411
+ describe('wer.lowthreshold.wildcard (percentage)', function () {
412
+ beforeEach(async function () {
413
+ const myCaps = {
414
+ [Capabilities.PROJECTNAME]: 'matching.matchingmode',
415
+ [Capabilities.CONTAINERMODE]: echoConnector,
416
+ [Capabilities.SCRIPTING_MATCHING_MODE]: 'wer',
417
+ [Capabilities.SCRIPTING_MATCHING_MODE_ARGS]: [10]
418
+ }
419
+ const driver = new BotDriver(myCaps)
420
+ this.compiler = driver.BuildCompiler()
421
+ this.container = await driver.Build()
422
+ })
423
+ afterEach(async function () {
424
+ this.container && await this.container.Clean()
425
+ })
426
+
427
+ it('should not match because of low threshold', async function () {
428
+ assert.isFalse(this.compiler.Match('This is an example', '* is * hot'))
429
+ })
430
+ })
431
+
432
+ describe('wer.highthreshold.wildcard (float)', function () {
433
+ beforeEach(async function () {
434
+ const myCaps = {
435
+ [Capabilities.PROJECTNAME]: 'matching.matchingmode',
436
+ [Capabilities.CONTAINERMODE]: echoConnector,
437
+ [Capabilities.SCRIPTING_MATCHING_MODE]: 'wer',
438
+ [Capabilities.SCRIPTING_MATCHING_MODE_ARGS]: [0.4]
439
+ }
440
+ const driver = new BotDriver(myCaps)
441
+ this.compiler = driver.BuildCompiler()
442
+ this.container = await driver.Build()
443
+ })
444
+ afterEach(async function () {
445
+ this.container && await this.container.Clean()
446
+ })
447
+
448
+ it('should match because of high threshold', async function () {
449
+ assert.isTrue(this.compiler.Match('this is an example', 'this is * sample'))
450
+ })
451
+ })
452
+ describe('wer.highthreshold.wildcard (percentage)', function () {
453
+ beforeEach(async function () {
454
+ const myCaps = {
455
+ [Capabilities.PROJECTNAME]: 'matching.matchingmode',
456
+ [Capabilities.CONTAINERMODE]: echoConnector,
457
+ [Capabilities.SCRIPTING_MATCHING_MODE]: 'wer',
458
+ [Capabilities.SCRIPTING_MATCHING_MODE_ARGS]: [30]
459
+ }
460
+ const driver = new BotDriver(myCaps)
461
+ this.compiler = driver.BuildCompiler()
462
+ this.container = await driver.Build()
463
+ })
464
+ afterEach(async function () {
465
+ this.container && await this.container.Clean()
466
+ })
467
+
468
+ it('should match because of high threshold', async function () {
469
+ assert.isTrue(this.compiler.Match('this is an example', 'this is another *'))
470
+ })
471
+ })
390
472
  })
@@ -20,6 +20,7 @@ describe('scriptingModificator.assertions', function () {
20
20
  ]
21
21
  },
22
22
  scriptingMemory: {},
23
+ container: {},
23
24
  botMsg: {
24
25
  buttons: [
25
26
  {
@@ -47,6 +48,7 @@ describe('scriptingModificator.assertions', function () {
47
48
  ]
48
49
  },
49
50
  scriptingMemory: {},
51
+ container: {},
50
52
  botMsg: {
51
53
  nlp: {
52
54
  intent: { name: 'test1' }
@@ -0,0 +1,7 @@
1
+ buy
2
+
3
+ #begin
4
+ INCLUDE sub1
5
+
6
+ #include sub2
7
+
@@ -0,0 +1,2 @@
1
+ |$productName |$customer
2
+ product1|schnitzel |attila
@@ -0,0 +1,7 @@
1
+ sub1
2
+
3
+ #me
4
+ schnitzel
5
+
6
+ #bot
7
+ JSON_PATH $.request|$productName