With some Javascript development know-how, you can extend Botium with your own logic hooks.
Logic Hooks
There are currently nine types of logic hook events where you can add your custom logic:
-
onConvoBegin: before a convo begins
-
Conversation step, me section:
-
onMeBegin: before a me message is sent.
-
onMeEnd: after a me message is sent
-
onMe: same as onMeBegin/onMeEnd, but the position (executed before, or after) depends on the order in the script. Use this instead of onMeBegin/onMeEnd if it has sense to execute a logichook before, and after sending the me message, like Pause Logic Hook
-
-
Conversation step, bot section:
-
onBotBegin: before a bot message received
-
onBotPrepare: after a bot message received but before assertions are done
-
onBotEnd: after a bot message received
-
onBot: same as onBegin/onMeEnd, but the position (executed before, or after) depends on the order in the script. Use this instead of onMeBegin/onMeEnd if it has sense to execute a logichook before, and after asserting the bot response, like Pause Logic Hook
-
-
onConvoEnd: after convo ends
The logic hooks are implemented as Javascript functions. Implementation of the hooks is optional, you just have to implement the hooks required by your logic.
When adding a global logic hook to Botium (Register as global scripting component), the logic hooks will be called on every convo and every convo step.
Please keep in mind, that the logic hooks are blocking the test.
Some tips for better performance:
-
Put your time consuming initialization into constructor, or into the onConvoBegin function.
-
Execute write processes (which have no influence on the test process) parallel.
Using Botium CLI to generate Skeleton Project
You can use the Botium CLI to generate a skeleton project with a sample custom logic hook in the current directory:
> botium-cli init-dev logichook
> botium-cli run
Code Sample - Logic Hook Class Skeleton
Best practice is to place your custom logic hook code in a Javascript file and export a Javascript class definition. As an example, place this in a file called MyCustomLogicHook.js:
module.exports = class MyCustomLogicHook {
constructor (context, caps, globalArgs) {
this.context = context
this.caps = caps
this.globalArgs = globalArgs
console.log(`MyCustomLogicHook constructor, globalArgs: ${utils.inspect(globalArgs)}`)
}
onConvoBegin ({ convo, args }) {
console.log(`MyCustomLogicHook onConvoBegin: ${convo.header.name}`)
}
onConvoEnd ({ convo, transcript, args }) {
console.log(`MyCustomLogicHook onConvoEnd ${convo.header.name}, conversation length: ${transcript.steps.length} steps`)
}
onMeStart ({ convo, convoStep, args }) {
console.log(`MyCustomLogicHook onMeStart ${convo.header.name}/${convoStep.stepTag}, args: ${utils.inspect(args)}, meMessage: ${convoStep.messageText}`)
}
onMeEnd ({ convo, convoStep, args }) {
console.log(`MyCustomLogicHook onMeEnd ${convo.header.name}/${convoStep.stepTag}, args: ${utils.inspect(args)}, meMessage: ${convoStep.messageText}`)
}
onMe ({ convo, convoStep, args }) {
console.log(`MyCustomLogicHook onMe ${convo.header.name}/${convoStep.stepTag}, args: ${utils.inspect(args)}, meMessage: ${convoStep.messageText}`)
}
onBotStart ({ convo, convoStep, args }) {
console.log(`MyCustomLogicHook onBotStart ${convo.header.name}/${convoStep.stepTag}, args: ${utils.inspect(args)}, expected: ${convoStep.messageText}`)
}
onBotPrepare ({ convo, convoStep, args }) {
console.log(`MyCustomLogicHook onBotPrepare ${convo.header.name}/${convoStep.stepTag}, args: ${utils.inspect(args)}, expected: ${convoStep.messageText}`)
}
onBotEnd ({ convo, convoStep, botMsg, args }) {
console.log(`MyCustomLogicHook onBotEnd ${convo.header.name}/${convoStep.stepTag}, args: ${utils.inspect(args)}, expected: ${convoStep.messageText}, meMessage: ${botMsg.messageText}`)
}
onBot ({ convo, convoStep, botMsg, args }) {
console.log(`MyCustomLogicHook onBot ${convo.header.name}/${convoStep.stepTag}, args: ${utils.inspect(args)}, expected: ${convoStep.messageText}, meMessage: ${botMsg ? botMsg.messageText : null}`)
}
}
Code Sample - Logic Hook File Code
For short logic hook it is possible to place the Javascript code directly in the component configuration:
{
"botium": {
"Capabilities": {
...
"LOGIC_HOOKS": [
{
"ref": "MY-LOGICHOOK-NAME",
"src": {
"onMeStart": "meMsg.messageText += ' from logichook'"
},
"global": false,
"args": {
"my-arg-1": "something"
}
}
]
}
}
}
Logic Hook API
Class Constructor Arguments (only for class definitions)
-
context - Scripting Context with several Botium internal functions
-
caps - Botium capabilities
-
globalArgs - the component configuration (from the Component Configuration field in Botium, or from the args field in botium.json) as JSON structure
onConvoBegin Arguments
-
convo - current convo
-
args - the logic hook args from the convo file (as JSON array - split by “|”)
-
scriptingMemory - scripting memory variables (a JSON object)
-
isGlobal - wether the logic hook has been registered globally or not
-
container - Botium Connector container (provides access to internal connector data)
onMeStart/onMeEnd/onMe
-
convo - see above
-
convoStep - the logic hook args from the convo file (as JSON array - split by “|”)
-
args - see above
-
scriptingMemory - see above
-
isGlobal - see above
-
container - see above
-
meMsg - request from the user
onBotStart Arguments
-
convo - see above
-
convoStep - the logic hook args from the convo file (as JSON array - split by “|”)
-
args - see above
-
scriptingMemory - see above
-
isGlobal - see above
-
container - see above
onBotPrepare Arguments
-
convo - see above
-
convoStep -see above
-
args - see above
-
scriptingMemory - see above
-
isGlobal - see above
-
container - see above
-
botMsg - the message from the bot
onBotEnd Arguments
-
convo - see above
-
convoStep -see above
-
args - see above
-
scriptingMemory - see above
-
isGlobal - see above
-
container - see above
-
botMsg - the message from the bot
onBot Arguments
-
convo - see above
-
convoStep -see above
-
args - see above
-
scriptingMemory - see above
-
isGlobal - see above
-
container - see above
-
botMsg - the message from the bot. CAN BE NULL DEPENDING ON ORDER IN SCRIPT.
onConvoEnd Arguments
-
convo - see above
-
args - see above
-
scriptingMemory - see above
-
isGlobal - see above
-
container - see above
-
transcript - the full conversation transcript
Deployment to Botium
There are 2 ways to deploy your custom logic hook to Botium.
Option 1: NPM package
Build an NPM package, exporting a Javascript class holding your logic. You have to add the NPM package to your Botium server - unpack the NPM package to the resources directory - the package.json of your NPM package is in the resources/your-logichook-name directory - and run “npm install” there.
Now you can use the Registered Components view to register your custom logic hook, using your-logichook-name as Component Source. (Registering works like for asserters)
Option 2: Shared Javascript file
You can just tell Botium to load the logic hook code from a Javascript file. The Javascript file has to be available on all Botium Box servers and agents, obviously, by placing it in the resources directory.
Now you can use the Registered Components view to register your custom logic hook, using your-logichook-filename.js as Component Source (the relative path in the resources directory). (Registering works like for asserters)
In both cases you can use botium-logichook- prefix to automatically register your logic hook.
In both cases logic hook is loaded if plugins are enabled.
Deployment to botium.json
When using botium-cli or botium-bindings, you have to register your logic hook in the botium.json file:
{
"botium": {
"Capabilities": {
...
"LOGIC_HOOKS": [
{
"ref": "MY-LOGICHOOK-NAME",
"src": "path-to-my-javascript-file-or-npm-package-name",
"global": false,
"args": {
"my-arg-1": "something"
}
}
]
}
}
}
Using the Logic Hook
You trigger the logic hook call by using the defined Component Ref
Code of the logic hook (in our example below: DUMMY_LOG_TESTCASE
and
DUMMY_INSERT_TO_SCRIPTING_MEMORY
). Everything after Component Ref
Code are args separated by |
-
begin: Before the conversation starts (use onConvoBegin hook)
-
me: before and after me request (use onMeStart/onMeEnd, or booth hooks)
-
bot: before and after bot response (use onBotStart/onBotEnd, or booth hooks)
-
end: After the conversation finished
restaurant
#begin
DUMMY_LOG_TESTCASE dbUrl | dbPassword
#me
hi
#bot
Hi. It looks like a nice drive today. What would you like me to do?
#me
where is the next restaurant
#bot
I understand you want me to find a location. I can find restaurants, gas stations and restrooms nearby.
#me
find my a restaurant
#bot
Of course. Do you have a specific cuisine in mind?
#me
DUMMY_INSERT_TO_SCRIPTING_MEMORY CUISINE1
$cuisine
#bot
Super! I've found 5 locations for you. Which one would you like to drive to?
#me
DUMMY_INSERT_TO_SCRIPTING_MEMORY CUISINE1 | CHOICE1
$choice
#bot
Sure! That restaurant gets great reviews.
#end
DUMMY_LOG_TESTCASE dbUrl | dbPassword
Comments
0 comments
Please sign in to leave a comment.