botium-core 1.13.18 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/botium-cjs.js +326 -387
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +326 -385
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +21 -25
  6. package/samples/extensions/asserterHooks/botium.json +1 -0
  7. package/samples/extensions/logichooks/botium.json +1 -0
  8. package/samples/extensions/logichooks/custom/MyAsserter.js +3 -3
  9. package/src/Capabilities.js +2 -1
  10. package/src/containers/PluginConnectorContainer.js +8 -0
  11. package/src/containers/plugins/SimpleRestContainer.js +17 -9
  12. package/src/containers/plugins/index.js +29 -41
  13. package/src/helpers/HookUtils.js +32 -68
  14. package/src/scripting/Convo.js +17 -5
  15. package/src/scripting/ScriptingMemory.js +0 -24
  16. package/src/scripting/logichook/LogicHookConsts.js +5 -1
  17. package/src/scripting/logichook/LogicHookUtils.js +27 -47
  18. package/src/scripting/logichook/asserter/ButtonsAsserter.js +5 -5
  19. package/src/scripting/logichook/logichooks/ConditionalBusinessHoursLogicHook.js +56 -0
  20. package/src/scripting/logichook/logichooks/ConditionalCapabilityValueBasedLogicHook.js +37 -0
  21. package/src/scripting/logichook/logichooks/ConditionalJsonPathBasedLogicHook.js +31 -0
  22. package/src/scripting/logichook/logichooks/ConditionalTimeBasedLogicHook.js +46 -0
  23. package/test/compiler/precompilerscript.spec.js +24 -26
  24. package/test/connectors/pluginconnectorcontainer.spec.js +60 -0
  25. package/test/connectors/simplerest.spec.js +24 -27
  26. package/test/convo/fillAndApplyScriptingMemory.spec.js +1 -47
  27. package/test/hooks/customhooks.spec.js +3 -25
  28. package/test/logichooks/hookfromsrc.spec.js +13 -3
  29. package/test/plugins/plugins.spec.js +29 -2
  30. package/test/scripting/logichooks/CustomConditionalLogicHook.js +21 -0
  31. package/test/scripting/logichooks/conditionalStepBusinessHoursLogicHook.spec.js +130 -0
  32. package/test/scripting/logichooks/conditionalStepCapabilityValueBasedLogicHook.spec.js +35 -0
  33. package/test/scripting/logichooks/conditionalStepJsonPathBasedLogicHook.spec.js +35 -0
  34. package/test/scripting/logichooks/conditionalStepTimeBasedLogicHook.spec.js +91 -0
  35. package/test/scripting/logichooks/convos/conditional_steps.convo.txt +12 -0
  36. package/test/scripting/logichooks/convos/conditional_steps_business_hours.convo.txt +16 -0
  37. package/test/scripting/logichooks/convos/conditional_steps_cap_value_based.convo.txt +12 -0
  38. package/test/scripting/logichooks/convos/conditional_steps_followed_by_bot_msg.convo.txt +15 -0
  39. package/test/scripting/logichooks/convos/conditional_steps_followed_by_me.convo.txt +18 -0
  40. package/test/scripting/logichooks/convos/conditional_steps_json_path_based.convo.txt.convo.txt +12 -0
  41. package/test/scripting/logichooks/convos/conditional_steps_multiple_condition_groups.convo.txt +20 -0
  42. package/test/scripting/logichooks/convos/conditional_steps_multiple_condition_groups_no_assertion.convo.txt +20 -0
  43. package/test/scripting/logichooks/convos/conditional_steps_time_based.convo.txt +12 -0
  44. package/test/scripting/logichooks/customConditionalStepLogicHook.spec.js +105 -0
  45. package/test/scripting/scriptingProvider.spec.js +1 -1
  46. package/test/security/allowUnsafe.spec.js +20 -129
  47. package/LICENSES-3RDPARTY.txt +0 -6450
  48. package/test/scripting/asserters/convos/customembeddedasserterwithhugo.convo.txt +0 -7
  49. package/test/scripting/asserters/convos/customembeddedasserterwithouthugo.convo.txt +0 -7
  50. package/test/scripting/asserters/customEmbeddedAsserter.json +0 -14
  51. package/test/scripting/asserters/customEmbeddedAsserter.spec.js +0 -55
  52. package/test/scripting/logichooks/convos/custom_embedded.convo.txt +0 -8
  53. package/test/scripting/logichooks/convos/custom_embedded_skip.convo.txt +0 -11
  54. package/test/scripting/logichooks/convos/custom_embedded_skip_followed_by_me.convo.txt +0 -11
  55. package/test/scripting/logichooks/convos/custom_embedded_skip_followed_by_nothing.convo.txt +0 -8
  56. package/test/scripting/logichooks/customEmbedded.json +0 -14
  57. package/test/scripting/logichooks/customEmbedded.spec.js +0 -44
  58. package/test/scripting/logichooks/customEmbeddedSkip.json +0 -14
  59. package/test/scripting/logichooks/customEmbeddedSkip.spec.js +0 -58
  60. package/test/security/convos/withscriptingmemoryfunction.convo.txt +0 -5
