From d55459b50eedf9d00af2f2df67562b1c9576f4ea Mon Sep 17 00:00:00 2001 From: Guy Khmel Date: Tue, 16 Jan 2018 18:34:12 +0200 Subject: [PATCH] Add Promise pattern and unittests --- .coveralls.yml | 2 + .travis.yml | 3 + .vscode - Copy/launch.json | 79 +++++ package-lock.json | 190 ++++++++++- package.json | 30 +- src/app.ts | 98 +++--- src/commons.ts | 40 ++- src/constants.ts | 2 +- src/hipChatMessage.ts | 19 +- src/server.ts | 7 +- src/slackMessage.ts | 40 ++- test/app.test.ts | 612 +++++++++++++++++++++++------------- test/commons.test.ts | 108 ++++--- test/hipChatMessage.test.ts | 38 +-- test/slackMessage.test.ts | 85 +++-- test/testCommons.ts | 7 +- typings.json | 4 + 17 files changed, 917 insertions(+), 447 deletions(-) create mode 100644 .coveralls.yml create mode 100644 .vscode - Copy/launch.json diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 00000000..15b6109f --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,2 @@ +service_name: travis-pro +repo_token: Gmv3hA2vMKiEAAdXIqRtZLJGRDF4Yno6a \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 5e5a8b64..3d74cbc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,3 +12,6 @@ script: - tsc -p ./tsconfig.json - npm run tslint - npm test +after_success: +- npm run coverage + diff --git a/.vscode - Copy/launch.json b/.vscode - Copy/launch.json new file mode 100644 index 00000000..0e0a0c30 --- /dev/null +++ b/.vscode - Copy/launch.json @@ -0,0 +1,79 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceRoot}/index.js" + }, + { + "name": "Run mocha", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "stopOnEntry": false, + "args": ["${file}", "--no-timeouts"], + + "cwd": "${workspaceRoot}", + "runtimeExecutable": null, + "env": { "NODE_ENV": "testing"} + }, + { + "name": "Current TS File", + "type": "node", + "request": "launch", + "args": ["${relativeFile}"], + "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], + "sourceMaps": true, + "cwd": "${workspaceRoot}", + "protocol": "inspector", + }, + { + "name": "Current TS Tests File", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "args": ["-r", "source-map-support/register", "${relativeFile}"], + "cwd": "${workspaceRoot}", + "protocol": "inspector", + "outFiles": ["${workspaceRoot}/test"] + }, + { + "name": "Run Tests", + "type": "node", + "request": "launch", + "cwd": "${workspaceRoot}", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "args": [ + "-u", "tdd", + "-r", "ts-node/register", + "--timeout", "999999", + "--colors" + ], + "runtimeArgs": [ + "--nolazy" + ], + "sourceMaps": true + }, + { + "name": "Launch Tests (debug)", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/.bin/mocha", + "stopOnEntry": false, + "args": ["--reporter", "spec", "--timeout", "5000", "--debug", "--require", "ts-node/register", "test/**/*.ts"], + "cwd": "${workspaceRoot}", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "dev" + }, + "externalConsole": false, + "sourceMaps": true, + "outDir": "${workspaceRoot}/test/" + } + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 52d1dc33..b2eaafd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha512-BdN2PXxOFnTXFcyONPW6t0fHjz2fvRZHVMFpaS0wYr+Y8fWEaNOs4V8LEu/fpzQlMx+ahdndgTaGTwPC+J/EeA==", "requires": { "@types/express": "4.11.0", - "@types/node": "8.5.8" + "@types/node": "9.3.0" } }, "@types/chai": { @@ -18,6 +18,14 @@ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.0.tgz", "integrity": "sha512-OuYBlXWHYthxIudMXMeQr92f6D97YoT9CUYCRb0BEP4OavC95jNcczjjr4Ob3H5E1IqlWqwj+leUZPSeth27Qw==" }, + "@types/es6-promise": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@types/es6-promise/-/es6-promise-3.3.0.tgz", + "integrity": "sha512-ixCIAEkLUKv9movnHKCzx2rzAJgEnSALDXPrOSSwOjWwXFs0ssSZKan+O2e3FExPPCbX+DfA9NcKsbvLuyUlNA==", + "requires": { + "es6-promise": "4.2.2" + } + }, "@types/express": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.11.0.tgz", @@ -33,7 +41,7 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.11.0.tgz", "integrity": "sha512-hOi1QNb+4G+UjDt6CEJ6MjXHy+XceY7AxIa28U9HgJ80C+3gIbj7h5dJNxOI7PU3DO1LIhGP5Bs47Dbf5l8+MA==", "requires": { - "@types/node": "8.5.8" + "@types/node": "9.3.0" } }, "@types/mime": { @@ -47,9 +55,9 @@ "integrity": "sha512-fwTTP5QLf4xHMkv7ovcKvmlLWX3GrxCa5DRQDOilVyYGCp+arZTAQJCy7/4GKezzYJjfWMpB/Cy4e8nrc9XioA==" }, "@types/node": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.8.tgz", - "integrity": "sha512-8KmlRxwbKZfjUHFIt3q8TF5S2B+/E5BaAoo/3mgc5h6FJzqxXkCK/VMetO+IRDtwtU6HUvovHMBn+XRj7SV9Qg==" + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.3.0.tgz", + "integrity": "sha512-wNBfvNjzsJl4tswIZKXCFQY0lss9nKUyJnG6T94X/eqjRgI2jHZ4evdjhQYBSan/vGtF6XVXPApOmNH2rf0KKw==" }, "@types/serve-static": { "version": "1.13.1", @@ -61,9 +69,9 @@ } }, "@types/sinon": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.1.2.tgz", - "integrity": "sha512-fL6bJHYRzbw/7ofbKiJ65SOAasoe5mZhHNSYKxWsF3sGl/arhRwDPwXJqM1xofKNTQD14HNX9VruicM7pm++mQ==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.1.3.tgz", + "integrity": "sha512-Xxn32Q3mAJHOMU20bxcT6HiPksUJEkZA+nyZS4NhLo8kKb8hLhkBgp5OeW/BI3+9QmdrvDRk3caYNqtYb+TEbA==" }, "@types/strip-bom": { "version": "3.0.0", @@ -743,6 +751,27 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "coveralls": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.0.tgz", + "integrity": "sha512-ZppXR9y5PraUOrf/DzHJY6gzNUhXYE3b9D43xEXs4QYZ7/Oe0Gy0CS+IPKWFfvQFXB3RG9QduaQUFehzSpGAFw==", + "dev": true, + "requires": { + "js-yaml": "3.10.0", + "lcov-parse": "0.0.10", + "log-driver": "1.2.5", + "minimist": "1.2.0", + "request": "2.83.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -903,6 +932,11 @@ "escape-html": "1.0.3" } }, + "es6-promise": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.2.tgz", + "integrity": "sha512-LSas5vsuA6Q4nEdf9wokY5/AJYXry98i0IzXsv49rYsgDGDNDPbqAYR1Pe23iFxygfbGZNR/5VrHXBCh2BhvUQ==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1283,6 +1317,12 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1498,6 +1538,12 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1692,6 +1738,12 @@ "invert-kv": "1.0.0" } }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -1743,6 +1795,12 @@ "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", "dev": true }, + "log-driver": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", + "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", + "dev": true + }, "lolex": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz", @@ -1788,6 +1846,12 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, "mime-db": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", @@ -1890,6 +1954,56 @@ } } }, + "mock-express-request": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/mock-express-request/-/mock-express-request-0.2.2.tgz", + "integrity": "sha512-EymHjY1k1jWIsaVaCsPdFterWO18gcNwQMb99OryhSBtIA33SZJujOLeOe03Rf2DTV997xLPyl2I098WCFm/mA==", + "dev": true, + "requires": { + "accepts": "1.3.4", + "fresh": "0.5.2", + "lodash": "4.17.4", + "mock-req": "0.2.0", + "parseurl": "1.3.2", + "range-parser": "1.2.0", + "type-is": "1.6.15" + } + }, + "mock-express-response": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/mock-express-response/-/mock-express-response-0.2.2.tgz", + "integrity": "sha512-+pRUv25LhyKZVSRCOzoZp8TW0nqvT7UlH7vpVzCibjjEucXL72gTgwEhmqbyTO2LI9IlyIeBBdflR9Ml5KQWMQ==", + "dev": true, + "requires": { + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "depd": "1.1.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "mock-express-request": "0.2.2", + "mock-res": "0.5.0", + "on-finished": "2.3.0", + "proxy-addr": "2.0.2", + "qs": "6.5.1", + "send": "0.16.1", + "utils-merge": "1.0.1", + "vary": "1.1.2" + } + }, + "mock-req": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mock-req/-/mock-req-0.2.0.tgz", + "integrity": "sha1-dJRGgE0sAGFpNC7nvmu6HP/VNMI=", + "dev": true + }, + "mock-res": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mock-res/-/mock-res-0.5.0.tgz", + "integrity": "sha1-mDaL6wnfdT9k9m2U5VNql7NqJDA=", + "dev": true + }, "moment": { "version": "2.18.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", @@ -3761,6 +3875,16 @@ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "dev": true }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "dev": true, + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3772,6 +3896,12 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, "ramda": { "version": "0.24.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz", @@ -4118,6 +4248,38 @@ "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", "dev": true }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -4151,9 +4313,9 @@ "dev": true }, "sinon": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.4.tgz", - "integrity": "sha512-ISJZDPf8RS2z4/LAgy1gIimAvF9zg9C9ClQhLTWYWm4HBZjo1WELXlVfkudjdYeN+GtQ2uVBe52m0npIV0gDow==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.5.tgz", + "integrity": "sha1-YgqbKsWZ+IsEVXYwcPFvQFftY5U=", "requires": { "diff": "3.3.1", "formatio": "1.2.0", @@ -4559,6 +4721,12 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", diff --git a/package.json b/package.json index 8950efb4..72d73942 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,11 @@ "description": "_A Slackbot that searches 10Bis site_", "dependencies": { "@types/chai": "^4.1.0", + "@types/es6-promise": "^3.3.0", "@types/express": "^4.11.0", "@types/mocha": "^2.2.46", - "@types/node": "^8.5.8", - "@types/sinon": "^4.1.2", + "@types/node": "^9.3.0", + "@types/sinon": "^4.1.3", "body-parser": "^1.18.2", "dateformat": "^3.0.2", "debug": "^3.1.0", @@ -18,18 +19,20 @@ "json-schema": "^0.2.3", "moment-timezone": "^0.5.14", "request": "^2.83.0", - "sinon": "^4.1.4", + "sinon": "^4.1.5", "typescript": "^2.6.2", "uuid": "^3.1.0", "winston": "^2.4.0" }, "devDependencies": { "chai": "^4.1.2", + "coveralls": "^3.0.0", "eslint": "^4.15.0", "eslint-plugin-chai-expect": "^1.1.1", "eslint-plugin-mocha": "^4.11.0", "mocha": "^4.1.0", "mocha-typescript": "^1.1.12", + "mock-express-response": "^0.2.2", "nyc": "^11.4.1", "rewire": "^3.0.2", "source-map-support": "^0.5.0", @@ -43,10 +46,29 @@ "tslint": "./node_modules/.bin/tslint --project ./", "start": "./node_modules/.bin/tsc --module commonjs --sourceMap --target ES6 -p ./tsconfig.json && node ./bin/www", "pretest": "./node_modules/.bin/tsc --module commonjs --sourceMap --target ES6 -p ./tsconfig.json", - "test": "./node_modules/.bin/nyc mocha", + "test": "./node_modules/.bin/mocha --recursive --timeout 15000 --require ts-node/register --bail", + "cover": "./node_modules/.bin/nyc npm t", + "coverage": "nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls", "watch": "./node_modules/.bin/mocha-typescript-watch", "prepare": "./node_modules/.bin/tsc --module commonjs --sourceMap --target ES6 -p ./tsconfig.json" }, + "nyc": { + "include": [ + "src/*", + "src/**/*" + ], + "exclude": [ + "typings" + ], + "require": [ + "ts-node/register" + ], + "reporter": [ + "json", + "html" + ], + "all": true + }, "repository": { "type": "git", "url": "git+https://github.com/mager/10bis.Slackbot.git" diff --git a/src/app.ts b/src/app.ts index ed8d818e..5d8bde0b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,5 @@ import * as bodyParser from "body-parser"; -import * as express from "express"; -import * as request from "request"; +import { Request, Response, NextFunction } from "express"; import * as winston from "winston"; import { Commons } from "./commons"; import { Constants } from "./constants"; @@ -11,20 +10,17 @@ winston.level = process.env.LOG_LEVEL; export class App { public express; - - constructor () { + private messageFormatters : Commons.MessageFormatter[]; + constructor (formatter? : Commons.MessageFormatter) { winston.debug("Booting %s", Constants.APP_NAME); + this.messageFormatters = [HipChatMessageFormatter.getInstance(), SlackMessageFormatter.getInstance()]; } - process (req: Commons.Request, res: Commons.Response) : Commons.Response { - const hipChatMessageFormatter = HipChatMessageFormatter.getInstance(); - const slackMessageFormatter = SlackMessageFormatter.getInstance(); - - var messageFormatter = Commons.verifyMessage(req, [hipChatMessageFormatter, slackMessageFormatter]); + process (req: Commons.Request, res: Response) : Promise { + let messageFormatter = Commons.verifyMessage(req, this.messageFormatters); if (!messageFormatter) { - res.status(400); - res.send(Constants.INVALID_MESSAGE_STRING); - return res; + res.status(400).send(Constants.INVALID_MESSAGE_STRING); + return Commons.ErrorPromiseWrapper(Constants.INVALID_MESSAGE_STRING); } @@ -32,70 +28,76 @@ export class App { if (!restaurantName) { const body = messageFormatter.getErrorMessage(null); - res.send(body); - return res; + res.status(400).send(body); + return Commons.ErrorPromiseWrapper(Constants.INVALID_MESSAGE_STRING); } restaurantName = restaurantName.trim(); if (restaurantName.toLowerCase() === Constants.TOTAL_KEYWORD.toLowerCase()) { - this.getTotalOrders(res, messageFormatter); + return this.getTotalOrders(res, messageFormatter); } else { - this.search(res, messageFormatter, restaurantName); + return this.search(res, messageFormatter, restaurantName); } - return res; } - search (res : Commons.Response, messageFormatter : Commons.MessageFormatter, restaurantName : string) : void { - if (restaurantName.length === 0) { // Behavior for empty command ("/10bis" with no content) - var body = messageFormatter.getDefaultResponse(); - res.send(body); - return; + search (res : Response, messageFormatter : Commons.MessageFormatter, restaurantName : string) : Promise { + if (!restaurantName || restaurantName.length === 0) { // Behavior for empty command ("/10bis" with no content) + let body : Commons.TenBisResponse = messageFormatter.getDefaultResponse(); + res.status(400).send(body); + return Commons.ErrorPromiseWrapper(Constants.INVALID_MESSAGE_STRING); } - var parsed_url = Commons.generateSearchRequest(restaurantName); + let parsed_url : string = Commons.generateSearchRequest(restaurantName); - request.get(parsed_url, function(error : Error, response : Commons.Response, body : string) { - if (!error && response.statusCode === 200) { - var data = JSON.parse(body); + return Commons.RequestGetWrapper(parsed_url) + .then((body) => { + let data = JSON.parse(body); if (!data || !data.length || data.length < 1) { const badResBody = messageFormatter.getErrorMessage(restaurantName); - res.send(badResBody); + res.json(badResBody); return; } const resBody = messageFormatter.generateSearchResponse(Commons.filterByRestaurantName(Commons.sortRestaurantsByDistance(data))); - res.send(resBody); - } else { - res.status(400); - res.send(Constants.ERROR_STRING); - } - }); + res.json(resBody); + }).catch((err) => { + if (err) { + winston.debug("Error in Search: " + err); + } else { + winston.debug("Error in Search"); + } + res.status(400).send(Constants.ERROR_STRING); + }); } - getTotalOrders (res : Commons.Response, messageFormatter : Commons.MessageFormatter) : void { - var parsed_url = Commons.generateGetTotalOrdersRequest(); + getTotalOrders (res : Response, messageFormatter : Commons.MessageFormatter) : Promise { + let parsed_url : string = Commons.generateGetTotalOrdersRequest(); winston.debug("Total Orders Url: " + parsed_url); - request.get(parsed_url, function(error : Error, response : Commons.Response, body : string) { - if (!error && response.statusCode === 200) { - var data = JSON.parse(body); + let requestPromise : Promise = Commons.RequestGetWrapper(parsed_url); + return requestPromise.then((body) => { + let data : Commons.Restaurant[] = JSON.parse(body); + + if (!data || !data.length || data.length < 1) { + const resBody = messageFormatter.getErrorMessage(null); + res.json(resBody); + return; + } - if (!data || !data.length || data.length < 1) { - const resBody = messageFormatter.getErrorMessage(null); - res.send(resBody); - return; - } + let restaurants : Commons.Restaurant[] = data.filter(Commons.filterTotalOrders); - var restaurants = data.filter(Commons.filterTotalOrders); + const resBody = messageFormatter.generateTotalOrdersResponse(Commons.filterByRestaurantName(restaurants)); + res.json(resBody); - const resBody = messageFormatter.generateTotalOrdersResponse(this.filterByRestaurantName(restaurants)); - res.send(resBody); + }).catch( (err) => { + if (err) { + winston.debug("Error in Get Total Orders: " + err); } else { - res.status(400); - res.send(Constants.ERROR_STRING); + winston.debug("Error in Get Total Orders"); } + res.status(400).send(Constants.ERROR_STRING); }); } } diff --git a/src/commons.ts b/src/commons.ts index e3d45d9b..feabc89b 100644 --- a/src/commons.ts +++ b/src/commons.ts @@ -1,13 +1,35 @@ +import * as http from "http"; +import { Request as ExpressRequest } from "express"; import * as moment from "moment-timezone"; import { Constants } from "./constants"; import * as url from "url"; +import * as request from "request"; +import { Send, Response } from "express"; export module Commons { export function getFormatedDateTime() : string { - var date = moment.tz(Constants.TIMEZONE).format(Constants.DATE_FORMAT); - var time = moment.tz(Constants.TIMEZONE).format(Constants.TIME_FORMAT); + let date : string = moment.tz(Constants.TIMEZONE).format(Constants.DATE_FORMAT); + let time : string = moment.tz(Constants.TIMEZONE).format(Constants.TIME_FORMAT); return date + "+" + time; - } + } + + export function RequestGetWrapper(url : string) : Promise { + return new Promise(function (resolve : Function, reject : Function) { + request.get(url, function(error : Error, response : Response, body : string) { + if (!error && response.statusCode === 200) { + resolve (body); // Succeess + } else { + reject(error); // Failure + } + }); + }); + } + + export function ErrorPromiseWrapper(errorString : string) : Promise { + return new Promise(function (resolve : Function, reject : Function) { + reject(errorString); // Failure + }); + } export class SearchRequestQuery { deliveryMethod: string; @@ -91,7 +113,7 @@ export module Commons { query.desiredDateAndTime = Commons.getFormatedDateTime(); query.timestamp = new Date().getTime(); - var parsedUrl = url.format({ + let parsedUrl : string = url.format({ pathname: "https://www.10bis.co.il/Restaurants/SearchRestaurants", query: query }); @@ -122,7 +144,7 @@ export module Commons { query.desiredDateAndTime = Commons.getFormatedDateTime(); query.timestamp = new Date().getTime(); - var parsedUrl = url.format({ + let parsedUrl : string = url.format({ pathname: "https://www.10bis.co.il/Restaurants/SearchRestaurants", query: query }); @@ -133,7 +155,7 @@ export module Commons { export function filterByRestaurantName (restaurants : Commons.Restaurant[]) : Commons.Restaurant[] { let flags = {}; - var filteredRestaurants = restaurants.filter(function(restarant : Commons.Restaurant) { + let filteredRestaurants : Commons.Restaurant[] = restaurants.filter(function(restarant : Commons.Restaurant) { if (flags[restarant.RestaurantName]) { return false; } @@ -1336,12 +1358,6 @@ export module Commons { body: any; } - export interface Response extends Express.Response { - statusCode: number; - status(num : number) : void; - send(body: Commons.TenBisResponse) : void; - } - export interface TenBisResponse { } } \ No newline at end of file diff --git a/src/constants.ts b/src/constants.ts index 87d706bc..7053d862 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,6 @@ export class Constants { - public static readonly INVALID_MESSAGE_STRING: string = "Invalid Message"; + public static readonly INVALID_MESSAGE_STRING: string = "Invalid Command"; public static readonly ERROR_STRING: string = "There was an error in your request"; public static readonly NO_RESTAURANTS_FOUND_STRING: string = "No Restaurants Found"; public static readonly APP_NAME : string = "10bis.slackbot"; diff --git a/src/hipChatMessage.ts b/src/hipChatMessage.ts index cdd52caa..3f45199b 100644 --- a/src/hipChatMessage.ts +++ b/src/hipChatMessage.ts @@ -1,6 +1,7 @@ import { Commons } from "./commons"; import { HipChatModule } from "./hipChatModule"; import { Constants } from "./constants"; +import { v4 as uuid } from "uuid"; // hipChatMessage.js @@ -61,8 +62,6 @@ it.ly/1TmKuKQ", } } */ -var uuid = require("uuid/v4"); - export class HipChatMessageFormatter implements Commons.MessageFormatter { public static COMMAND_OPERATOR : string = "/10bis"; @@ -90,7 +89,7 @@ export class HipChatMessageFormatter implements Commons.MessageFormatter { } getErrorMessage(restaurantName: string): Commons.TenBisResponse { - var restaurantString = ""; + let restaurantString : string = ""; if (restaurantName) { restaurantString = " for: " + restaurantName; } @@ -104,7 +103,7 @@ export class HipChatMessageFormatter implements Commons.MessageFormatter { getRestaurantName(req: HipChatModule.HipChatReq): string { if (req && req.body && req.body.item && req.body.item.message && req.body.item.message.message) { - var message = req.body.item.message.message; + let message : string = req.body.item.message.message; message = message.slice(HipChatMessageFormatter.COMMAND_OPERATOR.length + 1); //get the value @@ -115,14 +114,14 @@ export class HipChatMessageFormatter implements Commons.MessageFormatter { } generateSearchResponse(restaurants: Commons.Restaurant[]): Commons.TenBisResponse { - var title = "Found " + restaurants.length + " restaurants"; - var restaurantText = ""; + let title : string = "Found " + restaurants.length + " restaurants"; + let restaurantText : string = ""; if (restaurants.length > 0) { title += "\n"; restaurants.forEach(function (restaurant : Commons.Restaurant, index: number) { - var suffix = ""; - if (index < restaurants.length) { + let suffix : string = ""; + if (index + 1 < restaurants.length) { //exclude the last line suffix = "\n\n"; } restaurantText += "[" + (index + 1) + "] " + restaurant.RestaurantName + @@ -137,7 +136,7 @@ export class HipChatMessageFormatter implements Commons.MessageFormatter { } generateTotalOrdersResponse(restaurants: Commons.Restaurant[]): HipChatModule.HipChatResponse { - var restaurantsString = ""; + let restaurantsString : string = ""; if (restaurants.length > 0) { // Create a list @@ -190,7 +189,7 @@ export class HipChatMessageFormatter implements Commons.MessageFormatter { } getSuccessMessage (text : string, restaurant : Commons.Restaurant) : HipChatModule.HipChatResponse { - var response = new HipChatModule.HipChatResponse("green", text, false, "text"); + let response : HipChatModule.HipChatResponse = new HipChatModule.HipChatResponse("green", text, false, "text"); if (restaurant) { response.card = this.generateRestaurantCard(restaurant); diff --git a/src/server.ts b/src/server.ts index 72c3414c..3e54050e 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,9 +1,10 @@ import * as bodyParser from "body-parser"; -import * as express from "express"; import * as path from "path"; import * as errorHandler from "errorhandler"; +import * as express from "express"; import { Commons } from "./commons"; import { App } from "./app"; +import { Request, Response, NextFunction } from "express"; /** * The server. @@ -93,11 +94,11 @@ export class Server { router = express.Router(); let app = new App(); - router.get("/", function(req : Commons.Request, res : Commons.Response) { + router.get("/", function(req : Commons.Request, res : Response) { res.send("Sanity passed!"); }); - router.post("/post", function(req : Commons.Request, res : Commons.Response) { + router.post("/post", function(req : Commons.Request, res : Response) { app.process(req, res); }); diff --git a/src/slackMessage.ts b/src/slackMessage.ts index f80c4776..aeba93f8 100644 --- a/src/slackMessage.ts +++ b/src/slackMessage.ts @@ -46,8 +46,8 @@ Response: ] } */ -var commandOperator = "/10bis"; -var MAX_RESTAURANT_CARDS = 5; +let commandOperator : string = "/10bis"; +let MAX_RESTAURANT_CARDS : number = 5; export class SlackMessageFormatter implements Commons.MessageFormatter { @@ -67,18 +67,19 @@ export class SlackMessageFormatter implements Commons.MessageFormatter { getDefaultResponse(): Commons.TenBisResponse { return new SlackModule.SlackResponse("ephemeral", Constants.DEFAULT_RESPONSE, null); } - getErrorMessage(restaurantName: string): Commons.TenBisResponse { - var restaurantString = ""; + getErrorMessage(restaurantName: string) : Commons.TenBisResponse { + let restaurantString : string = ""; if (restaurantName) { restaurantString = " for: " + restaurantName; } - var response = new SlackModule.SlackResponse("ephemeral", Constants.NO_RESTAURANTS_FOUND_STRING + restaurantString, null); + let response : Commons.TenBisResponse = + new SlackModule.SlackResponse("ephemeral", Constants.NO_RESTAURANTS_FOUND_STRING + restaurantString, null); return response; } - getRestaurantName(req: Commons.Request): string { + getRestaurantName(req: Commons.Request) : string { if (req && req.body) { return req.body.text; } @@ -86,14 +87,13 @@ export class SlackMessageFormatter implements Commons.MessageFormatter { return null; } generateSearchResponse(restaurants: Commons.Restaurant[]): SlackModule.SlackResponse { - var title = "Found " + restaurants.length + " restaurants"; + let title : string = "Found " + restaurants.length + " restaurants"; - var attachments = []; + let attachments : SlackModule.SlackAttachment[] = []; if (restaurants.length > 0) { if (restaurants.length < MAX_RESTAURANT_CARDS) { - var generateRestaurantCard = this.generateRestaurantCard; - + let generateRestaurantCard : Function = this.generateRestaurantCard; // For up to 5 restaurants, create a card restaurants.forEach(function (restaurant : Commons.Restaurant, index : number) { attachments.push(generateRestaurantCard(restaurant)); @@ -107,9 +107,7 @@ export class SlackMessageFormatter implements Commons.MessageFormatter { " : https://www.10bis.co.il/Restaurants/Menu/Delivery?ResId=" + restaurant.RestaurantId + "\n"; }); - attachments.push({ - text: restaurantsString - }); + attachments.push(new SlackModule.SlackAttachment(null, null, null, null, restaurantsString, null, null)); } } @@ -126,17 +124,17 @@ export class SlackMessageFormatter implements Commons.MessageFormatter { return response; } generateTotalOrdersResponse(restaurants: Commons.Restaurant[]): SlackModule.SlackResponse { - var title = "Found " + restaurants.length + " restaurants"; + let title : string = "Found " + restaurants.length + " restaurants"; - var attachments = []; + let attachments : SlackModule.SlackAttachment[] = []; if (restaurants.length > 0) { if (restaurants.length < MAX_RESTAURANT_CARDS) { - var generateRestaurantTotalCard = this.generateRestaurantTotalCard; + let generateRestaurantCard : Function = this.generateRestaurantCard; // For up to 5 restaurants, create a card restaurants.forEach(function (restaurant : Commons.Restaurant, index : number) { - attachments.push(generateRestaurantTotalCard(restaurant)); + attachments.push(generateRestaurantCard(restaurant)); }); } else { @@ -173,8 +171,8 @@ export class SlackMessageFormatter implements Commons.MessageFormatter { return false; } - generateRestaurantCard (restaurant : Commons.Restaurant) { - var restaurantName = restaurant.RestaurantName; + generateRestaurantCard (restaurant : Commons.Restaurant) : SlackModule.SlackAttachment { + let restaurantName : string = restaurant.RestaurantName; let slackAttachment = new SlackModule.SlackAttachment( restaurantName + " : https://www.10bis.co.il/Restaurants/Menu/Delivery?ResId=" + restaurant.RestaurantId, @@ -201,8 +199,8 @@ export class SlackMessageFormatter implements Commons.MessageFormatter { return slackAttachment; } - generateRestaurantTotalCard (restaurant : Commons.Restaurant) { - var restaurantName = restaurant.RestaurantName; + generateRestaurantTotalCard (restaurant : Commons.Restaurant) : SlackModule.SlackAttachment { + let restaurantName : string = restaurant.RestaurantName; let slackAttachment = new SlackModule.SlackAttachment( restaurantName + " : https://www.10bis.co.il/Restaurants/Menu/Delivery?ResId=" + restaurant.RestaurantId, diff --git a/test/app.test.ts b/test/app.test.ts index d59f37fc..aa9e3a4d 100644 --- a/test/app.test.ts +++ b/test/app.test.ts @@ -11,11 +11,10 @@ import { Constants } from "../src/constants"; import * as sinon from "sinon"; import * as request from "request"; import { SinonStub } from "sinon"; +import { Request, Response, NextFunction } from "express"; - - - +let MockExpressResponse = require("mock-express-response"); let slackMessageFormatter : SlackMessageFormatter = SlackMessageFormatter.getInstance(); let hipChatMessageFormatter : HipChatMessageFormatter = HipChatMessageFormatter.getInstance(); let app : App = new App(); @@ -28,272 +27,449 @@ let badRestaurantName : string = "BlaBlaBla"; class EmptyRequest implements Commons.Request { body: any; } - let get : any; -let post : any; -describe("App", function () { - beforeEach(function() { - this.get = sinon.stub(request, "get"); - this.post = sinon.stub(request, "post"); - }); - - afterEach(function() { - (this.get as sinon.SinonStub).restore(); - (this.post as sinon.SinonStub).restore(); - }); - - it("process() should return one restaurant if valid Slack message", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(SlackModule.SlackResponse); +describe("App", () => { + it("process() should return one restaurant if valid Slack message", () => { + let res = new MockExpressResponse(); + return app.process(slackReq, res).then( (result) => { + expect(res.statusCode).to.equal(200); - let slackRes : SlackModule.SlackResponse = body as SlackModule.SlackResponse; + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; - expect(slackRes.text).to.equal("Found 1 restaurants"); - expect(slackRes.response_type).to.equal("in_channel"); - expect(slackRes.attachments).not.to.equal(null); - expect(slackRes.attachments.length).to.equal(1); - expect(slackRes.attachments[0].title).to.equal(validSlackMessage.text); - } - }; - app.process(slackReq, res); + expect(slackRes).not.to.equal(null); + expect(slackRes.text).to.equal("Found 1 restaurants"); + expect(slackRes.response_type).to.equal("in_channel"); + expect(slackRes.attachments).not.to.equal(null); + expect(slackRes.attachments.length).to.equal(1); + expect(slackRes.attachments[0].title).to.equal(validSlackMessage.text); + } + ); }); - it("process() should return one restaurant if valid HipChat message", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(HipChatModule.HipChatResponse); + it("process() should return one restaurant if valid HipChat message", () => { + let res = new MockExpressResponse(); + return app.process(hipChatReq, res).then( (result) => { + expect(res.statusCode).to.equal(200); - let hipChatRes : HipChatModule.HipChatResponse = body as HipChatModule.HipChatResponse; + let body = res._getJSON(); + expect(body).not.to.equal(null); + let hipChatRes : HipChatModule.HipChatResponse = body; + expect(hipChatRes).not.to.equal(null); - expect(hipChatRes.message.replace(/^\s+|\s+$/g, "")).to.equal("Found 1 restaurants"); - expect(hipChatRes.message_format).to.equal("text"); - expect(hipChatRes.card).not.to.equal(null); + expect(hipChatRes.message.replace(/^\s+|\s+$/g, "")).to.equal("Found 1 restaurants"); + expect(hipChatRes.message_format).to.equal("text"); + expect(hipChatRes.card).not.to.equal(null); - let message = validHipChatMessage.item.message.message; - if (message.indexOf(HipChatMessageFormatter.COMMAND_OPERATOR) === 0) { - message = message.slice(HipChatMessageFormatter.COMMAND_OPERATOR.length + 1); - } - expect(hipChatRes.card.title).to.equal(message); + let message = validHipChatMessage.item.message.message; + if (message.indexOf(HipChatMessageFormatter.COMMAND_OPERATOR) === 0) { + message = message.slice(HipChatMessageFormatter.COMMAND_OPERATOR.length + 1); } - }; - app.process(hipChatReq, res); + expect(hipChatRes.card.title).to.equal(message); + } + ); }); - it("process() should return default message if invalid Slack message", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(400); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).not.to.be.an.instanceof(SlackModule.SlackResponse); - expect(body).to.equal(Constants.INVALID_MESSAGE_STRING); - } - }; - app.process(badSlackReq, res); + it("process() should return default message if invalid Slack message", () => { + let res = new MockExpressResponse(); + + return app.process(badSlackReq, res).catch( (result) => { + expect(res.statusCode).to.equal(400); + + let body = res._getString(); + expect(body).not.to.equal(null); + expect(body).not.to.be.an.instanceof(SlackModule.SlackResponse); + expect(body).to.equal(Constants.INVALID_MESSAGE_STRING); + }); }); - it("process() should return default if invalid HipChat message", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(400); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).not.to.be.an.instanceof(HipChatModule.HipChatResponse); - expect(body).to.equal(Constants.INVALID_MESSAGE_STRING); - } - }; - app.process(badHipChatReq, res); + it("process() should return default if invalid HipChat message", () => { + + let res = new MockExpressResponse(); + + app.process(badHipChatReq, res).catch((result) => { + expect(res.statusCode).to.equal(400); + + let body = res._getString(); + expect(body).not.to.equal(null); + expect(body).not.to.be.an.instanceof(HipChatModule.HipChatResponse); + expect(body).to.equal(Constants.INVALID_MESSAGE_STRING); + }); }); - it("process() should return default if invalid message", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(400); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).to.equal(Constants.INVALID_MESSAGE_STRING); - } - }; - app.process(new EmptyRequest(), res); + it("process() should return default if invalid message", () => { + + let res = new MockExpressResponse(); + + app.process(new EmptyRequest(), res).catch( (result) => { + + expect(res.statusCode).to.equal(400); + + let body = res._getString(); + + expect(body).not.to.equal(null); + expect(body).to.equal(Constants.INVALID_MESSAGE_STRING); + }); }); - it("process() should return no restaurants if valid Slack message returns nothing", function () { + it("process() should return no restaurants if valid Slack message returns nothing", () => { let slackEmptyReq : SlackModule.SlackRequest = deepCopy(slackReq); - slackEmptyReq.body.text = "BlaBlaBla"; - - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(SlackModule.SlackResponse); + slackEmptyReq.body.text = badRestaurantName; - let slackRes : SlackModule.SlackResponse = body as SlackModule.SlackResponse; + let res = new MockExpressResponse(); + return app.process(slackEmptyReq, res).then ((result) => { - expect(slackRes.text).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING + " for: " + badRestaurantName); - expect(slackRes.response_type).to.equal("ephemeral"); - expect(slackRes.attachments).to.equal(null); - } - }; - app.process(slackEmptyReq, res); + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); + + expect(slackRes.text).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING + " for: " + badRestaurantName); + expect(slackRes.response_type).to.equal("ephemeral"); + expect(slackRes.attachments).to.equal(null); + }); }); - it("process() should return no restaurants if valid HipChat message returns nothing", function () { + it("process() should return no restaurants if valid HipChat message returns nothing", () => { let hipChatEmptyReq : HipChatModule.HipChatReq = deepCopy(hipChatReq); hipChatEmptyReq.body.item.message.message = HipChatMessageFormatter.COMMAND_OPERATOR + " " + badRestaurantName; + let res = new MockExpressResponse(); - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(HipChatModule.HipChatResponse); - - let hipChatRes : HipChatModule.HipChatResponse = body as HipChatModule.HipChatResponse; + return app.process(hipChatEmptyReq, res).then((result) => { + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let hipChatRes : HipChatModule.HipChatResponse = body; + expect(hipChatRes).not.to.equal(null); - expect(hipChatRes.message.replace(/^\s+|\s+$/g, "")).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING + " for: " + badRestaurantName); - expect(hipChatRes.message_format).to.equal("text"); - expect(hipChatRes.card).not.to.equal(null); + expect(hipChatRes.message.replace(/^\s+|\s+$/g, "")).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING + " for: " + badRestaurantName); + expect(hipChatRes.message_format).to.equal("text"); + expect(hipChatRes.card).not.to.equal(null); - let message = validHipChatMessage.item.message.message; - if (message.indexOf(HipChatMessageFormatter.COMMAND_OPERATOR) === 0) { - message = message.slice(HipChatMessageFormatter.COMMAND_OPERATOR.length + 1); - } + let message = validHipChatMessage.item.message.message; + if (message.indexOf(HipChatMessageFormatter.COMMAND_OPERATOR) === 0) { + message = message.slice(HipChatMessageFormatter.COMMAND_OPERATOR.length + 1); } - }; - app.process(hipChatEmptyReq, res); + }); }); - it("process() should return valid response if command is total", function () { + it("process() should return valid response if command is total", () => { let slackTotalReq : SlackModule.SlackRequest = deepCopy(slackReq); slackTotalReq.body.text = Constants.TOTAL_KEYWORD; - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { - expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(SlackModule.SlackResponse); + let res = new MockExpressResponse(); - let slackRes : SlackModule.SlackResponse = body as SlackModule.SlackResponse; - expect(slackRes.response_type).to.equal("ephemeral"); - } - }; - app.process(slackTotalReq, res); + app.process(slackTotalReq, res).then((result) => { + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); + expect(slackRes.response_type).to.equal("ephemeral"); + }); }); - it("process() should return no restaurants if valid HipChat message returns nothing", function () { + it("process() should return error if using empty restaurant name for slack", () => { + let slackTotalReq : SlackModule.SlackRequest = deepCopy(slackReq); + slackTotalReq.body.text = ""; + + let res = new MockExpressResponse(); + + app.process(slackTotalReq, res).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); + expect(slackRes.response_type).to.equal("ephemeral"); + expect(slackRes.text).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING); + }); + }); + it("process() should return error if using empty restaurant name for hipchat", () => { + let hipChatRequest : HipChatModule.HipChatReq = deepCopy(hipChatReq); + hipChatRequest.body.item.message.message = "/10bis "; + + let res = new MockExpressResponse(); + + app.process(hipChatRequest, res).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let hipChatResponse : HipChatModule.HipChatResponse = body; + + expect(hipChatResponse).not.to.equal(null); + expect(hipChatResponse.message_format).to.equal("text"); + expect(hipChatResponse.message).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING); + }); + }); + it("process() should return no restaurants if valid HipChat message returns nothing", () => { let hipChatTotalReq : HipChatModule.HipChatReq = deepCopy(hipChatReq); hipChatTotalReq.body.item.message.message = HipChatMessageFormatter.COMMAND_OPERATOR + " " + Constants.TOTAL_KEYWORD; + let res = new MockExpressResponse(); + + return app.process(hipChatTotalReq, res).then((result) => { + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let hipChatRes : HipChatModule.HipChatResponse = body; + expect(hipChatRes).not.to.equal(null); + expect(hipChatRes.message_format).to.equal("text"); + }); + }); + it("getTotalOrders() should return valid response if command is total", () => { + let res = new MockExpressResponse(); + + return app.getTotalOrders(res, SlackMessageFormatter.getInstance()).then((result) => { + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); + expect(slackRes.response_type).to.equal("ephemeral"); + }); + }); + it("getTotalOrders() should return valid response if command is total", () => { + let res = new MockExpressResponse(); + + return app.getTotalOrders(res, HipChatMessageFormatter.getInstance()).then((result) => { + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let hipChatRes : HipChatModule.HipChatResponse = body; + expect(hipChatRes).not.to.equal(null); + expect(hipChatRes.message_format).to.equal("text"); + }); + }); + it("search() with null restaurant name - Slack", () => { + let res = new MockExpressResponse(); + + return app.search(res, SlackMessageFormatter.getInstance(), null).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); + expect(slackRes.response_type).to.equal("ephemeral"); + expect(slackRes.text).to.equal(Constants.DEFAULT_RESPONSE); + }); + }); + it("search() with null restaurant name - HipChat", () => { + let res = new MockExpressResponse(); + + return app.search(res, HipChatMessageFormatter.getInstance(), null).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let hipChatResponse : HipChatModule.HipChatResponse = body; + + expect(hipChatResponse).not.to.equal(null); + expect(hipChatResponse.message_format).to.equal("text"); + expect(hipChatResponse.message).to.equal(Constants.DEFAULT_RESPONSE); + }); + }); + it("search() with empty restaurant name - Slack", () => { + let res = new MockExpressResponse(); + + return app.search(res, SlackMessageFormatter.getInstance(), "").catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); + expect(slackRes.response_type).to.equal("ephemeral"); + expect(slackRes.text).to.equal(Constants.DEFAULT_RESPONSE); + }); + }); + it("search() with empty restaurant name - HipChat", () => { + let res = new MockExpressResponse(); + + return app.search(res, HipChatMessageFormatter.getInstance(), "").catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let hipChatResponse : HipChatModule.HipChatResponse = body; + + expect(hipChatResponse).not.to.equal(null); + expect(hipChatResponse.message_format).to.equal("text"); + expect(hipChatResponse.message).to.equal(Constants.DEFAULT_RESPONSE); + }); + }); + describe("ResponseCode from 10bis != 200", () => { + beforeEach(function() { + this.get = sinon.stub(request, "get"); + let res = new MockExpressResponse(); + res.statusCode = 201; + + this.get.yields(null, res , null); + }); + + afterEach(function() { + (this.get as sinon.SinonStub).restore(); + }); + + it("process() with other response than 200", () => { + let res = new MockExpressResponse(); + + return app.process(slackReq, res).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getString(); - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(HipChatModule.HipChatResponse); + expect(body).not.to.be.an.instanceof(SlackModule.SlackResponse); + expect(body).to.be.equal(Constants.ERROR_STRING); + }); + }); + it("search() with response code = 201", () => { + let res = new MockExpressResponse(); - let hipChatRes : HipChatModule.HipChatResponse = body as HipChatModule.HipChatResponse; + return app.search(res, SlackMessageFormatter.getInstance(), badRestaurantName).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getString(); - expect(hipChatRes.message_format).to.equal("text"); - } - }; - app.process(hipChatTotalReq, res); + expect(body).not.to.equal(null); + expect(body).not.to.be.an.instanceof(SlackModule.SlackResponse); + expect(body).to.be.equal(Constants.ERROR_STRING); + }); + }); + it("getTotalOrders() with error = 201", () => { + let res = new MockExpressResponse(); + return app.getTotalOrders(res, SlackMessageFormatter.getInstance()).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getString(); + + expect(body).not.to.equal(null); + expect(body).not.to.be.an.instanceof(SlackModule.SlackResponse); + expect(body).to.be.equal(Constants.ERROR_STRING); + }); + }); }); - it("getTotalOrders() should return valid response if command is total", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { + + describe("ResponseCode from 10bis == 200 with empty response", () => { + beforeEach(function() { + this.get = sinon.stub(request, "get"); + let res = new MockExpressResponse(); + res.body = ""; + this.get.yields(null, res , null); + }); + + afterEach(function() { + (this.get as sinon.SinonStub).restore(); + }); + + it("process() with response == 200 with empty content", () => { + let res = new MockExpressResponse(); + + return app.process(slackReq, res).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(SlackModule.SlackResponse); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); - let slackRes : SlackModule.SlackResponse = body as SlackModule.SlackResponse; + expect(slackRes.text).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING + " for: " + "דיקסי"); expect(slackRes.response_type).to.equal("ephemeral"); - } - }; - app.getTotalOrders(res, SlackMessageFormatter.getInstance()); - }); - it("getTotalOrders() should return valid response if command is total", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(200); - }, - send: function(body: Commons.TenBisResponse) { + expect(slackRes.attachments).to.equal(null); + }); + }); + it("search() with response == 200 with empty content", () => { + let res = new MockExpressResponse(); + + return app.search(res, SlackMessageFormatter.getInstance(), badRestaurantName).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); expect(body).not.to.equal(null); - expect(body).to.be.an.instanceof(HipChatModule.HipChatResponse); + let slackRes : SlackModule.SlackResponse = body; - let hipChatRes : HipChatModule.HipChatResponse = body as HipChatModule.HipChatResponse; + expect(slackRes).not.to.equal(null); - expect(hipChatRes.message_format).to.equal("text"); - } - }; - app.getTotalOrders(res, HipChatMessageFormatter.getInstance()); + expect(slackRes.text).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING + " for: " + badRestaurantName); + expect(slackRes.response_type).to.equal("ephemeral"); + expect(slackRes.attachments).to.equal(null); + }); + }); + it("getTotalOrders() with response == 200 with empty content", () => { + let res = new MockExpressResponse(); + return app.getTotalOrders(res, SlackMessageFormatter.getInstance()).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + + expect(res.statusCode).to.be.equal(200); + let body = res._getJSON(); + expect(body).not.to.equal(null); + let slackRes : SlackModule.SlackResponse = body; + + expect(slackRes).not.to.equal(null); + + expect(slackRes.text).to.equal(Constants.NO_RESTAURANTS_FOUND_STRING); + expect(slackRes.response_type).to.equal("ephemeral"); + expect(slackRes.attachments).to.equal(null); + }); + }); }); - it("process() with error", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(400); - }, - send: function(body: Commons.TenBisResponse) { + + describe("Response from 10bis is error (400)", () => { + beforeEach(function() { + this.get = sinon.stub(request, "get"); + this.get.yields("error", null , null); + }); + + afterEach(function() { + (this.get as sinon.SinonStub).restore(); + }); + + it("process() with error (400)", () => { + let res = new MockExpressResponse(); + + return app.process(slackReq, res).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getString(); + expect(body).not.to.equal(null); expect(body).not.to.be.an.instanceof(SlackModule.SlackResponse); expect(body).to.be.equal(Constants.ERROR_STRING); - } - }; - this.get.yields("error", null , null); - app.process(slackReq, res); - }); - it("search() with error", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(400); - }, - send: function(body: Commons.TenBisResponse) { + }); + }); + it("search() with error (400)", () => { + let res = new MockExpressResponse(); + + return app.search(res, SlackMessageFormatter.getInstance(), badRestaurantName).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getString(); + expect(body).not.to.equal(null); expect(body).not.to.be.an.instanceof(HipChatModule.HipChatResponse); expect(body).to.be.equal(Constants.ERROR_STRING); - } - }; - this.get.yields("error", null , null); - app.search(res, SlackMessageFormatter.getInstance(), badRestaurantName); - }); - it("getTotalOrders() with error", function () { - let res : Commons.Response = { - statusCode: 200, - status: function(num : number) { - expect(num).to.equal(400); - }, - send: function(body: Commons.TenBisResponse) { + }); + }); + it("getTotalOrders() with error (400)", () => { + let res = new MockExpressResponse(); + + return app.getTotalOrders(res, SlackMessageFormatter.getInstance()).then((result) => { + throw new Error("I shouldn't be here"); + }).catch((result) => { + expect(res.statusCode).to.be.equal(400); + let body = res._getString(); + expect(body).not.to.equal(null); expect(body).not.to.be.an.instanceof(HipChatModule.HipChatResponse); expect(body).to.be.equal(Constants.ERROR_STRING); - } - }; - this.get.yields("error", null , null); - app.getTotalOrders(res, SlackMessageFormatter.getInstance()); + }); + }); }); }); \ No newline at end of file diff --git a/test/commons.test.ts b/test/commons.test.ts index dcc0b0e4..e1e6acd5 100644 --- a/test/commons.test.ts +++ b/test/commons.test.ts @@ -7,10 +7,8 @@ import "mocha"; import { expect } from "chai"; import { restaurants, validSlackMessage, validHipChatMessage, slackInvalidMessage, hipChatInvalidMessage } from "./testCommons"; -var rewire = require("rewire"); -var app = rewire("./../src/app.js"); -var slackMessageFormatter = SlackMessageFormatter.getInstance(); -var hipChatMessageFormatter = HipChatMessageFormatter.getInstance(); +let slackMessageFormatter : Commons.MessageFormatter = SlackMessageFormatter.getInstance(); +let hipChatMessageFormatter : Commons.MessageFormatter = HipChatMessageFormatter.getInstance(); export class Req { body: string; @@ -50,14 +48,14 @@ describe("App", function () { it("generateSearchRequest() should return a valid request", function () { - var generatedRequest = Commons.generateSearchRequest("Rest"); + let generatedRequest : string = Commons.generateSearchRequest("Rest"); expect(generatedRequest).not.to.equal(null); expect(generatedRequest.includes("searchPhrase=Rest")).to.equal(true); }); it("generateGetTotalOrdersRequest() should return a valid request", function () { - var generatedRequest = Commons.generateGetTotalOrdersRequest(); + let generatedRequest : string = Commons.generateGetTotalOrdersRequest(); expect(generatedRequest).not.to.equal(null); expect(generatedRequest.includes("deliveryMethod=Delivery")).to.equal(true); @@ -68,24 +66,24 @@ describe("App", function () { let restaurant2 : Commons.Restaurant = new Commons.RestaurantBuilder().setRestaurantName("Rest2").setRestaurantId(2).build(); let restaurant3 : Commons.Restaurant = new Commons.RestaurantBuilder().setRestaurantName("Rest1").setRestaurantId(3).build(); - var result = Commons.filterByRestaurantName([restaurant1, restaurant2, restaurant3]); + let restaurants : Commons.Restaurant[] = Commons.filterByRestaurantName([restaurant1, restaurant2, restaurant3]); - expect(result).not.to.equal(null); - expect(result.length).to.equal(2); - expect(result.some(function(element : Commons.Restaurant) { + expect(restaurants).not.to.equal(null); + expect(restaurants.length).to.equal(2); + expect(restaurants.some(function(element : Commons.Restaurant) { return element.RestaurantName === restaurant1.RestaurantName; })).to.equal(true); - expect(result.some(function(element : Commons.Restaurant) { + expect(restaurants.some(function(element : Commons.Restaurant) { return element.RestaurantName === restaurant2.RestaurantName; })).to.equal(true); }); it("filterByRestaurantName() should be ok with an empty array", function () { - var result = Commons.filterByRestaurantName([]); + let restaurants : Commons.Restaurant[] = Commons.filterByRestaurantName([]); - expect(result).not.to.equal(null); - expect(result.length).to.equal(0); + expect(restaurants).not.to.equal(null); + expect(restaurants.length).to.equal(0); }); it("filterByRestaurantName() should filter restaurants with the same name", function () { @@ -93,105 +91,105 @@ describe("App", function () { let restaurant2 : Commons.Restaurant = new Commons.RestaurantBuilder().setRestaurantName("Rest2").setRestaurantId(2).build(); let restaurant3 : Commons.Restaurant = new Commons.RestaurantBuilder().setRestaurantName("Rest1").setRestaurantId(3).build(); - var result = Commons.filterByRestaurantName([restaurant1, restaurant2, restaurant3]); + let restaurants : Commons.Restaurant[] = Commons.filterByRestaurantName([restaurant1, restaurant2, restaurant3]); - expect(result).not.to.equal(null); - expect(result.length).to.equal(2); - expect(result.some(function(element : Commons.Restaurant) { + expect(restaurants).not.to.equal(null); + expect(restaurants.length).to.equal(2); + expect(restaurants.some(function(element : Commons.Restaurant) { return element.RestaurantName === restaurant1.RestaurantName; })).to.equal(true); - expect(result.some(function(element : Commons.Restaurant) { + expect(restaurants.some(function(element : Commons.Restaurant) { return element.RestaurantName === restaurant2.RestaurantName; })).to.equal(true); }); it("sortRestaurantsByDistance() should sort restaurants by distance", function () { - var restaurant1 = new Commons.RestaurantBuilder() + let restaurant1 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest1") .setRestaurantId(1) .setDistanceFromUserInMeters(10) .build(); - var restaurant2 = new Commons.RestaurantBuilder() + let restaurant2 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest2") .setRestaurantId(2) .setDistanceFromUserInMeters(20) .build(); - var restaurant3 = new Commons.RestaurantBuilder() + let restaurant3 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest3") .setRestaurantId(1) .setDistanceFromUserInMeters(15) .build(); - var result = Commons.sortRestaurantsByDistance([restaurant1, restaurant2, restaurant3]); + let restaurants : Commons.Restaurant[] = Commons.sortRestaurantsByDistance([restaurant1, restaurant2, restaurant3]); - expect(result).not.to.equal(null); - expect(result.length).to.equal(3); - expect(result[0].RestaurantName).to.be.equal(restaurant1.RestaurantName); - expect(result[1].RestaurantName).to.be.equal(restaurant3.RestaurantName); - expect(result[2].RestaurantName).to.be.equal(restaurant2.RestaurantName); + expect(restaurants).not.to.equal(null); + expect(restaurants.length).to.equal(3); + expect(restaurants[0].RestaurantName).to.be.equal(restaurant1.RestaurantName); + expect(restaurants[1].RestaurantName).to.be.equal(restaurant3.RestaurantName); + expect(restaurants[2].RestaurantName).to.be.equal(restaurant2.RestaurantName); }); it("sortRestaurantsByDistance() should sort restaurants by distance even when there are bad distances", function () { - var restaurant4 = new Commons.RestaurantBuilder() + let restaurant4 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest4") .setRestaurantId(4) .setDistanceFromUserInMeters(25) .build(); - var restaurant1 = new Commons.RestaurantBuilder() + let restaurant1 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest1") .setRestaurantId(1) .build(); - var restaurant2 = new Commons.RestaurantBuilder() + let restaurant2 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest2") .setRestaurantId(2) .setDistanceFromUserInMeters(15) .build(); - var restaurant3 = new Commons.RestaurantBuilder() + let restaurant3 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest3") .setRestaurantId(1) .build(); - var result = Commons.sortRestaurantsByDistance([restaurant4, restaurant1, restaurant2, restaurant3]); + let restaurants : Commons.Restaurant[] = Commons.sortRestaurantsByDistance([restaurant4, restaurant1, restaurant2, restaurant3]); - expect(result).not.to.equal(null); - expect(result.length).to.equal(4); - expect(result[0].RestaurantName).to.be.equal(restaurant2.RestaurantName); - expect(result[1].RestaurantName).to.be.equal(restaurant4.RestaurantName); - expect(result[2].RestaurantName).to.be.equal(restaurant1.RestaurantName); - expect(result[3].RestaurantName).to.be.equal(restaurant3.RestaurantName); + expect(restaurants).not.to.equal(null); + expect(restaurants.length).to.equal(4); + expect(restaurants[0].RestaurantName).to.be.equal(restaurant2.RestaurantName); + expect(restaurants[1].RestaurantName).to.be.equal(restaurant4.RestaurantName); + expect(restaurants[2].RestaurantName).to.be.equal(restaurant1.RestaurantName); + expect(restaurants[3].RestaurantName).to.be.equal(restaurant3.RestaurantName); }); it("sortRestaurantsByDistance() should do nothing when fields are equal", function () { - var restaurant1 = new Commons.RestaurantBuilder() + let restaurant1 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest1") .setRestaurantId(1) .setDistanceFromUserInMeters(15) .build(); - var restaurant2 = new Commons.RestaurantBuilder() + let restaurant2 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest2") .setRestaurantId(2) .setDistanceFromUserInMeters(7) .build(); - var restaurant3 = new Commons.RestaurantBuilder() + let restaurant3 : Commons.Restaurant = new Commons.RestaurantBuilder() .setRestaurantName("Rest3") .setRestaurantId(3) .setDistanceFromUserInMeters(7) .build(); - var result = Commons.sortRestaurantsByDistance([restaurant1, restaurant2, restaurant3]); + let restaurants : Commons.Restaurant[] = Commons.sortRestaurantsByDistance([restaurant1, restaurant2, restaurant3]); - expect(result).not.to.equal(null); - expect(result.length).to.equal(3); - expect(result[0].RestaurantName).to.be.equal(restaurant2.RestaurantName); - expect(result[1].RestaurantName).to.be.equal(restaurant3.RestaurantName); - expect(result[2].RestaurantName).to.be.equal(restaurant1.RestaurantName); + expect(restaurants).not.to.equal(null); + expect(restaurants.length).to.equal(3); + expect(restaurants[0].RestaurantName).to.be.equal(restaurant2.RestaurantName); + expect(restaurants[1].RestaurantName).to.be.equal(restaurant3.RestaurantName); + expect(restaurants[2].RestaurantName).to.be.equal(restaurant1.RestaurantName); }); it("sortRestaurantsByDistance() should do nothing when no field", function () { @@ -200,17 +198,17 @@ describe("App", function () { let restaurant3 : Commons.Restaurant = new Commons.RestaurantBuilder().setRestaurantName("Rest3").setRestaurantId(3).build(); - var result = Commons.sortRestaurantsByDistance([restaurant1, restaurant2, restaurant3]); + let restaurants = Commons.sortRestaurantsByDistance([restaurant1, restaurant2, restaurant3]); - expect(result).not.to.equal(null); - expect(result.length).to.equal(3); - expect(result[0].RestaurantName).to.be.equal(restaurant1.RestaurantName); - expect(result[1].RestaurantName).to.be.equal(restaurant2.RestaurantName); - expect(result[2].RestaurantName).to.be.equal(restaurant3.RestaurantName); + expect(restaurants).not.to.equal(null); + expect(restaurants.length).to.equal(3); + expect(restaurants[0].RestaurantName).to.be.equal(restaurant1.RestaurantName); + expect(restaurants[1].RestaurantName).to.be.equal(restaurant2.RestaurantName); + expect(restaurants[2].RestaurantName).to.be.equal(restaurant3.RestaurantName); }); it("filterTotalOrders() should filter the restaurants correctly", function () { - var filteredRestaurants = restaurants.filter(Commons.filterTotalOrders); + let filteredRestaurants : Commons.Restaurant[] = restaurants.filter(Commons.filterTotalOrders); expect(filteredRestaurants).not.to.equal(null); expect(filteredRestaurants.length).to.equal(2); diff --git a/test/hipChatMessage.test.ts b/test/hipChatMessage.test.ts index 1af67f84..9b2b28a9 100644 --- a/test/hipChatMessage.test.ts +++ b/test/hipChatMessage.test.ts @@ -5,9 +5,9 @@ import { HipChatMessageFormatter } from "../src/hipChatMessage"; import { Commons } from "../src/commons"; import "mocha"; import { Constants } from "../src/constants"; +import { Request } from "express"; +import { expect } from "chai"; -var chai = require("chai"); -var expect = chai.expect; // we are using the "expect" style of Chai let hipChatMessage = HipChatMessageFormatter.getInstance(); let message = new HipChatModule.HipChatReqBody("room_message", @@ -103,7 +103,7 @@ describe("HipChatMessage", function() { }); it("isValidMessage() should return false if request body is missing", function() { - var req = null; + let req : Request = null; expect(hipChatMessage.isValidMessage(req)).to.equal(false); }); @@ -131,7 +131,7 @@ describe("HipChatMessage", function() { it("generateSearchResponse() should return a valid message with restaurant list", function() { let expectedResponse = deepCopy(goodResponse); - var response = hipChatMessage.generateSearchResponse(restaurants); + let response : HipChatModule.HipChatResponse = hipChatMessage.generateSearchResponse(restaurants); expect(response.color).to.equal(expectedResponse.color); expect(response.message.startsWith("Found 3 restaurants")).to.equal(true); @@ -141,7 +141,7 @@ describe("HipChatMessage", function() { it("generateSearchResponse() should return a valid message with restaurant list of 1 restaurant", function() { let expectedResponse = deepCopy(goodResponse); - var response = hipChatMessage.generateSearchResponse([restaurants[0]]); + let response : HipChatModule.HipChatResponse = hipChatMessage.generateSearchResponse([restaurants[0]]); expect(response.color).to.equal(expectedResponse.color); expect(response.message.startsWith("Found 1 restaurants")).to.equal(true); @@ -151,7 +151,7 @@ describe("HipChatMessage", function() { it("getRestaurantName() should return right restaruant name from request", function() { let req = new HipChatModule.HipChatReq(deepCopy(message)); - var restaurantName = hipChatMessage.getRestaurantName(req); + let restaurantName : string = hipChatMessage.getRestaurantName(req); expect(restaurantName).to.equal("דיקסי"); }); @@ -159,7 +159,7 @@ describe("HipChatMessage", function() { it("getRestaurantName() should return an empty restaruant name from request with only command", function() { let req = new HipChatModule.HipChatReq(deepCopy(message)); req.body.item.message.message = "/10bis"; - var restaurantName = hipChatMessage.getRestaurantName(req); + let restaurantName : string = hipChatMessage.getRestaurantName(req); expect(restaurantName).to.equal(""); }); @@ -167,14 +167,14 @@ describe("HipChatMessage", function() { it("getRestaurantName() should return null with bad field", function() { let req = new HipChatModule.HipChatReq(deepCopy(message)); req.body.item.message.message = null; - var restaurantName = hipChatMessage.getRestaurantName(req); + let restaurantName : string = hipChatMessage.getRestaurantName(req); expect(restaurantName).to.equal(null); }); it("getErrorMessage() should return a valid error message without restaurants name", function() { let expectedResponse = deepCopy(errorResponse); - var response = hipChatMessage.getErrorMessage(null); + let response : HipChatModule.HipChatResponse = hipChatMessage.getErrorMessage(null); expect(response.color).to.equal(expectedResponse.color); expect(response.message).to.equal(expectedResponse.message); @@ -184,7 +184,7 @@ describe("HipChatMessage", function() { it("getErrorMessage() should return a valid error message with passed restaurants name", function() { let expectedResponse = deepCopy(errorResponse); - var response = hipChatMessage.getErrorMessage("גוטה"); + let response : HipChatModule.HipChatResponse = hipChatMessage.getErrorMessage("גוטה"); expect(response.color).to.equal(expectedResponse.color); expect(response.message).to.equal(expectedResponse.message + " for: גוטה"); @@ -193,9 +193,9 @@ describe("HipChatMessage", function() { }); it("generateRestaurantCard() should return a valid card", function() { - let restaruant = generateRestaurant(); + let restaruant : Commons.Restaurant = generateRestaurant(); - var response = hipChatMessage.generateRestaurantCard(restaruant); + let response : HipChatModule.HipChatCard = hipChatMessage.generateRestaurantCard(restaruant); // Can"t do the following due to on the spot generation of guid and time // expect(response).to.deep.equal(validCard); @@ -210,8 +210,8 @@ describe("HipChatMessage", function() { }); it("generateTotalOrdersResponse() should return a valid message without restaurant list", function() { - let expectedResponse = deepCopy(goodResponse); - var response = hipChatMessage.generateTotalOrdersResponse([]); + let expectedResponse : HipChatModule.HipChatResponse = deepCopy(goodResponse); + let response : HipChatModule.HipChatResponse = hipChatMessage.generateTotalOrdersResponse([]); expect(response.color).to.equal(expectedResponse.color); expect(response.message).to.equal("No pool order restaurants found"); @@ -220,8 +220,8 @@ describe("HipChatMessage", function() { }); it("generateTotalOrdersResponse() should return a valid message with restaurant list", function() { - let expectedResponse = deepCopy(goodResponse); - var response = hipChatMessage.generateTotalOrdersResponse(restaurants); + let expectedResponse : HipChatModule.HipChatResponse = deepCopy(goodResponse); + let response : HipChatModule.HipChatResponse = hipChatMessage.generateTotalOrdersResponse(restaurants); expect(response.color).to.equal(expectedResponse.color); expect(response.message.includes("[1]")).to.equal(true); @@ -234,7 +234,7 @@ describe("HipChatMessage", function() { it("constructor() should throw an exception if launched twice", function() { //Already ran constructor for HipChatMessageFormatter - let hipChatMessageFormatter = HipChatMessageFormatter.getInstance(); + let hipChatMessageFormatter : Commons.MessageFormatter = HipChatMessageFormatter.getInstance(); expect(hipChatMessageFormatter).not.to.equal(null); expect(HipChatMessageFormatter.getInstance()).not.to.equal(null); @@ -245,9 +245,9 @@ describe("HipChatMessage", function() { } }); it("getDefaultResponse() should return a default response", function() { - let hipChatMessageFormatter = HipChatMessageFormatter.getInstance(); + let hipChatMessageFormatter : Commons.MessageFormatter = HipChatMessageFormatter.getInstance(); - let response = hipChatMessageFormatter.getDefaultResponse() as HipChatModule.HipChatResponse; + let response : HipChatModule.HipChatResponse = hipChatMessageFormatter.getDefaultResponse() as HipChatModule.HipChatResponse; expect(response.color).to.equal("green"); // tslint:disable-next-line:no-unused-expression diff --git a/test/slackMessage.test.ts b/test/slackMessage.test.ts index 689d9687..4a4ad76d 100644 --- a/test/slackMessage.test.ts +++ b/test/slackMessage.test.ts @@ -3,9 +3,8 @@ import { SlackModule } from "../src/slackModule"; import { deepCopy, restaurants } from "./testCommons"; import { SlackMessageFormatter } from "../src/slackMessage"; import { Commons } from "../src/commons"; +import { expect } from "chai"; -var chai = require("chai"); -var expect = chai.expect; // we are using the "expect" style of Chai let slackMessage = SlackMessageFormatter.getInstance(); let message = new SlackModule.SlackMessage("ItoB7oEyZIbNmHPfxHQ2GrbC", "T0001", "example", @@ -92,12 +91,12 @@ describe("SlackMessage", function() { }); it("isValidMessage() should return false if request body is missing", function() { - var req = null; + let req : SlackModule.SlackRequest = null; expect(slackMessage.isValidMessage(req)).to.equal(false); }); it("isValidMessage() should return true if message body is only the command", function() { - var req = new SlackModule.SlackRequest(null); + let req : SlackModule.SlackRequest = new SlackModule.SlackRequest(null); req.body = deepCopy(message); req.body.command = "/10bis"; req.body.text = ""; @@ -105,15 +104,15 @@ describe("SlackMessage", function() { }); it("isValidMessage() should return true if message body doesn't start with the command", function() { - var req = new SlackModule.SlackRequest(null); + let req : SlackModule.SlackRequest = new SlackModule.SlackRequest(null); req.body = deepCopy(message); req.body.command = "/test"; expect(slackMessage.isValidMessage(req)).to.equal(false); }); it("generateSearchResponse() should return a valid message without restaurant list", function() { - var expectedResponse = deepCopy(goodResponse); - var response = slackMessage.generateSearchResponse([]); + let expectedResponse : SlackModule.SlackResponse = deepCopy(goodResponse); + let response : SlackModule.SlackResponse = slackMessage.generateSearchResponse([]); expect(response.response_type).to.equal(expectedResponse.response_type); expect(response.text).to.equal(expectedResponse.text); @@ -121,8 +120,8 @@ describe("SlackMessage", function() { }); it("generateSearchResponse() should return a valid message with restaurant list", function() { - var expectedResponse = deepCopy(goodResponse); - var response = slackMessage.generateSearchResponse(restaurants); + let expectedResponse : SlackModule.SlackResponse = deepCopy(goodResponse); + let response : SlackModule.SlackResponse = slackMessage.generateSearchResponse(restaurants); expect(response.response_type).to.equal(expectedResponse.response_type); expect(response.text).to.equal("Found 3 restaurants"); @@ -136,7 +135,7 @@ describe("SlackMessage", function() { bigAmountOfRestaurants = bigAmountOfRestaurants.concat(restaurants); bigAmountOfRestaurants = bigAmountOfRestaurants.concat(restaurants); - var response = slackMessage.generateSearchResponse(bigAmountOfRestaurants); + let response : SlackModule.SlackResponse = slackMessage.generateSearchResponse(bigAmountOfRestaurants); expect(response.response_type).to.equal(goodResponse.response_type); expect(response.text).to.equal("Found " + bigAmountOfRestaurants.length + " restaurants"); @@ -145,47 +144,47 @@ describe("SlackMessage", function() { }); it("getRestaurantName() should return right restaruant name from request", function() { - let req = new SlackModule.SlackRequest(deepCopy(message)); - var restaurantName = slackMessage.getRestaurantName(req); + let req : SlackModule.SlackRequest = new SlackModule.SlackRequest(deepCopy(message)); + let restaurantName : string = slackMessage.getRestaurantName(req); expect(restaurantName).to.equal("דיקסי"); }); it("getRestaurantName() should return null if no body exists", function() { - let req = new SlackModule.SlackRequest(deepCopy(message)); + let req : SlackModule.SlackRequest = new SlackModule.SlackRequest(deepCopy(message)); req.body = null; - var restaurantName = slackMessage.getRestaurantName(req); + let restaurantName : string = slackMessage.getRestaurantName(req); expect(restaurantName).to.equal(null); }); it("getRestaurantName() should return an empty restaruant name from request with only command", function() { - var req = new SlackModule.SlackRequest(null); + let req : SlackModule.SlackRequest = new SlackModule.SlackRequest(null); req.body = deepCopy(message); req.body.text = ""; - var restaurantName = slackMessage.getRestaurantName(req); + let restaurantName : string = slackMessage.getRestaurantName(req); expect(restaurantName).to.equal(""); }); it("getRestaurantName() should return null with bad field", function() { - var req = new SlackModule.SlackRequest(null); + let req : SlackModule.SlackRequest = new SlackModule.SlackRequest(null); req.body = deepCopy(message); req.body.text = null; - var restaurantName = slackMessage.getRestaurantName(req); + let restaurantName : string = slackMessage.getRestaurantName(req); expect(restaurantName).to.equal(null); }); it("getErrorMessage() should return a valid error message without restaurants name", function() { - var expectedResponse = deepCopy(errorResponse); - var response = slackMessage.getErrorMessage(null); + let expectedResponse : SlackModule.SlackResponse = deepCopy(errorResponse); + let response : SlackModule.SlackResponse = slackMessage.getErrorMessage(null); expect(response.response_type).to.equal(expectedResponse.response_type); expect(response.text).to.equal(expectedResponse.text); }); it("getErrorMessage() should return a valid error message with passed restaurants name", function() { - var expectedResponse = deepCopy(errorResponse); - var response = slackMessage.getErrorMessage("גוטה"); + let expectedResponse : SlackModule.SlackResponse = deepCopy(errorResponse); + let response : SlackModule.SlackResponse = slackMessage.getErrorMessage("גוטה"); expect(response.response_type).to.equal(expectedResponse.response_type); expect(response.text).to.equal(expectedResponse.text + " for: גוטה"); @@ -202,23 +201,23 @@ describe("SlackMessage", function() { .setRestaurantLogoUrl("http://image.jpg") .build(); - var response = slackMessage.generateRestaurantCard(restaruant); + let attachment : SlackModule.SlackAttachment = slackMessage.generateRestaurantCard(restaruant); // Can"t do the following due to on the spot generation of guid and time // expect(response).to.deep.equal(validCard); - expect(response.color).to.equal(validCard.color); - expect(response.fallback).to.equal(validCard.fallback); - expect(response.fields).to.deep.equal(validCard.fields); - expect(response.text).to.equal(validCard.text); - expect(response.title).to.equal(validCard.title); - expect(response.title_link).to.equal(validCard.title_link); + expect(attachment.color).to.equal(validCard.color); + expect(attachment.fallback).to.equal(validCard.fallback); + expect(attachment.fields).to.deep.equal(validCard.fields); + expect(attachment.text).to.equal(validCard.text); + expect(attachment.title).to.equal(validCard.title); + expect(attachment.title_link).to.equal(validCard.title_link); }); it("generateTotalOrdersResponse() should return a valid message without restaurant list", function() { - var expectedResponse = deepCopy(goodResponse); - var response = slackMessage.generateTotalOrdersResponse([]); + let expectedResponse : SlackModule.SlackResponse = deepCopy(goodResponse); + let response : SlackModule.SlackResponse = slackMessage.generateTotalOrdersResponse([]); expect(response.response_type).to.equal(expectedResponse.response_type); expect(response.text).to.equal("No pool order restaurants found"); @@ -226,8 +225,8 @@ describe("SlackMessage", function() { }); it("generateTotalOrdersResponse() should return a valid message with restaurant list", function() { - var expectedResponse = deepCopy(goodResponse); - var response = slackMessage.generateTotalOrdersResponse([restaurants[0]]); + let expectedResponse : SlackModule.SlackResponse = deepCopy(goodResponse); + let response : SlackModule.SlackResponse = slackMessage.generateTotalOrdersResponse([restaurants[0]]); expect(response.response_type).to.equal(expectedResponse.response_type); expect(response.text).to.equal("Found 1 restaurants"); @@ -237,8 +236,8 @@ describe("SlackMessage", function() { it("generateTotalOrdersResponse() should return a valid message with restaurant list", function() { - var expectedResponse = deepCopy(goodResponse); - var response = slackMessage.generateTotalOrdersResponse(restaurants); + let expectedResponse : SlackModule.SlackResponse = deepCopy(goodResponse); + let response : SlackModule.SlackResponse = slackMessage.generateTotalOrdersResponse(restaurants); expect(response.response_type).to.equal(expectedResponse.response_type); expect(response.text).to.equal("Found 3 restaurants"); @@ -251,7 +250,7 @@ describe("SlackMessage", function() { bigAmountOfRestaurants = bigAmountOfRestaurants.concat(restaurants); bigAmountOfRestaurants = bigAmountOfRestaurants.concat(restaurants); bigAmountOfRestaurants = bigAmountOfRestaurants.concat(restaurants); - var response = slackMessage.generateTotalOrdersResponse(bigAmountOfRestaurants); + let response : SlackModule.SlackResponse = slackMessage.generateTotalOrdersResponse(bigAmountOfRestaurants); expect(response.response_type).to.equal(goodResponse.response_type); expect(response.text).to.equal("Found " + bigAmountOfRestaurants.length + " restaurants"); @@ -270,17 +269,17 @@ describe("SlackMessage", function() { .setRestaurantLogoUrl("http://image.jpg") .build(); - var response = slackMessage.generateRestaurantTotalCard(restaruant); + let attachment : SlackModule.SlackAttachment = slackMessage.generateRestaurantTotalCard(restaruant); // Can"t do the following due to on the spot generation of guid and time // expect(response).to.deep.equal(validCard); - expect(response.color).to.equal(validTotalCard.color); - expect(response.fallback).to.equal(validTotalCard.fallback); - expect(response.fields).to.deep.equal(validTotalCard.fields); - expect(response.text).to.equal(validTotalCard.text); - expect(response.title).to.equal(validTotalCard.title); - expect(response.title_link).to.equal(validTotalCard.title_link); + expect(attachment.color).to.equal(validTotalCard.color); + expect(attachment.fallback).to.equal(validTotalCard.fallback); + expect(attachment.fields).to.deep.equal(validTotalCard.fields); + expect(attachment.text).to.equal(validTotalCard.text); + expect(attachment.title).to.equal(validTotalCard.title); + expect(attachment.title_link).to.equal(validTotalCard.title_link); }); it("constructor() should throw an exception if launched twice", function() { diff --git a/test/testCommons.ts b/test/testCommons.ts index b9b3d990..8ffae389 100644 --- a/test/testCommons.ts +++ b/test/testCommons.ts @@ -1,14 +1,17 @@ import { Commons } from "../src/commons"; import { SlackModule } from "../src/slackModule"; import { HipChatModule } from "../src/hipChatModule"; +import { MockExpressResponse } from "mock-express-response"; +import { Response } from "express"; + export function deepCopy (o : Object) { return JSON.parse(JSON.stringify( o )); } export function compareKeys(objectA : any, objectB : any) : boolean { - var aKeys = Object.keys(objectA).sort(); - var bKeys = Object.keys(objectB).sort(); + let aKeys = Object.keys(objectA).sort(); + let bKeys = Object.keys(objectB).sort(); return JSON.stringify(aKeys) === JSON.stringify(bKeys); } diff --git a/typings.json b/typings.json index 7f22f231..7e53ea4a 100644 --- a/typings.json +++ b/typings.json @@ -1,9 +1,13 @@ { "globalDependencies": { + "es6-promise": "registry:dt/es6-promise#0.0.0+20160726191732", "mocha": "registry:dt/mocha#2.2.5+20170311011848", "node": "registry:dt/node#7.0.0+20170322231424" }, "dependencies": { "chai": "registry:npm/chai#3.5.0+20160723033700" + }, + "globalDevDependencies": { + "es6-shim": "registry:dt/es6-shim#0.31.2+20160726072212" } }