diff --git a/lib/alpha_vantage.coffee b/lib/alpha_vantage.coffee index 82f5271..ac20912 100644 --- a/lib/alpha_vantage.coffee +++ b/lib/alpha_vantage.coffee @@ -1,5 +1,6 @@ QueryString = require './query_string' AlphaVantageTimeSeriesDaily = require './alpha_vantage/time_series_daily' +AlphaVantageErrorMessage = require './alpha_vantage/error_message' AlphaVantageSlackMessage = require './alpha_vantage/slack_message' class AlphaVantage @@ -22,7 +23,7 @@ class AlphaVantage .get() (error, response, body) -> result = JSON.parse(body) if result.hasOwnProperty('Error Message') - callback(attachments: [{ color: '#ff0000', title: 'Error Message', text: result['Error Message'] }]) + callback(new AlphaVantageErrorMessage(result)) else outline = new AlphaVantageTimeSeriesDaily(result).outline() callback(new AlphaVantageSlackMessage(outline)) diff --git a/lib/alpha_vantage/error_message.coffee b/lib/alpha_vantage/error_message.coffee new file mode 100644 index 0000000..f4458ae --- /dev/null +++ b/lib/alpha_vantage/error_message.coffee @@ -0,0 +1,13 @@ +class AlphaVantageErrorMessage + _response = undefined + + constructor: (response) -> + _response = response + + format: -> + return attachments: [{ color: '#FF0000', title: 'Error Message', text: _response['Error Message'] }] + + toString: -> + return JSON.stringify(@format()) + +module.exports = AlphaVantageErrorMessage diff --git a/package.json b/package.json index 9ab6ca6..27e4e10 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "coveralls": "latest", "hubot-mock-adapter": "latest", "nyc": "latest", - "mocha": "latest" + "mocha": "latest", + "sinon": "latest" }, "engines": { "node": ">= 12.0.0", diff --git a/test/fixture/error_message.json b/test/fixture/error_message.json new file mode 100644 index 0000000..ca935a7 --- /dev/null +++ b/test/fixture/error_message.json @@ -0,0 +1,3 @@ +{ + "Error Message": "Invalid API call." +} diff --git a/test/lib/alpha_vantage.coffee b/test/lib/alpha_vantage.coffee index cc98fc2..a5d7f63 100644 --- a/test/lib/alpha_vantage.coffee +++ b/test/lib/alpha_vantage.coffee @@ -1,16 +1,55 @@ source = '../../lib/alpha_vantage' helper = require('../test_helper') expect = require('chai').expect +sinon = require('sinon') +Robot = require('hubot/src/robot') +AlphaVantageSlackMessage = require '../../lib/alpha_vantage/slack_message' +AlphaVantageErrorMessage = require '../../lib/alpha_vantage/error_message' AlphaVantage = require(source) describe 'AlphaVantage', -> + beforeEach -> + process.env.ALPHA_VANTAGE_API_KEY = 'alpha-vantage-key' + + afterEach -> + delete process.env.ALPHA_VANTAGE_API_KEY + describe '#new', -> it 'returns an instance with default values', () -> - process.env.ALPHA_VANTAGE_API_KEY = 'alpha-vantage-key' av = new AlphaVantage(function: 'FUNCTION', symbol: 'SYMBOL') expect(av).to.be.an.instanceof(AlphaVantage) expect(av).to.have.property('function', 'FUNCTION') expect(av).to.have.property('symbol', 'SYMBOL') expect(av).to.have.property('token', 'alpha-vantage-key') - delete process.env.ALPHA_VANTAGE_API_KEY + + describe '#execute', -> + robot = undefined + http_stub = undefined + + beforeEach -> + robot = new Robot(null, 'mock-adapter', false, 'hubot') + http_stub = (callback) -> + sinon.stub(robot, 'http').returns( + header: sinon.stub().returnsThis() + get: sinon.stub().callsFake(() -> return callback) + ) + + afterEach -> + robot.http.restore() + + describe 'when response is successful', -> + it 'calls callback with a message object ', () -> + http_stub((f) -> f('error', 'response', helper.fixture.time_series_daily)) + + new AlphaVantage(function: 'FUNCTION', symbol: 'SYMBOL').execute(robot, (message) -> + expect(message).to.be.an.instanceof(AlphaVantageSlackMessage) + ) + + describe 'when response is failure', -> + it 'calls callback with a message object ', () -> + http_stub((f) -> f('error', 'response', helper.fixture.error_message)) + + new AlphaVantage(function: 'FUNCTION', symbol: 'SYMBOL').execute(robot, (message) -> + expect(message).to.be.an.instanceof(AlphaVantageErrorMessage) + ) diff --git a/test/lib/alpha_vantage/error_message.coffee b/test/lib/alpha_vantage/error_message.coffee new file mode 100644 index 0000000..06393af --- /dev/null +++ b/test/lib/alpha_vantage/error_message.coffee @@ -0,0 +1,17 @@ +source = '../../../lib/alpha_vantage/error_message' +helper = require('../../test_helper') +expect = require('chai').expect + +AlphaVantageErrorMessage = require(source) +describe 'AlphaVantageErrorMessage', -> + subject = undefined + + beforeEach -> + object = { 'Error Message': 'Invalid API call.' } + subject = new AlphaVantageErrorMessage(object) + + describe '#format', -> + it 'returns a object for slack message', () -> + expect(subject.format().attachments).to.have.ordered.deep.members([ + { color: '#FF0000', title: 'Error Message', text: 'Invalid API call.' } + ]) diff --git a/test/lib/alpha_vantage/slack_message.coffee b/test/lib/alpha_vantage/slack_message.coffee index abe1e69..a3b8713 100644 --- a/test/lib/alpha_vantage/slack_message.coffee +++ b/test/lib/alpha_vantage/slack_message.coffee @@ -20,7 +20,7 @@ describe 'AlphaVantageSlackMessage', -> subject = new AlphaVantageSlackMessage(object) describe '#format', -> - it 'returns a string', () -> + it 'returns a object for slack message', () -> expect(subject.format()).to.include(text: 'MSFT *149.85* at December 4, 2019', mrkdwn: true) expect(subject.format().attachments).to.have.ordered.deep.members([ { color: '#35A64F', text: '+0.54 (+0.36%) at December 3, 2019' } diff --git a/test/test_helper.coffee b/test/test_helper.coffee index 198ebe5..966d63f 100644 --- a/test/test_helper.coffee +++ b/test/test_helper.coffee @@ -4,4 +4,5 @@ moment = require('moment-timezone') exports.moment = moment exports.fixture = + error_message: fs.readFileSync(path.join(__dirname, './fixture/error_message.json')) time_series_daily: fs.readFileSync(path.join(__dirname, './fixture/time_series_daily.json')) diff --git a/yarn.lock b/yarn.lock index 1346f7b..eda4bd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -89,6 +89,35 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.6.0.tgz#ec7670432ae9c8eb710400d112c201a362d83393" + integrity sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg== + dependencies: + type-detect "4.0.8" + +"@sinonjs/formatio@^3.2.1": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.2.2.tgz#771c60dfa75ea7f2d68e3b94c7e888a78781372c" + integrity sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ== + dependencies: + "@sinonjs/commons" "^1" + "@sinonjs/samsam" "^3.1.0" + +"@sinonjs/samsam@^3.1.0", "@sinonjs/samsam@^3.3.3": + version "3.3.3" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-3.3.3.tgz#46682efd9967b259b81136b9f120fd54585feb4a" + integrity sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ== + dependencies: + "@sinonjs/commons" "^1.3.0" + array-from "^2.1.1" + lodash "^4.17.15" + +"@sinonjs/text-encoding@^0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" + integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== + "@slack/client@3.16.1-sec.2": version "3.16.1-sec.2" resolved "https://registry.yarnpkg.com/@slack/client/-/client-3.16.1-sec.2.tgz#1c2edfec8bdd499949e9dab8482da63f7ab8aabb" @@ -188,6 +217,11 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= +array-from@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" + integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= + asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -583,7 +617,7 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= -diff@3.5.0: +diff@3.5.0, diff@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== @@ -1121,6 +1155,11 @@ is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -1236,6 +1275,11 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +just-extend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" + integrity sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw== + lcov-parse@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0" @@ -1286,6 +1330,11 @@ log@1.4.0: resolved "https://registry.yarnpkg.com/log/-/log-1.4.0.tgz#4ba1d890fde249b031dca03bc37eaaf325656f1c" integrity sha1-S6HYkP3iSbAx3KA7w36q8yVlbxw= +lolex@^4.1.0, lolex@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" + integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== + lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -1451,6 +1500,17 @@ nested-error-stacks@^2.0.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== +nise@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.2.tgz#b6d29af10e48b321b307e10e065199338eeb2652" + integrity sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA== + dependencies: + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/text-encoding" "^0.7.1" + just-extend "^4.0.2" + lolex "^4.1.0" + path-to-regexp "^1.7.0" + node-environment-flags@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" @@ -1632,6 +1692,13 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -1897,6 +1964,19 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +sinon@latest: + version "7.5.0" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.5.0.tgz#e9488ea466070ea908fd44a3d6478fd4923c67ec" + integrity sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q== + dependencies: + "@sinonjs/commons" "^1.4.0" + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/samsam" "^3.3.3" + diff "^3.5.0" + lolex "^4.2.0" + nise "^1.5.2" + supports-color "^5.5.0" + source-map@^0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -2056,7 +2136,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^5.3.0: +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -2110,7 +2190,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -type-detect@^4.0.0, type-detect@^4.0.5: +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==