@@ -1,11 +1,9 @@
1
- const { NodeVM } = require('vm2')
1
+ const util = require('util')
2
2
  const path = require('path')
3
3
  const fs = require('fs')
4
4
  const isClass = require('is-class')
5
5
  const debug = require('debug')('botium-core-asserterUtils')
6
6
 
7
- const { BotiumError } = require('../BotiumError')
8
-
9
7
  const { DEFAULT_ASSERTERS, DEFAULT_LOGIC_HOOKS, DEFAULT_USER_INPUTS } = require('./LogicHookConsts')
10
8
 
11
9
  DEFAULT_ASSERTERS.forEach((asserter) => {
@@ -129,19 +127,7 @@ module.exports = class LogicHookUtils {
129
127
  }
130
128
  }
131
129
 
132
- const _checkUnsafe = () => {
133
- if (!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE]) {
134
- throw new BotiumError(
135
- 'Security Error. Using unsafe component is not allowed',
136
- {
137
- type: 'security',
138
- subtype: 'allow unsafe',
139
- source: path.basename(__filename),
140
- cause: { src: !!src, ref, args, hookType }
141
- }
142
- )
143
- }
144
- }
130
+ const allowUnsafe = !!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE]
145
131
 
146
132
  if (!src) {
147
133
  const packageName = `botium-${hookType}-${ref}`
@@ -154,10 +140,10 @@ module.exports = class LogicHookUtils {
154
140
  } else if (isClass(CheckClass.PluginClass)) {
155
141
  return new CheckClass.PluginClass({ ref, ...this.buildScriptContext }, this.caps, args)
156
142
  } else {
157
- throw new Error(`${packageName} class or function or PluginClass field expected`)
143
+ throw new Error('Either class or function or PluginClass field expected')
158
144
  }
159
145
  } catch (err) {
160
- throw new Error(`Failed to fetch hook ${ref} ${hookType} from guessed package ${packageName} - ${err.message}`)
146
+ throw new Error(`Logic Hook specification ${ref} ${hookType} (${packageName}) invalid: ${err.message}`)
161
147
  }
162
148
  }
163
149
 
@@ -166,14 +152,14 @@ module.exports = class LogicHookUtils {
166
152
  const CheckClass = src
167
153
  return new CheckClass({ ref, ...this.buildScriptContext }, this.caps, args)
168
154
  } catch (err) {
169
- throw new Error(`Failed to load package ${ref} from provided class - ${err.message}`)
155
+ throw new Error(`Logic Hook specification ${ref} from class invalid: ${err.message}`)
170
156
  }
171
157
  }
172
158
  if (_.isFunction(src)) {
173
159
  try {
174
160
  return src({ ref, ...this.buildScriptContext }, this.caps, args)
175
161
  } catch (err) {
176
- throw new Error(`Failed to load package ${ref} from provided function - ${err.message}`)
162
+ throw new Error(`Logic Hook specification ${ref} from function invalid: ${err.message}`)
177
163
  }
178
164
  }
