UNPKG

node-red-contrib-telegrambot

Version:
107 lines (95 loc) 4.04 kB
const helper = require('node-red-node-test-helper'); const { expect } = require('chai'); const http = require('http'); const telegrambotModule = require('../../telegrambot/99-telegrambot.js'); const { startMock } = require('../fixtures/telegram-mock.js'); helper.init(require.resolve('node-red')); // Helper to pick an unused TCP port without binding. function findFreePort() { return new Promise(function (resolve) { const srv = http.createServer(); srv.listen(0, '127.0.0.1', function () { const port = srv.address().port; srv.close(function () { resolve(port); }); }); }); } // Wait for a predicate to become true, polling every 25ms up to maxMs. function waitFor(predicate, maxMs) { return new Promise(function (resolve, reject) { const deadline = Date.now() + (maxMs || 5000); (function tick() { if (predicate()) return resolve(); if (Date.now() > deadline) return reject(new Error('waitFor timed out')); setTimeout(tick, 25); })(); }); } describe('integration: webhook transport against a mocked Telegram API', function () { this.timeout(10000); let mock; let webhookPort; before(async function () { mock = await startMock(); webhookPort = await findFreePort(); await new Promise(function (r) { helper.startServer(r); }); }); after(async function () { await new Promise(function (r) { helper.stopServer(r); }); await mock.stop(); }); afterEach(async function () { await helper.unload(); mock.clearCalls(); }); function webhookFlow() { // sslTerminated:true makes the bot skip the local HTTPS-listener requirement, // so it'll happily speak plain HTTP locally. return [ { id: 'b1', type: 'telegram bot', botname: 'b', updatemode: 'webhook', bothost: 'https://example.invalid:8443', publicbotport: '8443', localbotport: String(webhookPort), localbothost: '127.0.0.1', sslterminated: true, baseapiurl: mock.url, }, { id: 'r1', type: 'telegram receiver', bot: 'b1', wires: [['out'], ['unauth']] }, { id: 'out', type: 'helper' }, { id: 'unauth', type: 'helper' }, ]; } it('calls setWebHook against the mocked API on startup', async function () { await new Promise(function (resolve) { helper.load(telegrambotModule, webhookFlow(), { b1: { token: 'fake' } }, resolve); }); await waitFor(function () { return mock.callsTo('setWebHook').length > 0; }, 5000); const calls = mock.callsTo('setWebHook'); expect(calls).to.have.length(1); // The body's `url` field is either parsed from form-urlencoded or json; both // should mention the configured host. We accept either via body or query because // node-telegram-bot-api has flipped this across versions. const url = (calls[0].body && calls[0].body.url) || (calls[0].query && calls[0].query.url) || ''; expect(String(url)).to.include('example.invalid'); }); // NOTE: a "deleteWebHook fires on close" assertion is intentionally omitted here. // The abortBot chain (deleteWebHook -> closeWebHook -> setStatusDisconnected -> done) // should make this observable through the mock, but in practice the mock-captured // request didn't show up where the assertion expected it. The setStatusDisconnected // callback resolves the close() promise before the underlying request's response // round-trips through the mock's record, which makes the test flaky to assert against. // Tracking as a follow-up; the close-path correctness is otherwise covered by the // node-level tests in test/nodes/. });