2011-06-15 5 views
25

Estoy intentando escribir una prueba de solicitud que afirme que aparecen los enlaces adecuados en el diseño de la aplicación dependiendo de si el usuario está conectado o desconectado . FWIW, estoy usando Devise para la pieza de autenticación."No se pudo encontrar una asignación válida para # <User ...>" solo en las segundas y sucesivas pruebas

Aquí es mi especificación:

require 'spec_helper' 
require 'devise/test_helpers' 

describe "Layout Links" do 
    context "the home page" do 
    context "session controls" do 
     context "for an authenticated user" do 
     before do 
      # I know these should all operate in isolation, but I 
      # want to make sure the user is explicitly logged out 
      visit destroy_user_session_path 

      @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123") 
      @user.confirm! 

      # I tried adding this per the Devise wiki, but no change 
      @request.env["devise.mapping"] = Devise.mappings[:user] 

      # Now log a new user in 
      visit new_user_session_path 
      fill_in "Email", :with => @user.email 
      fill_in "Password", :with => "Asd123" 
      click_button "Sign in" 
      get '/' 
     end 

     it "should not have a link to the sign in page" do 
      response.should_not have_selector(
      '#session a', 
      :href => new_user_session_path 
     ) 
     end 

     it "should not have a link to registration page" do 
      response.should_not have_selector(
      '#session a', 
      :href => new_user_registration_path 
     ) 
     end 

     it "should have a link to the edit profile page" do 
      response.should have_selector(
      '#session a', 
      :content => "My Profile", 
      :href => edit_user_registration_path 
     ) 
     end 

     it "should have a link to sign out page" do 
      response.should have_selector(
      '#session a', 
      :content => "Logout", 
      :href => destroy_user_session_path 
     ) 
     end 
     end # context "for an authenticated user" 
    end # context "session controls" 
    end 
end 

pasa la primera prueba, pero los tres últimos todos fallan con el error

Failure/Error: @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123") 
    RuntimeError: 
    Could not find a valid mapping for #<User id: xxx, ...> 

He buscado a través de la wiki Diseñar, grupo de Google y los resultados de búsqueda por una causa, pero todo lo que encuentro son preguntas o sugerencias sin respuesta para establecer config.include Devise::TestHelpers, :type => :controller, pero eso solo se aplica a las pruebas del controlador, no solicita prueba.


actualización

que he hecho un poco más de la solución de problemas y no puedo hacer cara o cruz de lo que está en última instancia, provocando el problema. Eche un vistazo al siguiente código.

En primer lugar, para algunos contexto, aquí está la declaración de fábrica del usuario. Funciona bien en pruebas unitarias.

# spec/factories.rb 
Factory.define :user do |f| 
    f.email { Faker::Internet.email } 
    f.email_confirmation { |f| f.email } 
    f.password "AbcD3fG" 
    f.password_confirmation "AbcD3fG" 
    f.remember_me { (Random.new.rand(0..1) == 1) ? true : false } 
end 

Ahora, consideremos la siguiente prueba de integración

# spec/requests/user_links_spec.rb 
require "spec_helper" 

describe "User Links" do 
    before(:each) do 
    # This doesn't trigger the problem 
    # @user = nil 

    # This doesn't trigger the problem 
    # @user = User.new 

    # This doesn't trigger the problem 
    # @user = User.create(
    # :email => "[email protected]", 
    # :email_confirmation => "[email protected]", 
    # :password => "asdf1234", 
    # :password_confirmation => "asdf1234" 
    #) 

    # This doesn't trigger the problem 
    # @user = User.new 
    # @user.email = Faker::Internet.email 
    # @user.email_confirmation = @user.email 
    # @user.password = "AbcD3fG" 
    # @user.password_confirmation = "AbcD3fG" 
    # @user.remember_me = (Random.new.rand(0..1) == 1) ? true : false 
    # @user.save! 

    # This triggers the problem! 
    @user = Factory(:user) 

    # This doesn't trigger the same problem, but it raises a ActiveRecord::AssociationTypeMismatch error instead. Still no idea why. It was working fine before in other request tests. 
    # @user = Factory(:brand) 
    end 

    context "when using `@user = Factory(:user)` in the setup: " do 
    2.times do |i| 
     it "this should pass on the 1st iteration, but not the 2nd (iteration ##{i+1})" do 
     # This doesn't trigger an error 
     true.should_not eql(false) 
     end 

     it "this should pass on the 1st iteration, but trigger the error that causes all successive test cases to fail (iteration ##{i+1})" do 
     # Every test case after this will be borken! 
     get '/' 
     end 

     it "this will fail on all iterations (iteration ##{i+1})" do 
     # This will now trigger an error 
     true.should_not eql(false) 
     end 
    end 
    end 
end 

Si comentar o reemplazamos el bit get '/' con cualquier otra cosa (o nada en absoluto), las pruebas de todos corren finas.

Entonces, no sé si esto es un problema factory_girl (tiendo a dudarlo ya que puedo usar fábricas de usuarios en otro lugar sin problema) o un problema de Devise (comencé a recibir estos errores después de configurar esa gema en mi aplicación, pero también solo tuve otra prueba de solicitud que funcionó bien, pero ahora está obteniendo ese error AssociationTypeMismatch, correlación ≠ causalidad ...) o un problema RSpec o algún otro conflicto joya de borde extraño.