179
165
  if (_.isObject(src) && !_.isString(src)) {
@@ -183,26 +169,15 @@ module.exports = class LogicHookUtils {
183
169
  const script = src[key]
184
170
  if (_.isFunction(script)) {
185
171
  return script(args)
186
- } else if (_.isString(script)) {
187
- try {
188
- const vm = new NodeVM({
189
- eval: false,
190
- require: false,
191
- sandbox: args
192
- })
193
- return vm.run(script)
194
- } catch (err) {
195
- throw new Error(`Script ${key} is not valid - ${err.message || err}`)
196
- }
197
172
  } else {
198
- throw new Error(`Script "${key}" is not valid - only functions and javascript code accepted`)
173
+ throw new Error(`Script ${key} is not valid - only functions accepted`)
199
174
  }
200
175
  }
201
176
  return result
202
177
  }, {})
203
178
  return hookObject
204
179
  } catch (err) {
205
- throw new Error(`Failed to load package ${ref} ${hookType} from provided src function - ${err.message}`)
180
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from provided src (${util.inspect(src)}) invalid: ${err.message}`)
206
181
  }
207
182
  }
208
183
 
@@ -215,8 +190,8 @@ module.exports = class LogicHookUtils {
215
190
  }]
216
191
  if (src.indexOf('/') >= 0) {
217
192
  tryLoads.push({
218
- tryLoadPackageName: src.substr(0, src.lastIndexOf('/')),
219
- tryLoadAsserterByName: src.substr(src.lastIndexOf('/') + 1)
193
+ tryLoadPackageName: src.substring(0, src.lastIndexOf('/')),
194
+ tryLoadAsserterByName: src.substring(src.lastIndexOf('/') + 1)
220
195
  })
221
196
  }
222
197
 
@@ -243,29 +218,34 @@ module.exports = class LogicHookUtils {
243
218
  } else if (_.isFunction(CheckClass.PluginClass)) {
244
219
  return CheckClass.PluginClass({ ref, ...this.buildScriptContext }, this.caps, args)
245
220
  } else {
246
- throw new Error(`${src} class or function expected`)
221
+ throw new Error('Expected class or function')
247
222
  }
248
223
  }
249
224
 
250
225
  for (const tryLoad of tryLoads) {
251
- const tryLoadFile = path.resolve(process.cwd(), tryLoad.tryLoadPackageName)
252
- if (fs.existsSync(tryLoadFile)) {
253
- _checkUnsafe()
226
+ if (this.caps.SAFEDIR) {
227
+ const tryLoadFile = path.resolve(this.caps.SAFEDIR, tryLoad.tryLoadPackageName)
228
+ if (tryLoadFile.startsWith(path.resolve(this.caps.SAFEDIR))) {
229
+ if (fs.existsSync(tryLoadFile)) {
230
+ try {
231
+ return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName)
232
+ } catch (err) {
233
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `)
234
+ }
235
+ }
236
+ }
237
+ }
238
+ if (allowUnsafe || tryLoad.tryLoadPackageName.startsWith('botium-')) {
254
239
  try {
255
- return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName)
240
+ return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName)
256
241
  } catch (err) {
257
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `)
242
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `)
258
243
  }
259
244
  }
