├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin └── botium-bindings.js ├── docs ├── architecture_nodocker.png ├── architecture_nodocker.xml ├── architecture_withdocker.png ├── architecture_withdocker.xml ├── botium-logo.png ├── manual │ ├── ide_chat.png │ └── ide_savetestcase.png ├── screenshots │ ├── chat.png │ └── ide_demo.png ├── testmybot_logo.jpg.jpg ├── testmybot_logo.pdf ├── testmybot_logo.png.png ├── testmybot_logo_fbheader.png └── testmybot_logo_square.png ├── index.js ├── package.json ├── report.js ├── rollup.config.js ├── samples └── hello │ ├── botium.json │ ├── package.json │ └── spec │ ├── botium.spec.js │ └── convo │ ├── give_me_a_picture.convo.txt │ ├── shopping_cart.convo.txt │ ├── should_fail.convo.txt │ └── should_fail_delivery.convo.txt └── src ├── BotiumBindings.js ├── cli └── index.js ├── helpers ├── jasmine.js ├── jest.js └── mocha.js └── metrics.js /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/* 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "standard" 3 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | botiumwork 61 | dist 62 | package-lock.json -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Guidelines for posting issues 2 | 3 | * Please review the [Troubleshooting Guide in the Botium Wiki](https://github.com/codeforequity-at/botium-core/wiki/Troubleshooting) 4 | * In case you have some troubles, please __ALWAYS__ attach the debug output from Botium (see "Enable Logging" in the Troubleshooting Guide) 5 | * Please don't post any secret information (like access keys for Dialogflow or IBM Watson) 6 | 7 | # Guidelines for code contributions 8 | 9 | Of course, code contributions are welcome! 10 | 11 | * Please fork the repository 12 | * Please create an issue and refer to it in the pull request 13 | * The NPM script "npm run build" has to succeed before posting a pull request 14 | ** it will enforce eslint and rollup build 15 | 16 | These points are subject to possible change at any time. 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Code For Equity 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Botium Bindings 2 | =============== 3 | 4 | [![NPM](https://nodei.co/npm/botium-bindings.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/botium-bindings/) 5 | 6 | [ ![Codeship Status for codeforequity-at/botium-bindings](https://app.codeship.com/projects/077a7140-3175-0135-cee8-5eb28f78bdf5/status?branch=master)](https://app.codeship.com/projects/225703) 7 | [![npm version](https://badge.fury.io/js/botium-bindings.svg)](https://badge.fury.io/js/botium-bindings) 8 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() 9 | [![docs](https://readthedocs.org/projects/botium-docs/badge/)](https://botium-docs.readthedocs.io/) 10 | 11 | **UPDATE 2020/11/05:** Botium has a FREE, hosted plan available! The new Botium Box Mini is our ❤️ to the community. [Take it for a test drive 🚗 ...](https://www.botium.ai/pricing/) 12 | 13 | [![](http://img.youtube.com/vi/ciVxojvRfng/0.jpg)](https://www.youtube.com/watch?v=ciVxojvRfng "Botium Box Mini") 14 | 15 | __This project was formerly known as "TestMyBot" - same scope, different name__ 16 | 17 | Botium is the Selenium for chatbots. Botium Bindings is the glue to bind Botium to test runners like Mocha, Jasmine and Jest. 18 | 19 | # Documentation 20 | 21 | See [here](https://botium-docs.readthedocs.io/) for Botium documentation. 22 | -------------------------------------------------------------------------------- /bin/botium-bindings.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const yargsCmd = require('yargs') 3 | 4 | const handleConfig = (argv) => { 5 | argv.verbose = argv.v = process.env.BOTIUM_VERBOSE === '1' || argv.verbose 6 | 7 | if (argv.verbose) { 8 | require('debug').enable('botium*') 9 | } 10 | 11 | return true 12 | } 13 | 14 | const wrapHandler = (builder) => { 15 | const origHandler = builder.handler 16 | builder.handler = (argv) => { 17 | if (handleConfig(argv)) { 18 | origHandler(argv) 19 | } 20 | } 21 | return builder 22 | } 23 | 24 | yargsCmd.usage('Botium Bindings\n\nUsage: $0 [options]') // eslint-disable-line 25 | .help('help').alias('help', 'h') 26 | .version('version', require('../package.json').version).alias('version', 'V') 27 | .showHelpOnFail(true) 28 | .strict(true) 29 | .demandCommand(1, 'You need at least one command before moving on') 30 | .command(wrapHandler(require('../src/cli'))) 31 | .option('verbose', { 32 | alias: 'v', 33 | describe: 'Enable verbose output (also read from env variable "BOTIUM_VERBOSE" - "1" means verbose)', 34 | default: false 35 | }) 36 | .argv 37 | -------------------------------------------------------------------------------- /docs/architecture_nodocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/architecture_nodocker.png -------------------------------------------------------------------------------- /docs/architecture_nodocker.xml: -------------------------------------------------------------------------------- 1 | 5Vhbb9s6DP41eYzhS+ykj2m7bAc4OyjQA2x7KhRbtrXKliHLSbpfP+rmxJc0aZsOBdagsElJtvh9JEV6EtwUu88cVflXlmA68d1kNwluJ77vuW4EF6l50prIW2hFxkliJu0V9+QXtiuNtiEJrjsTBWNUkKqrjFlZ4lh0dIhztu1OSxntvrVCGR4o7mNEh9pvJBG51i78aK//gkmW2zd70ZUeWaP4MeOsKc37Jn6Qqj89XCD7LGNonaOEbQ9UwadJcMMZE/qu2N1gKrG1sOl1qyOj7b45LsU5C+SYXLFBtMF2y2pj4smCASsAdxCuYbeVVMaUNfCA621OBL6vUCyVW3AF0OWioCB5cDvcjNnfBnOBdwcqs7nPmBVY8CeYYkbnZsV2z0IwN9jlBwwErlEiw3zWPmpvPdwYAI6g550GQ5JbnW9Y66JobZ/gPmtwGBlDTOQs3AEAXjQCgOdfAIAXOcPLyT+f/T9ibXDaWuvwpFAJ41pdl3Wlc44LGmSFlOywjAlpHYFM8i9aY3rHaiIIK2F8zYRgxcGEJSWZHBCssk8GKRcCxKU0wl/VAsFUJyMZchIMim01BX8SElJ/1VSUoaSGO9/1pNkuoLlalglnJJlSljGnKrO3UmH9Muy4pTd0y3CEp/ACNM0+Kk11y5NmwtmSR1LghCCH8UyyBXIlZbiPWVGwUpIl8qZYwzWR/3BsrP6D49P5WT8oxupNpgh13Wo37Y9ckM/gqsNnFA74XPjvw6d3XtzpY1Fyl6A6l5wp4SDD1IKzR3zDKOOgKVkpqU8JpVYFh2/oyh/oaY/nGLDD/PWOYF2u2GWyBHJYmpIYQ5Ru4FI7Mdj8UOWwpwekA/IBgrlMENXbvMDR6Lndk2LsqJiNxOTiEhyeEZQngR3E5AG3R0AfY7zPREwEJztnLatAxfAFsG5BM1gHI/lvNnfCIdpz32rfhPf8jJO5TJay9FX1GaprEivEEBdD9QHSeEfEdxlcztwPjfxDyS5EqpbvMIfEpuJFBSEAyZ++Hwo/TpV8NWt4bKtrkwFgbxm2mUWrcNIpzJ+tDJ47cDimcHRuuuX8GAPmDXeMyDO1ja1eFTYLekGjzTGrDuvr3oPag9I6Tj/6NAaDBymHaM0+z0cW7+cjlm/vdXzP/h6+r/xuUvbejW9/2K2soBhfM/YI2q+4rnGZQcj67vLun6MlU8Ia6EwM+3+goQt6AeG5V4NMOsp0dIn+JjodIu/d4HlhF4D50P72a8LFW57wjBTx+gavhfeDNHjW1T5y65CakF1zqA4d6BL6XZ7IcYFl35Cup2oSKWWHUPGf064G8jYWcqJ6kVkBmf1o0/ACuo40gcOmIfRGcvQz6fjsyB0WnJ1OWZd+FkyNY49psFF0PZjjmvwycauYbgSwqb5FymFk6KM4FcdLUogPwP9/KdxOZ6CpZG5XpobXk/BW9iRA5r3ZiGdl8543R5IZ7bVz0UhSGQmzV0QZiPvPk/rY2n8DDj79Bg== -------------------------------------------------------------------------------- /docs/architecture_withdocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/architecture_withdocker.png -------------------------------------------------------------------------------- /docs/architecture_withdocker.xml: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /docs/botium-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/botium-logo.png -------------------------------------------------------------------------------- /docs/manual/ide_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/manual/ide_chat.png -------------------------------------------------------------------------------- /docs/manual/ide_savetestcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/manual/ide_savetestcase.png -------------------------------------------------------------------------------- /docs/screenshots/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/screenshots/chat.png -------------------------------------------------------------------------------- /docs/screenshots/ide_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/screenshots/ide_demo.png -------------------------------------------------------------------------------- /docs/testmybot_logo.jpg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/testmybot_logo.jpg.jpg -------------------------------------------------------------------------------- /docs/testmybot_logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/testmybot_logo.pdf -------------------------------------------------------------------------------- /docs/testmybot_logo.png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/testmybot_logo.png.png -------------------------------------------------------------------------------- /docs/testmybot_logo_fbheader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/testmybot_logo_fbheader.png -------------------------------------------------------------------------------- /docs/testmybot_logo_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeforequity-at/botium-bindings/9e7a69b83914924726559fbe611eb4080437b13c/docs/testmybot_logo_square.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/BotiumBindings') 2 | 3 | module.exports.helper = { 4 | jasmine: () => require('./src/helpers/jasmine'), 5 | jest: () => require('./src/helpers/jest'), 6 | mocha: () => require('./src/helpers/mocha') 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "botium-bindings", 3 | "version": "2.1.15", 4 | "engines": { 5 | "node": ">=14" 6 | }, 7 | "bin": { 8 | "botium-bindings": "./bin/botium-bindings.js" 9 | }, 10 | "scripts": { 11 | "postinstall": "node ./report.js", 12 | "build": "npm run eslint && rollup -c", 13 | "eslint": "eslint \"./bin/**/*.js\" \"./src/**/*.js\"", 14 | "eslint:fix": "eslint --fix \"./bin/**/*.js\" \"./src/**/*.js\"", 15 | "test": "echo \"no tests specified\" && exit 0", 16 | "update-dependencies": "npm-check-updates --reject rollup -u --timeout 120000" 17 | }, 18 | "description": "Binding Botium, the Selenium for Chatbots, to test runners", 19 | "main": "index.js", 20 | "author": "Botium GmbH", 21 | "license": "MIT", 22 | "dependencies": { 23 | "@babel/runtime": "^7.21.0", 24 | "async": "^3.2.4", 25 | "botium-core": "1.13.16", 26 | "debug": "^4.3.4", 27 | "lodash": "^4.17.21", 28 | "mkdirp": "^3.0.0", 29 | "promise-retry": "^2.0.1", 30 | "yargs": "^17.7.1" 31 | }, 32 | "devDependencies": { 33 | "@babel/core": "^7.21.4", 34 | "@babel/node": "^7.20.7", 35 | "@babel/plugin-transform-runtime": "^7.21.4", 36 | "@babel/preset-env": "^7.21.4", 37 | "eslint": "^8.38.0", 38 | "eslint-config-standard": "^17.0.0", 39 | "eslint-plugin-import": "^2.27.5", 40 | "eslint-plugin-n": "^15.7.0", 41 | "eslint-plugin-promise": "^6.1.1", 42 | "eslint-plugin-standard": "^5.0.0", 43 | "license-checker": "^25.0.1", 44 | "npm-check-updates": "^16.10.8", 45 | "rollup": "^2.60.0", 46 | "rollup-plugin-babel": "^4.4.0", 47 | "rollup-plugin-commonjs": "^10.1.0", 48 | "rollup-plugin-json": "^4.0.0", 49 | "rollup-plugin-node-resolve": "^5.2.0" 50 | }, 51 | "repository": { 52 | "type": "git", 53 | "url": "git+https://github.com/codeforequity-at/botium-bindings.git" 54 | }, 55 | "keywords": [ 56 | "continuous", 57 | "testing", 58 | "chatbot" 59 | ], 60 | "bugs": { 61 | "url": "https://github.com/codeforequity-at/botium-core/issues" 62 | }, 63 | "homepage": "https://www.botium.ai" 64 | } 65 | -------------------------------------------------------------------------------- /report.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const os = require('os') 3 | 4 | const botiumAnalyticsHost = process.env.BOTIUM_ANALYTICS_HOST || 'v1.license.botium.cyaraportal.us' 5 | const botiumAnalyticsPort = process.env.BOTIUM_ANALYTICS_PORT || 443 6 | const https = botiumAnalyticsPort === 443 ? require('https') : require('http') 7 | const execTimeout = 10000 8 | 9 | function logIfVerbose (toLog, stream) { 10 | if (process.env.BOTIUM_ANALYTICS_VERBOSE === 'true') { 11 | (stream || console.log)(toLog) 12 | } 13 | } 14 | 15 | async function reportPostInstall () { 16 | if (process.env.BOTIUM_ANALYTICS === 'false') return 17 | 18 | const packageJson = require(path.join(__dirname, 'package.json')) 19 | 20 | const infoPayload = { 21 | rawPlatform: os.platform(), 22 | rawArch: os.arch(), 23 | library: packageJson.name, 24 | version: packageJson.version 25 | } 26 | 27 | const data = JSON.stringify(infoPayload) 28 | logIfVerbose(`Botium analytics payload: ${data}`) 29 | 30 | const reqOptions = { 31 | host: botiumAnalyticsHost, 32 | port: botiumAnalyticsPort, 33 | method: 'POST', 34 | path: '/metrics/installation/core', 35 | headers: { 36 | 'Content-Type': 'application/json', 37 | 'Content-Length': data.length 38 | }, 39 | timeout: execTimeout 40 | } 41 | await new Promise((resolve, reject) => { 42 | const req = https.request(reqOptions, (res) => { 43 | logIfVerbose(`Response status: ${res.statusCode}`) 44 | resolve() 45 | }) 46 | 47 | req.on('error', error => { 48 | logIfVerbose(error, console.error) 49 | reject(error) 50 | }) 51 | 52 | req.on('timeout', error => { 53 | logIfVerbose(error, console.error) 54 | reject(error) 55 | }) 56 | 57 | req.write(data) 58 | req.end() 59 | }) 60 | } 61 | 62 | if (require.main === module) { 63 | try { 64 | reportPostInstall().catch(e => { 65 | logIfVerbose(`\n\n${e}`, console.error) 66 | }).finally(() => { 67 | process.exit(0) 68 | }) 69 | } catch (e) { 70 | logIfVerbose(`\n\nTop level error: ${e}`, console.error) 71 | process.exit(0) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import json from 'rollup-plugin-json' 4 | 5 | export default { 6 | input: 'index.js', 7 | output: [ 8 | { 9 | file: 'dist/botium-bindings-es.js', 10 | format: 'es', 11 | sourcemap: true 12 | }, 13 | { 14 | file: 'dist/botium-bindings-cjs.js', 15 | format: 'cjs', 16 | sourcemap: true 17 | } 18 | ], 19 | plugins: [ 20 | commonjs({ 21 | exclude: 'node_modules/**' 22 | }), 23 | babel({ 24 | exclude: 'node_modules/**', 25 | runtimeHelpers: true 26 | }), 27 | json() 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /samples/hello/botium.json: -------------------------------------------------------------------------------- 1 | { 2 | "botium": { 3 | "Capabilities": { 4 | "PROJECTNAME": "hello", 5 | "CONTAINERMODE": "echo", 6 | "RETRY_CONVO_ONERROR_REGEXP": [ "delivery failure" ], 7 | "RETRY_CONVO_NUMRETRIES": 2 8 | }, 9 | "Sources": {}, 10 | "Envs": {} 11 | } 12 | } -------------------------------------------------------------------------------- /samples/hello/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "postinstall": "cd ../../ && npm install --no-save botium-connector-echo && cd samples/hello", 6 | "test": "mocha spec" 7 | }, 8 | "botium": { 9 | "convodirs": [ 10 | "spec/convo" 11 | ], 12 | "expandConvos": true, 13 | "expandUtterancesToConvos": false, 14 | "expandScriptingMemoryToConvos": false 15 | }, 16 | "devDependencies": { 17 | "mocha": "latest", 18 | "botium-bindings": "../..", 19 | "botium-connector-echo": "latest" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/hello/spec/botium.spec.js: -------------------------------------------------------------------------------- 1 | const bb = require('botium-bindings') 2 | bb.helper.mocha().setupMochaTestSuite() 3 | -------------------------------------------------------------------------------- /samples/hello/spec/convo/give_me_a_picture.convo.txt: -------------------------------------------------------------------------------- 1 | give me picture 2 | 3 | #me 4 | Hello, Bot! 5 | 6 | #bot 7 | You said: Hello, Bot! 8 | 9 | #me 10 | give me a picture 11 | 12 | #bot 13 | Here is a picture 14 | MEDIA logo.png 15 | -------------------------------------------------------------------------------- /samples/hello/spec/convo/shopping_cart.convo.txt: -------------------------------------------------------------------------------- 1 | shopping cart 2 | 3 | #me 4 | add to cart bananas 5 | 6 | #bot 7 | INTENT addtocart 8 | INTENT_CONFIDENCE 50 9 | ENTITIES product|.. 10 | ENTITY_VALUES bananas|.. 11 | 12 | #me 13 | show cart 14 | 15 | #bot 16 | In your cart: bananas 17 | INTENT showcart 18 | INTENT_CONFIDENCE 50 19 | 20 | #me 21 | clear cart 22 | 23 | #bot 24 | INTENT clearcart 25 | INTENT_CONFIDENCE 50 26 | -------------------------------------------------------------------------------- /samples/hello/spec/convo/should_fail.convo.txt: -------------------------------------------------------------------------------- 1 | should fail because weak intent 2 | 3 | #me 4 | weak intent 5 | 6 | #bot 7 | INTENT weak 8 | INTENT_CONFIDENCE 50 -------------------------------------------------------------------------------- /samples/hello/spec/convo/should_fail_delivery.convo.txt: -------------------------------------------------------------------------------- 1 | should fail because delivery failure 2 | 3 | #me 4 | fail 5 | 6 | #bot 7 | -------------------------------------------------------------------------------- /src/BotiumBindings.js: -------------------------------------------------------------------------------- 1 | const util = require('util') 2 | const path = require('path') 3 | const promiseRetry = require('promise-retry') 4 | const debug = require('debug')('botium-bindings-main') 5 | const { reportUsage } = require('./metrics') 6 | 7 | const { BotDriver, RetryHelper } = require('botium-core') 8 | 9 | module.exports = class BotiumBindings { 10 | constructor ({ botiumConfig, ...args } = {}) { 11 | args = Object.assign({}, this.getPackageJsonBotiumSection(), args) 12 | debug(`Botium Bindings args: ${util.inspect(args)}`) 13 | 14 | this.convodirs = args.convodirs || ['./spec/convo'] 15 | this.expandConvos = Object.prototype.hasOwnProperty.call(args, 'expandConvos') ? args.expandConvos : true 16 | this.expandUtterancesToConvos = Object.prototype.hasOwnProperty.call(args, 'expandUtterancesToConvos') ? args.expandUtterancesToConvos : false 17 | this.expandScriptingMemoryToConvos = Object.prototype.hasOwnProperty.call(args, 'expandScriptingMemoryToConvos') ? args.expandScriptingMemoryToConvos : false 18 | 19 | this.driver = new BotDriver(botiumConfig && botiumConfig.Capabilities, botiumConfig && botiumConfig.Sources, botiumConfig && botiumConfig.Envs) 20 | this.compiler = this.driver.BuildCompiler() 21 | this.container = null 22 | } 23 | 24 | getPackageJsonBotiumSection () { 25 | try { 26 | return require(path.resolve(process.cwd(), 'package.json')).botium || {} 27 | } catch (e) { 28 | } 29 | return {} 30 | } 31 | 32 | getTestSuiteName () { 33 | try { 34 | const botiumJson = require(process.env.BOTIUM_CONFIG || path.resolve(process.cwd(), 'botium.json')) 35 | return botiumJson.botium.Capabilities.PROJECTNAME 36 | } catch (e) { 37 | } 38 | let packageJson = null 39 | try { 40 | packageJson = require(path.resolve(process.cwd(), 'package.json')) 41 | return 'Botium Test Suite for ' + packageJson.name 42 | } catch (e) { 43 | } 44 | return 'Botium Test Suite' 45 | } 46 | 47 | async beforeAll () { 48 | this.container = await this.driver.Build() 49 | } 50 | 51 | async afterAll () { 52 | if (this.container) { 53 | await this.container.Clean() 54 | } 55 | this.container = null 56 | } 57 | 58 | async beforeEach () { 59 | if (this.container) { 60 | await this.container.Start() 61 | } else { 62 | throw new Error('Botium Initialization failed. Please see error messages above (enable debug logging).') 63 | } 64 | } 65 | 66 | async afterEach () { 67 | if (this.container) { 68 | await this.container.Stop() 69 | } 70 | } 71 | 72 | wrapBotiumError (err) { 73 | if (err.cause && err.cause.prettify) { 74 | return new Error(err.message + '\r\n' + err.cause.prettify()) 75 | } else { 76 | return new Error(err.message) 77 | } 78 | } 79 | 80 | setupTestSuite (testcaseCb, assertCb, failCb) { 81 | if (this.convodirs && this.convodirs.length) { 82 | this.convodirs.forEach((convodir) => { 83 | this.compiler.ReadScriptsFromDirectory(convodir) 84 | }) 85 | } 86 | if (this.expandUtterancesToConvos) { 87 | this.compiler.ExpandUtterancesToConvos() 88 | } 89 | if (this.expandScriptingMemoryToConvos) { 90 | this.compiler.ExpandScriptingMemoryToConvos() 91 | } 92 | if (this.expandConvos || this.expandUtterancesToConvos || this.expandScriptingMemoryToConvos) { 93 | this.compiler.ExpandConvos() 94 | } 95 | 96 | const usageMetrics = { 97 | metric: 'testexecution', 98 | connector: `${this.compiler.caps.CONTAINERMODE}`, 99 | projectname: `${this.compiler.caps.PROJECTNAME}`, 100 | convoCount: this.compiler.convos.length, 101 | convoStepCount: this.compiler.convos.reduce((sum, convo) => sum + convo.conversation.length, 0), 102 | partialConvoCount: Object.keys(this.compiler.partialConvos).length, 103 | utterancesRefCount: Object.keys(this.compiler.utterances).length, 104 | utterancesCount: Object.keys(this.compiler.utterances).reduce((sum, uttName) => sum + this.compiler.utterances[uttName].utterances.length, 0), 105 | scriptingMemoriesCount: this.compiler.scriptingMemories.length 106 | } 107 | reportUsage(usageMetrics) 108 | 109 | debug(`ready reading convos and utterances, number of test cases: (${this.compiler.convos.length}).`) 110 | 111 | if (assertCb) { 112 | this.compiler.scriptingEvents.assertBotResponse = assertCb 113 | } 114 | if (failCb) { 115 | this.compiler.scriptingEvents.fail = failCb 116 | } 117 | 118 | this.compiler.convos.forEach((convo) => { 119 | debug(`adding test case ${convo.header.toString()}`) 120 | testcaseCb(convo, (testcaseDone) => { 121 | if (this.container) { 122 | debug(`running testcase${convo.header.toString()}`) 123 | 124 | const retryHelper = new RetryHelper(this.container.caps, 'CONVO') 125 | promiseRetry(async (retry, number) => { 126 | try { 127 | await convo.Run(this.container) 128 | } catch (err) { 129 | if (retryHelper.shouldRetry(err)) { 130 | debug(`Running Convo "${convo.header.name}" trial #${number} failed, retry activated`) 131 | await this.container.Stop() 132 | await this.container.Start() 133 | debug(`Restarting container for Convo "${convo.header.name}" trial #${number} completed successfully.`) 134 | retry(err) 135 | } else { 136 | debug(`Running Convo "${convo.header.name}" trial #${number} failed finally`) 137 | throw err 138 | } 139 | } 140 | }, retryHelper.retrySettings) 141 | .then(() => { 142 | debug(`Test Case "${convo.header.name}" ready, calling done function.`) 143 | testcaseDone() 144 | }) 145 | .catch((err) => { 146 | debug(`Test Case "${convo.header.name}" failed: ${util.inspect(err)}`) 147 | testcaseDone(this.wrapBotiumError(err)) 148 | }) 149 | } else { 150 | testcaseDone(new Error('Botium Initialization failed. Please see error messages above (enable debug logging).')) 151 | } 152 | }) 153 | }) 154 | } 155 | 156 | UserSaysText (...args) { 157 | if (this.container) { 158 | return this.container.UserSaysText(...args) 159 | } else { 160 | return Promise.reject(new Error('Botium Initialization failed. Please see error messages above (enable debug logging).')) 161 | } 162 | } 163 | 164 | UserSays (...args) { 165 | if (this.container) { 166 | return this.container.UserSays(...args) 167 | } else { 168 | return Promise.reject(new Error('Botium Initialization failed. Please see error messages above (enable debug logging).')) 169 | } 170 | } 171 | 172 | WaitBotSays (...args) { 173 | if (this.container) { 174 | return this.container.WaitBotSays(...args) 175 | } else { 176 | return Promise.reject(new Error('Botium Initialization failed. Please see error messages above (enable debug logging).')) 177 | } 178 | } 179 | 180 | WaitBotSaysText (...args) { 181 | if (this.container) { 182 | return this.container.WaitBotSaysText(...args) 183 | } else { 184 | return Promise.reject(new Error('Botium Initialization failed. Please see error messages above (enable debug logging).')) 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/cli/index.js: -------------------------------------------------------------------------------- 1 | const util = require('util') 2 | const fs = require('fs') 3 | const path = require('path') 4 | const { mkdirpSync } = require('mkdirp') 5 | const debug = require('debug')('botium-bindings-cli') 6 | 7 | const testRunnerTypes = [ 8 | 'mocha', 9 | 'jest', 10 | 'jasmine' 11 | ] 12 | 13 | const handler = (argv) => { 14 | debug(`command options: ${util.inspect(argv)}`) 15 | 16 | const packageJsonFile = path.resolve(process.cwd(), 'package.json') 17 | if (!fs.existsSync(packageJsonFile)) { 18 | console.log(`No package.json file found at "${packageJsonFile}", exiting.`) 19 | process.exit(1) 20 | } 21 | const botiumSpecDir = path.resolve(process.cwd(), argv.specdir) 22 | if (!fs.existsSync(botiumSpecDir)) { 23 | mkdirpSync(botiumSpecDir) 24 | } 25 | const botiumConvoDir = path.resolve(process.cwd(), argv.convodir) 26 | if (!fs.existsSync(botiumConvoDir)) { 27 | mkdirpSync(botiumConvoDir) 28 | } 29 | 30 | const packageJson = require(path.resolve(process.cwd(), 'package.json')) 31 | if (packageJson.botium) { 32 | console.log(`Botium Section in File "${packageJsonFile}" already present, skipping ...`) 33 | } else { 34 | packageJson.botium = { 35 | convodirs: [ 36 | argv.convodir 37 | ], 38 | expandConvos: true, 39 | expandUtterancesToConvos: false, 40 | expandScriptingMemoryToConvos: false 41 | } 42 | console.log(`Added Botium Section in File "${packageJsonFile}".`) 43 | } 44 | packageJson.devDependencies = packageJson.devDependencies || {} 45 | if (!packageJson.devDependencies[argv.testRunner]) { 46 | packageJson.devDependencies[argv.testRunner] = 'latest' 47 | } 48 | if (!packageJson.devDependencies['botium-bindings']) { 49 | packageJson.devDependencies['botium-bindings'] = 'latest' 50 | } 51 | if (!packageJson.devDependencies['botium-connector-echo']) { 52 | packageJson.devDependencies['botium-connector-echo'] = 'latest' 53 | } 54 | packageJson.scripts = packageJson.scripts || {} 55 | if (!packageJson.scripts[argv.testRunner]) { 56 | if (argv.testRunner === 'jest') { 57 | packageJson.scripts[argv.testRunner] = `jest --env node ${argv.specdir}` 58 | } else { 59 | packageJson.scripts[argv.testRunner] = `${argv.testRunner} ${argv.specdir}` 60 | } 61 | } else { 62 | console.warn(`You already have an npm script called ${argv.testRunner}. In order to run botium tests, you'll need an npm script running "${argv.testRunner} ${argv.specdir}"`) 63 | } 64 | fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2)) 65 | 66 | const botiumJsonFile = path.resolve(process.cwd(), 'botium.json') 67 | if (fs.existsSync(botiumJsonFile)) { 68 | console.log(`Botium Configuration File "${botiumJsonFile}" already present, skipping ...`) 69 | } else { 70 | fs.writeFileSync(botiumJsonFile, JSON.stringify({ 71 | botium: { 72 | Capabilities: { 73 | PROJECTNAME: packageJson.name, 74 | CONTAINERMODE: 'echo' 75 | }, 76 | Sources: { }, 77 | Envs: { } 78 | } 79 | }, null, 2)) 80 | console.log(`Botium Configuration File written to "${botiumJsonFile}".`) 81 | } 82 | 83 | const botiumSpecFile = path.resolve(botiumSpecDir, 'botium.spec.js') 84 | if (fs.existsSync(botiumSpecFile)) { 85 | console.log(`Botium Spec File "${botiumSpecFile}" already present, skipping ...`) 86 | } else { 87 | if (argv.testRunner === 'mocha') { 88 | fs.writeFileSync(botiumSpecFile, 89 | `const bb = require('botium-bindings') 90 | bb.helper.mocha().setupMochaTestSuite() 91 | ` 92 | ) 93 | } else if (argv.testRunner === 'jasmine') { 94 | fs.writeFileSync(botiumSpecFile, 95 | `const bb = require('botium-bindings') 96 | bb.helper.jasmine().setupJasmineTestSuite() 97 | ` 98 | ) 99 | } else if (argv.testRunner === 'jest') { 100 | fs.writeFileSync(botiumSpecFile, 101 | `const bb = require('botium-bindings') 102 | bb.helper.jest().setupJestTestSuite() 103 | ` 104 | ) 105 | } 106 | console.log(`Botium Spec File written to "${botiumSpecFile}".`) 107 | } 108 | 109 | const botiumEchoSample = path.resolve(botiumConvoDir, 'give_me_a_picture.convo.txt') 110 | if (fs.existsSync(botiumEchoSample)) { 111 | console.log(`Botium Convo File "${botiumEchoSample}" already present, skipping ...`) 112 | } else { 113 | fs.writeFileSync(botiumEchoSample, 114 | `give me picture 115 | 116 | #me 117 | Hello, Bot! 118 | 119 | #bot 120 | You said: Hello, Bot! 121 | 122 | #me 123 | give me a picture 124 | 125 | #bot 126 | Here is a picture 127 | MEDIA http://www.botium.at/img/logo.png 128 | ` 129 | ) 130 | console.log(`Botium Convo File written to "${botiumEchoSample}".`) 131 | } 132 | console.log(`Botium initialization nearly ready. You should now run "npm install" to complete, and "npm run ${argv.testRunner}" to verify.`) 133 | } 134 | 135 | module.exports = { 136 | command: 'init [test-runner]', 137 | describe: 'Setup Botium project for a specific test runner', 138 | builder: (yargs) => { 139 | yargs.positional('test-runner', { 140 | describe: 'Test runner', 141 | choices: testRunnerTypes, 142 | default: 'mocha' 143 | }) 144 | yargs.option('specdir', { 145 | describe: 'Project directory to place the test specs', 146 | default: 'spec' 147 | }) 148 | yargs.option('convodir', { 149 | describe: 'Project directory to place the convo files', 150 | default: path.join('spec', 'convo') 151 | }) 152 | }, 153 | handler 154 | } 155 | -------------------------------------------------------------------------------- /src/helpers/jasmine.js: -------------------------------------------------------------------------------- 1 | /* global describe it beforeAll beforeEach afterAll afterEach fail */ 2 | 3 | const BotiumBindings = require('../BotiumBindings') 4 | 5 | const defaultTimeout = process.env.BOTIUM_JASMINE_TIMEOUT || 60000 6 | 7 | const setupJasmineTestCases = ({ timeout = defaultTimeout, testcaseSelector, bb } = {}) => { 8 | bb = bb || new BotiumBindings() 9 | 10 | bb.setupTestSuite( 11 | (testcase, testcaseFunction) => { 12 | if (testcaseSelector && !testcaseSelector(testcase)) return false 13 | 14 | it( 15 | testcase.header.name, 16 | (done) => { 17 | testcaseFunction((err) => { 18 | if (err) { 19 | fail(err) 20 | } 21 | done() 22 | }) 23 | }, 24 | timeout) 25 | return true 26 | }, 27 | null, 28 | (err) => fail(err) 29 | ) 30 | } 31 | 32 | const setupJasmineTestSuite = ({ timeout = defaultTimeout, name, testcaseSelector, bb } = {}) => { 33 | bb = bb || new BotiumBindings() 34 | name = name || bb.getTestSuiteName() 35 | 36 | describe(name, () => { 37 | beforeAll((done) => { 38 | bb.beforeAll().then(() => done()).catch(done.fail) 39 | }, timeout) 40 | 41 | beforeEach((done) => { 42 | bb.beforeEach().then(() => done()).catch(done.fail) 43 | }, timeout) 44 | 45 | afterEach((done) => { 46 | bb.afterEach().then(() => done()).catch(done.fail) 47 | }, timeout) 48 | 49 | afterAll((done) => { 50 | bb.afterAll().then(() => done()).catch(done.fail) 51 | }, timeout) 52 | 53 | setupJasmineTestCases({ timeout, testcaseSelector, bb }) 54 | }) 55 | } 56 | 57 | module.exports = { 58 | setupJasmineTestCases, 59 | setupJasmineTestSuite 60 | } 61 | -------------------------------------------------------------------------------- /src/helpers/jest.js: -------------------------------------------------------------------------------- 1 | /* global describe test it beforeAll beforeEach afterAll afterEach */ 2 | 3 | const BotiumBindings = require('../BotiumBindings') 4 | 5 | const setupJestTestCases = ({ testcaseSelector, bb } = {}) => { 6 | bb = bb || new BotiumBindings() 7 | 8 | let testCount = 0 9 | bb.setupTestSuite( 10 | (testcase, testcaseFunction) => { 11 | if (testcaseSelector && !testcaseSelector(testcase)) return false 12 | 13 | testCount++ 14 | test(testcase.header.name, testcaseFunction) 15 | return true 16 | } 17 | ) 18 | if (testCount === 0) { 19 | it.skip('skip empty test suite', () => {}) 20 | } 21 | } 22 | 23 | const setupJestTestSuite = ({ name, testcaseSelector, bb } = {}) => { 24 | bb = bb || new BotiumBindings() 25 | name = name || bb.getTestSuiteName() 26 | 27 | describe(name, () => { 28 | beforeAll((done) => { 29 | bb.beforeAll().then(() => done()).catch(done) 30 | }) 31 | 32 | beforeEach((done) => { 33 | bb.beforeEach().then(() => done()).catch(done) 34 | }) 35 | 36 | afterEach((done) => { 37 | bb.afterEach().then(() => done()).catch(done) 38 | }) 39 | 40 | afterAll((done) => { 41 | bb.afterAll().then(() => done()).catch(done) 42 | }) 43 | 44 | setupJestTestCases({ bb, testcaseSelector }) 45 | }) 46 | } 47 | 48 | module.exports = { 49 | setupJestTestCases, 50 | setupJestTestSuite 51 | } 52 | -------------------------------------------------------------------------------- /src/helpers/mocha.js: -------------------------------------------------------------------------------- 1 | /* global describe it before beforeEach after afterEach */ 2 | 3 | const BotiumBindings = require('../BotiumBindings') 4 | 5 | const defaultTimeout = process.env.BOTIUM_MOCHA_TIMEOUT || 60000 6 | 7 | const setupMochaTestCases = ({ timeout = defaultTimeout, testcaseSelector, bb } = {}) => { 8 | bb = bb || new BotiumBindings() 9 | 10 | bb.setupTestSuite( 11 | (testcase, testcaseFunction) => { 12 | if (testcaseSelector && !testcaseSelector(testcase)) return false 13 | 14 | it(testcase.header.name, testcaseFunction).timeout(timeout) 15 | return true 16 | } 17 | ) 18 | } 19 | 20 | const setupMochaTestSuite = ({ timeout = defaultTimeout, name, testcaseSelector, bb } = {}) => { 21 | bb = bb || new BotiumBindings() 22 | name = name || bb.getTestSuiteName() 23 | 24 | describe(name, () => { 25 | before(function (done) { 26 | this.timeout(timeout) 27 | bb.beforeAll().then(() => done()).catch(done) 28 | }) 29 | beforeEach(function (done) { 30 | this.timeout(timeout) 31 | bb.beforeEach().then(() => done()).catch(done) 32 | }) 33 | afterEach(function (done) { 34 | this.timeout(timeout) 35 | bb.afterEach().then(() => done()).catch(done) 36 | }) 37 | after(function (done) { 38 | this.timeout(timeout) 39 | bb.afterAll().then(() => done()).catch(done) 40 | }) 41 | 42 | setupMochaTestCases({ timeout, testcaseSelector, bb }) 43 | }) 44 | } 45 | 46 | module.exports = { 47 | setupMochaTestCases, 48 | setupMochaTestSuite 49 | } 50 | -------------------------------------------------------------------------------- /src/metrics.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const os = require('os') 3 | 4 | const botiumAnalyticsHost = process.env.BOTIUM_ANALYTICS_HOST || 'v1.license.botium.cyaraportal.us' 5 | const botiumAnalyticsPort = process.env.BOTIUM_ANALYTICS_PORT || 443 6 | const https = botiumAnalyticsPort === 443 ? require('https') : require('http') 7 | const execTimeout = 10000 8 | 9 | function logIfVerbose (toLog, stream) { 10 | if (process.env.BOTIUM_ANALYTICS_VERBOSE === 'true') { 11 | (stream || console.log)(toLog) 12 | } 13 | } 14 | 15 | async function reportUsage (metrics) { 16 | if (process.env.BOTIUM_ANALYTICS === 'false') return 17 | 18 | const packageJson = require(path.join(__dirname, '..', 'package.json')) 19 | 20 | const infoPayload = Object.assign({ 21 | rawPlatform: os.platform(), 22 | rawArch: os.arch(), 23 | library: packageJson.name, 24 | version: packageJson.version 25 | }, metrics) 26 | 27 | const data = JSON.stringify(infoPayload) 28 | logIfVerbose(`Botium analytics payload: ${data}`) 29 | 30 | const reqOptions = { 31 | host: botiumAnalyticsHost, 32 | port: botiumAnalyticsPort, 33 | method: 'POST', 34 | path: '/metrics/usage/core', 35 | headers: { 36 | 'Content-Type': 'application/json', 37 | 'Content-Length': data.length 38 | }, 39 | timeout: execTimeout 40 | } 41 | await new Promise((resolve, reject) => { 42 | const req = https.request(reqOptions, (res) => { 43 | logIfVerbose(`Response status: ${res.statusCode}`) 44 | resolve() 45 | }) 46 | 47 | req.on('error', error => { 48 | logIfVerbose(error, console.error) 49 | resolve() 50 | }) 51 | 52 | req.on('timeout', error => { 53 | logIfVerbose(error, console.error) 54 | resolve() 55 | }) 56 | 57 | req.write(data) 58 | req.end() 59 | }) 60 | } 61 | 62 | module.exports = { 63 | reportUsage: (metrics) => { 64 | reportUsage(metrics).catch(e => { 65 | logIfVerbose(`metrics error: ${e}`, console.error) 66 | }) 67 | } 68 | } 69 | --------------------------------------------------------------------------------