Botium не запускает мой тест с правильным порядком (?) - PullRequest
0 голосов
/ 06 марта 2019

Это мой файл botium.json (измененный URL):

{
  "botium": {
    "Capabilities": {
      "PROJECTNAME": "Production Test",
      "CONTAINERMODE": "webdriverio",
      "WEBDRIVERIO_OPTIONS": {
        "desiredCapabilities": {
          "browserName": "chrome",
          "chromeOptions": {
            "args": [ "--headless", "--no-sandbox", "--disable--dev-shm-usage" ]
          } 
        }
      },
      "WEBDRIVERIO_URL": "https://example.com",
      "WEBDRIVERIO_OPENBOT": "./actions/open_test",
      "WEBDRIVERIO_IGNOREWELCOMEMESSAGES": 2,
      "WEBDRIVERIO_SENDTOBOT": "./actions/send",
      "WEBDRIVERIO_GETBOTMESSAGE": "./actions/parse_response",
      "WEBDRIVERIO_INPUT_ELEMENT": "#vc-input",
      "WEBDRIVERIO_INPUT_ELEMENT_SENDBUTTON": "#vc-btn-send",
      "WEBDRIVERIO_OUTPUT_ELEMENT": ".vcw-message-container",
      "WEBDRIVERIO_START_SELENIUM": true,
      "WEBDRIVERIO_START_SELENIUM_OPTS": {
        "drivers": {
          "chrome": {
            "version": "2.36"
          }
        }
      },
      "ASSERTERS": [
        {
          "ref": "GALLERY",
          "src": "./asserters/gallery",
          "global": true
        }
      ]
    }
  }
}

Ниже приведен файл, который я использовал для получения сообщения бота (parse_response.js)

let debug = (thing) => {
    console.log(thing)
}

