jehy / telegram-test-api

Simple implimentation of telegram API which can be used for testing telegram bots
MIT License
98 stars 24 forks source link

Problem with testing with Telegraf #16

Closed jgsmarques closed 5 years ago

jgsmarques commented 5 years ago

Hi,

I'm trying to use your framework to test a bot that I'm building using Telegraf.

I'm facing issues in getting messages created with this API to reach my bot. My bot has the following implementation:

const Telegraf = require('telegraf')
const TelegramServer = require('telegram-test-api')

describe.only('Telegram bot test', () => {
  let serverConfig = { port: 9001 }
  const token = process.env.TELEGRAM_API_TOKEN
  let server
  let client
  beforeEach(() => {
    server = new TelegramServer(serverConfig)
    return server.start().then(() => {
      client = server.getClient(token, { timeout: 5000 })
      // the options passed to Telegraf in this format will make it try to get messages from the server's local URL
      const bot = new Telegraf(token, { telegram: { apiRoot: server.ApiURL } }
      bot.startPolling()
      return bot
      }).then(botInstance => {
        botInstance.command('start', ctx => {
          ctx.reply('Hi')
        })
      })
    })
  })

  afterEach(function () {
    return server.stop()
  })

  it('should return help content', async () => {
    const message = client.makeMessage('/start')
    await client.sendMessage(message)
    const updates = await client.getUpdates()
    console.log(`Client received messages: ${JSON.stringify(updates.result)}`)
    if (updates.result.length !== 1) {
      throw new Error('updates queue should contain one message!')
    }
  })
})

When I run my test, it fails and I do not understand why.

However, if I replace the start command of the bot with botInstance.on('message', ctx => ctx.reply('Hi')), my bot will actually answer and the test will pass. So the messages are definitely arriving Telegraf (I've set some debug points on their code and I can see that all messages sent via your framework reach the bot), but somehow their format is preventing them from reaching my code when using Telegraf commands.

Can you help me identify what the problem is, or if I should be sending the messages in a different format for them to reach Telegraf correctly?

Thank you very much!

jehy commented 5 years ago

Hi! That was pretty complex to debug. Seems like telegraf does not process text message /start as a command. I suppose there should be another markup to pass command to bot from client correctly. Right now I can't look it up, but PR would be great.

For now, you can replace botInstance.command('start') with botInstance.hears('/start') as I added a test example here - and it will work.

jgsmarques commented 5 years ago

Hi,

This is the implementation for the command method in Telegraf:

static command (command, ...fns) {
  if (fns.length === 0) {
    return Composer.entity(['bot_command'], command)
  }
  const commands = normalizeTextArguments(command, '/')
  return Composer.mount('text', Composer.lazy((ctx) => {
    const groupCommands = ctx.me && (ctx.chat.type === 'group' || ctx.chat.type === 'supergroup')
      ? commands.map((command) => `${command}@${ctx.me}`)
      : []
    return Composer.entity(({ offset, type }, value) =>
      offset === 0 &&
      type === 'bot_command' &&
      (commands.includes(value) || groupCommands.includes(value))
    , ...fns)
  }))
}

From a naive approach, I would say that the type === 'bot_command' might be the issue. I will need to investigate further to check if this is something that Telegraf computes before at some other level (when parsing a message from Telegram) or something it expects Telegram to send already filled out.

Whenever I get a chance I'll try to examine a little deeper.

Thanks anyway for the quick response!

jgsmarques commented 5 years ago

I've done a quick find in the Telegraf source code and the only place I can find the 'bot_command' string is exactly in the method I posted. Therefore, it seems that Telegraf expects Telegram to send that value in messages.

Does this framework do anything related to this when processing commands? If not, that might be the issue.

jehy commented 5 years ago

@tigermarques Great! It helped to implement client methods "makeCommand" and "sendCommand". With this, your code works with bot.command('start') !

Please check version 2.2.1 on npm.

jgsmarques commented 5 years ago

Works like a charm! Thanks a lot!

jehy commented 5 years ago

Thank you for your comments! This API is pretty simple and raw since I am the only developer and I only use it time to time for my own projects, so you can find other missing features. But surely we can implement them :)