260
- try {
261
- return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName)
262
- } catch (err) {
263
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `)
264
- }
265
245
  }
266
246
 
267
247
  loadErr.forEach(debug)
268
248
  }
269
- throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`)
249
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from "${util.inspect(src)}" invalid : no loader available`)
270
250
  }
271
251
  }
@@ -18,19 +18,19 @@ module.exports = class ButtonsAsserter {
18
18
  }
19
19
  const buttonsNotFound = []
20
20
  const buttonsFound = []
21
- const parsePayload = (payload) => {
21
+ const stringifyPayload = (payload) => {
22
22
  if (_.isNil(payload)) {
23
- return undefined
23
+ return ''
24
24
  }
25
25
  try {
26
- return JSON.parse(payload)
26
+ return JSON.stringify(JSON.parse(payload))
27
27
  } catch (e) {
28
- return payload
28
+ return JSON.stringify(payload)
29
29
  }
30
30
  }
31
31
  for (let i = 0; i < (args || []).length; i++) {
32
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])))
33
+ const matchByPayload = allButtons.some(b => this.context.Match(stringifyPayload(b.payload), normalizeText(args[i], !!this.caps[SCRIPTING_NORMALIZE_TEXT])))
34
34
  if (matchByText || matchByPayload) {
35
35
  buttonsFound.push(args[i])
36
36
  } else {
@@ -0,0 +1,56 @@
1
+ const util = require('util')
2
+ const moment = require('moment-timezone')
3
+ const debug = require('debug')('botium-core-ConditionalTimeBasedLogicHook')
4
+
5
+ module.exports = class ConditionalBusinessHoursLogicHook {
6
+ constructor (context, caps, globalArgs) {
7
+ this.context = context
8
+ this.caps = caps
9
+ this.globalArgs = globalArgs
10
+ }
11
+
12
+ _isBetween ({ now, start, end, days, timeZone }) {
13
+ if ((!start || !end) && (!days || days.length === 0)) {
14
+ throw new Error('ConditionalBusinessHoursLogicHook: Either start and end time or days array needs to be specified in params')
15
+ }
16
+ now.tz(timeZone)
17
+ if (days && days.length > 0 && !days.includes(now.format('dddd'))) {
18
+ return false
19
+ }
20
+
21
+ if (!start && !end && days && days.length > 0 && days.includes(now.format('dddd'))) {
22
+ return true
23
+ }
24
+
25
+ const momentStartTime = moment(start, 'HH:mm')
26
+ const startTime = now.clone().set({ hour: momentStartTime.hour(), minute: momentStartTime.minute() })
27
+ startTime.tz(timeZone)
28
+ const momentEndTime = moment(end, 'HH:mm')
29
+ const endTime = now.clone().set({ hour: momentEndTime.hour(), minute: momentEndTime.minute() })
30
+ endTime.tz(timeZone)
31
+ if (startTime.isSameOrAfter(endTime)) {
32
+ if (now.isSameOrAfter(startTime)) {
33
+ endTime.add(1, 'days')
34
+ } else {
35
+ startTime.add(-1, 'days')
36
+ }
37
+ }
38
+ return now.isBetween(startTime, endTime, 'minutes', '[]')
39
+ }
40
+
41
+ onBotPrepare ({ convo, convoStep, args }) {
42
+ const conditionGroupId = args[1]
43
+ let params
44
+ try {
45
+ params = JSON.parse(args[0])
46
+ } catch (e) {
47
+ throw new Error(`ConditionalBusinessHoursLogicHook: No parsable JSON object found in params: ${e}`)
48
+ }
49
+ convoStep.conditional = {
50
+ conditionGroupId
51
+ }
52
+ params.now = moment()
53
+ convoStep.conditional.skip = !this._isBetween(params)
54
+ debug(`ConditionalBusinessHoursLogicHook onBotPrepare ${convo.header.name}/${convoStep.stepTag}, args: ${util.inspect(args)}, convoStep.conditional: ${convoStep.conditional}`)
55
+ }
56
+ }
@@ -0,0 +1,37 @@
1
+ const util = require('util')
2
+ const jp = require('jsonpath')
3
+ const _ = require('lodash')
4
+ const debug = require('debug')('botium-core-ConditionalCapabilityValueBasedLogicHook')
5
+
6
+ module.exports = class ConditionalCapabilityValueBasedLogicHook {
7
+ constructor (context, caps, globalArgs) {
8
+ this.context = context
9
+ this.caps = caps
10
+ this.globalArgs = globalArgs
11
+ }
12
+
13
+ _isCapabilityValueEqual ({ capabilityName, jsonPath, value }) {
14
+ if (jsonPath) {
15
+ const capabilityObject = _.isObject(this.caps[capabilityName]) ? this.caps[capabilityName] : JSON.parse(this.caps[capabilityName])
16
+ const values = jp.query(capabilityObject, jsonPath)
17
+ return !!(values && values.length > 0 && values.includes(value))
18
+ } else {
19
+ return this.caps[capabilityName] === value
20
+ }
21
+ }
22
+
23
+ onBotPrepare ({ convo, convoStep, args }) {
24
+ const conditionGroupId = args[1]
25
+ let params
26
+ try {
27
+ params = JSON.parse(args[0])
28
+ } catch (e) {
29
+ throw new Error(`ConditionalCapabilityValueBasedLogicHook: No parsable JSON object found in params: ${e}`)
30
+ }
31
+ convoStep.conditional = {
32
+ conditionGroupId
33
+ }
34
+ convoStep.conditional.skip = !this._isCapabilityValueEqual(params)
35
+ debug(`ConditionalCapabilityValueBasedLogicHook onBotPrepare ${convo.header.name}/${convoStep.stepTag}, args: ${util.inspect(args)}, convoStep.conditional: ${convoStep.conditional}`)
36
+ }
37
+ }
@@ -0,0 +1,31 @@
1
+ const util = require('util')
2
+ const jp = require('jsonpath')
3
+ const debug = require('debug')('botium-core-ConditionalJsonPathBasedLogicHook')
4
+
5
+ module.exports = class ConditionalJsonPathBasedLogicHook {
6
+ constructor (context, caps, globalArgs) {
7
+ this.context = context
8
+ this.caps = caps
9
+ this.globalArgs = globalArgs
10
+ }
11
+
12
+ onBotPrepare ({ convo, convoStep, args, botMsg }) {
13
+ const conditionGroupId = args[1]
14
+ let params
15
+ try {
16
+ params = JSON.parse(args[0])
17
+ } catch (e) {
18
+ throw new Error(`ConditionalJsonPathBasedLogicHook: No parsable JSON object found in params: ${e}`)
19
+ }
20
+ convoStep.conditional = {
21
+ conditionGroupId
22
+ }
23
+ let skip = true
24
+ if (params.jsonPath) {
25
+ const values = jp.query(botMsg, params.jsonPath)
26
+ skip = !(values && values.length > 0 && values.includes(params.value))
27
+ }
28
+ convoStep.conditional.skip = skip
29
+ debug(`ConditionalJsonPathBasedLogicHook onBotPrepare ${convo.header.name}/${convoStep.stepTag}, args: ${util.inspect(args)}, convoStep.conditional: ${convoStep.conditional}`)
30
+ }
31
+ }
@@ -0,0 +1,46 @@
1
+ const util = require('util')
2
+ const moment = require('moment-timezone')
3
+ const debug = require('debug')('botium-core-ConditionalTimeBasedLogicHook')
4
+
5
+ module.exports = class ConditionalTimeBasedLogicHook {
6
+ constructor (context, caps, globalArgs) {
7
+ this.context = context
8
+ this.caps = caps
9
+ this.globalArgs = globalArgs
10
+ }
11
+
12
+ _isBetween ({ now, start, end, timeZone }) {
13
+ now.tz(timeZone)
14
+ const momentStartTime = moment(start, 'HH:mm')
15
+ const startTime = now.clone().set({ hour: momentStartTime.hour(), minute: momentStartTime.minute() })
16
+ startTime.tz(timeZone)
17
+ const momentEndTime = moment(end, 'HH:mm')
18
+ const endTime = now.clone().set({ hour: momentEndTime.hour(), minute: momentEndTime.minute() })
19
+ endTime.tz(timeZone)
20
+
21
+ if (startTime.isSameOrAfter(endTime)) {
22
+ if (now.isSameOrAfter(startTime)) {
23
+ endTime.add(1, 'days')
24
+ } else {
25
+ startTime.add(-1, 'days')
26
+ }
27
+ }
28
+ return now.isBetween(startTime, endTime, 'minutes', '[]')
29
+ }
30
+
31
+ onBotPrepare ({ convo, convoStep, args }) {
32
+ const conditionGroupId = args[1]
33
+ let params
34
+ try {
35
+ params = JSON.parse(args[0])
36
+ } catch (e) {
37
+ throw new Error(`ConditionalTimeBasedLogicHook: No parsable JSON object found in params: ${e}`)
38
+ }
39
+ convoStep.conditional = {
40
+ conditionGroupId
41
+ }
42
+ params.now = moment()
43
+ convoStep.conditional.skip = !this._isBetween(params)
44
+ debug(`ConditionalTimeBasedLogicHook onBotPrepare ${convo.header.name}/${convoStep.stepTag}, args: ${util.inspect(args)}, convoStep.conditional: ${convoStep.conditional}`)
45
+ }
46
+ }
@@ -33,13 +33,13 @@ const afterCustom = async (thisParam) => {
33
33
 
34
34
  describe('compiler.precompiler.script', function () {
35
35
  it('should execute non-standard json', async function () {
36
- await beforeCustom(this, `
36
+ await beforeCustom(this, ({ scriptData }) => {
37
37
  const utterances = {}
38
38
  for (const entry of scriptData) {
39
39
  utterances[entry.intent] = entry.sentences
40
40
  }
41
- module.exports = {utterances}
42
- `)
41
+ return { utterances }
42
+ })
43
43
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script.json')
44
44
  this.compiler.ExpandUtterancesToConvos()
45
45
  this.compiler.ExpandConvos()
@@ -54,15 +54,15 @@ describe('compiler.precompiler.script', function () {
54
54
  })
55
55
 
56
56
  it('should filter by extension, accepted', async function () {
57
- await beforeCustom(this, `
58
- if (filename.endsWith('.json')) {
57
+ await beforeCustom(this, ({ filename, scriptData }) => {
58
+ if (filename.endsWith('.json')) {
59
59
  const utterances = {}
60
60
  for (const entry of scriptData) {
61
61
  utterances[entry.intent] = entry.sentences
62
62
  }
63
- module.exports = {utterances}
63
+ return { utterances }
64
64
  }
65
- `)
65
+ })
66
66
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script.json')
67
67
  this.compiler.ExpandUtterancesToConvos()
68
68
  this.compiler.ExpandConvos()
@@ -71,15 +71,15 @@ describe('compiler.precompiler.script', function () {
71
71
  })
72
72
 
73
73
  it('should filter by extension, rejected', async function () {
74
- await beforeCustom(this, `
75
- if (filename.endsWith('.xxx')) {
74
+ await beforeCustom(this, ({ filename, scriptData }) => {
75
+ if (filename.endsWith('.xxx')) {
76
76
  const utterances = {}
77
77
  for (const entry of scriptData) {
78
78
  utterances[entry.intent] = entry.sentences
79
79
  }
80
- module.exports = {utterances}
80
+ return { utterances }
81
81
  }
82
- `)
82
+ })
83
83
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script.json')
84
84
  this.compiler.ExpandUtterancesToConvos()
85
85
  this.compiler.ExpandConvos()
@@ -88,15 +88,15 @@ describe('compiler.precompiler.script', function () {
88
88
  })
89
89
 
90
90
  it('should filter by content, accepted', async function () {
91
- await beforeCustom(this, `
91
+ await beforeCustom(this, ({ scriptData }) => {
92
92
  if (scriptData) {
93
93
  const utterances = {}
94
94
  for (const entry of scriptData) {
95
95
  utterances[entry.intent] = entry.sentences
96
96
  }
97
- module.exports = {utterances}
97
+ return { utterances }
98
98
  }
99
- `)
99
+ })
100
100
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script.json')
101
101
  this.compiler.ExpandUtterancesToConvos()
102
102
  this.compiler.ExpandConvos()
@@ -105,15 +105,15 @@ describe('compiler.precompiler.script', function () {
105
105
  })
106
106
 
107
107
  it('should filter by content, rejected', async function () {
108
- await beforeCustom(this, `
108
+ await beforeCustom(this, ({ scriptData }) => {
109
109
  if (scriptData.utterances) {
110
110
  const utterances = {}
111
111
  for (const entry of scriptData.utterances) {
112
112
  utterances[entry.intent] = entry.sentences
113
113
  }
114
- module.exports = {utterances}
114
+ return { utterances }
115
115
  }
116
- `)
116
+ })
117
117
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script.json')
118
118
  this.compiler.ExpandUtterancesToConvos()
119
119
  this.compiler.ExpandConvos()
@@ -122,13 +122,13 @@ describe('compiler.precompiler.script', function () {
122
122
  })
123
123
 
124
124
  it('should change extension', async function () {
125
- await beforeCustom(this, `
125
+ await beforeCustom(this, ({ filename, scriptData }) => {
126
126
  const utterances = {}
127
127
  for (const entry of scriptData) {
128
128
  utterances[entry.intent] = entry.sentences
129
129
  }
130
- module.exports = { scriptBuffer:{utterances}, filename: filename + ".json" }
131
- `)
130
+ return { scriptBuffer: { utterances }, filename: filename + '.json' }
131
+ })
132
132
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script.json.txt')
133
133
  this.compiler.ExpandUtterancesToConvos()
134
134
  this.compiler.ExpandConvos()
@@ -137,13 +137,13 @@ describe('compiler.precompiler.script', function () {
137
137
  })
138
138
 
139
139
  it('should not read anything without extension change', async function () {
140
- await beforeCustom(this, `
140
+ await beforeCustom(this, ({ scriptData }) => {
141
141
  const utterances = {}
142
142
  for (const entry of scriptData) {
143
143
  utterances[entry.intent] = entry.sentences
144
144
  }
145
- module.exports = { scriptBuffer:{utterances} }
146
- `)
145
+ return { scriptBuffer: { utterances } }
146
+ })
147
147
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script.json.txt')
148
148
  this.compiler.ExpandUtterancesToConvos()
149
149
  this.compiler.ExpandConvos()
@@ -152,9 +152,7 @@ describe('compiler.precompiler.script', function () {
152
152
  })
153
153
 
154
154
  it('should be able to precompile text to text', async function () {
155
- await beforeCustom(this, `
156
- module.exports = scriptData.replace("Hi!", "Hi Bot!")
157
- `)
155
+ await beforeCustom(this, ({ scriptData }) => scriptData.replace('Hi!', 'Hi Bot!'))
158
156
  this.compiler.ReadScript(path.resolve(__dirname, 'convos'), 'convos_precompiler_script_text_to_text.convo.txt')
159
157
  this.compiler.ExpandUtterancesToConvos()
160
158
  this.compiler.ExpandConvos()
@@ -0,0 +1,60 @@
1
+ const assert = require('chai').assert
2
+ const BotDriver = require('../../').BotDriver
3
+ const Capabilities = require('../../').Capabilities
4
+
5
+ const echoConnectorWithMetadata = ({ queueBotSays }) => {
6
+ return {
7
+ UserSays (msg) {
8
+ const botMsg = {
9
+ sender: 'bot',
10
+ sourceData: msg.sourceData,
11
+ messageText: `Response of ${msg.messageText}`
12
+ }
13
+ queueBotSays(botMsg)
14
+ },
15
+ GetMetaData () {
16
+ return Promise.resolve('Sample response from GetMetaData')
17
+ }
18
+ }
19
+ }
20
+ const echoConnectorWithoutMetadata = ({ queueBotSays }) => {
21
+ return {
22
+ UserSays (msg) {
23
+ const botMsg = {
24
+ sender: 'bot',
25
+ sourceData: msg.sourceData,
26
+ messageText: `Response of ${msg.messageText}`
27
+ }
28
+ queueBotSays(botMsg)
29
+ }
30
+ }
31
+ }
32
+
33
+ describe('compiler.precompiler.json', function () {
34
+ beforeEach(async function () {
35
+ this.init = async (withGetMetaData) => {
36
+ const myCaps = {
37
+ [Capabilities.PROJECTNAME]: 'connector.basecontainer',
38
+ [Capabilities.CONTAINERMODE]: withGetMetaData ? echoConnectorWithMetadata : echoConnectorWithoutMetadata
39
+ }
40
+ const driver = new BotDriver(myCaps)
41
+ this.compiler = driver.BuildCompiler()
42
+ this.container = await driver.Build()
43
+ }
44
+ })
45
+ afterEach(async function () {
46
+ this.container && await this.container.Clean()
47
+ })
48
+
49
+ it('should get metadata if its available', async function () {
50
+ await this.init(true)
51
+ const result = await this.container.GetMetaData()
52
+ assert.equal(result, 'Sample response from GetMetaData')
53
+ })
54
+
55
+ it('should get undefined if metadata is not available', async function () {
56
+ await this.init(false)
57
+ const result = await this.container.GetMetaData()
58
+ assert.equal(result, undefined)
59
+ })
60
+ })