2
0
mirror of https://github.com/yagop/node-telegram-bot-api synced 2025-08-22 18:07:16 +00:00

2052 lines
71 KiB
JavaScript
Raw Normal View History

const TelegramBot = require('..');
const request = require('request-promise');
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const stream = require('stream');
const is = require('is');
const utils = require('./utils');
const isCI = require('is-ci');
const concat = require('concat-stream');
// Allows self-signed certificates to be used in our tests
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
const TOKEN = process.env.TEST_TELEGRAM_TOKEN;
2017-07-05 23:51:03 +02:00
if (!TOKEN) {
throw new Error('Bot token not provided');
}
const PROVIDER_TOKEN = process.env.TEST_PROVIDER_TOKEN;
if (!PROVIDER_TOKEN && !isCI) { // If is not running in Travis / Appveyor
throw new Error('Provider token not supplied');
}
// Telegram service if not User Id
const USERID = process.env.TEST_USER_ID || 777000;
const GROUPID = process.env.TEST_GROUP_ID || -1001075450562;
const GAME_SHORT_NAME = process.env.TEST_GAME_SHORT_NAME || 'medusalab_test';
const STICKER_SET_NAME = process.env.TEST_STICKER_SET_NAME || 'pusheen';
const CURRENT_TIMESTAMP = Date.now();
const timeout = 60 * 1000;
let portindex = 8091;
const staticPort = portindex++;
const pollingPort = portindex++;
const webHookPort = portindex++;
const pollingPort2 = portindex++;
const webHookPort2 = portindex++;
const badTgServerPort = portindex++;
const staticUrl = `http://127.0.0.1:${staticPort}`;
2017-12-07 13:05:48 +03:00
const key = `${__dirname}/../examples/ssl/key.pem`;
const cert = `${__dirname}/../examples/ssl/crt.pem`;
const ip = '216.58.210.174'; // Google IP ¯\_(ツ)_/¯
2017-11-27 06:33:59 +03:00
const lat = 47.5351072;
const long = -52.7508537;
const FILE_PATH = `${__dirname}/data/photo.png`;
let FILE_ID;
let GAME_CHAT_ID;
let GAME_MSG_ID;
let BOT_USERNAME;
let CHAT_INFO;
let STICKER_FILE_ID_FROM_SET;
let STICKERS_FROM_BOT_SET;
before(function beforeAll() {
utils.startStaticServer(staticPort);
return utils.startMockServer(pollingPort)
.then(() => {
return utils.startMockServer(pollingPort2);
}).then(() => {
return utils.startMockServer(badTgServerPort, { bad: true });
});
});
describe('module.exports', function moduleExportsSuite() {
const nodeVersion = parseInt(process.versions.node.split('.')[0], 10);
it('is loaded from src/ on Node.js v6+ and above', function test() {
if (nodeVersion <= 5) this.skip(); // skip on Node.js v5 and below
assert.strictEqual(TelegramBot, require('../src/telegram'));
});
it('is loaded from lib/ on Node.js v5 and below', function test() {
if (nodeVersion > 5) this.skip(); // skip on newer versions
assert.strictEqual(TelegramBot, require('../lib/telegram'));
});
});
describe('TelegramBot', function telegramSuite() {
let bot;
let testbot;
let botPolling;
let botWebHook;
before(function beforeAll() {
this.timeout(timeout);
bot = new TelegramBot(TOKEN);
testbot = new TelegramBot(TOKEN, {
baseApiUrl: `http://127.0.0.1:${pollingPort}`,
polling: {
autoStart: false,
},
webHook: {
autoOpen: false,
port: webHookPort,
},
});
botPolling = new TelegramBot(TOKEN, {
baseApiUrl: `http://127.0.0.1:${pollingPort2}`,
polling: true,
});
botWebHook = new TelegramBot(TOKEN, {
webHook: {
port: webHookPort2,
},
});
utils.handleRatelimit(bot, 'sendPhoto', this);
utils.handleRatelimit(bot, 'sendMessage', this);
utils.handleRatelimit(bot, 'sendGame', this);
utils.handleRatelimit(bot, 'getMe', this);
utils.handleRatelimit(bot, 'getChat', this);
return bot.sendPhoto(USERID, FILE_PATH).then(resp => {
FILE_ID = resp.photo[0].file_id;
return bot.sendMessage(USERID, 'chat');
}).then(resp => {
GAME_CHAT_ID = resp.chat.id;
return bot.sendGame(USERID, GAME_SHORT_NAME);
}).then(resp => {
GAME_MSG_ID = resp.message_id;
}).then(() => {
return bot.getMe().then(resp => {
BOT_USERNAME = resp.username;
});
}).then(() =>
bot.getChat(GROUPID).then(resp => {
CHAT_INFO = resp;
}));
});
it('automatically starts polling', function test() {
assert.strictEqual(botPolling.isPolling(), true);
return utils.isPollingMockServer(pollingPort2);
});
it('automatically opens webhook', function test() {
assert.strictEqual(botWebHook.hasOpenWebHook(), true);
return utils.hasOpenWebHook(webHookPort2);
});
it('does not automatically poll if "autoStart" is false', function test() {
assert.strictEqual(testbot.isPolling(), false);
return utils.isPollingMockServer(pollingPort, true);
});
it('does not automatically open webhook if "autoOpen" is false', function test() {
assert.strictEqual(testbot.hasOpenWebHook(), false);
return utils.hasOpenWebHook(webHookPort, true);
});
it('correctly deletes the webhook if polling', function test() {
const myBot = new TelegramBot(TOKEN, {
polling: { autoStart: false, params: { timeout: 0 } },
});
utils.handleRatelimit(myBot, 'setWebHook', this);
myBot.on('polling_error', (error) => {
assert.ifError(error);
});
return myBot.setWebHook(ip, {}).then(() => {
return myBot.startPolling();
}).then(() => {
return myBot.stopPolling();
});
});
describe('Events', function eventsSuite() {
it('(polling) emits "message" on receiving message', function test(done) {
botPolling.once('message', () => {
return done();
});
});
it('(polling) emits "polling_error" if error occurs during polling', function test(done) {
const myBot = new TelegramBot(12345, { polling: true });
myBot.once('polling_error', (error) => {
assert.ok(error);
assert.strictEqual(error.code, 'ETELEGRAM');
return myBot.stopPolling().then(() => { done(); }).catch(done);
});
});
it('(webhook) emits "message" on receiving message', function test(done) {
botWebHook.once('message', () => {
return done();
});
utils.sendWebHookMessage(webHookPort2, TOKEN);
});
it('(webhook) emits "webhook_error" if could not parse webhook request body', function test(done) {
botWebHook.once('webhook_error', (error) => {
assert.ok(error);
assert.strictEqual(error.code, 'EPARSE');
return done();
});
utils.sendWebHookMessage(webHookPort2, TOKEN, { update: 'unparseable!', json: false });
});
});
describe('WebHook', function webHookSuite() {
2017-01-30 13:24:15 +03:00
it('returns 200 OK for health endpoint', function test(done) {
utils.sendWebHookRequest(webHookPort2, '/healthz').then(resp => {
assert.strictEqual(resp, 'OK');
2017-01-29 21:59:40 +03:00
return done();
});
});
it('returns 401 error if token is wrong', function test(done) {
utils.sendWebHookMessage(webHookPort2, 'wrong-token').catch(resp => {
assert.strictEqual(resp.statusCode, 401);
return done();
});
});
it('only accepts POST method', function test() {
const methods = ['GET', 'PUT', 'DELETE', 'OPTIONS'];
return Promise.all(methods, (method) => {
return utils.sendWebHookMessage(webHookPort2, TOKEN, {
method,
}).then(() => {
throw new Error(`expected error with webhook ${method} request`);
}).catch(resp => {
if (!resp.statusCode) throw resp;
if (resp.statusCode !== 418) throw new Error(`unexpected error: ${resp.body}`);
});
}); // Promise.each
});
});
describe('WebHook HTTPS', function webHookHTTPSSuite() {
const port = portindex++;
let httpsbot;
afterEach(function afterEach() {
return httpsbot.closeWebHook();
});
it('is enabled, through options.key and options.cert', function test() {
httpsbot = new TelegramBot(TOKEN, { webHook: { port, key, cert } });
return utils.sendWebHookMessage(port, TOKEN, { https: true });
});
it('is enabled, through options.pfx');
it('is enabled, through options.https', function test() {
httpsbot = new TelegramBot(TOKEN, {
webHook: {
port,
https: {
key: fs.readFileSync(key),
cert: fs.readFileSync(cert),
},
},
});
return utils.sendWebHookMessage(port, TOKEN, { https: true });
});
});
describe('errors', function errorsSuite() {
const botParse = new TelegramBot('useless-token', {
baseApiUrl: `http://localhost:${badTgServerPort}`,
});
it('FatalError is thrown if token is missing', function test() {
const myBot = new TelegramBot(null);
return myBot.sendMessage(USERID, 'text').catch(error => {
// FIX: assert.ok(error instanceof TelegramBot.errors.FatalError);
assert.strictEqual(error.code, 'EFATAL');
assert.ok(error.message.indexOf('not provided') > -1);
});
});
it('FatalError is thrown if file-type of Buffer could not be determined', function test() {
let buffer;
try {
buffer = Buffer.from('12345');
} catch (ex) {
buffer = new Buffer('12345');
}
return bot.sendPhoto(USERID, buffer).catch(error => {
// FIX: assert.ok(error instanceof TelegramBot.errors.FatalError);
assert.strictEqual(error.code, 'EFATAL');
assert.ok(error.message.indexOf('Unsupported') > -1);
});
});
it('FatalError is thrown on network error', function test() {
const myBot = new TelegramBot('useless-token', {
baseApiUrl: 'http://localhost:23', // are we sure this port is not bound to?
});
return myBot.getMe().catch(error => {
// FIX: assert.ok(error instanceof TelegramBot.errors.FatalError);
assert.strictEqual(error.code, 'EFATAL');
});
});
it('ParseError is thrown if response body could not be parsed', function test() {
botParse.sendMessage(USERID, 'text').catch(error => {
// FIX: assert.ok(error instanceof TelegramBot.errors.ParseError);
assert.strictEqual(error.code, 'EPARSE');
assert.ok(typeof error.response === 'object');
assert.ok(typeof error.response.body === 'string');
});
});
it('TelegramError is thrown if error is from Telegram', function test() {
return bot.sendMessage('404', 'text').catch(error => {
// FIX: assert.ok(error instanceof TelegramBot.errors.TelegramError);
assert.strictEqual(error.code, 'ETELEGRAM');
assert.ok(typeof error.response === 'object');
assert.ok(typeof error.response.body === 'object');
});
});
});
describe('#startPolling', function initPollingSuite() {
it('initiates polling', function test() {
return testbot.startPolling().then(() => {
return utils.isPollingMockServer(pollingPort);
});
});
it('returns error if using webhook', function test() {
return botWebHook.startPolling().catch((err) => {
// TODO: check for error in a better way
// FIX: assert.ok(err instanceof TelegramBot.errors.FatalError);
assert.strictEqual(err.code, 'EFATAL');
assert.ok(err.message.indexOf('mutually exclusive') !== -1);
});
});
});
describe('#isPolling', function isPollingSuite() {
it('returns true if bot is polling', function test() {
assert.strictEqual(testbot.isPolling(), true);
return utils.isPollingMockServer(pollingPort);
});
it('returns false if bot is not polling', function test() {
2017-01-06 12:41:00 +03:00
return testbot.stopPolling().then(() => {
assert.strictEqual(testbot.isPolling(), false);
2017-01-06 12:41:00 +03:00
utils.clearPollingCheck(pollingPort);
return utils.isPollingMockServer(pollingPort, true);
});
});
after(function after() {
return testbot.initPolling();
});
});
describe('#stopPolling', function stopPollingSuite() {
it('stops polling by bot', function test() {
return testbot.stopPolling().then(() => {
utils.clearPollingCheck(pollingPort);
return utils.isPollingMockServer(pollingPort, true);
});
});
});
describe('#openWebHook', function openWebHookSuite() {
it('opens webhook', function test() {
return testbot.openWebHook().then(() => {
return utils.hasOpenWebHook(webHookPort);
});
});
it('returns error if using polling', function test() {
return botPolling.openWebHook().catch((err) => {
// TODO: check for error in a better way
// FIX: assert.ok(err instanceof TelegramBot.errors.FatalError);
assert.strictEqual(err.code, 'EFATAL');
assert.ok(err.message.indexOf('mutually exclusive') !== -1);
});
});
});
describe('#hasOpenWebHook', function hasOpenWebHookSuite() {
it('returns true if webhook is opened', function test() {
assert.strictEqual(testbot.hasOpenWebHook(), true);
return utils.hasOpenWebHook(webHookPort);
});
it('returns false if webhook is closed', function test() {
testbot.closeWebHook().then(() => {
assert.strictEqual(testbot.hasOpenWebHook(), false);
return utils.hasOpenWebHook(webHookPort, true);
});
});
after(function after() {
return testbot.openWebHook();
});
});
describe('#closeWebHook', function closeWebHookSuite() {
it('closes webhook', function test() {
testbot.closeWebHook().then(() => {
return utils.hasOpenWebHook(webHookPort, true);
});
});
});
describe('#setWebHook', function setWebHookSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setWebHook', this);
});
it('should set a webHook', function test() {
return bot
.setWebHook(ip, {})
.then(resp => {
assert.strictEqual(resp, true);
});
});
it('should set a webHook with certificate', function test() {
return bot
.setWebHook(ip, { certificate: cert })
.then(resp => {
assert.strictEqual(resp, true);
});
});
it('(v0.25.0 and lower) should set a webHook with certificate', function test() {
return bot
.setWebHook(ip, cert)
.then(resp => {
assert.strictEqual(resp, true);
});
});
it('should delete the webHook', function test() {
return bot
.setWebHook('', {})
.then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#getWebHookInfo', function getWebHookInfoSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getWebHookInfo', this);
});
it('should return WebhookInfo', function test() {
return bot.getWebHookInfo().then(resp => {
assert.ok(is.object(resp));
assert.ok(is.boolean(resp.has_custom_certificate));
assert.ok(is.number(resp.pending_update_count));
});
});
});
describe('#deleteWebHook', function deleteWebHookSuite() {
before(function before() {
utils.handleRatelimit(bot, 'deleteWebHook', this);
});
it('should delete webhook', function test() {
return bot.deleteWebHook().then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#getUpdates', function getUpdatesSuite() {
const opts = {
timeout: 0,
limit: 10,
};
before(function before() {
utils.handleRatelimit(bot, 'setWebHook', this);
utils.handleRatelimit(bot, 'getUpdates', this);
return bot.deleteWebHook();
});
it('should return an Array', function test() {
return bot.getUpdates(opts).then(resp => {
assert.strictEqual(Array.isArray(resp), true);
});
});
it('(v0.25.0 and lower) should return an Array', function test() {
return bot.getUpdates(opts.timeout, opts.limit).then(resp => {
assert.strictEqual(Array.isArray(resp), true);
});
});
});
describe('#getMe', function getMeSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getMe', this);
});
it('should return an User object', function test() {
return bot.getMe().then(resp => {
assert.ok(is.object(resp));
assert.ok(is.number(resp.id));
assert.ok(is.string(resp.first_name));
});
});
});
describe('#getFileLink', function getFileLinkSuite() {
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'getFileLink', this);
});
it('should get a file link', function test() {
return bot.getFileLink(FILE_ID)
.then(fileURI => {
assert.ok(is.string(fileURI));
assert.ok(utils.isTelegramFileURI(fileURI));
});
});
});
describe('#getFileStream', function getFileStreamSuite() {
this.timeout(timeout);
before(function before() {
// utils.handleRatelimit(bot, 'getFileStream', this);
});
it('should get a file stream', function test(done) {
const fileStream = bot.getFileStream(FILE_ID);
assert.ok(fileStream instanceof stream.Readable);
assert.strictEqual(fileStream.path, FILE_ID);
fileStream.on('info', (info) => {
assert.ok(info);
assert.ok(utils.isTelegramFileURI(info.uri), `${info.uri} is not a file URI`);
fileStream.pipe(concat(function readFile(buffer) {
buffer.equals(fs.readFileSync(FILE_PATH)); // sync :(
return done();
}));
});
});
});
describe('#downloadFile', function downloadFileSuite() {
const downloadPath = os.tmpdir();
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'downloadFile', this);
});
it('should download a file', function test() {
return bot.downloadFile(FILE_ID, downloadPath)
.then(filePath => {
assert.ok(is.string(filePath));
assert.strictEqual(path.dirname(filePath), downloadPath);
assert.ok(fs.existsSync(filePath));
fs.unlinkSync(filePath); // Delete file after test
});
});
});
describe('#onText', function onTextSuite() {
it('should call `onText` callback on match', function test(done) {
const regexp = /\/onText (.+)/;
botWebHook.onText(regexp, (msg, match) => {
assert.strictEqual(match[1], 'ECHO ALOHA');
assert.ok(botWebHook.removeTextListener(regexp));
return done();
});
utils.sendWebHookMessage(webHookPort2, TOKEN, {
message: { text: '/onText ECHO ALOHA' },
});
});
it('should reset the global regex state with each message', function test(done) {
const regexp = /\/onText (.+)/g;
botWebHook.onText(regexp, () => {
assert.strictEqual(regexp.lastIndex, 0);
assert.ok(botWebHook.removeTextListener(regexp));
return done();
});
utils.sendWebHookMessage(webHookPort2, TOKEN, {
message: { text: '/onText ECHO ALOHA' },
});
});
});
describe('#removeTextListener', function removeTextListenerSuite() {
const regexp = /\/onText/;
const regexp2 = /\/onText/;
const callback = function noop() { };
after(function after() {
bot.removeTextListener(regexp);
bot.removeTextListener(regexp2);
});
it('removes the right text-listener', function test() {
bot.onText(regexp, callback);
bot.onText(regexp2, callback);
const textListener = bot.removeTextListener(regexp);
assert.strictEqual(regexp, textListener.regexp);
});
it('returns `null` if missing', function test() {
assert.strictEqual(null, bot.removeTextListener(/404/));
});
});
describe.skip('#onReplyToMessage', function onReplyToMessageSuite() { });
describe('#removeReplyListener', function removeReplyListenerSuite() {
const chatId = -1234;
const messageId = 1;
const callback = function noop() { };
it('returns the right reply-listener', function test() {
const id = bot.onReplyToMessage(chatId, messageId, callback);
const replyListener = bot.removeReplyListener(id);
assert.strictEqual(id, replyListener.id);
assert.strictEqual(chatId, replyListener.chatId);
assert.strictEqual(messageId, replyListener.messageId);
assert.strictEqual(callback, replyListener.callback);
});
it('returns `null` if missing', function test() {
// NOTE: '0' is never a valid reply listener ID :)
assert.strictEqual(null, bot.removeReplyListener(0));
});
});
/** Telegram Bot API Methods */
describe.skip('#logOut', function logOutSuite() { });
describe.skip('#close', function closeSuite() { });
describe('#sendMessage', function sendMessageSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendMessage', this);
});
it('should send a message', function test() {
return bot.sendMessage(USERID, 'test').then(resp => {
assert.ok(is.object(resp));
assert.ok(is.number(resp.message_id));
});
});
});
describe('#forwardMessage', function forwardMessageSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendMessage', this);
utils.handleRatelimit(bot, 'forwardMessage', this);
});
it('should forward a message', function test() {
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));
assert.ok(is.number(forwarded.message_id));
});
});
});
});
describe('#copyMessage', function copyMessageSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendMessage', this);
utils.handleRatelimit(bot, 'copyMessage', this);
});
it('should send copy of a message', function test() {
return bot.sendMessage(USERID, 'test').then(resp => {
const messageId = resp.message_id;
return bot.copyMessage(USERID, USERID, messageId)
.then(copy => {
assert.ok(is.object(copy));
assert.ok(is.number(copy.message_id));
});
});
});
});
describe('#sendPhoto', function sendPhotoSuite() {
let photoId;
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendPhoto', this);
});
it('should send a photo from file', function test() {
const photo = `${__dirname}/data/photo.png`;
return bot.sendPhoto(USERID, photo).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.array(resp.photo));
photoId = resp.photo[0].file_id;
});
});
it('should send a photo from id', function test() {
// Send the same photo as before
const photo = photoId;
return bot.sendPhoto(USERID, photo).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.array(resp.photo));
});
});
it('should send a photo from fs.readStream', function test() {
const photo = fs.createReadStream(`${__dirname}/data/photo.png`);
return bot.sendPhoto(USERID, photo).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.array(resp.photo));
});
});
it('should send a photo from request Stream', function test() {
const photo = request(`${staticUrl}/photo.png`);
return bot.sendPhoto(USERID, photo).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.array(resp.photo));
});
});
it('should send a photo from a Buffer', function test() {
const photo = fs.readFileSync(`${__dirname}/data/photo.png`);
return bot.sendPhoto(USERID, photo).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.array(resp.photo));
});
});
});
describe('#sendAudio', function sendAudioSuite() {
let audioId;
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendAudio', this);
});
it('should send an MP3 audio', function test() {
const audio = `${__dirname}/data/audio.mp3`;
return bot.sendAudio(USERID, audio).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.audio));
audioId = resp.audio.file_id;
});
});
it('should send an audio from id', function test() {
// Send the same audio as before
const audio = audioId;
return bot.sendAudio(USERID, audio).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.audio));
});
});
it('should send an audio from fs.readStream', function test() {
const audio = fs.createReadStream(`${__dirname}/data/audio.mp3`);
return bot.sendAudio(USERID, audio).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.audio));
});
});
it('should send an audio from request Stream', function test() {
const audio = request(`${staticUrl}/audio.mp3`);
return bot.sendAudio(USERID, audio).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.audio));
});
});
it('should send an audio from a Buffer', function test() {
const audio = fs.readFileSync(`${__dirname}/data/audio.mp3`);
return bot.sendAudio(USERID, audio).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.audio));
});
});
it('should send an audio file with thumb', function test() {
const audio = `${__dirname}/data/audio.mp3`;
const thumbImg = `attach://${__dirname}/data/sticker_thumb.png`;
return bot.sendAudio(USERID, audio, { thumb: thumbImg }).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.audio));
assert.ok(is.object(resp.audio.thumb));
});
});
});
describe('#sendDocument', function sendDocumentSuite() {
let documentId;
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendDocument', this);
});
it('should send a document from file', function test() {
const document = `${__dirname}/data/photo.gif`;
return bot.sendDocument(USERID, document).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.document));
documentId = resp.document.file_id;
});
});
it('should send a document from id', function test() {
// Send the same document as before
const document = documentId;
return bot.sendDocument(USERID, document).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.document));
});
});
it('should send a document from fs.readStream', function test() {
const document = fs.createReadStream(`${__dirname}/data/photo.gif`);
return bot.sendDocument(USERID, document).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.document));
});
});
it('should send a document from request Stream', function test() {
const document = request(`${staticUrl}/photo.gif`);
return bot.sendDocument(USERID, document).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.document));
});
});
it('should send a document from a Buffer', function test() {
const document = fs.readFileSync(`${__dirname}/data/photo.gif`);
return bot.sendDocument(USERID, document).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.document));
});
});
});
describe('#sendVideo', function sendVideoSuite() {
let videoId;
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendVideo', this);
});
it('should send a video from file', function test() {
const video = `${__dirname}/data/video.mp4`;
return bot.sendVideo(USERID, video).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
videoId = resp.video.file_id;
});
});
it('should send a video from id', function test() {
// Send the same video as before
return bot.sendVideo(USERID, videoId).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
});
});
it('should send a video from fs.readStream', function test() {
const video = fs.createReadStream(`${__dirname}/data/video.mp4`);
return bot.sendVideo(USERID, video).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
});
});
it('should send a video from request Stream', function test() {
const video = request(`${staticUrl}/video.mp4`);
return bot.sendVideo(USERID, video).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
});
});
it('should send a video from a Buffer', function test() {
const video = fs.readFileSync(`${__dirname}/data/video.mp4`);
return bot.sendVideo(USERID, video).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
});
});
});
describe('#sendAnimation', function sendAnimationSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendAnimation', this);
});
it('should send a gif as an animation', function test() {
return bot.sendAnimation(USERID, `${__dirname}/data/photo.gif`).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.document));
});
});
});
describe('#sendVoice', function sendVoiceSuite() {
let voiceId;
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendVoice', this);
});
it('should send a voice from file', function test() {
const voice = `${__dirname}/data/voice.ogg`;
return bot.sendVoice(USERID, voice).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.voice));
voiceId = resp.voice.file_id;
});
});
it('should send a voice from id', function test() {
// Send the same voice as before
return bot.sendVoice(USERID, voiceId).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.voice));
});
});
it('should send a voice from fs.readStream', function test() {
const voice = fs.createReadStream(`${__dirname}/data/voice.ogg`);
return bot.sendVoice(USERID, voice).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.voice));
});
});
it('should send a voice from request Stream', function test() {
const voice = request(`${staticUrl}/voice.ogg`);
return bot.sendVoice(USERID, voice).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.voice));
});
});
it('should send a voice from a Buffer', function test() {
const voice = fs.readFileSync(`${__dirname}/data/voice.ogg`);
return bot.sendVoice(USERID, voice).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.voice));
});
});
});
describe('#sendVideoNote', function sendVideoNoteSuite() {
let videoNoteId;
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendVideoNote', this);
});
it('should send a video from file', function test() {
const video = `${__dirname}/data/video.mp4`;
return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
videoNoteId = resp.video.file_id;
});
});
it('should send a video from id', function test() {
// Send the same videonote as before
assert.ok(videoNoteId);
return bot.sendVideoNote(USERID, videoNoteId, { length: 5 }).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
});
});
it('should send a video from fs.readStream', function test() {
const video = fs.createReadStream(`${__dirname}/data/video.mp4`);
return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
});
});
it('should send a video from a Buffer', function test() {
const video = fs.readFileSync(`${__dirname}/data/video.mp4`);
return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.video));
});
});
});
describe('#sendMediaGroup', function sendMediaGroupSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendMediaGroup', this);
});
it('should send group of photos/videos as album', function test() {
return bot.sendMediaGroup(USERID, [
{
type: 'photo',
media: `${__dirname}/data/photo.png`,
},
{
type: 'video',
media: `${__dirname}/data/video.mp4`,
},
{
type: 'photo',
media: FILE_ID,
},
], {
disable_notification: true,
}).then(resp => {
assert.ok(is.array(resp));
assert.strictEqual(resp.length, 3);
});
});
});
describe('#sendLocation', function sendLocationSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendLocation', this);
});
it('should send a location', function test() {
return bot.sendLocation(USERID, lat, long).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.location));
assert.ok(is.number(resp.location.latitude));
assert.ok(is.number(resp.location.longitude));
});
});
});
describe('#editMessageLiveLocation', function editMessageLiveLocationSuite() {
let message;
before(function before() {
utils.handleRatelimit(bot, 'editMessageLiveLocation', this);
const opts = { live_period: 86400 };
return bot.sendLocation(USERID, lat, long, opts).then(resp => { message = resp; });
});
it('edits live location', function test() {
const opts = { chat_id: USERID, message_id: message.message_id };
return bot.editMessageLiveLocation(lat + 1, long + 1, opts).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.location));
assert.ok(is.number(resp.location.latitude));
assert.ok(is.number(resp.location.longitude));
});
});
});
describe.skip('#stopMessageLiveLocation', function editMessageLiveLocationSuite() {
let message;
before(function before() {
utils.handleRatelimit(bot, 'stopMessageLiveLocation', this);
return bot.sendLocation(USERID, lat, long, { live_period: 86400 })
.then((resp) => {
message = resp;
});
});
it('stops location updates', function test() {
const opts = { chat_id: USERID, message_id: message.message_id };
return bot.stopMessageLiveLocation(opts).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.location));
assert.ok(is.number(resp.location.latitude));
assert.ok(is.number(resp.location.longitude));
});
});
});
describe('#sendVenue', function sendVenueSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendVenue', this);
});
it('should send a venue', function test() {
const title = 'The Village Shopping Centre';
const address = '430 Topsail Rd,St. John\'s, NL A1E 4N1, Canada';
return bot.sendVenue(USERID, lat, long, title, address).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.venue));
assert.ok(is.object(resp.venue.location));
assert.ok(is.number(resp.venue.location.latitude));
assert.ok(is.number(resp.venue.location.longitude));
assert.ok(is.string(resp.venue.title));
assert.ok(is.string(resp.venue.address));
});
});
});
// NOTE: We are skipping TelegramBot#sendContact() as the
// corresponding rate-limits enforced by the Telegram servers
// are too strict! During our initial tests, we were required
// to retry after ~72000 secs (1200 mins / 20 hrs).
// We surely can NOT wait for that much time during testing
// (or in most practical cases for that matter!)
describe.skip('#sendContact', function sendContactSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendContact', this);
});
it('should send a contact', function test() {
const phoneNumber = '+1(000)000-000';
const firstName = 'John Doe';
return bot.sendContact(USERID, phoneNumber, firstName).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.contact));
assert.ok(is.string(resp.contact.phone_number));
assert.ok(is.string(resp.contact.first_name));
});
});
});
describe('#sendPoll', function sendPollSuite() {
it('should send a Poll', function test() {
const question = '¿Are you okey?';
const answers = ['Yes', 'No'];
const opts = { is_anonymous: true };
return bot.sendPoll(GROUPID, question, answers, opts).then(resp => {
assert.ok(is.object(resp));
});
});
it('should send a Quiz', function test() {
const question = '¿Are you okey?';
const answers = ['Yes', 'No'];
const opts = {
is_anonymous: true,
type: 'quiz',
correct_option_id: 0
};
return bot.sendPoll(GROUPID, question, answers, opts).then(resp => {
assert.ok(is.object(resp));
});
});
});
describe('#sendDice', function sendDiceSuite() {
it('should send a Dice', function test() {
return bot.sendDice(GROUPID).then(resp => {
assert.ok(is.object(resp));
});
});
it('should send a Dart', function test() {
const opts = { emoji: '🎯' };
return bot.sendDice(GROUPID, opts).then(resp => {
assert.ok(is.object(resp));
});
});
});
describe('#sendChatAction', function sendChatActionSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendChatAction', this);
});
it('should send a chat action', function test() {
const action = 'typing';
return bot.sendChatAction(USERID, action).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#getUserProfilePhotos', function getUserProfilePhotosSuite() {
const opts = {
offset: 0,
limit: 1,
};
before(function before() {
utils.handleRatelimit(bot, 'getUserProfilePhotos', this);
});
it('should get user profile photos', function test() {
return bot.getUserProfilePhotos(USERID, opts).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.number(resp.total_count));
assert.ok(is.array(resp.photos));
Telegram Bot API v5.3 Support (#886) * Add new method sendPoll * getMyCommands * setMyCommands * Update doc/api * 1# Fix Test sendPhoto The sendPhoto method does not support .gif files, use sendAnimation. This fix remplace .gif file by .png * CustomTitle and ChatPermissions support setChatAdministratorCustomTitle setChatPermissions * Update Readme Update Badge Telegram API Version * Minor Fix and Fix setChatPhoto The Telegram Bots api has a bug that they are fixing and gives problems with the previous image. While they don't fix it, the image replacement is the fastest solution * Minor Fix and Add Test Fixed setChatPermissions Test: - sendDice - getMyCommands - setMyCommands - setChatAdministratorCustomTitle - setChatPermissions * Update Changelog and Package.json version * Fix typos in Changelog * Add support for poll_answer From: https://github.com/yagop/node-telegram-bot-api/pull/777 * Add JieJiSS contribution in Changelog * Add sendPoll Test * Add unpinAllChatMessages Support * Add copyMessage support * Add close and logOut Support * Add Test + Minor fixes * Update CHANGELOG Update version 0.50.1 * Update Readme Bot API Badge * Update Version to 0.51.0 * Bot API 5.1 support Improved Invite Links - Added the method createChatInviteLink - Added the method editChatInviteLink - Added the method revokeChatInviteLink * Update version to 0.52.0 and new tests - Update Changelog - New Test - Update version to 0.52.0 * Add new messageTypes - voice_chat_started - voice_chat_ended - voice_chat_participants_invited * Update Changelog and add new MessageType * New messageTypes and updates Add support for new messageTypes: - chat_invite_link - chat_member_updated Add support for new updates: - my_chat_member - chat_member * Telegram Bot API 5.2 Support * Update Changelog + readme * Fix Changelog * Telegram Bot API v5.3 Add new methods: * deleteMyCommands * banChatMember * getChatMemberCount Deprecated: * Method kickChatMember() * Method getChatMembersCount() New Test: * deleteMyCommands * banChatMember * getChatMemberCount * docs: gen on linux Co-authored-by: Mohammed Sohail <sohailsameja@gmail.com>
2021-06-29 10:38:33 +02:00
});
});
it('(v0.25.0 and lower) should get user profile photos', function test() {
return bot.getUserProfilePhotos(USERID, opts.offset, opts.limit).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.number(resp.total_count));
assert.ok(is.array(resp.photos));
});
});
});
describe('#getFile', function getFileSuite() {
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'getFile', this);
});
it('should get a file', function test() {
return bot.getFile(FILE_ID)
.then(resp => {
assert.ok(is.object(resp));
assert.ok(is.string(resp.file_path));
});
});
Telegram Bot API v5.3 Support (#886) * Add new method sendPoll * getMyCommands * setMyCommands * Update doc/api * 1# Fix Test sendPhoto The sendPhoto method does not support .gif files, use sendAnimation. This fix remplace .gif file by .png * CustomTitle and ChatPermissions support setChatAdministratorCustomTitle setChatPermissions * Update Readme Update Badge Telegram API Version * Minor Fix and Fix setChatPhoto The Telegram Bots api has a bug that they are fixing and gives problems with the previous image. While they don't fix it, the image replacement is the fastest solution * Minor Fix and Add Test Fixed setChatPermissions Test: - sendDice - getMyCommands - setMyCommands - setChatAdministratorCustomTitle - setChatPermissions * Update Changelog and Package.json version * Fix typos in Changelog * Add support for poll_answer From: https://github.com/yagop/node-telegram-bot-api/pull/777 * Add JieJiSS contribution in Changelog * Add sendPoll Test * Add unpinAllChatMessages Support * Add copyMessage support * Add close and logOut Support * Add Test + Minor fixes * Update CHANGELOG Update version 0.50.1 * Update Readme Bot API Badge * Update Version to 0.51.0 * Bot API 5.1 support Improved Invite Links - Added the method createChatInviteLink - Added the method editChatInviteLink - Added the method revokeChatInviteLink * Update version to 0.52.0 and new tests - Update Changelog - New Test - Update version to 0.52.0 * Add new messageTypes - voice_chat_started - voice_chat_ended - voice_chat_participants_invited * Update Changelog and add new MessageType * New messageTypes and updates Add support for new messageTypes: - chat_invite_link - chat_member_updated Add support for new updates: - my_chat_member - chat_member * Telegram Bot API 5.2 Support * Update Changelog + readme * Fix Changelog * Telegram Bot API v5.3 Add new methods: * deleteMyCommands * banChatMember * getChatMemberCount Deprecated: * Method kickChatMember() * Method getChatMembersCount() New Test: * deleteMyCommands * banChatMember * getChatMemberCount * docs: gen on linux Co-authored-by: Mohammed Sohail <sohailsameja@gmail.com>
2021-06-29 10:38:33 +02:00
});
describe.skip('#banChatMember', function banChatMemberSuite() { });
describe.skip('#unbanChatMember', function unbanChatMemberSuite() { });
describe.skip('#restrictChatMember', function restrictChatMemberSuite() { });
describe.skip('#promoteChatMember', function promoteChatMemberSuite() { });
describe.skip('#setChatAdministratorCustomTitle ', function setChatAdministratorCustomTitleSuite() {
it('should set chat permissions', function test() {
return bot.setChatAdministratorCustomTitle(GROUPID, USERID, 'Custom Name').then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe.skip('#banChatSenderChat', function banChatSenderChatSuite() { });
describe.skip('#unbanChatSenderChat', function banChatSenderChatSuite() { });
describe('#setChatPermissions ', function setChatPermissionsSuite() {
it('should set chat permissions', function test() {
const ChatPermissions = {
can_send_messages: true,
can_send_media_messages: true,
can_send_polls: false,
can_send_other_messages: false,
can_add_web_page_previews: true,
can_change_info: false,
can_invite_users: false,
can_pin_messages: true
};
return bot.setChatPermissions(GROUPID, ChatPermissions).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#exportChatInviteLink', function exportChatInviteLinkSuite() {
before(function before() {
utils.handleRatelimit(bot, 'exportChatInviteLink', this);
});
it('should export the group invite link', function test() {
return bot.exportChatInviteLink(GROUPID).then(resp => {
assert(resp.match(/^https:\/\/t\.me\/.+$/i), 'is a telegram invite link');
});
});
});
Bot API 5.1: Support Improved Invite Links and new messageTypes (#859) * Add new method sendPoll * getMyCommands * setMyCommands * Update doc/api * 1# Fix Test sendPhoto The sendPhoto method does not support .gif files, use sendAnimation. This fix remplace .gif file by .png * CustomTitle and ChatPermissions support setChatAdministratorCustomTitle setChatPermissions * Update Readme Update Badge Telegram API Version * Minor Fix and Fix setChatPhoto The Telegram Bots api has a bug that they are fixing and gives problems with the previous image. While they don't fix it, the image replacement is the fastest solution * Minor Fix and Add Test Fixed setChatPermissions Test: - sendDice - getMyCommands - setMyCommands - setChatAdministratorCustomTitle - setChatPermissions * Update Changelog and Package.json version * Fix typos in Changelog * Add support for poll_answer From: https://github.com/yagop/node-telegram-bot-api/pull/777 * Add JieJiSS contribution in Changelog * Add sendPoll Test * Add unpinAllChatMessages Support * Add copyMessage support * Add close and logOut Support * Add Test + Minor fixes * Update CHANGELOG Update version 0.50.1 * Update Readme Bot API Badge * Update Version to 0.51.0 * Bot API 5.1 support Improved Invite Links - Added the method createChatInviteLink - Added the method editChatInviteLink - Added the method revokeChatInviteLink * Update version to 0.52.0 and new tests - Update Changelog - New Test - Update version to 0.52.0 * Add new messageTypes - voice_chat_started - voice_chat_ended - voice_chat_participants_invited * Update Changelog and add new MessageType * New messageTypes and updates Add support for new messageTypes: - chat_invite_link - chat_member_updated Add support for new updates: - my_chat_member - chat_member
2021-03-29 16:37:10 +02:00
describe('#createChatInviteLink', function createChatInviteLinkSuite() {
let inviteLink;
before(function before() {
utils.handleRatelimit(bot, 'createChatInviteLink', this);
utils.handleRatelimit(bot, 'editChatInviteLink', this);
utils.handleRatelimit(bot, 'revokeChatInviteLink', this);
});
it('should create a chat invite link', function test() {
return bot.createChatInviteLink(GROUPID).then(resp => {
assert(resp.invite_link.match(/^https:\/\/t\.me\/.+$/i), 'is a telegram invite link');
Bot API 5.1: Support Improved Invite Links and new messageTypes (#859) * Add new method sendPoll * getMyCommands * setMyCommands * Update doc/api * 1# Fix Test sendPhoto The sendPhoto method does not support .gif files, use sendAnimation. This fix remplace .gif file by .png * CustomTitle and ChatPermissions support setChatAdministratorCustomTitle setChatPermissions * Update Readme Update Badge Telegram API Version * Minor Fix and Fix setChatPhoto The Telegram Bots api has a bug that they are fixing and gives problems with the previous image. While they don't fix it, the image replacement is the fastest solution * Minor Fix and Add Test Fixed setChatPermissions Test: - sendDice - getMyCommands - setMyCommands - setChatAdministratorCustomTitle - setChatPermissions * Update Changelog and Package.json version * Fix typos in Changelog * Add support for poll_answer From: https://github.com/yagop/node-telegram-bot-api/pull/777 * Add JieJiSS contribution in Changelog * Add sendPoll Test * Add unpinAllChatMessages Support * Add copyMessage support * Add close and logOut Support * Add Test + Minor fixes * Update CHANGELOG Update version 0.50.1 * Update Readme Bot API Badge * Update Version to 0.51.0 * Bot API 5.1 support Improved Invite Links - Added the method createChatInviteLink - Added the method editChatInviteLink - Added the method revokeChatInviteLink * Update version to 0.52.0 and new tests - Update Changelog - New Test - Update version to 0.52.0 * Add new messageTypes - voice_chat_started - voice_chat_ended - voice_chat_participants_invited * Update Changelog and add new MessageType * New messageTypes and updates Add support for new messageTypes: - chat_invite_link - chat_member_updated Add support for new updates: - my_chat_member - chat_member
2021-03-29 16:37:10 +02:00
inviteLink = resp.invite_link;
});
});
it('should edit chat invite link', function test() {
return bot.editChatInviteLink(GROUPID, inviteLink, { member_limit: 3 }).then(resp => {
assert.strictEqual(resp.member_limit, 3);
});
});
it('should revoke chat invite link', function test() {
return bot.revokeChatInviteLink(GROUPID, inviteLink).then(resp => {
assert.strictEqual(resp.is_revoked, true);
});
});
});
describe.skip('#approveChatJoinRequest', function approveChatJoinRequestSuite() { });
describe.skip('#declineChatJoinRequest', function declineChatJoinRequestSuite() { });
describe('#setChatPhoto', function setChatPhotoSuite() {
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'setChatPhoto', this);
});
it('should set a chat photo from file', function test() {
const photo = `${__dirname}/data/chat_photo.png`;
return bot.setChatPhoto(GROUPID, photo).then(resp => {
assert.strictEqual(resp, true);
});
});
it('should set a chat photo from fs.readStream', function test() {
const photo = fs.createReadStream(`${__dirname}/data/chat_photo.png`);
return bot.setChatPhoto(GROUPID, photo).then(resp => {
assert.strictEqual(resp, true);
});
});
it('should set a chat photo from request Stream', function test() {
const photo = request(`${staticUrl}/chat_photo.png`);
return bot.setChatPhoto(GROUPID, photo).then(resp => {
assert.strictEqual(resp, true);
});
});
it('should set a chat photo from a Buffer', function test() {
const photo = fs.readFileSync(`${__dirname}/data/chat_photo.png`);
return bot.setChatPhoto(GROUPID, photo).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#deleteChatPhoto', function deleteChatPhotoSuite() {
before(function before() {
utils.handleRatelimit(bot, 'deleteChatPhoto', this);
});
it('should delete the chat photo', function test() {
return bot.deleteChatPhoto(GROUPID).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#setChatTitle', function setChatTitleSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setChatTitle', this);
});
it('should set the chat title', function test() {
const random = Math.floor(Math.random() * 1000);
return bot.setChatTitle(GROUPID, `ntba test group (random: ${random})`).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#setChatDescription', function setChatDescriptionSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setChatDescription', this);
});
it('should set the chat description', function test() {
const random = Math.floor(Math.random() * 1000);
const description = `node-telegram-bot-api test group (random: ${random})`;
return bot.setChatDescription(GROUPID, description).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#pinChatMessage', function pinChatMessageSuite() {
let messageId;
before(function before() {
utils.handleRatelimit(bot, 'pinChatMessage', this);
return bot.sendMessage(GROUPID, 'To be pinned').then(resp => {
messageId = resp.message_id;
});
});
it('should pin chat message', function test() {
return bot.pinChatMessage(GROUPID, messageId).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#unpinChatMessage', function unpinChatMessageSuite() {
before(function before() {
utils.handleRatelimit(bot, 'unpinChatMessage', this);
});
it('should unpin chat message', function test() {
return bot.unpinChatMessage(GROUPID).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#unpinAllChatMessages', function unpinAllChatMessagesSuite() {
before(function before() {
utils.handleRatelimit(bot, 'unpinAllChatMessages', this);
});
it('should unpin all chats messages', function test() {
return bot.unpinAllChatMessages(GROUPID).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe.skip('#leaveChat', function leaveChatSuite() { });
describe('#getChat', function getChatSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getChat', this);
});
it('should return a Chat object', function test() {
return bot.getChat(USERID).then(resp => {
assert.ok(is.object(resp));
});
});
});
describe('#getChatAdministrators', function getChatAdministratorsSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getChatAdministrators', this);
});
it('should return an Array', function test() {
return bot.getChatAdministrators(GROUPID).then(resp => {
assert.ok(Array.isArray(resp));
});
});
});
describe('#getChatMemberCount', function getChatMemberCountSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getChatMemberCount', this);
});
it('should return an Integer', function test() {
return bot.getChatMemberCount(GROUPID).then(resp => {
assert.ok(Number.isInteger(resp));
});
});
});
describe('#getChatMember', function getChatMemberSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getChatMember', this);
});
it('should return a ChatMember', function test() {
return bot.getChatMember(GROUPID, USERID).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.user));
assert.ok(is.string(resp.status));
});
});
});
describe('#setChatStickerSet', function setChatStickerSetSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setChatStickerSet', this);
// Check if the chat can set sticker sets
if (!CHAT_INFO.can_set_sticker_set) {
this.skip();
}
});
it('should return a Boolean', function test() {
return bot.setChatStickerSet(GROUPID, STICKER_SET_NAME).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#deleteChatStickerSet', function deleteChatStickerSetSuite() {
2017-11-27 06:33:59 +03:00
before(function before() {
utils.handleRatelimit(bot, 'deleteChatStickerSet', this);
// Check if the chat can delete sticker sets
if (!CHAT_INFO.can_set_sticker_set) {
this.skip();
}
2017-11-27 06:33:59 +03:00
});
it('should return a Boolean', function test() {
return bot.deleteChatStickerSet(GROUPID).then(resp => {
assert.ok(is.boolean(resp));
2017-11-27 06:33:59 +03:00
});
});
});
describe.skip('#answerCallbackQuery', function answerCallbackQuerySuite() { });
2017-11-27 06:33:59 +03:00
describe('#setMyCommands', function setMyCommandsSuite() {
it('should set bot commands', function test() {
const opts = [
{ command: 'eat', description: 'Command for eat' },
{ command: 'run', description: 'Command for run' }
];
return bot.setMyCommands(opts).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#deleteMyCommands', function deleteMyCommandsSuite() {
it('should delete bot commands', function test() {
return bot.deleteMyCommands().then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#setMyDescription', function getMyCommandsSuite() {
it('should set bot description for users with a specific lang code', function test() {
return bot.setMyDescription({ description: 'Bot description' }).then(resp => {
assert.ok(is.boolean(resp));
});
});
it('should set bot description for Spanish users', function test() {
return bot.setMyDescription({ description: 'Spanish bot description', language_code: 'es' }).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#setMyName', function setMyNameSuite() {
it('should set bot name for Spanish users', function test() {
return bot.setMyName({ name: 'Spanish Bot', language_code: 'es' }).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#getMyName', function setMyNameSuite() {
it('should get bot name for Spanish users', function test() {
return bot.getMyName({ language_code: 'es' }).then(resp => {
assert.ok(is.equal(resp.name, 'Spanish Bot'));
});
});
});
describe('#getMyDescription', function getMyDescriptionSuite() {
it('should get bot description for a user without lang code', function test() {
return bot.getMyDescription().then(resp => {
assert.ok(is.equal(resp.description, 'Bot description'));
});
});
it('should get bot description for Spanish users', function test() {
return bot.getMyDescription({ language_code: 'es' }).then(resp => {
assert.ok(is.equal(resp.description, 'Spanish bot description'));
});
});
});
describe('#setMyShortDescription', function setMyShortDescriptionSuite() {
it('should set sort bot description for a user without lang code', function test() {
return bot.setMyShortDescription({ short_description: 'Bot sort description' }).then(resp => {
assert.ok(is.boolean(resp));
});
});
it('should set sort description for Spanish users', function test() {
return bot.setMyShortDescription({ short_description: 'Spanish bot sort description', language_code: 'es' }).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#getMyShortDescription', function getMyShortDescriptionSuite() {
it('should get bot sort description for a user without lang code', function test() {
return bot.getMyShortDescription().then(resp => {
assert.ok(is.equal(resp.short_description, 'Bot sort description'));
});
});
it('should get bot sort description for Spanish users', function test() {
return bot.getMyShortDescription({ language_code: 'es' }).then(resp => {
assert.ok(is.equal(resp.short_description, 'Spanish bot sort description'));
});
});
});
describe('#getMyCommands', function getMyCommandsSuite() {
it('should get bot commands', function test() {
return bot.getMyCommands().then(resp => {
assert.ok(is.array(resp));
});
});
});
describe('#setChatMenuButton', function setChatMenuButtonSuite() {
it('should set chat menu button', function test() {
return bot.setChatMenuButton({
chat_id: USERID,
menu_button: JSON.stringify({ type: 'web_app', text: 'Hello', web_app: { url: 'https://webappcontent.telegram.org/cafe' } }),
})
.then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#getChatMenuButton', function getChatMenuButtonSuite() {
it('should get chat menu button', function test() {
return bot.getChatMenuButton({ chat_id: USERID }).then(resp => {
assert.ok(is.equal(resp, {
type: 'web_app',
text: 'Hello',
web_app: { url: 'https://webappcontent.telegram.org/cafe' }
}));
});
});
});
describe('#setMyDefaultAdministratorRights', function setMyDefaultAdministratorRightsSuite() {
it('should set default administrator rights', function test() {
return bot.setMyDefaultAdministratorRights({
rights: JSON.stringify({
can_manage_chat: true,
can_change_info: true,
can_delete_messages: false,
can_invite_users: true,
can_restrict_members: false,
can_pin_messages: true,
can_promote_members: false,
can_manage_video_chats: false,
is_anonymous: false
}),
for_channels: false
}).then(resp => {
assert.ok(is.boolean(resp));
});
});
});
describe('#getMyDefaultAdministratorRights', function getMyDefaultAdministratorRightsSuite() {
it('should get my default administrator rights', function test() {
return bot.getMyDefaultAdministratorRights({
for_channels: false
}).then(resp => {
assert.ok(is.equal(resp, {
can_manage_chat: true,
can_change_info: true,
can_delete_messages: false,
can_invite_users: true,
can_restrict_members: false,
can_pin_messages: true,
can_promote_members: false,
can_manage_video_chats: false,
is_anonymous: false,
can_manage_topics: false,
}));
});
});
});
describe('#editMessageText', function editMessageTextSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendMessage', this);
utils.handleRatelimit(bot, 'editMessageText', this);
});
it('should edit a message sent by the bot', function test() {
return bot.sendMessage(USERID, 'test').then(resp => {
assert.strictEqual(resp.text, 'test');
const opts = {
chat_id: USERID,
message_id: resp.message_id
};
return bot.editMessageText('edit test', opts).then(msg => {
assert.strictEqual(msg.text, 'edit test');
});
});
});
});
describe('#editMessageCaption', function editMessageCaptionSuite() {
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendPhoto', this);
utils.handleRatelimit(bot, 'editMessageCaption', this);
});
it('should edit a caption sent by the bot', function test() {
const photo = `${__dirname}/data/photo.png`;
const options = { caption: 'test caption' };
return bot.sendPhoto(USERID, photo, options).then(resp => {
assert.strictEqual(resp.caption, 'test caption');
const opts = {
chat_id: USERID,
message_id: resp.message_id
};
return bot.editMessageCaption('new test caption', opts).then(msg => {
assert.strictEqual(msg.caption, 'new test caption');
});
});
});
});
describe('#editMessageMedia', function editMessageMediaSuite() {
let photoId;
let messageID;
before(function before() {
utils.handleRatelimit(bot, 'editMessageMedia', this);
const photo = `${__dirname}/data/photo.png`;
return bot.sendPhoto(USERID, photo).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.array(resp.photo));
photoId = resp.photo[0].file_id;
messageID = resp.message_id;
});
});
it('should edit a media message', function nextTest() {
return bot.editMessageMedia({ type: 'photo', media: photoId, caption: 'edited' }, { chat_id: USERID, message_id: messageID }).then(editedResp => {
assert.ok(is.object(editedResp));
assert.ok(is.string(editedResp.caption));
});
});
});
describe('#editMessageReplyMarkup', function editMessageReplyMarkupSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendMessage', this);
utils.handleRatelimit(bot, 'editMessageReplyMarkup', this);
});
it('should edit previously-set reply markup', function test() {
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));
});
});
});
});
describe('#stopPoll', function stopPollSuite() {
let msg;
before(function before() {
utils.handleRatelimit(bot, 'stopPoll', this);
return bot.sendPoll(GROUPID, '¿Poll for stop before?', ['Yes', 'No']).then(resp => {
msg = resp;
});
});
it('should stop a Poll', function test() {
return bot.stopPoll(GROUPID, msg.message_id).then(resp => {
assert.ok(is.boolean(resp.is_closed) && resp.is_closed === true);
});
}
);
});
describe('#deleteMessage', function deleteMessageSuite() {
let messageId;
before(function before() {
utils.handleRatelimit(bot, 'deleteMessage', this);
return bot.sendMessage(USERID, 'To be deleted').then(resp => {
messageId = resp.message_id;
});
});
it('should delete message', function test() {
return bot.deleteMessage(USERID, messageId).then(resp => {
assert.strictEqual(resp, true);
});
});
});
describe('#sendSticker', function sendStickerSuite() {
let stickerId;
this.timeout(timeout);
before(function before() {
utils.handleRatelimit(bot, 'sendSticker', this);
});
it('should send a sticker from file', function test() {
const sticker = `${__dirname}/data/sticker.webp`;
return bot.sendSticker(USERID, sticker).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.sticker));
stickerId = resp.sticker.file_id;
});
});
it('should send a sticker from id', function test() {
// Send the same photo as before
return bot.sendSticker(USERID, stickerId).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.sticker));
});
});
it('should send a sticker from fs.readStream', function test() {
const sticker = fs.createReadStream(`${__dirname}/data/sticker.webp`);
return bot.sendSticker(USERID, sticker).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.sticker));
});
});
it('should send a sticker from request Stream', function test() {
const sticker = request(`${staticUrl}/sticker.webp`);
return bot.sendSticker(USERID, sticker).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.sticker));
});
});
it('should send a sticker from a Buffer', function test() {
const sticker = fs.readFileSync(`${__dirname}/data/sticker.webp`);
return bot.sendSticker(USERID, sticker).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.sticker));
});
});
});
describe('#uploadStickerFile', function sendPhotoSuite() {
before(function before() {
utils.handleRatelimit(bot, 'uploadStickerFile', this);
});
it('should upload a sticker from file', function test() {
const sticker = `${__dirname}/data/sticker.png`;
bot.uploadStickerFile(USERID, sticker).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.string(resp.file_id));
});
});
// Other tests (eg. Buffer, URL) are skipped, because they rely on the same features as sendPhoto.
});
describe('#createNewStickerSet', function createNewStickerSetSuite() {
before(function before() {
utils.handleRatelimit(bot, 'createNewStickerSet', this);
});
it('should create a new sticker set', function test(done) {
const sticker = `${__dirname}/data/sticker.png`;
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.createNewStickerSet(USERID, stickerPackName, 'Sticker Pack Title', sticker, '😍').then((resp) => {
assert.ok(is.boolean(resp));
});
setTimeout(() => done(), 2000);
});
});
describe('#getStickerSet', function getStickerSetSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getStickerSet', this);
});
it('should get the sticker set given the name of the set', function test() {
return bot.getStickerSet(STICKER_SET_NAME).then(resp => {
assert.ok(is.object(resp));
assert.strictEqual(resp.name.toLowerCase(), STICKER_SET_NAME);
assert.ok(is.string(resp.title));
assert.ok(is.string(resp.sticker_type));
assert.ok(is.array(resp.stickers));
});
});
// This test depends on the previous test createNewStickerSet
it('should get the recent sticker set created given the name of the set', function test() {
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
return bot.getStickerSet(stickerPackName).then(resp => {
STICKER_FILE_ID_FROM_SET = resp.stickers[0].file_id;
assert.ok(is.object(resp));
assert.strictEqual(resp.name.toLowerCase(), stickerPackName.toLowerCase());
assert.ok(is.string(resp.title));
assert.ok(is.string(resp.sticker_type));
assert.ok(is.array(resp.stickers));
});
});
});
describe('#getCustomEmojiStickers', function getCustomEmojiStickersSuite() {
const CHERRY_EMOJI_STICKERS_ID = ['5380109565226391871', '5431711346724968789'];
const STICKER_EMOJI_SET_NAME = 'CherryEmoji';
it('should get the custom emoji stickers', function test() {
return bot.getCustomEmojiStickers([CHERRY_EMOJI_STICKERS_ID[0]]).then(resp => {
assert.ok(is.array(resp));
assert.ok(is.object(resp[0]));
assert.ok(is.string(resp[0].set_name) && resp[0].set_name === STICKER_EMOJI_SET_NAME);
assert.ok(resp[0].custom_emoji_id === CHERRY_EMOJI_STICKERS_ID[0]);
});
});
it('should get 2 custom emoji stickers', function test() {
return bot.getCustomEmojiStickers(CHERRY_EMOJI_STICKERS_ID).then(resp => {
assert.ok(is.array(resp) && resp.length === 2);
assert.ok(is.object(resp[1]));
assert.ok(is.string(resp[1].set_name) && resp[1].set_name === STICKER_EMOJI_SET_NAME);
assert.ok(resp[1].custom_emoji_id === CHERRY_EMOJI_STICKERS_ID[1]);
});
});
});
describe('#addStickerToSet', function addStickerToSetSuite() {
before(function before() {
utils.handleRatelimit(bot, 'addStickerToSet', this);
});
it('should add a sticker to a set', function test() {
const sticker = `${__dirname}/data/sticker.png`;
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.addStickerToSet(USERID, stickerPackName, sticker, '😊😍🤔', 'png_sticker').then((resp) => {
assert.ok(is.boolean(resp));
});
});
it('should add a sticker to a set using the file Id', function test(done) {
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.addStickerToSet(USERID, stickerPackName, STICKER_FILE_ID_FROM_SET, '😊🤔', 'png_sticker').then((resp) => {
assert.ok(is.boolean(resp));
});
setTimeout(() => done(), 2000);
});
});
describe('#setStickerPositionInSet', function setStickerPositionInSet() {
before(function before() {
utils.handleRatelimit(bot, 'setStickerPositionInSet', this);
});
it('should set the position of a sticker in a set', function test() {
bot.setStickerPositionInSet(STICKER_FILE_ID_FROM_SET, 0).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe('#deleteStickerFromSet', function deleteStickerFromSetSuite() {
before(function before() {
utils.handleRatelimit(bot, 'deleteStickerFromSet', this);
});
it('should delete a sticker from a set', function test() {
bot.deleteStickerFromSet(STICKER_FILE_ID_FROM_SET).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe('#setStickerEmojiList', function setStickerEmojiListSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setStickerEmojiList', this);
});
it('should get the list for the given sticker of the bot sticker pack', function test(done) {
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.getStickerSet(stickerPackName).then(resp => {
STICKERS_FROM_BOT_SET = resp.stickers;
assert.ok(is.array(STICKERS_FROM_BOT_SET));
});
setTimeout(() => done(), 2000);
});
it('should set a emoji list for the given sticker', function test() {
assert.ok(is.equal(STICKERS_FROM_BOT_SET[0].type, 'regular'));
bot.setStickerEmojiList(STICKERS_FROM_BOT_SET[0].file_id, ['🥳', '😀', '😇']).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe('#setStickerKeywords', function setStickerKeywordsSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setStickerKeywords', this);
});
it('should set a keywords list for the given sticker', function test() {
assert.ok(is.equal(STICKERS_FROM_BOT_SET[0].type, 'regular'));
bot.setStickerKeywords(STICKERS_FROM_BOT_SET[0].file_id, { keywords: ['house', 'cat'] }).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe.skip('#setStickerMaskPosition', function setStickerKeywordsSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setStickerMaskPosition', this);
});
it('should delete a sticker from a set', function test() {
bot.setStickerMaskPosition(STICKER_FILE_ID_FROM_SET, { point: 'eyes', scale: 2, x_shift: 1, y_shift: 1 }).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe('#setStickerSetTitle', function setStickerSetTitleSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setStickerSetTitle', this);
});
it('should set a new sticker set title', function test() {
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.setStickerSetTitle(stickerPackName, 'New title').then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe('#setStickerSetThumbnail', function setStickerSetThumbnailSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setStickerSetThumbnail', this);
});
it('should set a sticker set thumb', function test() {
const stickerThumb = `${__dirname}/data/sticker_thumb.png`;
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.setStickerSetThumbnail(USERID, stickerPackName, stickerThumb).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe.skip('#setCustomEmojiStickerSetThumbnail', function setCustomEmojiStickerSetThumbnailSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setCustomEmojiStickerSetThumbnail', this);
});
it('should set a custom emoji sticjer set as thumbnail', function test() {
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.setCustomEmojiStickerSetThumbnail(stickerPackName, { custom_emoji_id: null }).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe.skip('#deleteStickerSet', function deleteStickerSetSuite() {
before(function before() {
utils.handleRatelimit(bot, 'deleteStickerSet', this);
});
it('should delete sticker set', function test() {
const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;
bot.deleteStickerSet(stickerPackName).then((resp) => {
assert.ok(is.boolean(resp));
});
});
});
describe.skip('#answerInlineQuery', function answerInlineQuerySuite() { });
describe.skip('#answerWebAppQuery', function answerCallbackQuerySuite() { });
describe('#sendInvoice', function sendInvoiceSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendInvoice', this);
});
it('should send an invoice', function test() {
if (isCI) {
this.skip(); // Skip test for now
}
const title = 'Demo product';
const description = 'our test product';
const payload = 'sku-p001';
const providerToken = PROVIDER_TOKEN;
const currency = 'USD';
const prices = [{ label: 'product', amount: 11000 }, { label: 'tax', amount: 11000 }];
return bot.sendInvoice(USERID, title, description, payload, providerToken, currency, prices).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.invoice));
assert.ok(is.number(resp.invoice.total_amount));
});
});
});
describe('#createInvoiceLink', function createInvoiceLinkSuite() {
before(function before() {
utils.handleRatelimit(bot, 'createInvoiceLink', this);
});
it('should create an invoice link', function test() {
if (isCI) {
this.skip(); // Skip test for now
}
const title = 'Invoice link product';
const description = 'Our test invoice link product';
const payload = 'sku-p002';
const providerToken = PROVIDER_TOKEN;
const currency = 'EUR';
const prices = [{ label: 'NTBA API', amount: 12000 }, { label: 'tax', amount: 10000 }];
return bot.createInvoiceLink(title, description, payload, providerToken, currency, prices).then(resp => {
assert.ok(is.string(resp));
});
});
});
describe.skip('#answerShippingQuery', function answerShippingQuerySuite() { });
describe.skip('#answerPreCheckoutQuery', function answerPreCheckoutQuerySuite() { });
describe('#sendGame', function sendGameSuite() {
before(function before() {
utils.handleRatelimit(bot, 'sendGame', this);
});
it('should send a Game', function test() {
return bot.sendGame(USERID, GAME_SHORT_NAME).then(resp => {
assert.ok(is.object(resp));
assert.ok(is.object(resp.game));
});
});
});
describe('#setGameScore', function setGameScoreSuite() {
before(function before() {
utils.handleRatelimit(bot, 'setGameScore', this);
});
it('should set GameScore', function test() {
const score = Math.floor(Math.random() * 1000);
const opts = {
chat_id: GAME_CHAT_ID,
message_id: GAME_MSG_ID,
force: true
};
return bot.setGameScore(USERID, score, opts).then(resp => {
assert.ok(is.object(resp) || is.boolean(resp));
});
});
});
describe('#getGameHighScores', function getGameHighScoresSuite() {
before(function before() {
utils.handleRatelimit(bot, 'getGameHighScores', this);
});
it('should get GameHighScores', function test() {
const opts = {
chat_id: GAME_CHAT_ID,
message_id: GAME_MSG_ID,
};
return bot.getGameHighScores(USERID, opts).then(resp => {
assert.ok(is.array(resp));
});
});
});
}); // End Telegram