+0

me encontré con que esto ocurre incluso si los usuarios no son en realidad utilizado en cualquiera de los casos de prueba. Estoy publicando una actualización del ticket porque es demasiado grande para publicarlo en el formulario de comentarios. –

+0

Encontré un hilo en el grupo de correo Devise discutiendo sobre este mismo problema, pero hasta ahora no hay respuestas. http://groups.google.com/group/plataformatec-devise/browse_thread/thread/4ada5b12c0c279cd/053ee22cdcf658d1 –

Respuesta

9

Gracias a: http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-rails-3-console/

"Diseñar utiliza un mapeo entre clases y rutas, así que cuando un objeto construido de fábrica viene a través de idear después de una recarga de consola, o una redefinición de clase, entonces fallará ".

Ponlo en un inicializador o aplicación.rb

ActionDispatch::Callbacks.after do 
    # Reload the factories 
    return unless (Rails.env.development? || Rails.env.test?) 

    unless FactoryGirl.factories.blank? # first init will load factories, this should only run on subsequent reloads 
    FactoryGirl.factories.clear 
    FactoryGirl.find_definitions 
    end 
end 
+0

A veces se puede requerir el uso de 'ActionDispatch :: Callbacks.before', mi caso: http://stackoverflow.com/questions/36965377/rails-factorygirl-inside-app-in-development-env/37003351 – jmarceli

1

Sé que este es un hilo viejo, pero quería una respuesta para quien se encuentre con esto. no estoy seguro de dónde leo esto, pero apoyos a la persona que publicó sobre esto en otro foro.

Largo y corto es que los ayudantes de prueba no funcionan bien con las pruebas de integración.

Por lo tanto, elimine todas las referencias de Devise :: TestHelpers (algunas personas usan incluir, otras personas usan 'devise/testhelpers') dentro de las especificaciones mismas.

a continuación en el archivo spec_helper complemento:

RSpec.configure do |config| 
    config.include Devise::TestHelpers, :type => :controller 
end 
+1

Como mencioné en mi OP anterior, eso solo se aplica a las pruebas del controlador, no solicito pruebas mientras lo intentaba. ¿Estás diciendo que no puedes usar Devise desde adentro de una prueba de integración, y solo desde pruebas de controlador? –

1

solución de Halfnelson trabajó para mí también, pero ya que estoy usando el Fabrication gem en lugar de factorygirl, que tenía que hacer algunos ajustes. Este es el código que agregué a un inicializador:

if Rails.env.development? || Rails.env.test? 
    ActionDispatch::Callbacks.after do 
    Fabrication.clear_definitions 
    Rails.logger.debug 'Reloading fabricators' 
    end 
end 
8

Para futuros lectores: recibí el mismo error, pero por un motivo diferente.

Nuestra aplicación tenía múltiples modelos de usuario, donde uno derivado de la otra

Para bien de los argumentos:

class SimpleUser 

class User < SimpleUser 

En mi controlador utilicé una referencia a SimpleUser (la clase padre), pero Idear se configuró usar User (la clase hija).

Durante una invocación de Devise :: Mapping.find_scope! lo hace .is_a? comparación con la referencia del objeto y la clase configurada.

Como mi referencia era SimpleUser, y la clase configurada era User, ¿es is_a? falla porque la comparación pregunta si la clase de Padres es_a? Clase de niño, que siempre es falso

Espero que ayude a alguien más.

+0

Entonces, ¿Cuál es tu solución para este problema? – dennismonsewicz

+1

Si ve el error como estaba, asegúrese de que la clase que está utilizando sea de la misma clase que Devise estaba configurado para usar (o una subclase podría funcionar también). En mi caso, el error fue que estaba tratando de usar una clase padre de la clase que Devise estaba configurado para usar. –

3

Tuve este error en mi archivo de rutas porque tenía un punto final API del que quería permitir que los usuarios restablecieran sus contraseñas, pero quería que los usuarios realizasen el cambio de contraseña en la vista web, que no era namespaced bajo /api

así es como me fijo las rutas para hacer que funcione:

CoolApp::Application.routes.draw do 
    namespace :api, defaults: { format: :json } do 
    devise_scope :users do 
     post 'users/passwords', to: 'passwords#create' 
    end 

    resources :users, only: [:create, :update] 
    end 

    devise_for :users 

    root to: 'high_voltage/pages#show', id: 'home' 
end 
0

Sólo en caso de cualquier otra persona se encuentra con esto, por la misma razón que yo - yo tenía el mismo problema en básicamente todo mis pruebas después de un cambio en algunos archivos de configuración - resultó que se debió a que RAILS_ENV se configuró en development cuando realicé las pruebas por accidente. Podría valer la pena comprobar antes de añadir una prueba específica rieles inicializador :-)

18

Añadir esta línea a su routes.rb

# Devise 
devise_for :users # Or the name of the model you are using 
+0

Lo resolvió para mí – mycellius

0

En mi caso se trataba de un problema con el método de Devis confirm!. Así que en lugar de hacer esto (Minitest::Test código):

setup do 
    @admin = create(:admin).confirm! 
end 

he hecho esto:

setup do 
    @admin = create(:admin) 
    @admin.confirm! 
end 

y funcionó :)

Cuestiones relacionadas