diff --git a/README.md b/README.md index f2121ca..1ac22c2 100644 --- a/README.md +++ b/README.md @@ -242,7 +242,8 @@ end ``` There are also some helpers for controller tests. -Check out `telegram/bot/updates_controller/rspec_helpers`. +Check out `telegram/bot/updates_controller/rspec_helpers` and +`telegram/bot/updates_controller/testing`. ### Deploying diff --git a/lib/telegram/bot/updates_controller/rspec_helpers.rb b/lib/telegram/bot/updates_controller/rspec_helpers.rb index 9cf9a68..e2ffeea 100644 --- a/lib/telegram/bot/updates_controller/rspec_helpers.rb +++ b/lib/telegram/bot/updates_controller/rspec_helpers.rb @@ -1,23 +1,29 @@ +require 'telegram/bot/updates_controller/testing' + RSpec.shared_context 'telegram/bot/updates_controller' do let(:controller_class) { described_class } - let(:instance) { controller_class.new(bot, update) } + let(:controller) do + controller_class.new(bot, update).tap do |x| + x.extend Telegram::Bot::UpdatesController::Testing + end + end let(:update) { {payload_type => payload} } let(:payload_type) { 'some_type' } let(:payload) { double(:payload) } let(:bot) { Telegram::Bot::ClientStub.new(bot_name) } let(:bot_name) { 'bot' } - let(:session) do - session = Telegram::Bot::UpdatesController::Session::TestSessionHash.new - allow_any_instance_of(controller_class).to receive(:session) { session } - session + let(:session) { controller.send(:session) } + + def dispatch(bot = self.bot, update = self.update) + controller.dispatch_again(bot, update) end def dispatch_message(text, options = {}) - payload = build_payload :message, options.merge(text: text) - controller_class.dispatch bot, payload + update = build_update :message, options.merge(text: text) + dispatch bot, update end - def build_payload(type, content) + def build_update(type, content) deep_stringify type => content end diff --git a/lib/telegram/bot/updates_controller/session.rb b/lib/telegram/bot/updates_controller/session.rb index 0209f98..47139d3 100644 --- a/lib/telegram/bot/updates_controller/session.rb +++ b/lib/telegram/bot/updates_controller/session.rb @@ -59,18 +59,6 @@ module Telegram end end - class TestSessionHash < SessionHash - def initialize - @data = {} - @loaded = true - @exists = true - end - - alias_method :destroy, :clear - alias_method :load!, :id - alias_method :commit, :id - end - module ConfigMethods delegate :session_store, to: :config diff --git a/lib/telegram/bot/updates_controller/testing.rb b/lib/telegram/bot/updates_controller/testing.rb new file mode 100644 index 0000000..974c6a9 --- /dev/null +++ b/lib/telegram/bot/updates_controller/testing.rb @@ -0,0 +1,47 @@ +module Telegram + module Bot + class UpdatesController + module Testing + IVARS_TO_KEEP = %i(@_session).freeze + + # Perform multiple dispatches on same instance. + def dispatch_again(bot = nil, update = nil) + recycle! + initialize(bot, update) + dispatch + end + + # Cleans controller between dispatches. + # Seems like there is nothing to clean between requests for now: + # everything will be rewriten with #initialize. + # + # With `full` set to `true` it'll clear all cached instance variables. + def recycle!(full = false) + return unless full + (instance_variables - IVARS_TO_KEEP).each do |ivar| + remove_instance_variable(ivar) + end + end + + protected + + # Stubs session. + def session + @_session ||= Testing::SessionHash.new + end + + class SessionHash < Session::SessionHash + def initialize + @data = {} + @loaded = true + @exists = true + end + + alias_method :destroy, :clear + alias_method :load!, :id + alias_method :commit, :id + end + end + end + end +end diff --git a/lib/telegram/bot/updates_controller/typed_update.rb b/lib/telegram/bot/updates_controller/typed_update.rb index 45f8d6b..d41fa89 100644 --- a/lib/telegram/bot/updates_controller/typed_update.rb +++ b/lib/telegram/bot/updates_controller/typed_update.rb @@ -4,7 +4,7 @@ module Telegram # Include this module to type cast update to Virtus model # using `telegram-bot-types` gem (install this gem first). module TypedUpdate - def initialize(bot, update) + def initialize(bot = nil, update = nil) update = Types::Update.new(update) if update && !update.is_a?(Types::Update) super end diff --git a/spec/telegram/bot/updates_controller/testing_spec.rb b/spec/telegram/bot/updates_controller/testing_spec.rb new file mode 100644 index 0000000..561b6fd --- /dev/null +++ b/spec/telegram/bot/updates_controller/testing_spec.rb @@ -0,0 +1,27 @@ +RSpec.describe Telegram::Bot::UpdatesController::Testing do + include_context 'telegram/bot/updates_controller' + let(:controller_class) do + Class.new(Telegram::Bot::UpdatesController) do + attr_accessor :ivar + end + end + + describe '#recycle!' do + subject { -> { controller.recycle!(full) } } + before do + controller.ivar = :ival + session[:key] = 'sval' + end + let(:full) {} + + it { should_not change(controller, :ivar).from :ival } + it { should_not change { controller.send(:session)[:key] }.from 'sval' } + + context 'when full is true' do + let(:full) { true } + it { should change(controller, :ivar).from(:ival).to nil } + it { should change { controller.instance_variable_defined?(:@ivar) }.to false } + it { should_not change { controller.send(:session)[:key] }.from 'sval' } + end + end +end diff --git a/spec/telegram/bot/updates_controller/typed_update_spec.rb b/spec/telegram/bot/updates_controller/typed_update_spec.rb index 43ed138..2bca1d6 100644 --- a/spec/telegram/bot/updates_controller/typed_update_spec.rb +++ b/spec/telegram/bot/updates_controller/typed_update_spec.rb @@ -8,7 +8,7 @@ RSpec.describe Telegram::Bot::UpdatesController::TypedUpdate do end context 'when `update` is a virtus model' do - subject { instance } + subject { controller } %w( message inline_query diff --git a/spec/telegram/bot/updates_controller_spec.rb b/spec/telegram/bot/updates_controller_spec.rb index 8a7494b..eb8a3d2 100644 --- a/spec/telegram/bot/updates_controller_spec.rb +++ b/spec/telegram/bot/updates_controller_spec.rb @@ -78,7 +78,7 @@ RSpec.describe Telegram::Bot::UpdatesController do end describe '#action_for_payload' do - subject { instance.action_for_payload } + subject { controller.action_for_payload } (described_class::PAYLOAD_TYPES - %w(message)).each do |type| context "when payload is #{type}" do @@ -113,7 +113,7 @@ RSpec.describe Telegram::Bot::UpdatesController do end context 'when `update` is a virtus model' do - subject { instance } + subject { controller } let(:update) { Telegram::Bot::Types::Update.new(super()) } %w( message @@ -131,7 +131,7 @@ RSpec.describe Telegram::Bot::UpdatesController do end describe '#bot_username' do - subject { instance.bot_username } + subject { controller.bot_username } context 'when bot is not set' do let(:bot) {} @@ -145,7 +145,7 @@ RSpec.describe Telegram::Bot::UpdatesController do end describe '#process_action' do - subject { -> { instance.process_action(:action) } } + subject { -> { controller.process_action(:action) } } context 'when callbacks are defined' do let(:controller_class) do @@ -165,8 +165,8 @@ RSpec.describe Telegram::Bot::UpdatesController do end end - it { should change(instance, :hooked).to true } - it { should change(instance, :acted).to true } + it { should change(controller, :hooked).to true } + it { should change(controller, :acted).to true } context 'when callback returns false' do before do @@ -178,8 +178,8 @@ RSpec.describe Telegram::Bot::UpdatesController do end) end - it { should change(instance, :hooked).to true } - it { should_not change(instance, :acted).from nil } + it { should change(controller, :hooked).to true } + it { should_not change(controller, :acted).from nil } end end end