зеркало из
https://github.com/glebtv/telegram-bot.git
synced 2026-09-07 19:35:52 +03:00
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,3 +1,16 @@
|
|||||||
|
# Unreleased
|
||||||
|
|
||||||
|
- Make integration & controller specs consistent.
|
||||||
|
__Breaking changes__ for controller specs:
|
||||||
|
- Changed signature `dispatch(bot, update) => dispatch(update, bot)`.
|
||||||
|
- `update` helper is symbolized by default.
|
||||||
|
- `build_update(type, data)` is dropped in favor of `deep_stringify(type => data)`.
|
||||||
|
- Provide support for integration testing of bots in poller mode and non-Rails apps.
|
||||||
|
__Breaking changes__:
|
||||||
|
- Requiring `telegram/bot/rspec/integration` is deprecated in favor of
|
||||||
|
`telegram/bot/rspec/integration/rails`.
|
||||||
|
- `:telegram_bot` rspec tag is replaced with `telegram_bot: :rails`.
|
||||||
|
|
||||||
# 0.13.1
|
# 0.13.1
|
||||||
|
|
||||||
- Extracted typed response mappings to telegram-bot-types gem.
|
- Extracted typed response mappings to telegram-bot-types gem.
|
||||||
|
|||||||
92
README.md
92
README.md
@@ -192,8 +192,9 @@ end
|
|||||||
#### Reply helpers
|
#### Reply helpers
|
||||||
|
|
||||||
There are helpers to respond for basic actions. They just set chat/message/query
|
There are helpers to respond for basic actions. They just set chat/message/query
|
||||||
identifiers from update. See [`ReplyHelpers`](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/updates_controller/reply_helpers.rb) module for more information.
|
identifiers from update. See
|
||||||
Here are this methods signatures:
|
[`ReplyHelpers`](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/updates_controller/reply_helpers.rb)
|
||||||
|
module for more information. Here are this methods signatures:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
def respond_with(type, params); end
|
def respond_with(type, params); end
|
||||||
@@ -394,11 +395,11 @@ Telegram::Bot::UpdatesPoller.start(bot, controller_class)
|
|||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
There is `Telegram::Bot::ClientStub` class to stub client for tests.
|
There is a `Telegram::Bot::ClientStub` class to stub client for tests.
|
||||||
Instead of performing API requests it stores them in `requests` hash.
|
Instead of performing API requests it stores them in a `requests` hash.
|
||||||
|
|
||||||
To stub all possible clients use `Telegram::Bot::ClientStub.stub_all!` before
|
To stub all possible clients use `Telegram::Bot::ClientStub.stub_all!` before
|
||||||
initializing clients. Here is template for RSpec:
|
initializing clients. Here is a template for RSpec:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
# environments/test.rb
|
# environments/test.rb
|
||||||
@@ -416,47 +417,82 @@ RSpec.configure do |config|
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
There are integration and controller contexts for RSpec and some built-in matchers:
|
RSpec contexts and helpers are included automatically for groups and examples with matching
|
||||||
|
tags. In RSpec < 3.4 it's required to use `include_context` explicitly.
|
||||||
|
See [list of available helpers](https://github.com/telegram-bot-rb/telegram-bot/tree/master/lib/telegram/bot/rspec)
|
||||||
|
for details.
|
||||||
|
|
||||||
|
There are 3 types of integration tests:
|
||||||
|
|
||||||
|
- `:rails` - for testing bot in webhooks-mode in Rails application.
|
||||||
|
It simulates webhook requests POSTing data to controller's endpoint.
|
||||||
|
It works on the top of requests specs, so `rspec-rails` gem is required.
|
||||||
|
- `:rack` - For testing bot in webhooks-mode in non-Rails application.
|
||||||
|
It uses `rack-test` gem to POST requests to bot's endpoint.
|
||||||
|
- `:poller` - Calls `.dispatch` directly on controller class.
|
||||||
|
|
||||||
|
Pick the appropriate one, then require `telegram/bot/rspec/integration/#{type}`
|
||||||
|
and mark spec group with tag `telegram_bot: type`. See configuration options
|
||||||
|
for each type in
|
||||||
|
[telegram/bot/rspec/integration/](https://github.com/telegram-bot-rb/telegram-bot/tree/master/lib/telegram/bot/rspec/integration).
|
||||||
|
|
||||||
|
Here is an example test for a Rails app:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
# spec/requests/telegram_webhooks_spec.rb
|
# spec/requests/telegram_webhooks_spec.rb
|
||||||
require 'telegram/bot/rspec/integration'
|
require 'telegram/bot/rspec/integration/rails'
|
||||||
|
|
||||||
RSpec.describe TelegramWebhooksController, :telegram_bot do
|
RSpec.describe TelegramWebhooksController, telegram_bot: :rails do
|
||||||
# for old rspec add:
|
# for old RSpec:
|
||||||
# include_context 'telegram/bot/integration'
|
# include_context 'telegram/bot/integration/rails'
|
||||||
|
|
||||||
|
# Main method is #dispatch(update). Some helpers are:
|
||||||
|
# dispatch_message(text, options = {})
|
||||||
|
# dispatch_command(cmd, *args)
|
||||||
|
|
||||||
|
# Available matchers can be found in Telegram::Bot::RSpec::ClientMatchers.
|
||||||
|
it 'shows usage of basic matchers'
|
||||||
|
# The most basic one is #make_telegram_request(bot, endpoint, params_matcher)
|
||||||
|
expect { dispatch_command(:start) }.
|
||||||
|
to make_telegram_request(bot, :sendMessage, hash_including(text: 'msg text'))
|
||||||
|
|
||||||
|
# There are some shortcuts for dispatching basic updates and testing responses.
|
||||||
|
expect { dispatch_message('Hi') }.to send_telegram_message(bot, /msg regexp/, some: :option)
|
||||||
|
end
|
||||||
|
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
subject { -> { dispatch_command :start } }
|
subject { -> { dispatch_command :start } }
|
||||||
|
# Using built in matcher for `respond_to`:
|
||||||
it { should respond_with_message 'Hi there!' }
|
it { should respond_with_message 'Hi there!' }
|
||||||
end
|
end
|
||||||
|
|
||||||
# There is context for callback queries with related matchers.
|
# There is context for callback queries with related matchers,
|
||||||
|
# use :callback_query tag to include it.
|
||||||
describe '#hey_callback_query', :callback_query do
|
describe '#hey_callback_query', :callback_query do
|
||||||
let(:data) { "hey:#{name}" }
|
let(:data) { "hey:#{name}" }
|
||||||
let(:name) { 'Joe' }
|
let(:name) { 'Joe' }
|
||||||
it { should answer_callback_query('Hey Joe') }
|
it { should answer_callback_query('Hey Joe') }
|
||||||
it { should edit_current_message :text, text: 'Done' }
|
it { should edit_current_message :text, text: 'Done' }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# For controller specs use
|
|
||||||
require 'telegram/bot/updates_controller/rspec_helpers'
|
|
||||||
RSpec.describe TelegramWebhooksController, type: :telegram_bot_controller do
|
|
||||||
# for old rspec add:
|
|
||||||
# include_context 'telegram/bot/updates_controller'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Matchers are available for custom specs:
|
|
||||||
include Telegram::Bot::RSpec::ClientMatchers
|
|
||||||
|
|
||||||
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'))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Place integration tests inside `spec/requests`
|
There is a context for testing bot controller in the way similar to Rails controller tests.
|
||||||
when using RSpec's `infer_spec_type_from_file_location!`,
|
It's supposed to be a low-level alternative for integration tests. Among the differences is
|
||||||
or just add `type: :request` to `describe`.
|
that controller tests use a single controller instance for all dispatches in specific exaple,
|
||||||
|
session is stubbed (does not use configured store engine), and update is not serialized
|
||||||
|
so it also supports mocks. This can be useful for unit testing, but should not be used as
|
||||||
|
the default way to test the bot.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
require 'telegram/bot/updates_controller/rspec_helpers'
|
||||||
|
RSpec.describe TelegramWebhooksController, type: :telegram_bot_controller do
|
||||||
|
# for old RSpec:
|
||||||
|
# include_context 'telegram/bot/updates_controller'
|
||||||
|
|
||||||
|
# Same helpers and matchers like dispatch_command, answer_callback_query are available here.
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
See sample app for more examples.
|
See sample app for more examples.
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ module Telegram
|
|||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
def deprecation_0_14
|
def deprecation_0_15
|
||||||
@deprecation ||= begin
|
@deprecation ||= begin
|
||||||
require 'active_support/deprecation'
|
require 'active_support/deprecation'
|
||||||
ActiveSupport::Deprecation.new('0.14', 'Telegram::Bot')
|
ActiveSupport::Deprecation.new('0.15', 'Telegram::Bot')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
require 'active_support/concern'
|
require 'active_support/concern'
|
||||||
require 'active_support/core_ext/hash/indifferent_access'
|
require 'active_support/core_ext/hash/indifferent_access'
|
||||||
require 'active_support/json'
|
require 'active_support/json'
|
||||||
require 'action_dispatch/http/mime_type'
|
require 'action_dispatch'
|
||||||
require 'action_dispatch/http/request'
|
|
||||||
|
|
||||||
module Telegram
|
module Telegram
|
||||||
module Bot
|
module Bot
|
||||||
|
|||||||
@@ -24,33 +24,6 @@ module Telegram
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# # Create routes for all Telegram.bots to use same controller:
|
|
||||||
# telegram_webhooks TelegramController
|
|
||||||
#
|
|
||||||
# # Or pass custom bots usin any of supported config options:
|
|
||||||
# telegram_webhooks TelegramController, [
|
|
||||||
# bot,
|
|
||||||
# {token: token, username: username},
|
|
||||||
# other_bot_token,
|
|
||||||
# ]
|
|
||||||
def telegram_webhooks(controllers, bots = nil, **options)
|
|
||||||
Bot.deprecation_0_14.deprecation_warning(:telegram_webhooks, <<-TXT.strip_heredoc)
|
|
||||||
It brings unnecessary complexity and encourages writeng less readable code.
|
|
||||||
Please use telegram_webhook method instead.
|
|
||||||
It's signature `telegram_webhook(controller, bot = :default, **options)`.
|
|
||||||
Multiple-bot environments now requires calling this method in a loop
|
|
||||||
or using statement for each bot.
|
|
||||||
TXT
|
|
||||||
unless controllers.is_a?(Hash)
|
|
||||||
bots = bots ? Array.wrap(bots) : Telegram.bots.values
|
|
||||||
controllers = Hash[bots.map { |x| [x, controllers] }]
|
|
||||||
end
|
|
||||||
controllers.each do |bot, controller|
|
|
||||||
controller, bot_options = controller if controller.is_a?(Array)
|
|
||||||
telegram_webhook(controller, bot, options.merge(bot_options || {}))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Define route which processes requests using given controller and bot.
|
# Define route which processes requests using given controller and bot.
|
||||||
#
|
#
|
||||||
# telegram_webhook TelegramController, bot
|
# telegram_webhook TelegramController, bot
|
||||||
|
|||||||
@@ -2,6 +2,15 @@ module Telegram
|
|||||||
module Bot
|
module Bot
|
||||||
module RSpec
|
module RSpec
|
||||||
autoload :ClientMatchers, 'telegram/bot/rspec/client_matchers'
|
autoload :ClientMatchers, 'telegram/bot/rspec/client_matchers'
|
||||||
|
|
||||||
|
module_function
|
||||||
|
|
||||||
|
# Yelds a block if `include_context` is supported.
|
||||||
|
def with_include_context
|
||||||
|
::RSpec.configure do |config|
|
||||||
|
yield(config) if config.respond_to?(:include_context)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
39
lib/telegram/bot/rspec/callback_query_helpers.rb
Обычный файл
39
lib/telegram/bot/rspec/callback_query_helpers.rb
Обычный файл
@@ -0,0 +1,39 @@
|
|||||||
|
require 'telegram/bot/rspec'
|
||||||
|
require 'telegram/bot/rspec/message_helpers'
|
||||||
|
|
||||||
|
# Shared helpers for testing callback query updates.
|
||||||
|
RSpec.shared_context 'telegram/bot/callback_query' do
|
||||||
|
include_context 'telegram/bot/message_helpers'
|
||||||
|
|
||||||
|
subject { -> { dispatch callback_query: payload } }
|
||||||
|
let(:payload) { {id: callback_query_id, from: from, message: message, data: data} }
|
||||||
|
let(:callback_query_id) { 11 }
|
||||||
|
let(:message_id) { 22 }
|
||||||
|
let(:message) { {message_id: message_id, chat: chat, text: 'message text'} }
|
||||||
|
let(:data) { raise '`let(:data) { "callback query data here" }` is required' }
|
||||||
|
|
||||||
|
# Matcher to check that origin message got edited.
|
||||||
|
def edit_current_message(type, options = {})
|
||||||
|
description = 'edit current message'
|
||||||
|
options = options.merge(
|
||||||
|
message_id: message[:message_id],
|
||||||
|
chat_id: chat_id,
|
||||||
|
)
|
||||||
|
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
||||||
|
bot, :"editMessage#{type.to_s.camelize}", description: description
|
||||||
|
).with(hash_including(options))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Matcher to check that callback query is answered.
|
||||||
|
def answer_callback_query(text = Regexp.new(''), options = {})
|
||||||
|
description = "answer callback query with #{text.inspect}"
|
||||||
|
text = a_string_matching(text) if text.is_a?(Regexp)
|
||||||
|
options = options.merge(
|
||||||
|
callback_query_id: payload[:id],
|
||||||
|
text: text,
|
||||||
|
)
|
||||||
|
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
||||||
|
bot, :answerCallbackQuery, description: description
|
||||||
|
).with(hash_including(options))
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,85 +1,10 @@
|
|||||||
RSpec.shared_context 'telegram/bot/integration' do
|
require 'telegram/bot'
|
||||||
let(:bot) { Telegram.bot }
|
Telegram::Bot.deprecation_0_15.warn(
|
||||||
let(:default_message_options) { {from: from, chat: chat} }
|
"`require 'telegram/bot/rspec/integration'` is deprecated in favor of " \
|
||||||
let(:from) { {id: from_id} }
|
"`require 'telegram/bot/rspec/integration/rails'`"
|
||||||
let(:from_id) { 123 }
|
)
|
||||||
let(:chat) { {id: chat_id} }
|
require 'telegram/bot/rspec/integration/rails'
|
||||||
let(:chat_id) { 456 }
|
|
||||||
let(:controller_path) do
|
|
||||||
route_name = Telegram::Bot::RoutesHelper.route_name_for_bot(bot)
|
|
||||||
Rails.application.routes.url_helpers.public_send("#{route_name}_path")
|
|
||||||
end
|
|
||||||
let(:request_headers) do
|
|
||||||
{
|
|
||||||
'ACCEPT' => 'application/json',
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
let(:clear_session?) { described_class.respond_to?(:session_store) }
|
|
||||||
before { described_class.session_store.try!(:clear) if clear_session? }
|
|
||||||
|
|
||||||
include Telegram::Bot::RSpec::ClientMatchers
|
Telegram::Bot::RSpec.with_include_context do |config|
|
||||||
|
config.include_context 'telegram/bot/integration/rails', telegram_bot: true
|
||||||
def dispatch(update)
|
|
||||||
if ActionPack::VERSION::MAJOR >= 5
|
|
||||||
post(controller_path, params: update.to_json, headers: request_headers)
|
|
||||||
else
|
|
||||||
post(controller_path, update.to_json, request_headers)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def dispatch_message(text, options = {})
|
|
||||||
dispatch message: default_message_options.merge(options).merge(text: text)
|
|
||||||
end
|
|
||||||
|
|
||||||
def dispatch_command(*args)
|
|
||||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
||||||
dispatch_message("/#{args.join ' '}", options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Matcher to check response. Make sure to define `let(:chat_id)`.
|
|
||||||
def respond_with_message(expected = Regexp.new(''))
|
|
||||||
raise 'Define chat_id to use respond_with_message' unless defined?(chat_id)
|
|
||||||
send_telegram_message(bot, expected, chat_id: chat_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
RSpec.shared_context 'telegram/bot/callback_query', callback_query: true do
|
|
||||||
include_context 'telegram/bot/integration'
|
|
||||||
|
|
||||||
subject { -> { dispatch callback_query: payload } }
|
|
||||||
let(:payload) { {id: 11, from: from, message: message, data: data} }
|
|
||||||
let(:message) { {message_id: 22, chat: chat, text: 'message text'} }
|
|
||||||
|
|
||||||
# Matcher to check that origin message got edited.
|
|
||||||
def edit_current_message(type, options = {})
|
|
||||||
description = 'edit current message'
|
|
||||||
options = options.merge(
|
|
||||||
message_id: message[:message_id],
|
|
||||||
chat_id: chat_id,
|
|
||||||
)
|
|
||||||
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
|
||||||
bot, :"editMessage#{type.to_s.camelize}", description: description
|
|
||||||
).with(hash_including(options))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Matcher to check that callback query is answered.
|
|
||||||
def answer_callback_query(text = Regexp.new(''), options = {})
|
|
||||||
description = "answer callback query with #{text.inspect}"
|
|
||||||
text = a_string_matching(text) if text.is_a?(Regexp)
|
|
||||||
options = options.merge(
|
|
||||||
callback_query_id: payload[:id],
|
|
||||||
text: text,
|
|
||||||
)
|
|
||||||
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
|
||||||
bot, :answerCallbackQuery, description: description
|
|
||||||
).with(hash_including(options))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
|
||||||
if config.respond_to?(:include_context)
|
|
||||||
config.include_context 'telegram/bot/integration', :telegram_bot
|
|
||||||
config.include_context 'telegram/bot/callback_query', :telegram_bot, :callback_query
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
14
lib/telegram/bot/rspec/integration/poller.rb
Обычный файл
14
lib/telegram/bot/rspec/integration/poller.rb
Обычный файл
@@ -0,0 +1,14 @@
|
|||||||
|
require 'telegram/bot/rspec/integration/shared'
|
||||||
|
|
||||||
|
RSpec.shared_context 'telegram/bot/integration/poller' do
|
||||||
|
include_context 'telegram/bot/integration/shared'
|
||||||
|
let(:controller_class) { described_class }
|
||||||
|
|
||||||
|
def dispatch(update)
|
||||||
|
controller_class.dispatch(bot, update.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Telegram::Bot::RSpec.with_include_context do |config|
|
||||||
|
config.include_context 'telegram/bot/integration/poller', telegram_bot: :poller
|
||||||
|
end
|
||||||
24
lib/telegram/bot/rspec/integration/rack.rb
Обычный файл
24
lib/telegram/bot/rspec/integration/rack.rb
Обычный файл
@@ -0,0 +1,24 @@
|
|||||||
|
require 'telegram/bot/rspec/integration/shared'
|
||||||
|
require 'rack/test'
|
||||||
|
|
||||||
|
RSpec.shared_context 'telegram/bot/integration/rack' do
|
||||||
|
include_context 'telegram/bot/integration/shared'
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
let(:request_path) { raise '`let(:request_path) { path to bot }` is required' }
|
||||||
|
let(:app) { raise '`let(:app) { your rack app here }` is required' }
|
||||||
|
let(:request_headers) do
|
||||||
|
{
|
||||||
|
'ACCEPT' => 'application/json',
|
||||||
|
'CONTENT_TYPE' => 'application/json',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def dispatch(update)
|
||||||
|
post request_path, update.to_json, request_headers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Telegram::Bot::RSpec.with_include_context do |config|
|
||||||
|
config.include_context 'telegram/bot/integration/rack', telegram_bot: :rack
|
||||||
|
end
|
||||||
28
lib/telegram/bot/rspec/integration/rails.rb
Обычный файл
28
lib/telegram/bot/rspec/integration/rails.rb
Обычный файл
@@ -0,0 +1,28 @@
|
|||||||
|
require 'telegram/bot/rspec/integration/shared'
|
||||||
|
|
||||||
|
RSpec.shared_context 'telegram/bot/integration/rails', type: :request do
|
||||||
|
include_context 'telegram/bot/integration/shared'
|
||||||
|
|
||||||
|
let(:controller_path) do
|
||||||
|
route_name = Telegram::Bot::RoutesHelper.route_name_for_bot(bot)
|
||||||
|
Rails.application.routes.url_helpers.public_send("#{route_name}_path")
|
||||||
|
end
|
||||||
|
let(:request_headers) do
|
||||||
|
{
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def dispatch(update)
|
||||||
|
if ActionPack::VERSION::MAJOR >= 5
|
||||||
|
post(controller_path, params: update.to_json, headers: request_headers)
|
||||||
|
else
|
||||||
|
post(controller_path, update.to_json, request_headers)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Telegram::Bot::RSpec.with_include_context do |config|
|
||||||
|
config.include_context 'telegram/bot/integration/rails', telegram_bot: :rails
|
||||||
|
end
|
||||||
14
lib/telegram/bot/rspec/integration/shared.rb
Обычный файл
14
lib/telegram/bot/rspec/integration/shared.rb
Обычный файл
@@ -0,0 +1,14 @@
|
|||||||
|
require 'active_support/json'
|
||||||
|
require 'telegram/bot'
|
||||||
|
require 'telegram/bot/rspec/message_helpers'
|
||||||
|
require 'telegram/bot/rspec/callback_query_helpers'
|
||||||
|
|
||||||
|
RSpec.shared_context 'telegram/bot/integration/shared' do
|
||||||
|
include Telegram::Bot::RSpec::ClientMatchers
|
||||||
|
include_context 'telegram/bot/message_helpers'
|
||||||
|
include_context 'telegram/bot/callback_query', :callback_query
|
||||||
|
|
||||||
|
let(:bot) { Telegram.bot }
|
||||||
|
let(:clear_session?) { described_class.respond_to?(:session_store) }
|
||||||
|
before { described_class.session_store.try!(:clear) if clear_session? }
|
||||||
|
end
|
||||||
26
lib/telegram/bot/rspec/message_helpers.rb
Обычный файл
26
lib/telegram/bot/rspec/message_helpers.rb
Обычный файл
@@ -0,0 +1,26 @@
|
|||||||
|
# Shared helpers for testing message updates.
|
||||||
|
RSpec.shared_context 'telegram/bot/message_helpers' do
|
||||||
|
let(:default_message_options) { {from: from, chat: chat} }
|
||||||
|
let(:from) { {id: from_id} }
|
||||||
|
let(:from_id) { 123 }
|
||||||
|
let(:chat) { {id: chat_id} }
|
||||||
|
let(:chat_id) { 456 }
|
||||||
|
|
||||||
|
# Shortcut for dispatching messages with default params.
|
||||||
|
def dispatch_message(text, options = {})
|
||||||
|
dispatch message: default_message_options.merge(options).merge(text: text)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Dispatch command message.
|
||||||
|
def dispatch_command(cmd, *args)
|
||||||
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||||
|
args.unshift("/#{cmd}")
|
||||||
|
dispatch_message(args.join(' '), options)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Matcher to check response. Make sure to define `let(:chat_id)`.
|
||||||
|
def respond_with_message(expected = Regexp.new(''))
|
||||||
|
raise 'Define chat_id to use respond_with_message' unless defined?(chat_id)
|
||||||
|
send_telegram_message(bot, expected, chat_id: chat_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,37 +1,32 @@
|
|||||||
require 'telegram/bot/updates_controller/testing'
|
require 'telegram/bot/updates_controller/testing'
|
||||||
|
require 'telegram/bot/rspec/message_helpers'
|
||||||
|
require 'telegram/bot/rspec/callback_query_helpers'
|
||||||
|
|
||||||
RSpec.shared_context 'telegram/bot/updates_controller' do
|
RSpec.shared_context 'telegram/bot/updates_controller' do
|
||||||
|
include Telegram::Bot::RSpec::ClientMatchers
|
||||||
|
include_context 'telegram/bot/message_helpers'
|
||||||
|
include_context 'telegram/bot/callback_query', :callback_query
|
||||||
|
|
||||||
let(:controller_class) { described_class }
|
let(:controller_class) { described_class }
|
||||||
let(:controller) do
|
let(:controller) do
|
||||||
controller_class.new(bot, update).tap do |x|
|
controller_class.new(*controller_args).tap do |x|
|
||||||
x.extend Telegram::Bot::UpdatesController::Testing
|
x.extend Telegram::Bot::UpdatesController::Testing
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
let(:update) { build_update(payload_type, payload) }
|
let(:controller_args) { [bot, deep_stringify(update)] }
|
||||||
|
let(:update) { {payload_type => payload} }
|
||||||
let(:payload_type) { :some_type }
|
let(:payload_type) { :some_type }
|
||||||
let(:payload) { double(:payload) }
|
let(:payload) { double(:payload) }
|
||||||
let(:bot) { Telegram::Bot::ClientStub.new(bot_name) }
|
let(:bot) { Telegram::Bot::ClientStub.new(bot_name) }
|
||||||
let(:bot_name) { 'bot' }
|
let(:bot_name) { 'bot' }
|
||||||
let(:session) { controller.send(:session) }
|
let(:session) { controller.send(:session) }
|
||||||
let(:from_id) { 123 }
|
|
||||||
let(:chat_id) { 456 }
|
|
||||||
let(:default_message_options) { {from: {id: from_id}, chat: {id: chat_id}} }
|
|
||||||
|
|
||||||
include Telegram::Bot::RSpec::ClientMatchers
|
# Process update.
|
||||||
|
def dispatch(update = self.update, bot = self.bot)
|
||||||
def dispatch(bot = self.bot, update = self.update)
|
controller.dispatch_again(bot, deep_stringify(update))
|
||||||
controller.dispatch_again(bot, update)
|
|
||||||
end
|
|
||||||
|
|
||||||
def dispatch_message(text, options = {})
|
|
||||||
update = build_update :message, default_message_options.merge(options).merge(text: text)
|
|
||||||
dispatch bot, update
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_update(type, content)
|
|
||||||
deep_stringify type => content
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Same as `.as_json` but mocks-friendly.
|
||||||
def deep_stringify(input)
|
def deep_stringify(input)
|
||||||
case input
|
case input
|
||||||
when Array then input.map(&method(__callee__))
|
when Array then input.map(&method(__callee__))
|
||||||
@@ -39,15 +34,8 @@ 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
|
||||||
|
|
||||||
RSpec.configure do |config|
|
Telegram::Bot::RSpec.with_include_context do |config|
|
||||||
if config.respond_to?(:include_context)
|
|
||||||
config.include_context 'telegram/bot/updates_controller', type: :telegram_bot_controller
|
config.include_context 'telegram/bot/updates_controller', type: :telegram_bot_controller
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
require 'integration_helper'
|
require 'integration_helper'
|
||||||
|
|
||||||
RSpec.describe DefaultBotController, :telegram_bot, type: :request do
|
RSpec.describe DefaultBotController, telegram_bot: :rails do
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
subject { -> { dispatch_command :start } }
|
subject { -> { dispatch_command :start } }
|
||||||
it { should respond_with_message 'from default' }
|
it { should respond_with_message 'from default' }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
require 'integration_helper'
|
require 'integration_helper'
|
||||||
|
|
||||||
RSpec.describe NamedBotController, :telegram_bot, type: :request do
|
RSpec.describe NamedBotController, telegram_bot: :rails do
|
||||||
let(:bot) { Telegram.bots[:named] }
|
let(:bot) { Telegram.bots[:named] }
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
subject { -> { dispatch_command :start } }
|
subject { -> { dispatch_command :start } }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
require 'integration_helper'
|
require 'integration_helper'
|
||||||
|
|
||||||
RSpec.describe OtherBotController, :telegram_bot, type: :request do
|
RSpec.describe OtherBotController, telegram_bot: :rails do
|
||||||
let(:bot) { Telegram.bots[:other] }
|
let(:bot) { Telegram.bots[:other] }
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
subject { -> { dispatch_command :start } }
|
subject { -> { dispatch_command :start } }
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
require 'telegram/bot/rspec/integration'
|
require 'telegram/bot/rspec/integration/rails'
|
||||||
require 'action_controller'
|
require 'action_controller'
|
||||||
require 'action_dispatch'
|
require 'action_dispatch'
|
||||||
require 'action_dispatch/testing/integration'
|
|
||||||
|
|
||||||
require 'rails'
|
require 'rails'
|
||||||
require 'telegram/bot/railtie'
|
require 'telegram/bot/railtie'
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ RSpec.configure do |config|
|
|||||||
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This config option will be enabled by default on RSpec 4,
|
||||||
|
# but for reasons of backwards compatibility, you have to
|
||||||
|
# set it on RSpec 3.
|
||||||
|
#
|
||||||
|
# It causes the host group and examples to inherit metadata
|
||||||
|
# from the shared context.
|
||||||
|
config.shared_context_metadata_behavior = :apply_to_host_groups
|
||||||
|
|
||||||
config.mock_with :rspec do |mocks|
|
config.mock_with :rspec do |mocks|
|
||||||
# Prevents you from mocking or stubbing a method that does not exist on
|
# Prevents you from mocking or stubbing a method that does not exist on
|
||||||
# a real object. This is generally recommended, and will default to
|
# a real object. This is generally recommended, and will default to
|
||||||
|
|||||||
24
spec/support/examples/integration.rb
Обычный файл
24
spec/support/examples/integration.rb
Обычный файл
@@ -0,0 +1,24 @@
|
|||||||
|
RSpec.shared_examples 'shared integration examples' do
|
||||||
|
let(:bot) { Telegram::Bot::ClientStub.new('token') }
|
||||||
|
let(:controller_class) do
|
||||||
|
Class.new(Telegram::Bot::UpdatesController) do
|
||||||
|
def start(data = nil, *)
|
||||||
|
respond_with :message, text: "Hi #{data}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def callback_query(data, *)
|
||||||
|
answer_callback_query "pong: #{data}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#start' do
|
||||||
|
subject { -> { dispatch_command(:start, :test_data) } }
|
||||||
|
it { should respond_with_message('Hi test_data') }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#callback_query', :callback_query do
|
||||||
|
let(:data) { :test_data }
|
||||||
|
it { should answer_callback_query "pong: #{data}" }
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -7,7 +7,6 @@ RSpec.describe Telegram::Bot::Middleware do
|
|||||||
|
|
||||||
describe '#call' do
|
describe '#call' do
|
||||||
subject { instance.call(env) }
|
subject { instance.call(env) }
|
||||||
let(:env) { {'action_dispatch.request.request_parameters' => json_body} }
|
|
||||||
let(:update) { {'message' => {'id' => 1}} }
|
let(:update) { {'message' => {'id' => 1}} }
|
||||||
let(:env) do
|
let(:env) do
|
||||||
Rack::MockRequest.env_for('/',
|
Rack::MockRequest.env_for('/',
|
||||||
@@ -21,7 +20,6 @@ RSpec.describe Telegram::Bot::Middleware do
|
|||||||
if ActionPack::VERSION::MAJOR < 5
|
if ActionPack::VERSION::MAJOR < 5
|
||||||
# Before Rails 5, params are parsed in middleware.
|
# Before Rails 5, params are parsed in middleware.
|
||||||
# In Rails 5, they are parsed in Request#request_parameters.
|
# In Rails 5, they are parsed in Request#request_parameters.
|
||||||
require 'action_dispatch/middleware/params_parser'
|
|
||||||
let(:instance) { ActionDispatch::ParamsParser.new(super()) }
|
let(:instance) { ActionDispatch::ParamsParser.new(super()) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -95,108 +95,4 @@ RSpec.describe Telegram::Bot::RoutesHelper do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#telegram_webhooks' do
|
|
||||||
subject { mapper.telegram_webhooks(*input) }
|
|
||||||
let(:mapper) { double(:mapper).tap { |x| x.extend described_class } }
|
|
||||||
let(:bots) { {default: bot, other: other_bot} }
|
|
||||||
let(:controller) { double(:controller, name: :controller) }
|
|
||||||
let(:other_controller) { double(:other_controller, name: :other_controller) }
|
|
||||||
before { allow(Telegram).to receive(:bots) { bots } }
|
|
||||||
around { |ex| Telegram::Bot.deprecation_0_14.silence { ex.run } }
|
|
||||||
|
|
||||||
def assert_routes(*expected) # rubocop:disable AbcSize
|
|
||||||
expected.each do |(bot, controller, route_name, options)|
|
|
||||||
expected_path = options.delete(:path) || "telegram/#{bot.token}"
|
|
||||||
expect(mapper).to receive(:post) do |path, params|
|
|
||||||
expect(path).to eq expected_path
|
|
||||||
middleware = params[:to]
|
|
||||||
expect(middleware.controller).to eq(controller)
|
|
||||||
expect(middleware.bot.token).to eq(bot.token)
|
|
||||||
expect(middleware.bot.username).to eq(bot.username)
|
|
||||||
expect(params[:as]).to eq route_name
|
|
||||||
expect(params).to include(options) if options
|
|
||||||
end
|
|
||||||
end
|
|
||||||
subject
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when called with controller' do
|
|
||||||
let(:input) { [controller, option: :val] }
|
|
||||||
|
|
||||||
it 'creates routes for every bot and this controller' do
|
|
||||||
assert_routes [bot, controller, 'default_telegram_webhook', option: :val],
|
|
||||||
[other_bot, controller, 'other_telegram_webhook', option: :val]
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and bot does not have configured token' do
|
|
||||||
let(:bot) { create_bot(nil) }
|
|
||||||
it 'creates routes for every bot and this controller' do
|
|
||||||
assert_routes [bot, controller, 'default_telegram_webhook', option: :val],
|
|
||||||
[other_bot, controller, 'other_telegram_webhook', option: :val]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and bot has colon in token' do
|
|
||||||
let(:bot) { create_bot('some:token') }
|
|
||||||
it 'replaces colon with underscore' do
|
|
||||||
assert_routes [
|
|
||||||
bot,
|
|
||||||
controller,
|
|
||||||
'default_telegram_webhook',
|
|
||||||
option: :val,
|
|
||||||
path: 'telegram/some_token',
|
|
||||||
], [other_bot, controller, 'other_telegram_webhook', option: :val]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when called with hash' do
|
|
||||||
let(:input) do
|
|
||||||
[
|
|
||||||
{
|
|
||||||
bot => controller,
|
|
||||||
'custom_token' => [other_controller, as: :custom_route, option: :other_val],
|
|
||||||
other: controller,
|
|
||||||
},
|
|
||||||
option: :val,
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates routes for every bot and its controller' do
|
|
||||||
assert_routes [bot, controller, 'default_telegram_webhook', option: :val],
|
|
||||||
[
|
|
||||||
create_bot('custom_token'),
|
|
||||||
other_controller,
|
|
||||||
:custom_route,
|
|
||||||
option: :other_val,
|
|
||||||
],
|
|
||||||
[Telegram.bots[:other], controller, 'other_telegram_webhook', option: :val]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when called with controller and smth castable to bot' do
|
|
||||||
let(:input) do
|
|
||||||
[
|
|
||||||
controller,
|
|
||||||
['custom_token', token: bot.token, username: 'new_name'],
|
|
||||||
option: :val,
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates routes for every created bot and controller' do
|
|
||||||
assert_routes [
|
|
||||||
create_bot('custom_token'),
|
|
||||||
controller,
|
|
||||||
'telegram_webhook',
|
|
||||||
option: :val,
|
|
||||||
], [
|
|
||||||
create_bot(bot.token, 'new_name'),
|
|
||||||
controller,
|
|
||||||
'telegram_webhook',
|
|
||||||
option: :val,
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
42
spec/telegram/bot/rspec/callback_query_helpers_spec.rb
Обычный файл
42
spec/telegram/bot/rspec/callback_query_helpers_spec.rb
Обычный файл
@@ -0,0 +1,42 @@
|
|||||||
|
require 'telegram/bot/rspec/integration/poller'
|
||||||
|
|
||||||
|
RSpec.describe 'Integration spec helpers', telegram_bot: :poller do
|
||||||
|
let(:bot) { Telegram::Bot::ClientStub.new('token') }
|
||||||
|
let(:controller_class) do
|
||||||
|
Class.new(Telegram::Bot::UpdatesController) do
|
||||||
|
include Telegram::Bot::UpdatesController::CallbackQueryContext
|
||||||
|
|
||||||
|
def callback_query(data = nil, *)
|
||||||
|
answer_callback_query "data: #{data}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def context_callback_query(data = nil, *)
|
||||||
|
answer_callback_query "data: #{data}", extra: :param
|
||||||
|
end
|
||||||
|
|
||||||
|
def answer_and_edit_callback_query(data = nil, *)
|
||||||
|
answer_callback_query "data: #{data}"
|
||||||
|
edit_message :text, text: 'edited-text', extra: :param
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#callback_query', :callback_query do
|
||||||
|
let(:data) { 'unknown:command' }
|
||||||
|
it { should answer_callback_query("data: #{data}") }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#context_callback_query', :callback_query do
|
||||||
|
let(:data) { 'context:test:payload' }
|
||||||
|
it { should answer_callback_query('data: test:payload', extra: :param) }
|
||||||
|
it { should_not edit_current_message(:text) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#answer_and_edit_callback_query', :callback_query do
|
||||||
|
let(:data) { 'answer_and_edit:test:payload' }
|
||||||
|
it do
|
||||||
|
should answer_callback_query(/test:payload/).
|
||||||
|
and edit_current_message(:text, text: /edited/, extra: :param)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
5
spec/telegram/bot/rspec/integration/poller_spec.rb
Обычный файл
5
spec/telegram/bot/rspec/integration/poller_spec.rb
Обычный файл
@@ -0,0 +1,5 @@
|
|||||||
|
require 'telegram/bot/rspec/integration/poller'
|
||||||
|
|
||||||
|
RSpec.describe 'Poller integration spec', telegram_bot: :poller do
|
||||||
|
include_examples 'shared integration examples'
|
||||||
|
end
|
||||||
20
spec/telegram/bot/rspec/integration/rack_spec.rb
Обычный файл
20
spec/telegram/bot/rspec/integration/rack_spec.rb
Обычный файл
@@ -0,0 +1,20 @@
|
|||||||
|
require 'telegram/bot/rspec/integration/rack'
|
||||||
|
|
||||||
|
RSpec.describe 'Rack integration spec', telegram_bot: :rack do
|
||||||
|
include_examples 'shared integration examples'
|
||||||
|
let(:request_path) { '/bot' }
|
||||||
|
let(:app) do
|
||||||
|
path = request_path
|
||||||
|
bot_app = Telegram::Bot::Middleware.new(bot, controller_class)
|
||||||
|
app = Rack::Builder.new do
|
||||||
|
map(path) { run bot_app }
|
||||||
|
run ->(env) { raise "Route is not mapped: #{env['PATH_INFO']}" }
|
||||||
|
end
|
||||||
|
if ActionPack::VERSION::MAJOR >= 5
|
||||||
|
app
|
||||||
|
else
|
||||||
|
require 'action_dispatch/middleware/params_parser'
|
||||||
|
ActionDispatch::ParamsParser.new(app)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
1
spec/telegram/bot/rspec/integration/rails_spec.rb
Обычный файл
1
spec/telegram/bot/rspec/integration/rails_spec.rb
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
# Tested in spec/integration
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
require 'telegram/bot/rspec/integration'
|
|
||||||
require 'action_controller'
|
|
||||||
require 'action_dispatch'
|
|
||||||
require 'action_dispatch/testing/integration'
|
|
||||||
|
|
||||||
RSpec.describe 'Integrations helper', :telegram_bot do
|
|
||||||
include ActionDispatch::Integration::Runner
|
|
||||||
def reset_template_assertion
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:app) do
|
|
||||||
app = Telegram::Bot::Middleware.new(bot, controller)
|
|
||||||
if ActionPack::VERSION::MAJOR >= 5
|
|
||||||
app
|
|
||||||
else
|
|
||||||
require 'action_dispatch/middleware/params_parser'
|
|
||||||
ActionDispatch::ParamsParser.new(app)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
let(:bot) { Telegram::Bot::ClientStub.new('token') }
|
|
||||||
let(:controller_path) { '/' }
|
|
||||||
let(:controller) do
|
|
||||||
Class.new(Telegram::Bot::UpdatesController) do
|
|
||||||
def start(*args)
|
|
||||||
respond_with :message, text: "Start: #{args.inspect}, option: #{payload[:option]}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#default_message_options' do
|
|
||||||
subject { default_message_options }
|
|
||||||
it { should eq from: {id: from_id}, chat: {id: chat_id} }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#dispatch' do
|
|
||||||
subject { -> { dispatch message: {text: '/start', **default_message_options} } }
|
|
||||||
it { should respond_with_message 'Start: [], option: ' }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#dispatch_message' do
|
|
||||||
subject { -> { dispatch_message "/start #{args.join ' '}", options } }
|
|
||||||
let(:args) { %w[asd qwe] }
|
|
||||||
let(:options) { {} }
|
|
||||||
it { should respond_with_message "Start: #{args.inspect}, option: " }
|
|
||||||
|
|
||||||
context 'with options' do
|
|
||||||
let(:options) { {option: 1} }
|
|
||||||
it { should respond_with_message "Start: #{args.inspect}, option: 1" }
|
|
||||||
|
|
||||||
context 'and chat_id is not set' do
|
|
||||||
let(:options) { super().merge(chat: nil) }
|
|
||||||
it { should raise_error(/chat is not present/) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#dispatch_command' do
|
|
||||||
subject { -> { dispatch_command :start, *args } }
|
|
||||||
let(:args) { [] }
|
|
||||||
it { should respond_with_message "Start: #{args.inspect}, option: " }
|
|
||||||
|
|
||||||
context 'with args' do
|
|
||||||
let(:args) { %w[asd qwe] }
|
|
||||||
it { should respond_with_message "Start: #{args.inspect}, option: " }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with options' do
|
|
||||||
let(:args) { ['asd', 'qwe', option: 1] }
|
|
||||||
it { should respond_with_message "Start: #{args[0...-1].inspect}, option: 1" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'callback queries', :callback_query do
|
|
||||||
let(:controller) do
|
|
||||||
Class.new(Telegram::Bot::UpdatesController) do
|
|
||||||
include Telegram::Bot::UpdatesController::CallbackQueryContext
|
|
||||||
|
|
||||||
def callback_query(data = nil, *)
|
|
||||||
answer_callback_query "data: #{data}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def context_callback_query(data = nil, *)
|
|
||||||
answer_callback_query "data: #{data}", extra: :param
|
|
||||||
end
|
|
||||||
|
|
||||||
def answer_and_edit_callback_query(data = nil, *)
|
|
||||||
answer_callback_query "data: #{data}"
|
|
||||||
edit_message :text, text: 'edited-text', extra: :param
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#callback_query' do
|
|
||||||
let(:data) { 'unknown:command' }
|
|
||||||
it { should answer_callback_query("data: #{data}") }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#context_callback_query' do
|
|
||||||
let(:data) { 'context:test:payload' }
|
|
||||||
it { should answer_callback_query('data: test:payload', extra: :param) }
|
|
||||||
it { should_not edit_current_message(:text) }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#answer_and_edit_callback_query' do
|
|
||||||
let(:data) { 'answer_and_edit:test:payload' }
|
|
||||||
it do
|
|
||||||
should answer_callback_query(/test:payload/).
|
|
||||||
and edit_current_message(:text, text: /edited/, extra: :param)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
115
spec/telegram/bot/rspec/message_helpers_spec.rb
Обычный файл
115
spec/telegram/bot/rspec/message_helpers_spec.rb
Обычный файл
@@ -0,0 +1,115 @@
|
|||||||
|
require 'telegram/bot/rspec/integration/poller'
|
||||||
|
|
||||||
|
RSpec.describe 'Integration: message helpers', telegram_bot: :poller do
|
||||||
|
describe '#default_message_options' do
|
||||||
|
subject { default_message_options }
|
||||||
|
it { should eq from: {id: from_id}, chat: {id: chat_id} }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#dispatch_message' do
|
||||||
|
subject { -> { dispatch_message text, options } }
|
||||||
|
let(:text) { '/start asd qwe' }
|
||||||
|
let(:options) { {} }
|
||||||
|
let(:result) { double(:result) }
|
||||||
|
|
||||||
|
it 'invokes dispatch' do
|
||||||
|
expect(self).to receive(:dispatch).with(
|
||||||
|
message: hash_including(default_message_options.merge(
|
||||||
|
text: text,
|
||||||
|
)),
|
||||||
|
) { result }
|
||||||
|
expect(subject.call).to eq result
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with options' do
|
||||||
|
let(:options) { {option: 1} }
|
||||||
|
it 'invokes dispatch' do
|
||||||
|
expect(self).to receive(:dispatch).with(
|
||||||
|
message: hash_including(default_message_options.merge(
|
||||||
|
text: text,
|
||||||
|
).merge(options)),
|
||||||
|
) { result }
|
||||||
|
expect(subject.call).to eq result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#dispatch_command' do
|
||||||
|
subject { -> { dispatch_command :start, *args } }
|
||||||
|
let(:args) { [] }
|
||||||
|
let(:result) { double(:result) }
|
||||||
|
|
||||||
|
it 'invokes dispatch' do
|
||||||
|
expect(self).to receive(:dispatch).with(
|
||||||
|
message: hash_including(default_message_options.merge(
|
||||||
|
text: '/start',
|
||||||
|
)),
|
||||||
|
) { result }
|
||||||
|
expect(subject.call).to eq result
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with args & options' do
|
||||||
|
let(:args) { [*params, options] }
|
||||||
|
let(:params) { %w[qwe asd] }
|
||||||
|
let(:options) { {option: 1} }
|
||||||
|
it 'invokes dispatch' do
|
||||||
|
expect(self).to receive(:dispatch).with(
|
||||||
|
message: hash_including(default_message_options.merge(
|
||||||
|
text: "/start #{params.join(' ')}",
|
||||||
|
).merge(options)),
|
||||||
|
) { result }
|
||||||
|
expect(subject.call).to eq result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Old specs
|
||||||
|
RSpec.describe 'Integration: message helpers', telegram_bot: :poller do
|
||||||
|
let(:bot) { Telegram::Bot::ClientStub.new('token') }
|
||||||
|
let(:controller_class) do
|
||||||
|
Class.new(Telegram::Bot::UpdatesController) do
|
||||||
|
def start(*args)
|
||||||
|
respond_with :message, text: "Start: #{args.inspect}, option: #{payload['option']}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#default_message_options' do
|
||||||
|
subject { default_message_options }
|
||||||
|
it { should eq from: {id: from_id}, chat: {id: chat_id} }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#dispatch_message' do
|
||||||
|
subject { -> { dispatch_message "/start #{args.join ' '}", options } }
|
||||||
|
let(:args) { %w[asd qwe] }
|
||||||
|
let(:options) { {} }
|
||||||
|
it { should respond_with_message "Start: #{args.inspect}, option: " }
|
||||||
|
|
||||||
|
context 'with options' do
|
||||||
|
let(:options) { {option: 1} }
|
||||||
|
it { should respond_with_message "Start: #{args.inspect}, option: 1" }
|
||||||
|
|
||||||
|
context 'and chat_id is not set' do
|
||||||
|
let(:options) { super().merge(chat: nil) }
|
||||||
|
it { should raise_error(/chat is not present/) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#dispatch_command' do
|
||||||
|
subject { -> { dispatch_command :start, *args } }
|
||||||
|
let(:args) { [] }
|
||||||
|
it { should respond_with_message "Start: #{args.inspect}, option: " }
|
||||||
|
|
||||||
|
context 'with args' do
|
||||||
|
let(:args) { %w[asd qwe] }
|
||||||
|
it { should respond_with_message "Start: #{args.inspect}, option: " }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with options' do
|
||||||
|
let(:args) { ['asd', 'qwe', option: 1] }
|
||||||
|
it { should respond_with_message "Start: #{args[0...-1].inspect}, option: 1" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -27,7 +27,7 @@ RSpec.describe Telegram::Bot::UpdatesController::CallbackQueryContext do
|
|||||||
describe '#dispatch' do
|
describe '#dispatch' do
|
||||||
subject { -> { dispatch } }
|
subject { -> { dispatch } }
|
||||||
let(:payload_type) { :callback_query }
|
let(:payload_type) { :callback_query }
|
||||||
let(:payload) { {'data' => data} }
|
let(:payload) { {data: data} }
|
||||||
let(:data) { text }
|
let(:data) { text }
|
||||||
let(:text) { 'asd qwe zxc' }
|
let(:text) { 'asd qwe zxc' }
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ RSpec.describe Telegram::Bot::UpdatesController::Instrumentation do
|
|||||||
include_context 'telegram/bot/updates_controller'
|
include_context 'telegram/bot/updates_controller'
|
||||||
|
|
||||||
subject { -> { dispatch } }
|
subject { -> { dispatch } }
|
||||||
let(:update) do
|
let(:update) { {message: default_message_options.merge(text: '/start')} }
|
||||||
build_update :message, default_message_options.merge(text: '/start')
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:controller_class) do
|
let(:controller_class) do
|
||||||
Class.new(Telegram::Bot::UpdatesController) do
|
Class.new(Telegram::Bot::UpdatesController) do
|
||||||
@@ -36,11 +34,11 @@ RSpec.describe Telegram::Bot::UpdatesController::Instrumentation do
|
|||||||
|
|
||||||
action = action_name(:start_processing)
|
action = action_name(:start_processing)
|
||||||
expect(events[action].size).to eq(1)
|
expect(events[action].size).to eq(1)
|
||||||
expect(events[action][0].last).to include(update: update)
|
expect(events[action][0].last).to include(update: deep_stringify(update))
|
||||||
|
|
||||||
action = action_name(:process_action)
|
action = action_name(:process_action)
|
||||||
expect(events[action].size).to eq(1)
|
expect(events[action].size).to eq(1)
|
||||||
expect(events[action][0].last).to include(update: update)
|
expect(events[action][0].last).to include(update: deep_stringify(update))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ RSpec.describe Telegram::Bot::UpdatesController do
|
|||||||
let(:respond_type) { :photo }
|
let(:respond_type) { :photo }
|
||||||
let(:result) { double(:result) }
|
let(:result) { double(:result) }
|
||||||
let(:payload_type) { :message }
|
let(:payload_type) { :message }
|
||||||
let(:payload) { {message_id: double(:message_id)} }
|
let(:payload) { {message_id: double(:message_id), chat: chat} }
|
||||||
let(:chat) { {'id' => double(:chat_id)} }
|
let(:chat) { {id: double(:chat_id)} }
|
||||||
|
|
||||||
shared_examples 'missing chat' do
|
shared_examples 'missing chat' do
|
||||||
context 'when chat is missing' do
|
context 'when chat is missing' do
|
||||||
@@ -19,9 +19,8 @@ RSpec.describe Telegram::Bot::UpdatesController do
|
|||||||
include_examples 'missing chat'
|
include_examples 'missing chat'
|
||||||
|
|
||||||
it 'sets chat_id & reply_to_message_id' do
|
it 'sets chat_id & reply_to_message_id' do
|
||||||
expect(controller).to receive(:chat) { chat }
|
|
||||||
expect(bot).to receive("send_#{respond_type}").
|
expect(bot).to receive("send_#{respond_type}").
|
||||||
with(params.merge(chat_id: chat['id'])) { result }
|
with(params.merge(chat_id: chat[:id])) { result }
|
||||||
should eq result
|
should eq result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -31,19 +30,18 @@ RSpec.describe Telegram::Bot::UpdatesController do
|
|||||||
include_examples 'missing chat'
|
include_examples 'missing chat'
|
||||||
|
|
||||||
it 'sets chat_id & reply_to_message_id' do
|
it 'sets chat_id & reply_to_message_id' do
|
||||||
expect(controller).to receive(:chat) { chat }
|
|
||||||
expect(bot).to receive("send_#{respond_type}").with(params.merge(
|
expect(bot).to receive("send_#{respond_type}").with(params.merge(
|
||||||
chat_id: chat['id'],
|
chat_id: chat[:id],
|
||||||
reply_to_message_id: payload[:message_id],
|
reply_to_message_id: payload[:message_id],
|
||||||
)) { result }
|
)) { result }
|
||||||
should eq result
|
should eq result
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when update is not set' do
|
context 'when update is not set' do
|
||||||
let(:update) { {chat: chat} }
|
let(:controller_args) { [bot, chat: deep_stringify(chat)] }
|
||||||
it 'sets chat_id' do
|
it 'sets chat_id' do
|
||||||
expect(bot).to receive("send_#{respond_type}").
|
expect(bot).to receive("send_#{respond_type}").
|
||||||
with(params.merge(chat_id: chat['id'])) { result }
|
with(params.merge(chat_id: chat[:id])) { result }
|
||||||
should eq result
|
should eq result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -70,7 +68,7 @@ RSpec.describe Telegram::Bot::UpdatesController do
|
|||||||
it 'sets chat_id & message_id' do
|
it 'sets chat_id & message_id' do
|
||||||
expect(bot).to receive("edit_message_#{type}").with(params.merge(
|
expect(bot).to receive("edit_message_#{type}").with(params.merge(
|
||||||
message_id: payload[:message][:message_id],
|
message_id: payload[:message][:message_id],
|
||||||
chat_id: payload[:message][:chat]['id'],
|
chat_id: payload[:message][:chat][:id],
|
||||||
)) { result }
|
)) { result }
|
||||||
should eq result
|
should eq result
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ RSpec.describe Telegram::Bot::UpdatesController::Session do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def build_message(text, from)
|
def build_message(text, from)
|
||||||
{'message' => {'text' => text, 'from' => from.stringify_keys}}
|
deep_stringify(message: {text: text, from: from})
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'stores session between requests' do
|
it 'stores session between requests' do
|
||||||
|
|||||||
@@ -278,11 +278,13 @@ RSpec.describe Telegram::Bot::UpdatesController do
|
|||||||
instance_eval(&block)
|
instance_eval(&block)
|
||||||
context 'when re-initialized' do
|
context 'when re-initialized' do
|
||||||
let(:controller) do
|
let(:controller) do
|
||||||
described_class.new(double(:other_bot), build_update(:message,
|
initial_update = deep_stringify message: {
|
||||||
text: 'original message',
|
text: 'original message',
|
||||||
from: double(:original_from),
|
from: double(:original_from),
|
||||||
chat: double(:original_chat),
|
chat: double(:original_chat),
|
||||||
)).tap { |x| x.send(:initialize, bot, update) }
|
}
|
||||||
|
described_class.new(double(:other_bot), initial_update).
|
||||||
|
tap { |x| x.send(:initialize, *controller_args) }
|
||||||
end
|
end
|
||||||
instance_eval(&block)
|
instance_eval(&block)
|
||||||
end
|
end
|
||||||
@@ -300,7 +302,7 @@ RSpec.describe Telegram::Bot::UpdatesController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when options hash is given' do
|
context 'when options hash is given' do
|
||||||
let(:update) { {from: from, chat: chat} }
|
let(:controller_args) { [bot, from: from, chat: chat] }
|
||||||
with_reinitialize do
|
with_reinitialize do
|
||||||
its(:bot) { should eq bot }
|
its(:bot) { should eq bot }
|
||||||
its(:update) { should eq nil }
|
its(:update) { should eq nil }
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user