问题
edit: change topic to overriding basic functons on botium-webdriverio-connector
How to trigger button click ?
from this link: https://github.com/codeforequity-at/botium-core/wiki/Botium-Scripting
it says that you just need to put
#me
BUTTON btnTitle
but what actually happened is that it sends literal BUTTON btnTitle
as text to the bot
for context, i implemented a custom WEBDRIVERIO_GETBOTMESSAGE and send back this
{
"sender": "bot",
"buttons": [
{
"text": "reply1"
},
{
"text": "reply2"
}
],
"cards": [],
"media": []
}
回答1:
i decided to override the WEBDRIVERIO_SENDTOBOT function. running on botium-cli 0.0.44, probably there are better solutions on newer versions.
edit: add more details, source code & implementation
in the end, i override these functions WEBDRIVERIO_OPENBOT
WEBDRIVERIO_SENDTOBOT
WEBDRIVERIO_GETBOTMESSAGE
and also add a custom asserter to assert gallery messages
botium.json
{
"botium": {
"Capabilities": {
"PROJECTNAME": "Production Test",
"CONTAINERMODE": "webdriverio",
"WEBDRIVERIO_OPTIONS": {
"desiredCapabilities": {
"browserName": "chrome"
}
},
"WEBDRIVERIO_URL": "the bot url",
"WEBDRIVERIO_OPENBOT": "./actions/open_test",
"WEBDRIVERIO_IGNOREWELCOMEMESSAGES": 1,
"WEBDRIVERIO_SENDTOBOT": "./actions/send",
"WEBDRIVERIO_GETBOTMESSAGE": "./actions/parse_response",
"WEBDRIVERIO_START_SELENIUM": true,
"WEBDRIVERIO_START_SELENIUM_OPTS": {
"drivers": {
"chrome": {
"version": "2.36"
}
}
},
"ASSERTERS": [
{
"ref": "GALLERY",
"src": "./asserters/gallery",
"global": true
}
]
}
}
}
./actions/open_test
module.exports = (container, browser) => {
return browser
.waitForVisible('#toggle-chat', 20000)
.click('#toggle-chat') // click chat button
.pause(2000)
.waitForVisible('#get-started', 20000)
.click('#get-started') // click get started, initiate the chat
.pause(2000)
}
./actions/send
module.exports = (container, browser, msg) => {
if (msg.messageText && msg.messageText !== '' && msg.messageText.indexOf('BUTTON') !== 0) { // send text message
return browser
.waitForEnabled('#text-input', 10000)
.setValue('#text-input', msg.messageText)
.keys('Enter')
} else if (msg.messageText.indexOf('BUTTON') === 0) { // if message started with "BUTTON xxx", safe to assume the tester want to click button xxx
let buttonTitle = msg.messageText.split(' ')[1]
if (!buttonTitle) throw new Error('BUTTON invalid (1)')
return browser.waitForEnabled(`[chatmessagebuttontitle="${ buttonTitle }"]`, 10000)
.click(`[chatmessagebuttontitle="${ buttonTitle }"]`)
} else { // unhandled, send arbitary message
return browser
.waitForEnabled('#text-input', 10000)
.setValue('#text-input', 'unhandled')
.keys('Enter')
}
}
./actions/parse_response
module.exports = (container, browser, elementId) => {
const botMsg = { sender: 'bot', buttons: [], cards: [], media: [] }
/**
*
* ... parsing some html here to populate buttons, media and cards
* ... can't put all the code for security reasons, sorry
* ... here are example
*
* btw, elementId is NOT an html id attribute, so cannot query with "#" + elementId
* cannot find documentation for webdriver elementId, but this page helps
* http://v4.webdriver.io/api/protocol/elementIdElements.html
*
*/
browser.elementIdElements(elementId, '.bot-bubble')
.then(elements => elements.value)
.then(elements =>
Promise.all(
elements.map(element =>
browser.elementIdText(element.ELEMENT).then(text => text.value)
)
).then(messages => {
// i only need the first message, also this function only called for each bot message bubble, so safe to assume there is only 1 message
if (messages.length > 0) botMsg.messageText = messages[0]
// send the bot response back to botium
container.BotSays(botMsg)
})
)
}
./asserter/gallery
/**
* @typedef Card
* @property {String} image
* @property {String} title
* @property {String} subtitle
* @property {Array<String>} buttons
*
* @typedef BotMesage
* @property {Array<Card>} cards
*/
/**
* @typedef GalleryAssertStepParam
* @property {*} convo
* @property {Array<String>} args
* @property {BotMesage} botMsg
*/
module.exports = class GalleryAsserter {
/**
* this function is called whenever parse_response.js finishes
* @param {GalleryAssertStepParam} param
*/
assertConvoStep(param) {
let args = param.args
let botMsg = param.botMsg
// args needs to be an array, simple check
if (!args.concat) return Promise.reject(new Error('args for GALLERY is not an array'))
if (args.length > botMsg.cards.length) return Promise.reject(new Error('number of gallery cards doesnt match. expecting ' + args.length +'. Got ' + botMsg.cards.length))
// basic logic to check if the card that is passed from parse_response.js is equals to card that is written in test scripts
for (var i = 0; i < args.length; i++) {
// ParseGalleryString is a function that convert arbitary string to a Card object
// example of the arbitary string: "( title=some title, subtitle= some subtitle, image=image url, buttons=btn1, btn2, btn3 )"
// will be converted to JSON { title: "some title", subtitle: "some subtitle", ... }
let card = ParseGalleryString(args[i])
let testcard = botMsg.cards[i]
if (card.image !== testcard.image) return Promise.reject(new Error(`card[${i}] doesn't pass. expecting image to be ${ card.image }, got ${ testcard.image }`))
if (card.title !== testcard.title) return Promise.reject(new Error(`card[${i}] doesn't pass. expecting title to be ${ card.title }, got ${ testcard.title }`))
if (card.subtitle !== testcard.subtitle) return Promise.reject(new Error(`card[${i}] doesn't pass. expecting subtitle to be ${ card.subtitle }, got ${ testcard.subtitle }`))
if (card.buttons.length !== testcard.buttons.length) return Promise.reject(new Error(`card[${i}] doesn't pass. expecting ${ card.buttons.length }(${card.buttons.join(', ')}) buttons, got ${ testcard.buttons.length }(${testcard.buttons.join(', ')})`))
if (card.buttons.join('_') !== testcard.buttons.join('_')) return Promise.reject(new Error(`card[${i}] doesn't pass. expecting buttons to be ${ card.buttons.join(', ') }, got ${ testcard.buttons.join(', ') }`))
}
return Promise.resolve()
}
}
then to use the custom asserter testgallery.convo.txt
Test Gallery
#me
show me some cat breeds
#bot
here are some cat breeds
#bot
GALLERY (image=http://cat.pic/1.png, title=Alaskan Malmute, subtitle=This is actually not a cat, buttons=Pet, Give Food, Info) | (image=http://cat.pic/2.png, title=Cobra Kai, subtitle=This is actually a movie, buttons=Watch, Like, Dislike)
this setup works for botium-cli version 0.0.44 tried to update to botium 0.0.45 but got some error on selenium driver
回答2:
Triggering button clicks is part of Botium Core 1.4.8. For button clicks the result of WEBDRIVERIO_GETBOTMESSAGE is not considered, Botium just looks for button titles (source code with default selenium selector is here.
The described behaviour, that the literal text is sent to the bot, is most likely due to an older version of Botium Core. Please check the version you are using. If you are using version 1.4.8, please enable logging and extend your question with the log output.
来源:https://stackoverflow.com/questions/54645876/overriding-actions-for-botium-webdriverio-connector