botium-core 1.13.17 → 1.13.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botium-core",
3
- "version": "1.13.17",
3
+ "version": "1.13.18",
4
4
  "description": "The Selenium for Chatbots",
5
5
  "main": "index.js",
6
6
  "module": "dist/botium-es.js",
package/src/BotDriver.js CHANGED
@@ -3,7 +3,7 @@ const fs = require('fs')
3
3
  const path = require('path')
4
4
  const async = require('async')
5
5
  const { rimraf } = require('rimraf')
6
- const { mkdirpSync } = require('mkdirp')
6
+ const mkdirp = require('mkdirp')
7
7
  const sanitize = require('sanitize-filename')
8
8
  const moment = require('moment')
9
9
  const randomize = require('randomatic')
@@ -130,7 +130,7 @@ module.exports = class BotDriver {
130
130
  (tempDirectoryCreated) => {
131
131
  tempDirectory = path.resolve(process.cwd(), this.caps[Capabilities.TEMPDIR], sanitize(`${this.caps[Capabilities.PROJECTNAME]} ${moment().format('YYYYMMDD HHmmss')} ${randomize('Aa0', 5)}`))
132
132
  try {
133
- mkdirpSync(tempDirectory)
133
+ mkdirp.sync(tempDirectory)
134
134
  tempDirectoryCreated()
135
135
  } catch (err) {
136
136
  tempDirectoryCreated(new Error(`Unable to create temp directory ${tempDirectory}: ${err.message}`))
@@ -68,6 +68,12 @@ module.exports = {
68
68
  SIMPLEREST_POLL_INTERVAL: 'SIMPLEREST_POLL_INTERVAL',
69
69
  SIMPLEREST_POLL_TIMEOUT: 'SIMPLEREST_PING_TIMEOUT',
70
70
  SIMPLEREST_POLL_UPDATE_CONTEXT: 'SIMPLEREST_POLL_UPDATE_CONTEXT',
71
+ SIMPLEREST_CONTEXT_IGNORE_JSONPATH: 'SIMPLEREST_CONTEXT_IGNORE_JSONPATH',
72
+ SIMPLEREST_CONTEXT_IGNORE_MATCH: 'SIMPLEREST_CONTEXT_IGNORE_MATCH',
73
+ SIMPLEREST_CONTEXT_SKIP_JSONPATH: 'SIMPLEREST_CONTEXT_SKIP_JSONPATH',
74
+ SIMPLEREST_CONTEXT_SKIP_MATCH: 'SIMPLEREST_CONTEXT_SKIP_MATCH',
75
+ SIMPLEREST_CONTEXT_CONTINUE_JSONPATH: 'SIMPLEREST_CONTEXT_CONTINUE_JSONPATH',
76
+ SIMPLEREST_CONTEXT_CONTINUE_MATCH: 'SIMPLEREST_CONTEXT_CONTINUE_MATCH',
71
77
  SIMPLEREST_BODY_JSONPATH: 'SIMPLEREST_BODY_JSONPATH',
72
78
  SIMPLEREST_RESPONSE_JSONPATH: 'SIMPLEREST_RESPONSE_JSONPATH',
73
79
  SIMPLEREST_RESPONSE_HOOK: 'SIMPLEREST_RESPONSE_HOOK',
@@ -1,6 +1,6 @@
1
1
  const util = require('util')
2
2
  const async = require('async')
3
- const { rimraf } = require('rimraf')
3
+ const rimraf = require('rimraf')
4
4
  const Bottleneck = require('bottleneck')
5
5
  const _ = require('lodash')
6
6
  const request = require('request')
@@ -173,9 +173,12 @@ module.exports = class BaseContainer {
173
173
  (rimraffed) => {
174
174
  if (this.caps[Capabilities.CLEANUPTEMPDIR]) {
175
175
  debug(`Cleanup rimrafing temp dir ${this.tempDirectory}`)
176
- rimraf(this.tempDirectory)
177
- .catch((err) => debug(`Cleanup temp dir ${this.tempDirectory} failed: ${util.inspect(err)}`))
178
- .finally(() => rimraffed())
176
+ try {
177
+ rimraf.sync(this.tempDirectory)
178
+ rimraffed()
179
+ } catch (err) {
180
+ rimraffed(new Error(`Cleanup temp directory ${this.tempDirectory} failed: ${util.inspect(err)}`))
181
+ }
179
182
  } else {
180
183
  rimraffed()
181
184
  }
@@ -293,6 +293,47 @@ module.exports = class SimpleRestContainer {
293
293
  debug(`current session context: ${util.inspect(this.view.context)}`)
294
294
  }
295
295
 
296
+ const _isAnyContextJsonPathMatch = (capName, capNameMatch) => {
297
+ const jsonPaths = getAllCapValues(capName, this.caps)
298
+ if (jsonPaths.length > 0) {
299
+ const jsonPathsMatch = getAllCapValues(capNameMatch, this.caps)
300
+ for (const [index, jsonPath] of jsonPaths.entries()) {
301
+ const contextNodes = jp.query(this.view.context, jsonPath)
302
+ if (_.isArray(contextNodes) && contextNodes.length > 0) {
303
+ if (jsonPathsMatch[index]) {
304
+ if (contextNodes[0] === jsonPathsMatch[index]) {
305
+ return {
306
+ jsonPath,
307
+ match: contextNodes[0]
308
+ }
309
+ }
310
+ } else {
311
+ return {
312
+ jsonPath
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+ return null
319
+ }
320
+
321
+ const ignoreMatch = _isAnyContextJsonPathMatch(Capabilities.SIMPLEREST_CONTEXT_IGNORE_JSONPATH, Capabilities.SIMPLEREST_CONTEXT_IGNORE_MATCH)
322
+ if (ignoreMatch) {
323
+ if (ignoreMatch.match) debug(`ignoring response for context match: ${ignoreMatch.jsonPath} = ${ignoreMatch.match}`)
324
+ else debug(`ignoring response for context: ${ignoreMatch.jsonPath}`)
325
+ return
326
+ }
327
+
328
+ const skipMatch = _isAnyContextJsonPathMatch(Capabilities.SIMPLEREST_CONTEXT_SKIP_JSONPATH, Capabilities.SIMPLEREST_CONTEXT_SKIP_MATCH)
329
+ if (skipMatch) {
330
+ if (skipMatch.match) debug(`skipping response for context match: ${skipMatch.jsonPath} = ${skipMatch.match}`)
331
+ else debug(`skipping response for context: ${skipMatch.jsonPath}`)
332
+
333
+ setTimeout(() => this._doRequest({ messageText: '' }, true, true), 0)
334
+ return
335
+ }
336
+
296
337
  const result = []
297
338
  if (isFromUser) {
298
339
  const _extractFrom = (root, jsonPaths) => {
@@ -442,6 +483,14 @@ module.exports = class SimpleRestContainer {
442
483
  }
443
484
  }
444
485
  }
486
+
487
+ const continueMatch = _isAnyContextJsonPathMatch(Capabilities.SIMPLEREST_CONTEXT_CONTINUE_JSONPATH, Capabilities.SIMPLEREST_CONTEXT_CONTINUE_MATCH)
488
+ if (continueMatch) {
489
+ if (continueMatch.match) debug(`continue with next response for context match: ${continueMatch.jsonPath} = ${continueMatch.match}`)
490
+ else debug(`continue with next response for context: ${continueMatch.jsonPath}`)
491
+
492
+ setTimeout(() => this._doRequest({ messageText: '' }, true, true), 0)
493
+ }
445
494
  return result
446
495
  }
447
496
 
@@ -404,6 +404,15 @@ class Convo {
404
404
  throw failErr
405
405
  }
406
406
 
407
+ if (convoStep.skip === true) {
408
+ skipTranscriptStep = true
409
+ const nextConvoStep = this.conversation[i + 1]
410
+ if (nextConvoStep && nextConvoStep.sender === 'bot') {
411
+ waitForBotSays = false
412
+ }
413
+ continue
414
+ }
415
+
407
416
  if (!botMsg || (!botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp)) {
408
417
  const failErr = new BotiumError(`${this.header.name}/${convoStep.stepTag}: bot says nothing`)
409
418
  debug(failErr)
@@ -940,10 +940,16 @@ module.exports = class ScriptingProvider {
940
940
  convoFilter: null
941
941
  }, options)
942
942
  const expandedConvos = []
943
+ // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
944
+ const context = {
945
+ globalContext: {
946
+ totalConvoCount: 0
947
+ }
948
+ }
943
949
  debug(`ExpandConvos - Using utterances expansion mode: ${this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE]}`)
944
950
  this.convos.forEach((convo) => {
945
951
  convo.expandPartialConvos()
946
- for (const expanded of this._expandConvo(convo, options, {})) {
952
+ for (const expanded of this._expandConvo(convo, options, context)) {
947
953
  expanded.header.assertionCount = this.GetAssertionCount(expanded)
948
954
  if (options.justHeader) {
949
955
  const ConvoWithOnlyHeader = {
@@ -959,6 +965,7 @@ module.exports = class ScriptingProvider {
959
965
  }
960
966
  })
961
967
  this.convos = expandedConvos
968
+ this.totalConvoCount = context.globalContext.totalConvoCount
962
969
  if (!options.justHeader) {
963
970
  this._sortConvos()
964
971
  } else {
@@ -971,17 +978,24 @@ module.exports = class ScriptingProvider {
971
978
  // drop unwanted convos
972
979
  convoFilter: null
973
980
  }, options)
981
+ // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
982
+ const context = {
983
+ globalContext: {
984
+ totalConvoCount: 0
985
+ }
986
+ }
974
987
  debug(`ExpandConvos - Using utterances expansion mode: ${this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE]}`)
975
988
  // creating a nested generator, calling the other.
976
989
  // We hope this.convos does not changes while this iterator is used
977
990
  const _convosIterable = function * (options) {
978
991
  for (const convo of this.convos) {
979
992
  convo.expandPartialConvos()
980
- yield * this._expandConvo(convo, options, {})
993
+ yield * this._expandConvo(convo, options, context)
981
994
  }
982
995
  }.bind(this)
983
996
 
984
997
  this.convosIterable = _convosIterable(options)
998
+ this.totalConvoCount = context.globalContext.totalConvoCount
985
999
  }
986
1000
 
987
1001
  /**
@@ -1173,6 +1187,9 @@ module.exports = class ScriptingProvider {
1173
1187
  }
1174
1188
  } else {
1175
1189
  const expanded = Object.assign(_.cloneDeep(currentConvo), { conversation: _.cloneDeep(convoStepsStack) })
1190
+ if (!_.isNil(_.get(context, 'globalContext.totalConvoCount'))) {
1191
+ context.globalContext.totalConvoCount++
1192
+ }
1176
1193
  if (!options.convoFilter || options.convoFilter(expanded)) {
1177
1194
  yield expanded
1178
1195
  }
@@ -1,3 +1,4 @@
1
+ const _ = require('lodash')
1
2
  const { SCRIPTING_NORMALIZE_TEXT } = require('../../../Capabilities')
2
3
  const { BotiumError } = require('../../BotiumError')
3
4
  const { buttonsFromMsg } = require('../helpers')
@@ -11,17 +12,29 @@ module.exports = class ButtonsAsserter {
11
12
  }
12
13
 
13
14
  _evalButtons (args, botMsg) {
14
- const allButtons = buttonsFromMsg(botMsg, true).map(b => b.text).filter(b => b).map(b => normalizeText(b, !!this.caps[SCRIPTING_NORMALIZE_TEXT]))
15
+ const allButtons = buttonsFromMsg(botMsg, true).map(b => ({ text: b.text, payload: b.payload })).filter(b => b).map(b => ({ text: normalizeText(b.text, !!this.caps[SCRIPTING_NORMALIZE_TEXT]), payload: b.payload }))
15
16
  if (!args || args.length === 0) {
16
- return { allButtons, buttonsNotFound: [], buttonsFound: allButtons }
17
+ return { allButtons, buttonsNotFound: [], buttonsFound: allButtons.map(b => b.text) }
17
18
  }
18
19
  const buttonsNotFound = []
19
20
  const buttonsFound = []
21
+ const parsePayload = (payload) => {
22
+ if (_.isNil(payload)) {
23
+ return undefined
24
+ }
25
+ try {
26
+ return JSON.parse(payload)
27
+ } catch (e) {
28
+ return payload
29
+ }
30
+ }
20
31
  for (let i = 0; i < (args || []).length; i++) {
21
- if (allButtons.findIndex(b => this.context.Match(b, normalizeText(args[i], !!this.caps[SCRIPTING_NORMALIZE_TEXT]))) < 0) {
22
- buttonsNotFound.push(args[i])
23
- } else {
32
+ const matchByText = allButtons.some(b => this.context.Match(b.text, normalizeText(args[i], !!this.caps[SCRIPTING_NORMALIZE_TEXT])))
33
+ const matchByPayload = allButtons.some(b => _.isEqual(parsePayload(b.payload), parsePayload(args[i])))
34
+ if (matchByText || matchByPayload) {
24
35
  buttonsFound.push(args[i])
36
+ } else {
37
+ buttonsNotFound.push(args[i])
25
38
  }
26
39
  }
27
40
  return { allButtons, buttonsNotFound, buttonsFound }
@@ -42,7 +55,7 @@ module.exports = class ButtonsAsserter {
42
55
  cause: {
43
56
  not: true,
44
57
  expected: args,
45
- actual: allButtons,
58
+ actual: JSON.stringify(allButtons, null, 2),
46
59
  diff: buttonsFound
47
60
  }
48
61
  }
@@ -67,7 +80,7 @@ module.exports = class ButtonsAsserter {
67
80
  cause: {
68
81
  not: false,
69
82
  expected: args,
70
- actual: allButtons,
83
+ actual: JSON.stringify(allButtons, null, 2),
71
84
  diff: buttonsNotFound
72
85
  }
73
86
  }
@@ -85,7 +98,7 @@ module.exports = class ButtonsAsserter {
85
98
  cause: {
86
99
  not: false,
87
100
  expected: args,
88
- actual: allButtons,
101
+ actual: JSON.stringify(allButtons, null, 2),
89
102
  diff: buttonsNotFound
90
103
  }
91
104
  }
@@ -1,4 +1,3 @@
1
-
2
1
  module.exports = class ClearQueueLogicHook {
3
2
  constructor (context, caps = {}) {
4
3
  this.context = context
@@ -1,4 +1,3 @@
1
-
2
1
  module.exports = ({ requestOptions, context }) => {
3
2
  let counter = 1
4
3
  requestOptions.body = { bodyFieldRequestHook: counter++ }
@@ -319,7 +319,6 @@ describe('connectors.simplerest', function () {
319
319
  scope2.persist(false)
320
320
  })
321
321
  })
322
-
323
322
  describe('build', function () {
324
323
  it('should build JSON GET url', async function () {
325
324
  const myCaps = Object.assign({}, myCapsGet)
@@ -997,7 +996,6 @@ describe('connectors.simplerest', function () {
997
996
  assert.deepEqual(values, ['$.1', '$.2', '$.3', '$.4'])
998
997
  })
999
998
  })
1000
-
1001
999
  describe('useresponse', function () {
1002
1000
  beforeEach(async function () {
1003
1001
  this.init = async (caps) => {
@@ -1151,7 +1149,6 @@ describe('connectors.simplerest', function () {
1151
1149
  }
1152
1150
  })
1153
1151
  })
1154
-
1155
1152
  describe('inbound', function () {
1156
1153
  it('should accept inbound message with matching jsonpath', async function () {
1157
1154
  const myCaps = Object.assign({}, myCapsGet)
@@ -1249,7 +1246,6 @@ describe('connectors.simplerest', function () {
1249
1246
  return result
1250
1247
  })
1251
1248
  })
1252
-
1253
1249
  describe('polling', function () {
1254
1250
  it('should poll HTTP url', async function () {
1255
1251
  const caps = {
@@ -1313,4 +1309,83 @@ describe('connectors.simplerest', function () {
1313
1309
  scope.persist(false)
1314
1310
  }).timeout(5000)
1315
1311
  })
1312
+ describe('flow', function () {
1313
+ it('should ignore matching message', async function () {
1314
+ const caps = {
1315
+ [Capabilities.CONTAINERMODE]: 'simplerest',
1316
+ [Capabilities.WAITFORBOTTIMEOUT]: 1000,
1317
+ [Capabilities.SIMPLEREST_URL]: 'https://mock.com/flowignore',
1318
+ [Capabilities.SIMPLEREST_RESPONSE_JSONPATH]: ['$.text'],
1319
+ [Capabilities.SIMPLEREST_CONTEXT_IGNORE_JSONPATH]: '$.ignore',
1320
+ [Capabilities.SIMPLEREST_CONTEXT_IGNORE_MATCH]: 'Y'
1321
+ }
1322
+ const scope = nock('https://mock.com')
1323
+ .get('/flowignore').reply(200, { text: 'ignore it', ignore: 'Y' })
1324
+
1325
+ const driver = new BotDriver(caps)
1326
+ const container = await driver.Build()
1327
+ await container.Start()
1328
+
1329
+ await container.UserSays({ text: 'hallo' })
1330
+ try {
1331
+ await container.WaitBotSays()
1332
+ assert.fail('expected response to be ignored')
1333
+ } catch (err) {
1334
+ assert.equal(err.message, 'Bot did not respond within 1s')
1335
+ }
1336
+ await container.Stop()
1337
+ await container.Clean()
1338
+ scope.persist(false)
1339
+ })
1340
+ it('should skip matching message', async function () {
1341
+ const caps = {
1342
+ [Capabilities.CONTAINERMODE]: 'simplerest',
1343
+ [Capabilities.SIMPLEREST_URL]: 'https://mock.com/flowskip',
1344
+ [Capabilities.SIMPLEREST_RESPONSE_JSONPATH]: ['$.text'],
1345
+ [Capabilities.SIMPLEREST_CONTEXT_SKIP_JSONPATH]: '$.skip',
1346
+ [Capabilities.SIMPLEREST_CONTEXT_SKIP_MATCH]: 'Y'
1347
+ }
1348
+ const scope = nock('https://mock.com')
1349
+ .get('/flowskip').reply(200, { text: 'skip it', skip: 'Y' })
1350
+ .get('/flowskip').reply(200, { text: 'not skip it', skip: 'N' })
1351
+
1352
+ const driver = new BotDriver(caps)
1353
+ const container = await driver.Build()
1354
+ await container.Start()
1355
+
1356
+ await container.UserSays({ text: 'hello' })
1357
+ const botMsg = await container.WaitBotSays()
1358
+ assert.equal(botMsg.messageText, 'not skip it')
1359
+
1360
+ await container.Stop()
1361
+ await container.Clean()
1362
+ scope.persist(false)
1363
+ })
1364
+ it('should continue on matching message', async function () {
1365
+ const caps = {
1366
+ [Capabilities.CONTAINERMODE]: 'simplerest',
1367
+ [Capabilities.SIMPLEREST_URL]: 'https://mock.com/flowcontinue',
1368
+ [Capabilities.SIMPLEREST_RESPONSE_JSONPATH]: ['$.text'],
1369
+ [Capabilities.SIMPLEREST_CONTEXT_CONTINUE_JSONPATH]: '$.continue',
1370
+ [Capabilities.SIMPLEREST_CONTEXT_CONTINUE_MATCH]: 'Y'
1371
+ }
1372
+ const scope = nock('https://mock.com')
1373
+ .get('/flowcontinue').reply(200, { text: 'continue it', continue: 'Y' })
1374
+ .get('/flowcontinue').reply(200, { text: 'not continue it', continue: 'N' })
1375
+
1376
+ const driver = new BotDriver(caps)
1377
+ const container = await driver.Build()
1378
+ await container.Start()
1379
+
1380
+ await container.UserSays({ text: 'hello' })
1381
+ const botMsg1 = await container.WaitBotSays()
1382
+ assert.equal(botMsg1.messageText, 'continue it')
1383
+ const botMsg2 = await container.WaitBotSays()
1384
+ assert.equal(botMsg2.messageText, 'not continue it')
1385
+
1386
+ await container.Stop()
1387
+ await container.Clean()
1388
+ scope.persist(false)
1389
+ })
1390
+ })
1316
1391
  })
@@ -12,28 +12,36 @@ describe('scripting.asserters.buttonsAsserter', function () {
12
12
  })
13
13
 
14
14
  it('should succeed on existing button', async function () {
15
+ const payload = {
16
+ value: 'test'
17
+ }
15
18
  await this.buttonsAsserter.assertConvoStep({
16
19
  convoStep: { stepTag: 'test' },
17
- args: ['test'],
20
+ args: ['test', JSON.stringify(payload)],
18
21
  botMsg: {
19
22
  buttons: [
20
23
  {
21
- text: 'test'
24
+ text: 'test',
25
+ payload
22
26
  }
23
27
  ]
24
28
  }
25
29
  })
26
30
  })
27
31
  it('should succeed on existing card button', async function () {
32
+ const payload = {
33
+ value: 'test'
34
+ }
28
35
  await this.buttonsAsserter.assertConvoStep({
29
36
  convoStep: { stepTag: 'test' },
30
- args: ['test'],
37
+ args: ['test', JSON.stringify(payload)],
31
38
  botMsg: {
32
39
  cards: [
33
40
  {
34
41
  buttons: [
35
42
  {
36
- text: 'test'
43
+ text: 'test',
44
+ payload
37
45
  }
38
46
  ]
39
47
  }
@@ -42,42 +50,28 @@ describe('scripting.asserters.buttonsAsserter', function () {
42
50
  })
43
51
  })
44
52
  it('should succeed on existing card buttons', async function () {
53
+ const payload = {
54
+ value: 'test'
55
+ }
56
+ const payloadCard = {
57
+ value: 'card'
58
+ }
45
59
  await this.buttonsAsserter.assertConvoStep({
46
60
  convoStep: { stepTag: 'test' },
47
- args: ['test', 'test1'],
48
- botMsg: {
49
- buttons: [
50
- {
51
- text: 'test'
52
- }
53
- ],
54
- cards: [
55
- {
56
- buttons: [
57
- {
58
- text: 'test1'
59
- }
60
- ]
61
- }
62
- ]
63
- }
64
- })
65
- })
66
- it('should succeed on existing card buttons 2', async function () {
67
- await this.buttonsAsserter.assertConvoStep({
68
- convoStep: { stepTag: 'test' },
69
- args: ['test', 'test1'],
61
+ args: ['test', 'test1', JSON.stringify(payload), JSON.stringify(payloadCard)],
70
62
  botMsg: {
71
63
  buttons: [
72
64
  {
73
- text: 'test'
65
+ text: 'test',
66
+ payload
74
67
  }
75
68
  ],
76
69
  cards: [
77
70
  {
78
71
  buttons: [
79
72
  {
80
- text: 'test1'
73
+ text: 'test1',
74
+ payload: payloadCard
81
75
  }
82
76
  ]
83
77
  }
@@ -86,29 +80,36 @@ describe('scripting.asserters.buttonsAsserter', function () {
86
80
  })
87
81
  })
88
82
  it('should succeed on not existing button', async function () {
83
+ const notPayload = {
84
+ value: 'test1'
85
+ }
89
86
  await this.buttonsAsserter.assertNotConvoStep({
90
87
  convoStep: { stepTag: 'test' },
91
- args: ['test1'],
88
+ args: ['test1', JSON.stringify(notPayload)],
92
89
  botMsg: {
93
90
  buttons: [
94
91
  {
95
- text: 'test'
92
+ text: 'test',
93
+ payload: {
94
+ value: 'test'
95
+ }
96
96
  }
97
97
  ]
98
98
  }
99
99
  })
100
100
  })
101
101
  it('should fail on unexpected button', async function () {
102
+ const buttons = [
103
+ {
104
+ text: 'test'
105
+ }
106
+ ]
102
107
  try {
103
108
  await this.buttonsAsserter.assertNotConvoStep({
104
109
  convoStep: { stepTag: 'test' },
105
110
  args: ['test', 'test1'],
106
111
  botMsg: {
107
- buttons: [
108
- {
109
- text: 'test'
110
- }
111
- ]
112
+ buttons
112
113
  }
113
114
  })
114
115
  assert.fail('should have failed')
@@ -119,10 +120,40 @@ describe('scripting.asserters.buttonsAsserter', function () {
119
120
  assert.isArray(err.context.cause.expected)
120
121
  assert.isTrue(err.context.cause.not)
121
122
  assert.deepEqual(err.context.cause.expected, ['test', 'test1'])
122
- assert.deepEqual(err.context.cause.actual, ['test'])
123
+ assert.deepEqual(err.context.cause.actual, JSON.stringify(buttons, null, 2))
123
124
  assert.deepEqual(err.context.cause.diff, ['test'])
124
125
  }
125
126
  })
127
+ it('should fail on unexpected button payload', async function () {
128
+ const payload = {
129
+ value: 'test'
130
+ }
131
+ const buttons = [
132
+ {
133
+ text: 'test',
134
+ payload
135
+ }
136
+ ]
137
+ try {
138
+ await this.buttonsAsserter.assertNotConvoStep({
139
+ convoStep: { stepTag: 'test' },
140
+ args: [JSON.stringify(payload)],
141
+ botMsg: {
142
+ buttons
143
+ }
144
+ })
145
+ assert.fail('should have failed')
146
+ } catch (err) {
147
+ assert.isTrue(err.message.indexOf(`Not expected button(s) with text "${JSON.stringify(payload)}"`) > 0)
148
+ assert.isNotNull(err.context)
149
+ assert.isNotNull(err.context.cause)
150
+ assert.isArray(err.context.cause.expected)
151
+ assert.isTrue(err.context.cause.not)
152
+ assert.deepEqual(err.context.cause.expected, [JSON.stringify(payload)])
153
+ assert.deepEqual(err.context.cause.actual, JSON.stringify(buttons, null, 2))
154
+ assert.deepEqual(err.context.cause.diff, [JSON.stringify(payload)])
155
+ }
156
+ })
126
157
  it('should succeed on existing button if has no arg', async function () {
127
158
  await this.buttonsAsserter.assertConvoStep({
128
159
  convoStep: { stepTag: 'test' },
@@ -147,23 +178,24 @@ describe('scripting.asserters.buttonsAsserter', function () {
147
178
  assert.isArray(err.context.cause.expected)
148
179
  assert.isNotTrue(err.context.cause.not)
149
180
  assert.deepEqual(err.context.cause.expected, [])
150
- assert.deepEqual(err.context.cause.actual, [])
181
+ assert.deepEqual(err.context.cause.actual, '[]')
151
182
  }
152
183
  })
153
184
  it('should succeed on not existing button if has no arg and negated', async function () {
154
185
  await this.buttonsAsserter.assertNotConvoStep({ convoStep: { stepTag: 'test' } })
155
186
  })
156
187
  it('should fail on button if has no arg and negated', async function () {
188
+ const buttons = [
189
+ {
190
+ text: 'test'
191
+ }
192
+ ]
157
193
  try {
158
194
  await this.buttonsAsserter.assertNotConvoStep({
159
195
  convoStep: { stepTag: 'test' },
160
196
  args: [],
161
197
  botMsg: {
162
- buttons: [
163
- {
164
- text: 'test'
165
- }
166
- ]
198
+ buttons
167
199
  }
168
200
  })
169
201
  assert.fail('should have failed')
@@ -174,7 +206,7 @@ describe('scripting.asserters.buttonsAsserter', function () {
174
206
  assert.isArray(err.context.cause.expected)
175
207
  assert.isTrue(err.context.cause.not)
176
208
  assert.deepEqual(err.context.cause.expected, [])
177
- assert.deepEqual(err.context.cause.actual, ['test'])
209
+ assert.deepEqual(err.context.cause.actual, JSON.stringify(buttons, null, 2))
178
210
  }
179
211
  })
180
212
  })
@@ -302,16 +334,17 @@ describe('scripting.asserters.buttonsAsserter', function () {
302
334
  })
303
335
 
304
336
  it('should fail with normalized text', async function () {
337
+ const buttons = [
338
+ {
339
+ text: '<html><h1>test html header</h1><p>test html text</p>'
340
+ }
341
+ ]
305
342
  try {
306
343
  await this.cardsAsserter.assertConvoStep({
307
344
  convoStep: { stepTag: 'test' },
308
345
  args: ['Test Html header1 test html text'],
309
346
  botMsg: {
310
- buttons: [
311
- {
312
- text: '<html><h1>test html header</h1><p>test html text</p>'
313
- }
314
- ]
347
+ buttons
315
348
  }
316
349
  })
317
350
  assert.fail('should have failed')
@@ -321,7 +354,8 @@ describe('scripting.asserters.buttonsAsserter', function () {
321
354
  assert.isNotNull(err.context.cause)
322
355
  assert.isArray(err.context.cause.expected)
323
356
  assert.deepEqual(err.context.cause.expected, ['Test Html header1 test html text'])
324
- assert.deepEqual(err.context.cause.actual, ['test html header test html text'])
357
+ buttons[0].text = 'test html header test html text'
358
+ assert.deepEqual(err.context.cause.actual, JSON.stringify(buttons, null, 2))
325
359
  assert.deepEqual(err.context.cause.diff, ['Test Html header1 test html text'])
326
360
  }
327
361
  })
@@ -0,0 +1,11 @@
1
+ custom embedded
2
+
3
+ #me
4
+ hello
5
+
6
+ #bot
7
+ hello fail
8
+ MY-LOGICHOOK-SKIP
9
+
10
+ #bot
11
+ hello
@@ -0,0 +1,11 @@
1
+ custom embedded
2
+
3
+ #me
4
+ hello
5
+
6
+ #bot
7
+ hello fail
8
+ MY-LOGICHOOK-SKIP
9
+
10
+ #me
11
+ hello