module.exports = (container, browser, elementId) => {
    console.log('CHECKING ELEMENT', elementId)

    const botMsg = { sender: 'bot', buttons: [], cards: [], media: [] }

    Promise.resolve(1)
    .then(() => browser.elementIdAttribute(elementId, 'class'))
    .then(elemClass => elemClass.value.indexOf('from-me') > -1 ? Promise.reject(new Error('from-me')) : Promise.resolve(1))
    .then(() => console.log('FROM ME DECIDED', elementId))

    // get the images
    .then(() => browser.elementIdElement(elementId, '.vcw-message-bubble')
    // .then(elements => Promise.resolve(console.log('getting images', elementId)).then(() => elements))
    .then(elements => elements.value.ELEMENT))
    .then(buble => browser.elementIdElement(buble, 'img'))
    .then(img => img.value ? browser.elementIdAttribute(img.value.ELEMENT, 'src').then(src => botMsg.media.push({mediaUri: src.value})) : Promise.resolve())
    .catch(e => e.message === 'from-me' ? Promise.reject(e) : Promise.resolve(debug('no images: ' + elementId)))

    // get the audio
    .then(() => browser.elementIdElement(elementId, '.vcw-message-bubble').then(elements => elements.value.ELEMENT))
    .then(buble => browser.elementIdElement(buble, 'source'))
    .then(img => img.value ? browser.elementIdAttribute(img.value.ELEMENT, 'src').then(src => botMsg.media.push({mediaUri: src.value})) : Promise.resolve())
    .catch(e => e.message === 'from-me' ? Promise.reject(e) : Promise.resolve(debug('no audio: ' + elementId)))

    // get the video
    .then(() => browser.elementIdElement(elementId, '.vcw-message-bubble').then(elements => elements.value.ELEMENT))
    .then(buble => browser.elementIdElement(buble, 'source'))
    .then(img => img.value ? browser.elementIdAttribute(img.value.ELEMENT, 'src').then(src => botMsg.media.push({mediaUri: src.value})) : Promise.resolve())
    .catch(e => e.message === 'from-me' ? Promise.reject(e) : Promise.resolve(debug('no video: ' + elementId)))

    // get the buttons postback & quick replies
    .then(() => browser.elementIdElements(elementId, '.quick-reply').then(elements => elements.value))
    .then(elements => 
        Promise.all(
            elements.map(element => 
                browser.elementIdText(element.ELEMENT).then(text => Object.assign({text: text.value}))
            )
        ).then(replies => {
            botMsg.buttons = botMsg.buttons.concat(replies)
        })
    )
    .catch(e => e.message === 'from-me' ? Promise.reject(e) : Promise.resolve(debug('no qr: ' + elementId)))

    // get url buttons
    .then(() => browser.elementIdElements(elementId, '.vcw-message-button').then(elements => elements.value))
    .then(elements => 
        Promise.all(
            elements.map(element => 
                browser.elementIdText(element.ELEMENT).then(text => Object.assign({text: text.value}))
            )
        ).then(replies => {
            botMsg.buttons = botMsg.buttons.concat(replies)
        })
    )
    .catch(e => e.message === 'from-me' ? Promise.reject(e) : Promise.resolve(debug('no btn: ' + elementId)))

    // get the gallery cards
    .then(() => 
        browser.elementIdElements(elementId, '.vcw-card')
        // .then(xx => Promise.resolve(console.log('GALLERY', xx)).then(() => xx))
        .then(elements => elements.value)
    )
    .then(elements => 
        Promise.all(
            elements.map(
                element => {
                    let card = { buttons: [] }
                    return browser.elementIdElement(element.ELEMENT, 'img')

                    .then(elem => elem.value ? browser.elementIdAttribute(elem.value.ELEMENT, 'src') : Object.assign({ }))
                    // .then(imgElem => )

                    .then(src => card.image = src.value)
                    .then(() => browser.elementIdElement(element.ELEMENT, '.vcw-card-text-title'))

                    .then(elem => elem.value ? browser.elementIdText(elem.value.ELEMENT) : Object.assign({}))
                    // .then(titleElem => )

                    .then(title => card.title = title.value)
                    .then(() => browser.elementIdElement(element.ELEMENT, '.vcw-card-text-subtitle'))

                    .then(elem => elem.value ? browser.elementIdText(elem.value.ELEMENT) : Object.assign({}))
                    // .then(subtitleElem => )

                    .then(subtitle => card.subtitle = subtitle.value)                    
                    .then(() => browser.elementIdElement(element.ELEMENT, '.vcw-card-button-wrapper'))

                    .then(elem => elem.value.ELEMENT)
                    .then(wrapperElement => browser.elementIdElements(wrapperElement, '.vcw-card-button'))

                    .then(elem => elem.value)
                    .then(buttons => 
                        Promise.all(
                            buttons.map(button => browser.elementIdText(button.ELEMENT)
                            .then(text => text.value))
                        )
                        .then(buttons => card.buttons = buttons)
                    )
                    .then(() => card)
                    .catch(e => {
                        console.log(e)
                    })
                }
            )
        ).then(cards => botMsg.cards = cards)
    )
    .catch(e => e.message === 'from-me' ? Promise.reject(e) : Promise.resolve(debug('no gallery: ' + elementId)))

    // get the message
    .then(() => browser.elementIdElements(elementId, '.vcw-message-bubble').then(elements => elements.value)
    )
    .then(elements => 
        Promise.all(
            elements.map(element => 
                browser.elementIdText(element.ELEMENT).then(text => text.value)
            )
        ).then(messages => {
            if (messages.length > 0) botMsg.messageText = messages[0]
        })
    )
    .catch(e => e.message === 'from-me' ? Promise.reject(e) : Promise.resolve(debug('no text: ' + elementId + ' | ' + e.message)))

    .then(() => {
        if (botMsg.buttons.length > 0 && !botMsg.messageText) { // qr only
            setTimeout(() => {
                container.BotSays(botMsg)
            }, 1000)
        } else {
            container.BotSays(botMsg)
        }
    })
    .catch(err => {
        if (err.message === 'from-me') {
            return Promise.resolve(1)
        }
        console.log('error', elementId, err)
        return Promise.reject(err)
    })
}

Используемый файлдля галереи assert:

const ParseGalleryString = (galleryString) => {

    let tokens = galleryString.match(reg)
    if (!tokens) return {}

    /** @type {Card} */
    let card = {}

    tokens.forEach(token => {
        let ctoken = token.replace(/\[/g, '').replace(/\]/g, '')
        let vals = ctoken.split(':')
        let key = vals[0]
        let val = vals[1]

        if (val) {
            vals.splice(0, 1)
            val = vals.join(':')
        }

        if (!key) return

        if (key === 'buttons') val = val.split(',').map(v => v.trim())
        else val = val.trim()

        card[key] = val
    })

    if (!card.buttons) card.buttons = []

    return card
}

