Nota: He leído this pregunta y la respuesta, pero por alguna razón el código no funciona para mí. (Consulte a continuación el error que estoy recibiendo)Método de destrucción de prueba RSpec (Rails Tutorial 3.2 Ch. 9, Ej. 10)
El ejercicio 10 del Capítulo 9 de Rails Tutorial le pide que: Modifique la acción de destrucción [para los usuarios] para evitar que los usuarios administradores se destruyan a sí mismos. (Escriba primero una prueba)
La parte difícil aquí es probarla, porque la aplicación ya oculta el enlace "eliminar" para el usuario actual, por lo que debe hacer la solicitud http directamente.
Obtuve el código funcionando, y lo probé quitando la pieza de código que oculta el enlace de eliminación para el usuario actual. Efectivamente, si hago clic en el enlace de eliminación para el usuario actualmente conectado, me redirige y me da el mensaje de notificación.
De users_controller.rb
def destroy
@user = User.find(params[:id])
if current_user?(@user)
redirect_to users_path, notice: "You can't destroy yourself."
else
@user.destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
end
El problema que estoy teniendo es por escrito las pruebas de este que va a enviar la solicitud de eliminación y llamar al método destroy. Probé la solución de Rspec test for destroy if no delete link, que estoy copiando aquí:
De user_pages_spec.rb
describe "destroy" do
let(:admin) { FactoryGirl.create(:admin) }
it "should not allow the admin to delete herself" do
sign_in admin
#expect { delete user_path(admin), method: :delete }.should change(User, :count)
expect { delete :destroy, :id => admin.id }.should_not change(User, :count)
end
end
Pero cuando corro esto, me sale este error de RSpec
Failures:
1) User Pages destroy should not allow the admin to delete herself
Failure/Error: expect { delete :destroy, :id => admin.id }.should_not change(User, :count)
ArgumentError:
bad argument (expected URI object or URI string)
# ./spec/requests/user_pages_spec.rb:180:in `block (4 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:180:in `block (3 levels) in <top (required)>'
Entonces, mis preguntas son: 1) ¿Por qué este código está fallando? 2) ¿Cómo simulo una "eliminación" para llamar a la acción destruir en mi controlador?
Medio Ambiente: Mac OS X rubí 1.9.3p194 Rails 3.2.3
gemas para las pruebas:
grupo: Prueba de hacer joya 'rspec-carriles', '2.9.0' joya 'capibara ',' 1.1.2 ' gema' rb-fsevent ',' 0.4.3.1 ',: require => falso gema' gruñido ',' 1.0.3 ' gema' guard-spork ',' 0.3.2 ' gema 'spork', '0.9.0' gema 'factory_girl_rails', '1.4.0' final
Más información He probado un montón de maneras de tratar de simular clic en el enlace de eliminación y ninguno parece funcionar. He estado usando la gema del depurador para ver si se está llamando al método de destrucción. En la prueba de que hace clic en el enlace para eliminar un usuario diferente, el método destroy se llama y funciona bien:
it "should be able to delete another user" do
expect { click_link('delete') }.to change(User, :count).by(-1)
end
Pero nada de lo que han tratado de generar la solicitud de eliminación directa ha trabajado para llamar al método destroy.
Gracias por su ayuda!
Will
** ACTUALIZACIÓN **
Probé la sugerencia de DVG:
describe "destroy" do
let(:admin) { FactoryGirl.create(:admin) }
it "should not allow the admin to delete herself" do
sign_in admin
#expect { delete user_path(admin), method: :delete }.should change(User, :count)
expect { delete :destroy, :id => admin }.to_not change(User, :count)
end
end
Y dio este mensaje:
6) User Pages destroy should not allow the admin to delete herself
Failure/Error: expect { delete :destroy, :id => admin }.to_not change(User, :count)
ArgumentError:
bad argument (expected URI object or URI string)
# ./spec/requests/user_pages_spec.rb:190:in `block (4 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:190:in `block (3 levels) in <top (required)>'
SOLUCIÓN
Lo descubrí después de FOREVER.
tuve que usar rack :: Prueba de emitir la solicitud DELETE, pero capibara y rack :: Prueba no comparten la misma MockSession, por lo que tuvo que retirarse en el: remember_token y galletas: sample_app_session y ponerlos en la solicitud DELETE manualmente. Aquí está lo que funcionó. (El otro problema que tenía, se enumeran a continuación, fue que tuve una declaración force_ssl que no estaba dejando que mi acción destruir a ser llamado.
describe "destroy" do
let!(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
end
it "should delete a normal user" do
user = FactoryGirl.create(:user)
expect { delete user_path(user), {},
'HTTP_COOKIE' => "remember_token=#{admin.remember_token},
#{Capybara.current_session.driver.response.headers["Set-Cookie"]}" }.
to change(User, :count).by(-1)
end
it "should not allow the admin to delete herself" do
expect { delete user_path(admin), {},
'HTTP_COOKIE' => "remember_token=#{admin.remember_token},
#{Capybara.current_session.driver.response.headers["Set-Cookie"]}" }.
to_not change(User, :count)
end
end
tuve una declaración force_ssl después de mis before_filters en mi users_controller.rb y esto fue de alguna manera tirar cosas fuera de lo que nunca llegué a la acción de destruir.
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:edit, :update, :index]
before_filter :existing_user, only: [:new, :create]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
#force_ssl
def index
@users = User.paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
@microposts = @user.microposts.paginate(page: params[:page])
end
def destroy
@user = User.find(params[:id])
if current_user?(@user)
redirect_to users_path, notice: "You can't destroy yourself."
else
@user.destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
end
Estos fueron útiles para llegar a una solución
https://gist.github.com/484787
http://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles/
Una cosa que acabo de descubrir, que no es exactamente mi problema, pero podría ser un problema * * es que el método let es lento, por lo que se podía imaginar que atornillar la espera to_not cambiar la funcionalidad. ¡Así que ajusté el código para usar let! al crear el usuario administrador. –
¿cuál es el escenario que está probando? El administrador inicia sesión, el enlace de eliminación está oculto, pero de alguna manera crea la solicitud de eliminación. (solo pregunta) –
Buena pregunta. La mayoría de las respuestas es que esto fue un ejercicio en el Tutorial de Rails. Resultó que fue un buen ejercicio, porque aprendí todo tipo de cosas sobre cookies, solicitudes de http, Capybara y Rack :: Test. Supongo que podría estar probando el escenario donde falla el código para ocultar el enlace de eliminación y quiero que mi controlador tenga una copia de seguridad. –