Stub concebe autenticação nas especificações do controlador com múltiplos escopos

Eu queria fazer uma autenticação falsa nas especificações do meu controlador.

A solução proposta no devise wiki ( https://github.com/plataformatec/devise/wiki/How-To:-Stub-authentication-in-controller-specs ) não funcionou porque stubs warden autentica! de uma forma que não verifica o escopo e funciona corretamente apenas no caso de você ter apenas um escopo.

def sign_in(user = double('user'))
if user.nil?
allow
(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})
allow
(controller).to receive(:current_user).and_return(nil)
else
# no matter what you pass to authenticate!
# it will always return resource you want (will not check scope)
allow
(request.env['warden']).to receive(:authenticate!).and_return(user)
allow
(controller).to receive(:current_user).and_return(user)
end
end

Se você tiver vários escopos, deve fazer algo assim:

def fake_sign_in(resource_or_scope = :user, options = {})
if resource_or_scope.is_a?(Symbol)
scope
= resource_or_scope
resource
= double(resource_or_scope)
else
resource
= resource_or_scope
scope
= options[:scope] || resource.class.to_s.underscore
end
# Since we have multiple scopes we need to check if scope option provided to
# authenticate! matches scope that we are logging in
allow
(request.env['warden']).to receive(:authenticate!) do |options|
if options[:scope].to_sym == scope.to_sym
resource

else
throw :warden, :scope => scope
end
end
allow
(controller).to receive("current_#{scope}").and_return(resource)
end

def fake_sign_out(scope = :user)
allow
(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => scope})
allow
(controller).to receive("current_#{scope}").and_return(nil)
end

Observe que também separei o login e o logout.

Para o código completo, consulte https://gist.github.com/vlado/812948efe4fb0667a964