module.exports = class GalleryAsserter {

    /**
     * 
     * @param {GalleryAssertStepParam} param
     */
    assertConvoStep(param) {
        let args = param.args
        let botMsg = param.botMsg

        if (args[0] === 'skip') return Promise.resolve()

        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))

        for (var i = 0; i < args.length; i++) {
            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()
    }

}

И мой файл convo:

#me
Find events

#bot
Please wait as I retrieve our list of events. Alternatively, you may find out more
BUTTONS More

#bot
Showing all events at all libraries

#bot
GALLERY skip

#bot
Would you like to add to or change your search filters?

#bot
BUTTONS Category | Language | Library | Clear All Filters | Cancel

что мне показывал --verbose:

    2019-03-06T13:13:41.964Z botium-Convo Mobile Part 1/Line 68: user says {
  "sender": "me",
  "channel": null,
  "messageText": "Find events",
  "stepTag": "Line 68",
  "not": false,
  "asserters": [],
  "logicHooks": []
}
2019-03-06T13:13:41.965Z botium-connector-webdriverio UserSays called BotiumMockMessage {
  sender: 'me',
  channel: null,
  messageText: 'Find events',
  media: null,
  buttons: null,
  cards: null,
  sourceData: undefined,
  sourceAction: undefined,
  attachments: null }
2019-03-06T13:13:43.649Z botium-Convo Mobile Part 1 wait for bot null
2019-03-06T13:13:43.710Z botium-connector-webdriverio Found new bot response element .vcw-message-container, id 0.4377955000683098-61
CHECKING ELEMENT 0.4377955000683098-61
2019-03-06T13:13:43.711Z botium-connector-webdriverio polling for bot output (.vcw-message-container)
2019-03-06T13:13:44.255Z botium-connector-webdriverio Found new bot response element .vcw-message-container, id 0.4377955000683098-62
CHECKING ELEMENT 0.4377955000683098-62
2019-03-06T13:13:44.255Z botium-connector-webdriverio polling for bot output (.vcw-message-container)
FROM ME DECIDED 0.4377955000683098-62
2019-03-06T13:13:44.531Z botium-connector-webdriverio BotSays called { sender: 'bot',
  buttons: [ { text: 'More' } ],
  cards: [],
  media: [],
  messageText: 'Please wait as I retrieve our list of events. Alternatively, you may find out more' }
