botium-core 1.13.5 → 1.13.6

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 (60) hide show
  1. package/dist/botium-cjs.js +21 -7
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +21 -7
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/helpers/RetryHelper.js +3 -2
  7. package/src/scripting/MatchFunctions.js +3 -1
  8. package/src/scripting/ScriptingProvider.js +14 -4
  9. package/src/scripting/logichook/asserter/BotRepliesConsumedAsserter.js +1 -1
  10. package/src/scripting/logichook/asserter/BotRepliesUnconsumedCountAsserter.js +1 -1
  11. package/src/scripting/logichook/asserter/ButtonsAsserter.js +1 -1
  12. package/src/scripting/logichook/asserter/ButtonsCountAsserter.js +1 -1
  13. package/src/scripting/logichook/asserter/ButtonsCountRecAsserter.js +1 -1
  14. package/src/scripting/logichook/asserter/CardsAsserter.js +1 -1
  15. package/src/scripting/logichook/asserter/CardsCountAsserter.js +1 -1
  16. package/src/scripting/logichook/asserter/CardsCountRecAsserter.js +1 -1
  17. package/src/scripting/logichook/asserter/EntitiesAsserter.js +1 -1
  18. package/src/scripting/logichook/asserter/EntityContentAsserter.js +2 -2
  19. package/src/scripting/logichook/asserter/EntityValuesAsserter.js +1 -1
  20. package/src/scripting/logichook/asserter/FormsAsserter.js +1 -1
  21. package/src/scripting/logichook/asserter/IntentAsserter.js +3 -3
  22. package/src/scripting/logichook/asserter/IntentConfidenceAsserter.js +4 -4
  23. package/src/scripting/logichook/asserter/IntentUniqueAsserter.js +2 -2
  24. package/src/scripting/logichook/asserter/JsonPathAsserter.js +5 -5
  25. package/src/scripting/logichook/asserter/JsonPathCountAsserter.js +2 -2
  26. package/src/scripting/logichook/asserter/MediaAsserter.js +1 -1
  27. package/src/scripting/logichook/asserter/MediaCountAsserter.js +1 -1
  28. package/src/scripting/logichook/asserter/MediaCountRecAsserter.js +1 -1
  29. package/src/scripting/logichook/asserter/PauseAsserter.js +1 -1
  30. package/src/scripting/logichook/asserter/ResponseLengthAsserter.js +3 -2
  31. package/src/scripting/logichook/asserter/TextContainsAllAsserter.js +2 -1
  32. package/src/scripting/logichook/asserter/TextContainsAllICAsserter.js +2 -1
  33. package/src/scripting/logichook/asserter/TextContainsAnyAsserter.js +1 -0
  34. package/src/scripting/logichook/asserter/TextContainsAnyICAsserter.js +2 -1
  35. package/src/scripting/logichook/asserter/TextEqualsAnyAsserter.js +2 -1
  36. package/src/scripting/logichook/asserter/TextEqualsAnyICAsserter.js +2 -1
  37. package/src/scripting/logichook/asserter/TextRegexpAllAsserter.js +2 -1
  38. package/src/scripting/logichook/asserter/TextRegexpAllICAsserter.js +2 -1
  39. package/src/scripting/logichook/asserter/TextRegexpAnyAsserter.js +1 -0
  40. package/src/scripting/logichook/asserter/TextRegexpAnyICAsserter.js +2 -1
  41. package/src/scripting/logichook/asserter/TextWildcardAllAsserter.js +2 -1
  42. package/src/scripting/logichook/asserter/TextWildcardAllICAsserter.js +2 -1
  43. package/src/scripting/logichook/asserter/TextWildcardAnyAsserter.js +1 -0
  44. package/src/scripting/logichook/asserter/TextWildcardAnyICAsserter.js +2 -1
  45. package/src/scripting/logichook/asserter/TextWildcardExactAllAsserter.js +2 -1
  46. package/src/scripting/logichook/asserter/TextWildcardExactAllICAsserter.js +2 -1
  47. package/src/scripting/logichook/asserter/TextWildcardExactAnyAsserter.js +1 -0
  48. package/src/scripting/logichook/asserter/TextWildcardExactAnyICAsserter.js +2 -1
  49. package/src/scripting/logichook/asserter/WerAsserter.js +10 -8
  50. package/test/convo/transcript.spec.js +6 -6
  51. package/test/scripting/asserters/convos/{wer_threshold_nok.yml → wer_threshold_nok_float.yml} +0 -0
  52. package/test/scripting/asserters/convos/wer_threshold_nok_percentage.yml +7 -0
  53. package/test/scripting/asserters/convos/{wer_threshold_ok.yml → wer_threshold_ok_float.yml} +0 -0
  54. package/test/scripting/asserters/convos/wer_threshold_ok_percentage.yml +7 -0
  55. package/test/scripting/asserters/entityContentAsserter.spec.js +2 -7
  56. package/test/scripting/asserters/intentAsserter.spec.js +1 -1
  57. package/test/scripting/asserters/jsonpathAsserter.spec.js +1 -1
  58. package/test/scripting/asserters/werAsserter.spec.js +25 -5
  59. package/test/scripting/matching/matchingmode.spec.js +42 -2
  60. package/test/scripting/scriptingModificator.spec.js +1 -2
