зеркало из
https://github.com/glebtv/telegram-bot.git
synced 2026-09-03 09:46:17 +03:00
Сравнить коммиты
10 Коммитов
v0.9.0.alp
...
v0.9.0
| Автор | SHA1 | Дата | |
|---|---|---|---|
|
|
ec1d5bad7d | ||
|
|
194fc78202 | ||
|
|
ececfa660e | ||
|
|
9e67122465 | ||
|
|
caee9809d0 | ||
|
|
4b511f51a7 | ||
|
|
d2d6202fa7 | ||
|
|
dd38cfea93 | ||
|
|
3cb6e930b8 | ||
|
|
e42a293804 |
@@ -1,6 +1,12 @@
|
|||||||
# Unreleased
|
# 0.9.0
|
||||||
|
|
||||||
|
- Async API requests.
|
||||||
- One more description for StaleChat error.
|
- One more description for StaleChat error.
|
||||||
|
- edit_message_* methods.
|
||||||
|
- API methods from 2016-10-03 update
|
||||||
|
- Fix typo in module name: CallbackQueyContext -> CallbackQueryContext.
|
||||||
|
- Take `chat` from `message` for callback queries
|
||||||
|
- RSpec matchers.
|
||||||
|
|
||||||
# 0.8.0
|
# 0.8.0
|
||||||
|
|
||||||
|
|||||||
40
README.md
40
README.md
@@ -17,7 +17,8 @@ Package contains:
|
|||||||
- Middleware and routes helpers for production env.
|
- Middleware and routes helpers for production env.
|
||||||
- Poller with automatic source-reloader for development env.
|
- Poller with automatic source-reloader for development env.
|
||||||
- Rake tasks to update webhook urls.
|
- Rake tasks to update webhook urls.
|
||||||
- Async requests for Telegram and/or Botan API. Let the queue adapter handle errors!
|
- __[Async mode](#async-mode)__ for Telegram and/or Botan API.
|
||||||
|
Let the queue adapter handle network errors!
|
||||||
|
|
||||||
Here is sample [telegram_bot_app](https://github.com/telegram-bot-rb/telegram_bot_app)
|
Here is sample [telegram_bot_app](https://github.com/telegram-bot-rb/telegram_bot_app)
|
||||||
with session, keyboards and inline queries.
|
with session, keyboards and inline queries.
|
||||||
@@ -132,6 +133,7 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
|||||||
# do_smth_with(data)
|
# do_smth_with(data)
|
||||||
|
|
||||||
# There are `chat` & `from` shortcut methods.
|
# There are `chat` & `from` shortcut methods.
|
||||||
|
# For callback queries `chat` if taken from `message` when it's available.
|
||||||
response = from ? "Hello #{from['username']}!" : 'Hi there!'
|
response = from ? "Hello #{from['username']}!" : 'Hi there!'
|
||||||
# There is `respond_with` helper to set `chat_id` from received message:
|
# There is `respond_with` helper to set `chat_id` from received message:
|
||||||
respond_with :message, text: response
|
respond_with :message, text: response
|
||||||
@@ -246,7 +248,7 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
You can use `CallbackQueyContext` in the similar way to split `#callback_query` into
|
You can use `CallbackQueryContext` in the similar way to split `#callback_query` into
|
||||||
several specific methods. It doesn't require session support, and takes context from
|
several specific methods. It doesn't require session support, and takes context from
|
||||||
data. If data has a prefix with colon like this `my_ctx:smth...` it'll call
|
data. If data has a prefix with colon like this `my_ctx:smth...` it'll call
|
||||||
`my_ctx_callback_query('smth...')` when there is such action method. Otherwise
|
`my_ctx_callback_query('smth...')` when there is such action method. Otherwise
|
||||||
@@ -334,6 +336,23 @@ There are also some helpers for controller tests.
|
|||||||
Check out `telegram/bot/updates_controller/rspec_helpers` and
|
Check out `telegram/bot/updates_controller/rspec_helpers` and
|
||||||
`telegram/bot/updates_controller/testing`.
|
`telegram/bot/updates_controller/testing`.
|
||||||
|
|
||||||
|
Built-in RSpec matchers will help you to write tests fast:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
include Telegram::Bot::RSpec::ClientMatchers # no need if you already use controller herlpers
|
||||||
|
|
||||||
|
expect(&process_update).to send_telegram_message(bot, /msg regexp/, some: :option)
|
||||||
|
expect(&process_update).
|
||||||
|
to make_telegram_request(bot, :sendMessage, hash_including(text: 'msg text'))
|
||||||
|
|
||||||
|
# controller specs are even simplier:
|
||||||
|
describe '#start' do
|
||||||
|
subject { -> { dispatch_message '/start' } }
|
||||||
|
it { should respond_with_message(/Hello/) }
|
||||||
|
end
|
||||||
|
# See sample app for more examples.
|
||||||
|
```
|
||||||
|
|
||||||
### Deploying
|
### Deploying
|
||||||
|
|
||||||
Use `rake telegram:bot:set_webhook` to update webhook url for all configured bots.
|
Use `rake telegram:bot:set_webhook` to update webhook url for all configured bots.
|
||||||
@@ -384,11 +403,28 @@ you can implement your own worker class to handle such requests. This allows:
|
|||||||
- Handle and retry network and other errors with queue adapter.
|
- Handle and retry network and other errors with queue adapter.
|
||||||
- ???
|
- ???
|
||||||
|
|
||||||
|
Instead of performing request instantly client serializes it, pushes to queue,
|
||||||
|
and immediately return control back. The job is then fetched with a worker
|
||||||
|
and real API request is performed. And this all is absolutely transparent for the app.
|
||||||
|
|
||||||
To enable this mode add `async: true` to bot's and botan's config.
|
To enable this mode add `async: true` to bot's and botan's config.
|
||||||
For more information and custom configuration check out
|
For more information and custom configuration check out
|
||||||
[docs](http://www.rubydoc.info/github/telegram-bot-rb/telegram-bot/master/Telegram/Bot/Async) or
|
[docs](http://www.rubydoc.info/github/telegram-bot-rb/telegram-bot/master/Telegram/Bot/Async) or
|
||||||
[source](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/async.rb).
|
[source](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/async.rb).
|
||||||
|
|
||||||
|
If you want async mode, but don't want to setup queue, know that Rails 5 are shipped
|
||||||
|
with Async adapter by default, and there is
|
||||||
|
[Sucker Punch](https://github.com/brandonhilkert/sucker_punch) for Rails 4.
|
||||||
|
|
||||||
|
Be aware of some limitations:
|
||||||
|
|
||||||
|
- Client will not return API response.
|
||||||
|
- Sending files is not available in async mode [now],
|
||||||
|
because them can not be serialized.
|
||||||
|
|
||||||
|
To disable async mode for the block of code use `bot.async(false) { bot.send_photo }`.
|
||||||
|
Yes, it's threadsafe too.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
After checking out the repo, run `bin/setup` to install dependencies.
|
After checking out the repo, run `bin/setup` to install dependencies.
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ module Telegram
|
|||||||
autoload :DebugClient, 'telegram/bot/debug_client'
|
autoload :DebugClient, 'telegram/bot/debug_client'
|
||||||
autoload :Initializers, 'telegram/bot/initializers'
|
autoload :Initializers, 'telegram/bot/initializers'
|
||||||
autoload :Middleware, 'telegram/bot/middleware'
|
autoload :Middleware, 'telegram/bot/middleware'
|
||||||
|
autoload :RSpec, 'telegram/bot/rspec'
|
||||||
autoload :UpdatesController, 'telegram/bot/updates_controller'
|
autoload :UpdatesController, 'telegram/bot/updates_controller'
|
||||||
autoload :UpdatesPoller, 'telegram/bot/updates_poller'
|
autoload :UpdatesPoller, 'telegram/bot/updates_poller'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -63,21 +63,27 @@ module Telegram
|
|||||||
%w(
|
%w(
|
||||||
answerCallbackQuery
|
answerCallbackQuery
|
||||||
answerInlineQuery
|
answerInlineQuery
|
||||||
|
editMessageCaption
|
||||||
|
editMessageReplyMarkup
|
||||||
|
editMessageText
|
||||||
forwardMessage
|
forwardMessage
|
||||||
getChat
|
getChat
|
||||||
getChatAdministrators
|
getChatAdministrators
|
||||||
getChatMember
|
getChatMember
|
||||||
getChatMembersCount
|
getChatMembersCount
|
||||||
getFile
|
getFile
|
||||||
|
getGameHighScores
|
||||||
getMe
|
getMe
|
||||||
getUpdates
|
getUpdates
|
||||||
getUserProfilePhotos
|
getUserProfilePhotos
|
||||||
|
getWebhookInfo
|
||||||
kickChatMember
|
kickChatMember
|
||||||
leaveChat
|
leaveChat
|
||||||
sendAudio
|
sendAudio
|
||||||
sendChatAction
|
sendChatAction
|
||||||
sendContact
|
sendContact
|
||||||
sendDocument
|
sendDocument
|
||||||
|
sendGame
|
||||||
sendLocation
|
sendLocation
|
||||||
sendMessage
|
sendMessage
|
||||||
sendPhoto
|
sendPhoto
|
||||||
@@ -85,6 +91,7 @@ module Telegram
|
|||||||
sendVenue
|
sendVenue
|
||||||
sendVideo
|
sendVideo
|
||||||
sendVoice
|
sendVoice
|
||||||
|
setGameScore
|
||||||
setWebhook
|
setWebhook
|
||||||
unbanChatMember
|
unbanChatMember
|
||||||
).each do |method|
|
).each do |method|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ module Telegram
|
|||||||
@requests = Hash.new { |h, k| h[k] = [] }
|
@requests = Hash.new { |h, k| h[k] = [] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def request(action, body)
|
def request(action, body = {})
|
||||||
requests[action.to_sym] << body
|
requests[action.to_sym] << body
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
7
lib/telegram/bot/rspec.rb
Обычный файл
7
lib/telegram/bot/rspec.rb
Обычный файл
@@ -0,0 +1,7 @@
|
|||||||
|
module Telegram
|
||||||
|
module Bot
|
||||||
|
module RSpec
|
||||||
|
autoload :ClientMatchers, 'telegram/bot/rspec/client_matchers'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
151
lib/telegram/bot/rspec/client_matchers.rb
Обычный файл
151
lib/telegram/bot/rspec/client_matchers.rb
Обычный файл
@@ -0,0 +1,151 @@
|
|||||||
|
module Telegram
|
||||||
|
module Bot
|
||||||
|
module RSpec
|
||||||
|
# Proxy that uses RSpec::Mocks::ArgListMatcher when it's available.
|
||||||
|
# Otherwise just performs `#==` match.
|
||||||
|
#
|
||||||
|
# Also allows to check argumets with custom block.
|
||||||
|
class ArgListMatcher
|
||||||
|
attr_reader :expected, :expected_proc
|
||||||
|
|
||||||
|
def initialize(*args, &block)
|
||||||
|
@expected_proc = block if block_given?
|
||||||
|
@expected =
|
||||||
|
if mocks_matcher?
|
||||||
|
::RSpec::Mocks::ArgumentListMatcher.new(*args)
|
||||||
|
else
|
||||||
|
args
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def args_match?(*actual)
|
||||||
|
if expected_proc
|
||||||
|
expected_proc[*actual]
|
||||||
|
true
|
||||||
|
elsif mocks_matcher?
|
||||||
|
expected.args_match?(*actual)
|
||||||
|
else
|
||||||
|
expected == actual
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def args
|
||||||
|
mocks_matcher? ? expected.args : expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def mocks_matcher?
|
||||||
|
defined?(::RSpec::Mocks::ArgumentListMatcher)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
if mocks_matcher?
|
||||||
|
expected.expected_args.inspect
|
||||||
|
elsif expected_proc
|
||||||
|
'(proc matcher)'
|
||||||
|
else
|
||||||
|
expected.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Matchers to test requests to Telegram API.
|
||||||
|
#
|
||||||
|
# Complex matchers requires `rspec-mocks` to be installed.
|
||||||
|
module ClientMatchers
|
||||||
|
class MakeTelegramRequest < ::RSpec::Matchers::BuiltIn::BaseMatcher
|
||||||
|
EXPECTATION_TYPES = {
|
||||||
|
exactly: :==,
|
||||||
|
at_most: :>=,
|
||||||
|
at_least: :<=,
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
attr_reader :performed_requests, :description
|
||||||
|
|
||||||
|
def initialize(bot, action, description: nil)
|
||||||
|
@bot = bot
|
||||||
|
@action = action
|
||||||
|
@description = description || "make #{action} telegram request"
|
||||||
|
exactly(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def matches?(proc) # rubocop:disable AbcSize
|
||||||
|
raise ArgumentError, 'matcher only supports block expectations' unless proc.is_a?(Proc)
|
||||||
|
original_requests_count = bot.requests[action].count
|
||||||
|
proc.call
|
||||||
|
@performed_requests = bot.requests[action].drop(original_requests_count)
|
||||||
|
@matching_requests_count = performed_requests.count do |request|
|
||||||
|
!arg_list_matcher || arg_list_matcher.args_match?(request)
|
||||||
|
end
|
||||||
|
expectation_method = EXPECTATION_TYPES[expectation_type]
|
||||||
|
expected_number.public_send(expectation_method, matching_requests_count)
|
||||||
|
end
|
||||||
|
|
||||||
|
def with(*args, &block)
|
||||||
|
@arg_list_matcher = ArgListMatcher.new(*args, &block)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
EXPECTATION_TYPES.each_key do |type|
|
||||||
|
define_method type do |count|
|
||||||
|
@expectation_type = type
|
||||||
|
@expected_number = Integer(count)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def times
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message
|
||||||
|
"expected to #{base_message}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message_when_negated
|
||||||
|
"expected not to #{base_message}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def supports_block_expectations?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :bot, :action, :expectation_type, :expected_number,
|
||||||
|
:arg_list_matcher, :matching_requests_count
|
||||||
|
|
||||||
|
def base_message
|
||||||
|
"make #{expectation_type.to_s.tr('_', ' ')} #{expected_number} " \
|
||||||
|
"#{bot.inspect}.#{action} requests,".tap do |msg|
|
||||||
|
msg << " with #{arg_list_matcher}," if arg_list_matcher
|
||||||
|
msg << " but made #{matching_requests_count}"
|
||||||
|
if performed_requests
|
||||||
|
actual_args = performed_requests.map(&:inspect).join(', ')
|
||||||
|
msg << ", and #{performed_requests.count} with #{actual_args}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check that bot performed request to telegram API:
|
||||||
|
#
|
||||||
|
# expect { dispatch_message('Hi!') }.
|
||||||
|
# to make_telegram_request(bot, :sendMessage).
|
||||||
|
# with(text: 'Hello!', chat_id: chat_id)
|
||||||
|
def make_telegram_request(bot, action)
|
||||||
|
MakeTelegramRequest.new(bot, action)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Helper for asserting message is sent. Note that options are checked
|
||||||
|
# with `hash_including`. For strict checks use #make_telegram_request.
|
||||||
|
def send_telegram_message(bot, text = nil, options = {})
|
||||||
|
text = a_string_matching(text) if text.is_a?(Regexp)
|
||||||
|
options = options.merge(text: text) if text
|
||||||
|
description = "send telegram message #{text.inspect}"
|
||||||
|
MakeTelegramRequest.new(bot, :sendMessage, description: description).
|
||||||
|
with(hash_including(options))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -50,14 +50,14 @@ module Telegram
|
|||||||
# ControllerClass.new(bot, from: telegram_user, chat: telegram_chat).
|
# ControllerClass.new(bot, from: telegram_user, chat: telegram_chat).
|
||||||
# process(:help, *args)
|
# process(:help, *args)
|
||||||
#
|
#
|
||||||
class UpdatesController < AbstractController::Base # rubocop:disable ClassLength
|
class UpdatesController < AbstractController::Base
|
||||||
abstract!
|
abstract!
|
||||||
|
|
||||||
require 'telegram/bot/updates_controller/session'
|
require 'telegram/bot/updates_controller/session'
|
||||||
require 'telegram/bot/updates_controller/log_subscriber'
|
require 'telegram/bot/updates_controller/log_subscriber'
|
||||||
require 'telegram/bot/updates_controller/instrumentation'
|
require 'telegram/bot/updates_controller/instrumentation'
|
||||||
require 'telegram/bot/updates_controller/reply_helpers'
|
require 'telegram/bot/updates_controller/reply_helpers'
|
||||||
autoload :CallbackQueyContext, 'telegram/bot/updates_controller/callback_query_context'
|
autoload :CallbackQueryContext, 'telegram/bot/updates_controller/callback_query_context'
|
||||||
autoload :MessageContext, 'telegram/bot/updates_controller/message_context'
|
autoload :MessageContext, 'telegram/bot/updates_controller/message_context'
|
||||||
|
|
||||||
include AbstractController::Callbacks
|
include AbstractController::Callbacks
|
||||||
@@ -140,10 +140,12 @@ module Telegram
|
|||||||
@_payload, @_payload_type = payload_data
|
@_payload, @_payload_type = payload_data
|
||||||
end
|
end
|
||||||
|
|
||||||
# Accessor to `'chat'` field of payload. Can be overriden with `chat` option
|
# Accessor to `'chat'` field of payload. Also tries `'chat'` in `'message'`
|
||||||
# for #initialize.
|
# when there is no such field in payload.
|
||||||
|
#
|
||||||
|
# Can be overriden with `chat` option for #initialize.
|
||||||
def chat
|
def chat
|
||||||
@_chat ||= payload && payload['chat']
|
@_chat ||= payload.try! { |x| x['chat'] || x['message'] && x['message']['chat'] }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Accessor to `'from'` field of payload. Can be overriden with `from` option
|
# Accessor to `'from'` field of payload. Can be overriden with `from` option
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module Telegram
|
|||||||
class UpdatesController
|
class UpdatesController
|
||||||
# Use separate actions for different callback queries.
|
# Use separate actions for different callback queries.
|
||||||
# It doesn't require session support. Simply add `%{context}:` prefix to data.
|
# It doesn't require session support. Simply add `%{context}:` prefix to data.
|
||||||
module CallbackQueyContext
|
module CallbackQueryContext
|
||||||
protected
|
protected
|
||||||
|
|
||||||
# Uses #context_from_callback_query as context name.
|
# Uses #context_from_callback_query as context name.
|
||||||
|
|||||||
@@ -14,11 +14,14 @@ RSpec.shared_context 'telegram/bot/updates_controller' do
|
|||||||
let(:bot_name) { 'bot' }
|
let(:bot_name) { 'bot' }
|
||||||
let(:session) { controller.send(:session) }
|
let(:session) { controller.send(:session) }
|
||||||
|
|
||||||
|
include Telegram::Bot::RSpec::ClientMatchers
|
||||||
|
|
||||||
def dispatch(bot = self.bot, update = self.update)
|
def dispatch(bot = self.bot, update = self.update)
|
||||||
controller.dispatch_again(bot, update)
|
controller.dispatch_again(bot, update)
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispatch_message(text, options = {})
|
def dispatch_message(text, options = nil)
|
||||||
|
options ||= respond_to?(:default_message_options) ? default_message_options : {}
|
||||||
update = build_update :message, options.merge(text: text)
|
update = build_update :message, options.merge(text: text)
|
||||||
dispatch bot, update
|
dispatch bot, update
|
||||||
end
|
end
|
||||||
@@ -34,4 +37,9 @@ RSpec.shared_context 'telegram/bot/updates_controller' do
|
|||||||
else input
|
else input
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Matcher to check response. Make sure to define `let(:chat_id)`.
|
||||||
|
def respond_with_message(expected)
|
||||||
|
send_telegram_message(bot, expected, chat_id: chat_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module Telegram
|
module Telegram
|
||||||
module Bot
|
module Bot
|
||||||
VERSION = '0.9.0.alpha2'.freeze
|
VERSION = '0.9.0'.freeze
|
||||||
|
|
||||||
def self.gem_version
|
def self.gem_version
|
||||||
Gem::Version.new VERSION
|
Gem::Version.new VERSION
|
||||||
|
|||||||
87
spec/telegram/bot/rspec/client_matchers_spec.rb
Обычный файл
87
spec/telegram/bot/rspec/client_matchers_spec.rb
Обычный файл
@@ -0,0 +1,87 @@
|
|||||||
|
RSpec.describe Telegram::Bot::RSpec::ClientMatchers do
|
||||||
|
let(:bot) { Telegram::Bot::ClientStub.new('TestBot') }
|
||||||
|
let(:other_bot) { Telegram::Bot::ClientStub.new('OtherTestBot') }
|
||||||
|
|
||||||
|
include described_class
|
||||||
|
|
||||||
|
describe '#make_telegram_request' do
|
||||||
|
context 'without args' do
|
||||||
|
it 'works for matching' do
|
||||||
|
block = ->(*) { bot.send_message(text: 'test') }
|
||||||
|
expect(&block).to make_telegram_request(bot, :sendMessage)
|
||||||
|
expect { 3.times(&block) }.to make_telegram_request(bot, :sendMessage).exactly(3).times
|
||||||
|
expect { 3.times(&block) }.to make_telegram_request(bot, :sendMessage).at_least(2).times
|
||||||
|
expect { 3.times(&block) }.to make_telegram_request(bot, :sendMessage).at_most(4).times
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works for not-matching' do
|
||||||
|
block = ->(*) { bot.get_me }
|
||||||
|
expect {}.to_not make_telegram_request(bot, :getMe)
|
||||||
|
expect { other_bot.get_me }.to_not make_telegram_request(bot, :getMe)
|
||||||
|
expect { 3.times(&block) }.to_not make_telegram_request(bot, :getMe)
|
||||||
|
expect { 3.times(&block) }.to_not make_telegram_request(bot, :getMe).exactly(2).times
|
||||||
|
expect { 3.times(&block) }.to_not make_telegram_request(bot, :getMe).exactly(4).times
|
||||||
|
expect { 3.times(&block) }.to_not make_telegram_request(bot, :getMe).at_least(4).times
|
||||||
|
expect { 3.times(&block) }.to_not make_telegram_request(bot, :getMe).at_most(2).times
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with args' do
|
||||||
|
it 'works for exact matching' do
|
||||||
|
args = {text: 'test', parseMode: :Markdown}
|
||||||
|
block = ->(*) { bot.send_message(args) }
|
||||||
|
expect(&block).to make_telegram_request(bot, :sendMessage).with(args)
|
||||||
|
expect(&block).to_not make_telegram_request(bot, :sendMessage).with(args.except(:text))
|
||||||
|
expect { 3.times(&block) }.to make_telegram_request(bot, :sendMessage).
|
||||||
|
with(args).exactly(3).times
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works for block matchers' do
|
||||||
|
args = {text: 'test', parseMode: :Markdown}
|
||||||
|
block = ->(*) { bot.send_message(args) }
|
||||||
|
expect(&block).to make_telegram_request(bot, :sendMessage).
|
||||||
|
with { |actual| expect(actual).to eq(args) }
|
||||||
|
# It ignores block's result! Custom expectations must be used inside block.
|
||||||
|
expect(&block).to make_telegram_request(bot, :sendMessage).
|
||||||
|
with { |actual| actual == {} }
|
||||||
|
expect do
|
||||||
|
expect(&block).to_not make_telegram_request(bot, :sendMessage).
|
||||||
|
with { |actual| expect(actual).to eq({}) }
|
||||||
|
end.to raise_error RSpec::Expectations::ExpectationNotMetError
|
||||||
|
n = -1
|
||||||
|
expect { 3.times { |i| bot.send_message text: i } }.
|
||||||
|
to make_telegram_request(bot, :sendMessage).exactly(3).times.
|
||||||
|
with { |actual| expect(actual).to eq(text: n += 1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works for RSpec::Mocks matchers' do
|
||||||
|
args = {text: 'test', parseMode: :Markdown}
|
||||||
|
block = ->(*) { bot.send_message(args) }
|
||||||
|
expect(&block).to make_telegram_request(bot, :sendMessage).with(hash_including(args))
|
||||||
|
expect(&block).to make_telegram_request(bot, :sendMessage).with(
|
||||||
|
text: a_string_matching(/est$/),
|
||||||
|
parseMode: :Markdown,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#send_telegram_message' do
|
||||||
|
let(:args) { {text: 'test', parseMode: :Markdown} }
|
||||||
|
let(:block) { ->(*) { bot.send_message(args) } }
|
||||||
|
|
||||||
|
it 'works for matching' do
|
||||||
|
expect(&block).to send_telegram_message(bot, 'test')
|
||||||
|
expect(&block).to send_telegram_message(bot, /^tes/)
|
||||||
|
expect(&block).to send_telegram_message(bot, 'test', parseMode: :Markdown)
|
||||||
|
expect(&block).to send_telegram_message(bot, a_string_including('es'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works for not-matching' do
|
||||||
|
expect(&block).to_not send_telegram_message(bot, 'test!')
|
||||||
|
expect(&block).to_not send_telegram_message(bot, /tes$/)
|
||||||
|
expect(&block).to_not send_telegram_message(bot, 'test', parseMode: :HTML)
|
||||||
|
expect(&block).to_not send_telegram_message(bot, a_string_including('smth'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
RSpec.describe Telegram::Bot::UpdatesController::CallbackQueyContext do
|
RSpec.describe Telegram::Bot::UpdatesController::CallbackQueryContext do
|
||||||
include_context 'telegram/bot/updates_controller'
|
include_context 'telegram/bot/updates_controller'
|
||||||
let(:controller_class) do
|
let(:controller_class) do
|
||||||
described_class = self.described_class
|
described_class = self.described_class
|
||||||
|
|||||||
@@ -293,4 +293,49 @@ RSpec.describe Telegram::Bot::UpdatesController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#chat' do
|
||||||
|
subject { controller.chat }
|
||||||
|
let(:payload_type) { :message }
|
||||||
|
let(:payload) { {chat: 'test_value'} }
|
||||||
|
it { should eq payload[:chat] }
|
||||||
|
|
||||||
|
context 'when payload is not set' do
|
||||||
|
let(:payload) {}
|
||||||
|
it { should eq nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when payload has no such field' do
|
||||||
|
let(:payload) { {smth: 'other'} }
|
||||||
|
it { should eq nil }
|
||||||
|
|
||||||
|
context 'but has `message`' do
|
||||||
|
let(:payload) { {message: message} }
|
||||||
|
let(:message) { {text: 'Hello bot!'} }
|
||||||
|
it { should eq nil }
|
||||||
|
|
||||||
|
context 'with `chat` set' do
|
||||||
|
let(:message) { super().merge(chat: 'test value') }
|
||||||
|
it { should eq message[:chat] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#from' do
|
||||||
|
subject { controller.from }
|
||||||
|
let(:payload_type) { :message }
|
||||||
|
let(:payload) { {from: 'test_value'} }
|
||||||
|
it { should eq payload[:from] }
|
||||||
|
|
||||||
|
context 'when payload is not set' do
|
||||||
|
let(:payload) {}
|
||||||
|
it { should eq nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when payload has no such field' do
|
||||||
|
let(:payload) { {smth: 'other'} }
|
||||||
|
it { should eq nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user