2019-03-06T13:13:44.531Z botium-Convo Mobile Part 1: bot says {
  "sender": "bot",
  "buttons": [
    {
      "text": "More"
    }
  ],
  "cards": [],
  "media": [],
  "messageText": "Please wait as I retrieve our list of events. Alternatively, you may find out more",
  "channel": "default"
}
2019-03-06T13:13:44.532Z botium-ScriptingProvider assertBotResponse Mobile Part 1/Line 71 (Line 68: #me - Find events  ) BOT: Please wait as I retrieve our list of events. Alternatively, you may find out more = Please wait as I retrieve our list of events. Alternatively, you may find out more ...
2019-03-06T13:13:44.532Z botium-Convo Mobile Part 1 wait for bot null
2019-03-06T13:13:45.842Z botium-connector-webdriverio Found new bot response element .vcw-message-container, id 0.4377955000683098-65
CHECKING ELEMENT 0.4377955000683098-65
2019-03-06T13:13:45.843Z botium-connector-webdriverio polling for bot output (.vcw-message-container)
FROM ME DECIDED 0.4377955000683098-65
2019-03-06T13:13:46.126Z botium-connector-webdriverio BotSays called { sender: 'bot',
  buttons: [],
  cards: [],
  media: [],
  messageText: 'Showing all events at all libraries' }
2019-03-06T13:13:46.126Z botium-Convo Mobile Part 1: bot says {
  "sender": "bot",
  "buttons": [],
  "cards": [],
  "media": [],
  "messageText": "Showing all events at all libraries",
  "channel": "default"
}
2019-03-06T13:13:46.126Z botium-ScriptingProvider assertBotResponse Mobile Part 1/Line 75 (Line 68: #me - Find events  ) BOT: Showing all events at all libraries = Showing all events at all libraries ...
2019-03-06T13:13:46.127Z botium-Convo Mobile Part 1 wait for bot null
2019-03-06T13:13:46.376Z botium-connector-webdriverio Found new bot response element .vcw-message-container, id 0.4377955000683098-67
CHECKING ELEMENT 0.4377955000683098-67
2019-03-06T13:13:46.377Z botium-connector-webdriverio polling for bot output (.vcw-message-container)
FROM ME DECIDED 0.4377955000683098-67
no images: 'image_url',
no audio: 0.4377955000683098-67
no video: 0.4377955000683098-67
2019-03-06T13:13:47.124Z botium-connector-webdriverio Found new bot response element .vcw-message-container, id 0.4377955000683098-82
CHECKING ELEMENT 0.4377955000683098-82
2019-03-06T13:13:47.124Z botium-connector-webdriverio polling for bot output (.vcw-message-container)
FROM ME DECIDED 0.4377955000683098-82
2019-03-06T13:13:47.500Z botium-connector-webdriverio Found new bot response element .vcw-message-container, id 0.4377955000683098-89
CHECKING ELEMENT 0.4377955000683098-89
2019-03-06T13:13:47.501Z botium-connector-webdriverio polling for bot output (.vcw-message-container)
FROM ME DECIDED 0.4377955000683098-89
no images: 'image_url',
no audio: 0.4377955000683098-89
no video: 0.4377955000683098-89
2019-03-06T13:13:49.335Z botium-connector-webdriverio BotSays called { sender: 'bot',
  buttons: [],
  cards: [],
  media: [],
  messageText: 'Would you like to add to or change your search filters?' }
2019-03-06T13:13:49.335Z botium-Convo Mobile Part 1: bot says {
  "sender": "bot",
  "buttons": [],
  "cards": [],
  "media": [],
  "messageText": "Would you like to add to or change your search filters?",
  "channel": "default"
}
2019-03-06T13:13:49.335Z botium-Convo Mobile Part 1 wait for bot null
2019-03-06T13:13:49.352Z botium-connector-webdriverio BotSays called { sender: 'bot',
  buttons: [],
  cards: 
   [ { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
     { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
     { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
     { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
     { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
     { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
     { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
     { buttons: [Array],
       image:  'image_url',
       title: 'title',
       subtitle: 'subtitle'
  media: [] }
2019-03-06T13:13:49.352Z botium-Convo Mobile Part 1: bot says {
  "sender": "bot",
  "buttons": [],
  "cards": [
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    },
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    },
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    },
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    },
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    },
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    },
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    },
    {
      "buttons": [
        "Find Out More",
        "Description"
      ],
      "image": 'image_url',
      "title":'title',
      "subtitle":'subtitle'
    }
  ],
  "media": [],
  "channel": "default"
}
2019-03-06T13:13:49.352Z botium-ScriptingProvider assertBotResponse Mobile Part 1/Line 81 (Line 68: #me - Find events  ) BOT: undefined = Would you like to add to or change your search filters? ...
2019-03-06T13:13:49.353Z botium-cli-run Mobile Part 1 failed: { TranscriptError: Error: Mobile Part 1/Line 81: Expected bot response (on Line 68: #me - Find events  ) "undefined" to match one of "Would you like to add to or change your search filters?"

Мой порядок проверки файла convo был вернымбот будет отвечать на основе этого порядка при ручном тестировании.

Но, основываясь на журнале от --verbose, в последней строке возникла эта ошибка: "undefined = Вы хотите добавить к илиизменить фильтры поиска? "А также из журнала кажется, что бот ответил так:

  1. "Отображение всех событий"
  2. "Хотите добавить или изменить фильтры поиска?"
  3. Галерея.

Неопределенная ошибка была правильной, если последним, кто ответил ботом, была галерея.Вопрос в том, почему бот не отвечает в правильном порядке (как это было при ручном тестировании), если я запускаю с botium?

1 Ответ

0 голосов
/ 11 марта 2019

Botium действительно заботится о том, чтобы идентифицированные элементы обрабатывались подряд, объединяя в цепочку обещания обработки ( здесь - это код).

Проблема, похоже, находится в вашем parse_response.js - он на самом деле ничего не возвращает, поэтому цепочка обработки не может ждать. Попробуйте добавить оператор return при запуске цепочки Promise:

...
module.exports = (container, browser, elementId) => {
    console.log('CHECKING ELEMENT', elementId)

    const botMsg = { sender: 'bot', buttons: [], cards: [], media: [] }

    return Promise.resolve(1)
    ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...