From 3947683ad12f10a129e6e88c053063703a24905e Mon Sep 17 00:00:00 2001 From: Devin Doolin Date: Mon, 25 Apr 2016 04:31:36 +0900 Subject: [PATCH] Further updates for Bots 2.0 - Adds support for callback_query-type messages - Adds a showAlert option to answerCallbackQuery to more-closely align with the real bot API - Adds tests for message editing functionality - Adds a global test timeout of 10s and adds done() calls to all tests for assurance --- package.json | 4 +- src/telegram.js | 8 ++- test/index.js | 153 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 130 insertions(+), 35 deletions(-) diff --git a/package.json b/package.json index 87cdd57..dfc2066 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ ], "scripts": { "prepublish": "./node_modules/.bin/babel -d ./lib src", - "test": "./node_modules/.bin/mocha test/index.js", + "test": "./node_modules/.bin/mocha test/index.js --timeout 10000", "test-cov": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", "gen-doc": "./node_modules/.bin/babel --no-babelrc --plugins transform-es2015-spread,transform-es2015-destructuring,transform-strict-mode,transform-es2015-parameters,transform-es2015-shorthand-properties,transform-object-rest-spread,transform-class-properties -d lib-doc src && ./node_modules/.bin/jsdoc2md --src lib-doc/telegram.js -t README.hbs > README.md", "eslint": "./node_modules/.bin/eslint ./src" @@ -201,4 +201,4 @@ "hireable": true } ] -} \ No newline at end of file +} diff --git a/src/telegram.js b/src/telegram.js index d901434..7340ed1 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -69,6 +69,7 @@ class TelegramBot extends EventEmitter { const message = update.message; const inlineQuery = update.inline_query; const chosenInlineResult = update.chosen_inline_result; + const callbackQuery = update.callback_query; if (message) { debug('Process Update message %j', message); @@ -110,6 +111,9 @@ class TelegramBot extends EventEmitter { } else if (chosenInlineResult) { debug('Process Update chosen_inline_result %j', chosenInlineResult); this.emit('chosen_inline_result', chosenInlineResult); + } else if (callbackQuery) { + debug('Process Update callback_query %j', callbackQuery); + this.emit('callback_query', callbackQuery); } } @@ -505,13 +509,15 @@ class TelegramBot extends EventEmitter { * * @param {Number|String} callbackQueryId Unique identifier for the query to be answered * @param {String} text Text of the notification. If not specified, nothing will be shown to the user + * @param {Boolean} showAlert Whether to show an alert or a notification at the top of the screen * @param {Object} [options] Additional Telegram query options * @return {Promise} * @see https://core.telegram.org/bots/api#answercallbackquery */ - answerCallbackQuery(callbackQueryId, text, form = {}) { + answerCallbackQuery(callbackQueryId, text, showAlert, form = {}) { form.callback_query_id = callbackQueryId; form.text = text; + form.show_alert = showAlert; return this._request('answerCallbackQuery', { form }); } diff --git a/test/index.js b/test/index.js index d8c813a..1c9609d 100644 --- a/test/index.js +++ b/test/index.js @@ -17,13 +17,14 @@ const USERID = process.env.TEST_USER_ID || 777000; describe('Telegram', function telegramSuite() { describe('#setWebHook', function setWebHookSuite() { - it('should set a webHook', function test() { + it('should set a webHook', function test(done) { const bot = new Telegram(TOKEN); // Google IP ¯\_(ツ)_/¯ return bot .setWebHook('216.58.210.174') .then(resp => { assert.equal(resp, true); + done(); }); }); @@ -150,13 +151,14 @@ describe('Telegram', function telegramSuite() { }); describe('#forwardMessage', function forwardMessageSuite() { - it('should forward a message', function test() { + it('should forward a message', function test(done) { const bot = new Telegram(TOKEN); return bot.sendMessage(USERID, 'test').then(resp => { const messageId = resp.message_id; return bot.forwardMessage(USERID, USERID, messageId) .then(forwarded => { assert.ok(is.object(forwarded)); + done(); }); }); }); @@ -164,208 +166,290 @@ describe('Telegram', function telegramSuite() { describe('#sendPhoto', function sendPhotoSuite() { let photoId; - it('should send a photo from file', function test() { + it('should send a photo from file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); photoId = resp.photo[0].file_id; + done(); }); }); - it('should send a photo from id', function test() { + it('should send a photo from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before const photo = photoId; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a photo from fs.readStream', function test() { + it('should send a photo from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const photo = fs.createReadStream(`${__dirname}/bot.gif`); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a photo from request Stream', function test() { + it('should send a photo from request Stream', function test(done) { const bot = new Telegram(TOKEN); const photo = request('https://telegram.org/img/t_logo.png'); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a photo from a Buffer', function test() { + it('should send a photo from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const photo = fs.readFileSync(`${__dirname}/bot.gif`); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendChatAction', function sendChatActionSuite() { - it('should send a chat action', function test() { + it('should send a chat action', function test(done) { const bot = new Telegram(TOKEN); const action = 'typing'; return bot.sendChatAction(USERID, action).then(resp => { assert.equal(resp, true); + done(); + }); + }); + }); + + describe('#editMessageText', function editMessageTextSuite() { + it('should edit a message sent by the bot', function test(done) { + const bot = new Telegram(TOKEN); + return bot.sendMessage(USERID, 'test').then(resp => { + assert.equal(resp.text, 'test'); + const opts = { + chat_id: USERID, + message_id: resp.message_id + }; + return bot.editMessageText('edit test', opts).then(msg => { + assert.equal(msg.text, 'edit test'); + done(); + }); + }); + }); + }); + + describe('#editMessageCaption', function editMessageCaptionSuite() { + it('should edit a caption sent by the bot', function test(done) { + const bot = new Telegram(TOKEN); + const photo = `${__dirname}/bot.gif`; + const options = { caption: 'test caption' }; + return bot.sendPhoto(USERID, photo, options).then(resp => { + assert.equal(resp.caption, 'test caption'); + const opts = { + chat_id: USERID, + message_id: resp.message_id + }; + return bot.editMessageCaption('new test caption', opts).then(msg => { + assert.equal(msg.caption, 'new test caption'); + done(); + }); + }); + }); + }); + + describe('#editMessageReplyMarkup', function editMessageReplyMarkupSuite() { + it('should edit previously-set reply markup', function test(done) { + const bot = new Telegram(TOKEN); + return bot.sendMessage(USERID, 'test').then(resp => { + const replyMarkup = JSON.stringify({ + inline_keyboard: [[{ + text: 'Test button', + callback_data: 'test' + }]] + }); + const opts = { + chat_id: USERID, + message_id: resp.message_id + }; + return bot.editMessageReplyMarkup(replyMarkup, opts).then(msg => { + // Keyboard markup is not returned, do a simple object check + assert.ok(is.object(msg)); + done(); + }); }); }); }); describe('#sendAudio', function sendAudioSuite() { - it('should send an OGG audio', function test() { + it('should send an OGG audio', function test(done) { const bot = new Telegram(TOKEN); const audio = request('https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg'); return bot.sendAudio(USERID, audio).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendDocument', function sendDocumentSuite() { let documentId; - it('should send a document from file', function test() { + it('should send a document from file', function test(done) { const bot = new Telegram(TOKEN); const document = `${__dirname}/bot.gif`; return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); documentId = resp.document.file_id; + done(); }); }); - it('should send a document from id', function test() { + it('should send a document from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before const document = documentId; return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a document from fs.readStream', function test() { + it('should send a document from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const document = fs.createReadStream(`${__dirname}/bot.gif`); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a document from request Stream', function test() { + it('should send a document from request Stream', function test(done) { const bot = new Telegram(TOKEN); const document = request('https://telegram.org/img/t_logo.png'); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a document from a Buffer', function test() { + it('should send a document from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const document = fs.readFileSync(`${__dirname}/bot.gif`); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendSticker', function sendStickerSuite() { let stickerId; - it('should send a sticker from file', function test() { + it('should send a sticker from file', function test(done) { const bot = new Telegram(TOKEN); const sticker = `${__dirname}/sticker.webp`; return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); stickerId = resp.sticker.file_id; + done(); }); }); - it('should send a sticker from id', function test() { + it('should send a sticker from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before return bot.sendSticker(USERID, stickerId).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a sticker from fs.readStream', function test() { + it('should send a sticker from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const sticker = fs.createReadStream(`${__dirname}/sticker.webp`); return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a sticker from request Stream', function test() { + it('should send a sticker from request Stream', function test(done) { const bot = new Telegram(TOKEN); const sticker = request('https://www.gstatic.com/webp/gallery3/1_webp_ll.webp'); return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a sticker from a Buffer', function test() { + it('should send a sticker from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const sticker = fs.readFileSync(`${__dirname}/sticker.webp`); return bot.sendDocument(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendVideo', function sendVideoSuite() { let videoId; - it('should send a video from file', function test() { + it('should send a video from file', function test(done) { const bot = new Telegram(TOKEN); const video = `${__dirname}/video.mp4`; return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); videoId = resp.video.file_id; + done(); }); }); - it('should send a video from id', function test() { + it('should send a video from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before return bot.sendVideo(USERID, videoId).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a video from fs.readStream', function test() { + it('should send a video from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const video = fs.createReadStream(`${__dirname}/video.mp4`); return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a video from request Stream', function test() { + it('should send a video from request Stream', function test(done) { const bot = new Telegram(TOKEN); const sticker = request('http://techslides.com/demos/sample-videos/small.mp4'); return bot.sendVideo(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a video from a Buffer', function test() { + it('should send a video from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const video = fs.readFileSync(`${__dirname}/video.mp4`); return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendVoice', function sendVoiceSuite() { - it('should send an OGG audio as voice', function test() { + it('should send an OGG audio as voice', function test(done) { const bot = new Telegram(TOKEN); const voice = request('https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg'); return bot.sendVoice(USERID, voice).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); @@ -398,17 +482,18 @@ describe('Telegram', function telegramSuite() { describe('#getFile', function getFileSuite() { let fileId; - // To get a file we have to send any file first - it('should send a photo from file', function test() { + // To get a file we have to send any file first + it('should send a photo from file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); fileId = resp.photo[0].file_id; + done(); }); }); - it('should get a file', function test() { + it('should get a file', function test(done) { const bot = new Telegram(TOKEN); return bot @@ -416,6 +501,7 @@ describe('Telegram', function telegramSuite() { .then(resp => { assert.ok(is.object(resp)); assert.ok(is.string(resp.file_path)); + done(); }); }); }); @@ -423,17 +509,18 @@ describe('Telegram', function telegramSuite() { describe('#getFileLink', function getFileLinkSuite() { let fileId; - // To get a file we have to send any file first - it('should send a photo from file', function test() { + // To get a file we have to send any file first + it('should send a photo from file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); fileId = resp.photo[0].file_id; + done(); }); }); - it('should get a file link', function test() { + it('should get a file link', function test(done) { const bot = new Telegram(TOKEN); return bot @@ -441,6 +528,7 @@ describe('Telegram', function telegramSuite() { .then(fileURI => { assert.ok(is.string(fileURI)); assert.equal(fileURI.indexOf('https'), 0); + done(); // TODO: validate URL with some library or regexp }); }); @@ -449,7 +537,7 @@ describe('Telegram', function telegramSuite() { describe('#downloadFile', function downloadFileSuite() { const downloadPath = __dirname; - it('should download a file', function test() { + it('should download a file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; @@ -464,6 +552,7 @@ describe('Telegram', function telegramSuite() { assert.ok(is.string(filePath)); assert.ok(fs.existsSync(filePath)); fs.unlinkSync(filePath); // Delete file after test + done(); }); }); });