@@ -6,12 +6,12 @@ module.exports = class WerAsserter {
6
6
  constructor (context, caps = {}) {
7
7
  this.context = context
8
8
  this.caps = caps
9
- this.name = 'WerAsserter'
9
+ this.name = 'Word Error Rate Asserter'
10
10
  }
11
11
 
12
12
  assertConvoStep ({ convo, convoStep, args, botMsg }) {
13
13
  if (!args || args.length < 1) {
14
- return Promise.reject(new BotiumError(`${convoStep.stepTag}: WerAsserter Missing argument`,
14
+ return Promise.reject(new BotiumError(`${convoStep.stepTag}: ${this.name} - no argument given`,
15
15
  {
16
16
  type: 'asserter',
17
17
  subtype: 'wrong parameters',
@@ -21,7 +21,7 @@ module.exports = class WerAsserter {
21
21
  ))
22
22
  }
23
23
  if (args.length > 2) {
24
- return Promise.reject(new BotiumError(`${convoStep.stepTag}: WerAsserter Too much argument "${args}"`,
24
+ return Promise.reject(new BotiumError(`${convoStep.stepTag}: ${this.name} - too many arguments "${args}"`,
25
25
  {
26
26
  type: 'asserter',
27
27
  subtype: 'wrong parameters',
@@ -32,12 +32,14 @@ module.exports = class WerAsserter {
32
32
  }
33
33
 
34
34
  const utterance = args[0]
35
- const threshold = args[1]
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)
37
+ const wer = speechScorer.wordErrorRate(botMsg.messageText, utterance).toFixed(2)
38
38
  if (wer > threshold) {
39
+ const _toPercent = (s) => `${(s * 100).toFixed(0)}%`
40
+
39
41
  return Promise.reject(new BotiumError(
40
- `${convoStep.stepTag}: Word error rate ${wer} > ${threshold} for ${utterance}`,
42
+ `${convoStep.stepTag}: Word Error Rate (${_toPercent(wer)}) higher than accepted (${_toPercent(threshold)})`,
41
43
  {
42
44
  type: 'asserter',
43
45
  source: this.name,
@@ -47,8 +49,8 @@ module.exports = class WerAsserter {
47
49
  }
48
50
  },
49
51
  cause: {
50
- expected: `Word error rate <= ${threshold}`,
51
- actual: `Word error rate = ${wer}`
52
+ expected: `<=${_toPercent(threshold)}`,
53
+ actual: `${_toPercent(wer)}`
52
54
  }
53
55
  }
54
56
  ))
@@ -287,11 +287,11 @@ describe('convo.transcript', function () {
287
287
 
288
288
  assert.equal(err.transcript.err.context.input.messageText, 'Hello')
289
289
  assert.equal(err.transcript.err.context.errors[0].type, 'asserter')
290
- assert.equal(err.transcript.err.context.errors[0].source, 'TextMatchAsserter')
290
+ assert.equal(err.transcript.err.context.errors[0].source, 'Text Match Asserter')
291
291
  assert.equal(err.transcript.err.context.errors[1].type, 'asserter')
292
- assert.equal(err.transcript.err.context.errors[1].source, 'ButtonsAsserter')
292
+ assert.equal(err.transcript.err.context.errors[1].source, 'Buttons Asserter')
293
293
  assert.equal(err.transcript.err.context.errors[2].type, 'asserter')
294
- assert.equal(err.transcript.err.context.errors[2].source, 'ButtonsAsserter')
294
+ assert.equal(err.transcript.err.context.errors[2].source, 'Buttons Asserter')
295
295
  }
296
296
  })
297
297
  it('should throw simple error with multiple asserting errors if its enabled and assertConvoEnd fail', async function () {
@@ -317,11 +317,11 @@ describe('convo.transcript', function () {
317
317
 
318
318
  assert.equal(err.transcript.err.context.input.messageText, 'Hello')
319
319
  assert.equal(err.transcript.err.context.errors[0].type, 'asserter')
320
- assert.equal(err.transcript.err.context.errors[0].source, 'TextMatchAsserter')
320
+ assert.equal(err.transcript.err.context.errors[0].source, 'Text Match Asserter')
321
321
  assert.equal(err.transcript.err.context.errors[1].type, 'asserter')
322
- assert.equal(err.transcript.err.context.errors[1].source, 'ButtonsAsserter')
322
+ assert.equal(err.transcript.err.context.errors[1].source, 'Buttons Asserter')
323
323
  assert.equal(err.transcript.err.context.errors[2].type, 'asserter')
324
- assert.equal(err.transcript.err.context.errors[2].source, 'ButtonsAsserter')
324
+ assert.equal(err.transcript.err.context.errors[2].source, 'Buttons Asserter')
325
325
  assert.equal(err.transcript.err.context.errors[3].type, 'asserter')
326
326
  assert.equal(err.transcript.err.context.errors[3].source, 'assertConvoEnd')
327
327
  }
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: wer_threshold_nok
3
+ steps:
4
+ - me:
5
+ - test 123
6
+ - bot:
7
+ - TEXT_WER tast 123|10
@@ -0,0 +1,7 @@
1
+ convos:
2
+ - name: wer_threshold_ok
3
+ steps:
4
+ - me:
5
+ - test 123
6
+ - bot:
7
+ - TEXT_WER tast 123|60
@@ -20,10 +20,9 @@ describe('scripting.asserters.entityContentAsserter', function () {
20
20
  })
21
21
  assert.fail('should have failed')
22
22
  } catch (err) {
23
- assert.isTrue(err.message.indexOf('EntityContentAsserter Missing argument') > 0)
23
+ assert.isTrue(err.message.indexOf('Missing argument') > 0)
24
24
  assert.isNotNull(err.context)
25
25
  assert.equal(err.context.type, 'asserter')
26
- assert.equal(err.context.source, 'EntityContentAsserter')
27
26
  }
28
27
  })
29
28
 
@@ -36,10 +35,9 @@ describe('scripting.asserters.entityContentAsserter', function () {
36
35
  })
37
36
  assert.fail('should have failed')
38
37
  } catch (err) {
39
- assert.isTrue(err.message.indexOf('EntityContentAsserter Missing argument') > 0)
38
+ assert.isTrue(err.message.indexOf('Missing argument') > 0)
40
39
  assert.isNotNull(err.context)
41
40
  assert.equal(err.context.type, 'asserter')
42
- assert.equal(err.context.source, 'EntityContentAsserter')
43
41
  }
44
42
  })
45
43
 
@@ -55,7 +53,6 @@ describe('scripting.asserters.entityContentAsserter', function () {
55
53
  assert.isTrue(err.message.indexOf('Expected entity "something" but found nothing') > 0)
56
54
  assert.isNotNull(err.context)
57
55
  assert.equal(err.context.type, 'asserter')
58
- assert.equal(err.context.source, 'EntityContentAsserter')
59
56
  }
60
57
  })
61
58
 
@@ -88,7 +85,6 @@ describe('scripting.asserters.entityContentAsserter', function () {
88
85
  assert.isTrue(err.message.indexOf('test: Missing entity content: [ \'something_value\' ] of entity "something"') >= 0)
89
86
  assert.isNotNull(err.context)
90
87
  assert.equal(err.context.type, 'asserter')
91
- assert.equal(err.context.source, 'EntityContentAsserter')
92
88
  assert.isNotNull(err.context.cause)
93
89
  assert.equal(err.context.cause.entity, 'something')
94
90
  assert.deepEqual(err.context.cause.expected, ['something_value'])
@@ -126,7 +122,6 @@ describe('scripting.asserters.entityContentAsserter', function () {
126
122
  assert.isTrue(err.message.indexOf('test: Missing entity content: [ \'entity1_value1\', \'entity1_value3\' ] of entity "entity1"') >= 0)
127
123
  assert.isNotNull(err.context)
128
124
  assert.equal(err.context.type, 'asserter')
129
- assert.equal(err.context.source, 'EntityContentAsserter')
130
125
  assert.isNotNull(err.context.cause)
131
126
  assert.equal(err.context.cause.entity, 'entity1')
132
127
  assert.deepEqual(err.context.cause.expected, ['entity1_value1', 'entity1_value1', 'entity1_value3'])
@@ -62,7 +62,7 @@ const _assert = (expected, found) => {
62
62
  ))
63
63
 
64
64
  if (!expected) {
65
- return assert.isRejected(promise, `${steptag}: IntentAsserter Missing argument`)
65
+ return assert.isRejected(promise, `${steptag}: NLU Intent Asserter Missing argument`)
66
66
  } else if (!found) {
67
67
  return assert.isRejected(promise, `${steptag}: Expected intent "${expected}" but found nothing`)
68
68
  } else if (expected !== found) {
@@ -278,7 +278,7 @@ describe('scripting.asserters.jsonPathAsserter', function () {
278
278
  })
279
279
  assert.fail('should have failed')
280
280
  } catch (err) {
281
- assert.isTrue(err.message.indexOf('JsonPathAsserter 0 arguments expected') > 0)
281
+ assert.isTrue(err.message.indexOf('0 arguments expected') > 0)
282
282
  }
283
283
  })
284
284
  it('should succeed on existing jsonpath from pathPattern', async function () {
@@ -27,16 +27,36 @@ describe('scripting.asserters.werAsserter', function () {
27
27
  this.container && await this.container.Clean()
28
28
  })
29
29
 
30
- it('ok', async function () {
31
- this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_ok.yml'))
30
+ it('ok (float)', async function () {
31
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_ok_float.yml'))
32
32
 
33
33
  this.compiler.ExpandScriptingMemoryToConvos()
34
34
  assert.equal(this.compiler.convos.length, 1)
35
35
  await this.compiler.convos[0].Run(this.container)
36
36
  })
37
+ it('ok (percentage)', async function () {
38
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_ok_percentage.yml'))
37
39
 
38
- it('nok', async function () {
39
- this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_nok.yml'))
40
+ this.compiler.ExpandScriptingMemoryToConvos()
41
+ assert.equal(this.compiler.convos.length, 1)
42
+ await this.compiler.convos[0].Run(this.container)
43
+ })
44
+
45
+ it('nok (float)', async function () {
46
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_nok_float.yml'))
47
+
48
+ this.compiler.ExpandScriptingMemoryToConvos()
49
+ assert.equal(this.compiler.convos.length, 1)
50
+
51
+ try {
52
+ await this.compiler.convos[0].Run(this.container)
53
+ assert.fail('expected error')
54
+ } catch (err) {
55
+ assert.equal(err.message, 'wer_threshold_nok/Line 2: assertion error - Line 2: Word Error Rate (50%) higher than accepted (10%)')
56
+ }
57
+ })
58
+ it('nok (percentage)', async function () {
59
+ this.compiler.ReadScriptsFromDirectory(path.resolve(__dirname, 'convos', 'wer_threshold_nok_percentage.yml'))
40
60
 
41
61
  this.compiler.ExpandScriptingMemoryToConvos()
42
62
  assert.equal(this.compiler.convos.length, 1)
@@ -45,7 +65,7 @@ describe('scripting.asserters.werAsserter', function () {
45
65
  await this.compiler.convos[0].Run(this.container)
46
66
  assert.fail('expected error')
47
67
  } catch (err) {
48
- assert.equal(err.message, 'wer_threshold_nok/Line 2: assertion error - Line 2: Word error rate 0.5 > 0.1 for tast 123')
68
+ assert.equal(err.message, 'wer_threshold_nok/Line 2: assertion error - Line 2: Word Error Rate (50%) higher than accepted (10%)')
49
69
  }
50
70
  })
51
71
  })
@@ -306,7 +306,7 @@ describe('scripting.matching.matchingmode', function () {
306
306
  })
307
307
  })
308
308
 
309
- describe('wer.lowthreshold', function () {
309
+ describe('wer.lowthreshold (float)', function () {
310
310
  beforeEach(async function () {
311
311
  const myCaps = {
312
312
  [Capabilities.PROJECTNAME]: 'matching.matchingmode',
@@ -326,8 +326,28 @@ describe('scripting.matching.matchingmode', function () {
326
326
  assert.isFalse(this.compiler.Match('test 123', 'tast 123'))
327
327
  })
328
328
  })
329
+ describe('wer.lowthreshold (percentage)', function () {
330
+ beforeEach(async function () {
331
+ const myCaps = {
332
+ [Capabilities.PROJECTNAME]: 'matching.matchingmode',
333
+ [Capabilities.CONTAINERMODE]: echoConnector,
334
+ [Capabilities.SCRIPTING_MATCHING_MODE]: 'wer',
335
+ [Capabilities.SCRIPTING_MATCHING_MODE_ARGS]: [10]
336
+ }
337
+ const driver = new BotDriver(myCaps)
338
+ this.compiler = driver.BuildCompiler()
339
+ this.container = await driver.Build()
340
+ })
341
+ afterEach(async function () {
342
+ this.container && await this.container.Clean()
343
+ })
344
+
345
+ it('should not match because of low threshold', async function () {
346
+ assert.isFalse(this.compiler.Match('test 123', 'tast 123'))
347
+ })
348
+ })
329
349
 
330
- describe('wer.highthreshold', function () {
350
+ describe('wer.highthreshold (float)', function () {
331
351
  beforeEach(async function () {
332
352
  const myCaps = {
333
353
  [Capabilities.PROJECTNAME]: 'matching.matchingmode',
@@ -343,6 +363,26 @@ describe('scripting.matching.matchingmode', function () {
343
363
  this.container && await this.container.Clean()
344
364
  })
345
365
 
366
+ it('should match because of high threshold', async function () {
367
+ assert.isTrue(this.compiler.Match('test 123', 'tast 123'))
368
+ })
369
+ })
370
+ describe('wer.highthreshold (percentage)', function () {
371
+ beforeEach(async function () {
372
+ const myCaps = {
373
+ [Capabilities.PROJECTNAME]: 'matching.matchingmode',
374
+ [Capabilities.CONTAINERMODE]: echoConnector,
375
+ [Capabilities.SCRIPTING_MATCHING_MODE]: 'wer',
376
+ [Capabilities.SCRIPTING_MATCHING_MODE_ARGS]: [60]
377
+ }
378
+ const driver = new BotDriver(myCaps)
379
+ this.compiler = driver.BuildCompiler()
380
+ this.container = await driver.Build()
381
+ })
382
+ afterEach(async function () {
383
+ this.container && await this.container.Clean()
384
+ })
385
+
346
386
  it('should match because of high threshold', async function () {
347
387
  assert.isTrue(this.compiler.Match('test 123', 'tast 123'))
348
388
  })
@@ -55,9 +55,8 @@ describe('scriptingModificator.assertions', function () {
55
55
  })
56
56
  assert.fail('should have failed')
57
57
  } catch (err) {
58
- assert.isTrue(err.message.indexOf('Expected asserter IntentAsserter with args "test1" to fail') > 0)
58
+ assert.isTrue(err.message.indexOf('Expected asserter NLU Intent Asserter with args "test1" to fail') > 0)
59
59
  assert.isNotNull(err.context)
60
- assert.equal(err.context.source, 'IntentAsserter')
61
60
  }
62
61
  })
63
62
  })