mirror of
https://github.com/heartcombo/devise.git
synced 2022-11-09 12:18:31 -05:00
Move Devise::TestHelpers
to Devise::Test::ControllerHelpers
.
This commit is contained in:
parent
22dd3b489d
commit
3f3ec236bb
8 changed files with 155 additions and 135 deletions
|
@ -39,6 +39,11 @@ module Devise
|
||||||
autoload :Authenticatable, 'devise/strategies/authenticatable'
|
autoload :Authenticatable, 'devise/strategies/authenticatable'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Test
|
||||||
|
autoload :ControllerHelpers, 'devise/test/controller_helpers'
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# Constants which holds devise configuration for extensions. Those should
|
# Constants which holds devise configuration for extensions. Those should
|
||||||
# not be modified by the "end user" (this is why they are constants).
|
# not be modified by the "end user" (this is why they are constants).
|
||||||
ALL = []
|
ALL = []
|
||||||
|
|
139
lib/devise/test/controller_helpers.rb
Normal file
139
lib/devise/test/controller_helpers.rb
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
module Devise
|
||||||
|
module Test
|
||||||
|
# Devise::Test::ControllerHelpers provides a facility to test controllers in isolation
|
||||||
|
# when using ActionController::TestCase allowing you to quickly sign_in or
|
||||||
|
# sign_out a user. Do not use Devise::TestHelpers in integration tests.
|
||||||
|
#
|
||||||
|
# Notice you should not test Warden specific behavior (like Warden callbacks)
|
||||||
|
# using Devise::TestHelpers since it is a stub of the actual behavior. Such
|
||||||
|
# callbacks should be tested in your integration suite instead.
|
||||||
|
module ControllerHelpers
|
||||||
|
def self.included(base)
|
||||||
|
base.class_eval do
|
||||||
|
setup :setup_controller_for_warden, :warden if respond_to?(:setup)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Override process to consider warden.
|
||||||
|
def process(*)
|
||||||
|
# Make sure we always return @response, a la ActionController::TestCase::Behaviour#process, even if warden interrupts
|
||||||
|
_catch_warden { super } # || @response # _catch_warden will setup the @response object
|
||||||
|
|
||||||
|
# process needs to return the ActionDispath::TestResponse object
|
||||||
|
@response
|
||||||
|
end
|
||||||
|
|
||||||
|
# We need to set up the environment variables and the response in the controller.
|
||||||
|
def setup_controller_for_warden #:nodoc:
|
||||||
|
@request.env['action_controller.instance'] = @controller
|
||||||
|
end
|
||||||
|
|
||||||
|
# Quick access to Warden::Proxy.
|
||||||
|
def warden #:nodoc:
|
||||||
|
@request.env['warden'] ||= begin
|
||||||
|
manager = Warden::Manager.new(nil) do |config|
|
||||||
|
config.merge! Devise.warden_config
|
||||||
|
end
|
||||||
|
Warden::Proxy.new(@request.env, manager)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# sign_in a given resource by storing its keys in the session.
|
||||||
|
# This method bypass any warden authentication callback.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# sign_in :user, @user # sign_in(scope, resource)
|
||||||
|
# sign_in @user # sign_in(resource)
|
||||||
|
#
|
||||||
|
def sign_in(resource_or_scope, resource=nil)
|
||||||
|
scope ||= Devise::Mapping.find_scope!(resource_or_scope)
|
||||||
|
resource ||= resource_or_scope
|
||||||
|
warden.instance_variable_get(:@users).delete(scope)
|
||||||
|
warden.session_serializer.store(resource, scope)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Sign out a given resource or scope by calling logout on Warden.
|
||||||
|
# This method bypass any warden logout callback.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# sign_out :user # sign_out(scope)
|
||||||
|
# sign_out @user # sign_out(resource)
|
||||||
|
#
|
||||||
|
def sign_out(resource_or_scope)
|
||||||
|
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||||
|
@controller.instance_variable_set(:"@current_#{scope}", nil)
|
||||||
|
user = warden.instance_variable_get(:@users).delete(scope)
|
||||||
|
warden.session_serializer.delete(scope, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
# Catch warden continuations and handle like the middleware would.
|
||||||
|
# Returns nil when interrupted, otherwise the normal result of the block.
|
||||||
|
def _catch_warden(&block)
|
||||||
|
result = catch(:warden, &block)
|
||||||
|
|
||||||
|
env = @controller.request.env
|
||||||
|
|
||||||
|
result ||= {}
|
||||||
|
|
||||||
|
# Set the response. In production, the rack result is returned
|
||||||
|
# from Warden::Manager#call, which the following is modelled on.
|
||||||
|
case result
|
||||||
|
when Array
|
||||||
|
if result.first == 401 && intercept_401?(env) # does this happen during testing?
|
||||||
|
_process_unauthenticated(env)
|
||||||
|
else
|
||||||
|
result
|
||||||
|
end
|
||||||
|
when Hash
|
||||||
|
_process_unauthenticated(env, result)
|
||||||
|
else
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def _process_unauthenticated(env, options = {})
|
||||||
|
options[:action] ||= :unauthenticated
|
||||||
|
proxy = env['warden']
|
||||||
|
result = options[:result] || proxy.result
|
||||||
|
|
||||||
|
ret = case result
|
||||||
|
when :redirect
|
||||||
|
body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
|
||||||
|
[proxy.status, proxy.headers, [body]]
|
||||||
|
when :custom
|
||||||
|
proxy.custom_response
|
||||||
|
else
|
||||||
|
env["PATH_INFO"] = "/#{options[:action]}"
|
||||||
|
env["warden.options"] = options
|
||||||
|
Warden::Manager._run_callbacks(:before_failure, env, options)
|
||||||
|
|
||||||
|
status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
|
||||||
|
@controller.response.headers.merge!(headers)
|
||||||
|
r_opts = { status: status, content_type: headers["Content-Type"], location: headers["Location"] }
|
||||||
|
r_opts[Rails.version.start_with?('5') ? :body : :text] = response.body
|
||||||
|
@controller.send :render, r_opts
|
||||||
|
nil # causes process return @response
|
||||||
|
end
|
||||||
|
|
||||||
|
# ensure that the controller response is set up. In production, this is
|
||||||
|
# not necessary since warden returns the results to rack. However, at
|
||||||
|
# testing time, we want the response to be available to the testing
|
||||||
|
# framework to verify what would be returned to rack.
|
||||||
|
if ret.is_a?(Array)
|
||||||
|
# ensure the controller response is set to our response.
|
||||||
|
@controller.response ||= @response
|
||||||
|
@response.status = ret.first
|
||||||
|
@response.headers.clear
|
||||||
|
ret.second.each { |k,v| @response[k] = v }
|
||||||
|
@response.body = ret.third
|
||||||
|
end
|
||||||
|
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,137 +1,13 @@
|
||||||
module Devise
|
module Devise
|
||||||
# Devise::TestHelpers provides a facility to test controllers in isolation
|
|
||||||
# when using ActionController::TestCase allowing you to quickly sign_in or
|
|
||||||
# sign_out a user. Do not use Devise::TestHelpers in integration tests.
|
|
||||||
#
|
|
||||||
# Notice you should not test Warden specific behavior (like Warden callbacks)
|
|
||||||
# using Devise::TestHelpers since it is a stub of the actual behavior. Such
|
|
||||||
# callbacks should be tested in your integration suite instead.
|
|
||||||
module TestHelpers
|
module TestHelpers
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
base.class_eval do
|
base.class_eval do
|
||||||
setup :setup_controller_for_warden, :warden if respond_to?(:setup)
|
ActiveSupport::Deprecation.warn <<-DEPRECATION
|
||||||
end
|
[Devise] including `Devise::TestHelpers` is deprecated and will be removed from Devise.
|
||||||
end
|
For controller tests, please include `Devise::Test::ControllerHelpers` instead.
|
||||||
|
DEPRECATION
|
||||||
# Override process to consider warden.
|
include Devise::Test::ControllerHelpers
|
||||||
def process(*)
|
end
|
||||||
# Make sure we always return @response, a la ActionController::TestCase::Behaviour#process, even if warden interrupts
|
|
||||||
_catch_warden { super } # || @response # _catch_warden will setup the @response object
|
|
||||||
|
|
||||||
# process needs to return the ActionDispath::TestResponse object
|
|
||||||
@response
|
|
||||||
end
|
|
||||||
|
|
||||||
# We need to set up the environment variables and the response in the controller.
|
|
||||||
def setup_controller_for_warden #:nodoc:
|
|
||||||
@request.env['action_controller.instance'] = @controller
|
|
||||||
end
|
|
||||||
|
|
||||||
# Quick access to Warden::Proxy.
|
|
||||||
def warden #:nodoc:
|
|
||||||
@request.env['warden'] ||= begin
|
|
||||||
manager = Warden::Manager.new(nil) do |config|
|
|
||||||
config.merge! Devise.warden_config
|
|
||||||
end
|
|
||||||
Warden::Proxy.new(@request.env, manager)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# sign_in a given resource by storing its keys in the session.
|
|
||||||
# This method bypass any warden authentication callback.
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
#
|
|
||||||
# sign_in :user, @user # sign_in(scope, resource)
|
|
||||||
# sign_in @user # sign_in(resource)
|
|
||||||
#
|
|
||||||
def sign_in(resource_or_scope, resource=nil)
|
|
||||||
scope ||= Devise::Mapping.find_scope!(resource_or_scope)
|
|
||||||
resource ||= resource_or_scope
|
|
||||||
warden.instance_variable_get(:@users).delete(scope)
|
|
||||||
warden.session_serializer.store(resource, scope)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Sign out a given resource or scope by calling logout on Warden.
|
|
||||||
# This method bypass any warden logout callback.
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
#
|
|
||||||
# sign_out :user # sign_out(scope)
|
|
||||||
# sign_out @user # sign_out(resource)
|
|
||||||
#
|
|
||||||
def sign_out(resource_or_scope)
|
|
||||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
|
||||||
@controller.instance_variable_set(:"@current_#{scope}", nil)
|
|
||||||
user = warden.instance_variable_get(:@users).delete(scope)
|
|
||||||
warden.session_serializer.delete(scope, user)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
# Catch warden continuations and handle like the middleware would.
|
|
||||||
# Returns nil when interrupted, otherwise the normal result of the block.
|
|
||||||
def _catch_warden(&block)
|
|
||||||
result = catch(:warden, &block)
|
|
||||||
|
|
||||||
env = @controller.request.env
|
|
||||||
|
|
||||||
result ||= {}
|
|
||||||
|
|
||||||
# Set the response. In production, the rack result is returned
|
|
||||||
# from Warden::Manager#call, which the following is modelled on.
|
|
||||||
case result
|
|
||||||
when Array
|
|
||||||
if result.first == 401 && intercept_401?(env) # does this happen during testing?
|
|
||||||
_process_unauthenticated(env)
|
|
||||||
else
|
|
||||||
result
|
|
||||||
end
|
|
||||||
when Hash
|
|
||||||
_process_unauthenticated(env, result)
|
|
||||||
else
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def _process_unauthenticated(env, options = {})
|
|
||||||
options[:action] ||= :unauthenticated
|
|
||||||
proxy = env['warden']
|
|
||||||
result = options[:result] || proxy.result
|
|
||||||
|
|
||||||
ret = case result
|
|
||||||
when :redirect
|
|
||||||
body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
|
|
||||||
[proxy.status, proxy.headers, [body]]
|
|
||||||
when :custom
|
|
||||||
proxy.custom_response
|
|
||||||
else
|
|
||||||
env["PATH_INFO"] = "/#{options[:action]}"
|
|
||||||
env["warden.options"] = options
|
|
||||||
Warden::Manager._run_callbacks(:before_failure, env, options)
|
|
||||||
|
|
||||||
status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
|
|
||||||
@controller.response.headers.merge!(headers)
|
|
||||||
r_opts = { status: status, content_type: headers["Content-Type"], location: headers["Location"] }
|
|
||||||
r_opts[Rails.version.start_with?('5') ? :body : :text] = response.body
|
|
||||||
@controller.send :render, r_opts
|
|
||||||
nil # causes process return @response
|
|
||||||
end
|
|
||||||
|
|
||||||
# ensure that the controller response is set up. In production, this is
|
|
||||||
# not necessary since warden returns the results to rack. However, at
|
|
||||||
# testing time, we want the response to be available to the testing
|
|
||||||
# framework to verify what would be returned to rack.
|
|
||||||
if ret.is_a?(Array)
|
|
||||||
# ensure the controller response is set to our response.
|
|
||||||
@controller.response ||= @response
|
|
||||||
@response.status = ret.first
|
|
||||||
@response.headers.clear
|
|
||||||
ret.second.each { |k,v| @response[k] = v }
|
|
||||||
@response.body = ret.third
|
|
||||||
end
|
|
||||||
|
|
||||||
ret
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ require 'test_helper'
|
||||||
class CustomRegistrationsControllerTest < Devise::ControllerTestCase
|
class CustomRegistrationsControllerTest < Devise::ControllerTestCase
|
||||||
tests Custom::RegistrationsController
|
tests Custom::RegistrationsController
|
||||||
|
|
||||||
include Devise::TestHelpers
|
include Devise::Test::ControllerHelpers
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
request.env["devise.mapping"] = Devise.mappings[:user]
|
request.env["devise.mapping"] = Devise.mappings[:user]
|
||||||
|
|
|
@ -27,7 +27,7 @@ end
|
||||||
class CustomStrategyTest < Devise::ControllerTestCase
|
class CustomStrategyTest < Devise::ControllerTestCase
|
||||||
tests CustomStrategyController
|
tests CustomStrategyController
|
||||||
|
|
||||||
include Devise::TestHelpers
|
include Devise::Test::ControllerHelpers
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
Warden::Strategies.add(:custom_strategy, CustomStrategy)
|
Warden::Strategies.add(:custom_strategy, CustomStrategy)
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'test_helper'
|
||||||
|
|
||||||
class PasswordsControllerTest < Devise::ControllerTestCase
|
class PasswordsControllerTest < Devise::ControllerTestCase
|
||||||
tests Devise::PasswordsController
|
tests Devise::PasswordsController
|
||||||
include Devise::TestHelpers
|
include Devise::Test::ControllerHelpers
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
request.env["devise.mapping"] = Devise.mappings[:user]
|
request.env["devise.mapping"] = Devise.mappings[:user]
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'test_helper'
|
||||||
|
|
||||||
class SessionsControllerTest < Devise::ControllerTestCase
|
class SessionsControllerTest < Devise::ControllerTestCase
|
||||||
tests Devise::SessionsController
|
tests Devise::SessionsController
|
||||||
include Devise::TestHelpers
|
include Devise::Test::ControllerHelpers
|
||||||
|
|
||||||
test "#create doesn't raise unpermitted params when sign in fails" do
|
test "#create doesn't raise unpermitted params when sign in fails" do
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class TestHelpersTest < Devise::ControllerTestCase
|
class TestControllerHelpersTest < Devise::ControllerTestCase
|
||||||
tests UsersController
|
tests UsersController
|
||||||
include Devise::TestHelpers
|
include Devise::Test::ControllerHelpers
|
||||||
|
|
||||||
test "redirects if attempting to access a page unauthenticated" do
|
test "redirects if attempting to access a page unauthenticated" do
|
||||||
get :index
|
get :index
|
Loading…
Add table
Reference in a new issue