testing a redirect in rspec and devise - ruby-on-rails

i want to to write a controler test to check that on a successful sign in, a user is redirected to a certain page. the current test I have at the moment is returning a 200.
require 'rails_helper'
RSpec.describe Admin::EntriesController, :type => :controller do
setup_factories
describe "after login" do
it "should redirect to pending after logged in" do
sign_in admin
expect(response).to redirect_to('admin/entries/pending')
end
end
end
which returns
Failure/Error: expect(response).to redirect_to('admin/entries/pending')
Expected response to be a <redirect>, but was <200>
the relevant controller
class AdminController < Devise::RegistrationsController
before_filter :authenticate_admin!
protected
def after_sign_in_path_for(admin)
pending_admin_entries_path
end
end
am I attempting this is in the right way, where am i going wrong?
thanks

sign_in user in RSpec doesn't make a request so you cannot test the redirection.
For after_sign_in_path, you can test like this:
it 'redirects user to pending admin entries path' do
expect(controller.after_sign_in_path(user)).to eq pending_admin_entries_path
end

Related

Is there any way to give logged in condition in rspec? (Ruby on Rails)

my rspec file ->
describe 'GET /users' do
it 'test user list page' do
get '/users'
expect(response).to have_http_status(:success)
end
end
I maked login in my app, but I don't know how to define
'login' with 'before' in rspec file.
my login is using session, and I don't have to use specific user.
how can I check user logged in on rspec request test?
I want to test logged in user can access to /users url in rspec file
you can do it by mocking. The details depend on how your login status is determined, but suppose your application controller has a before_action like this:
# application_controller.rb
before_action :verify_login
# typically the checking is delegated
def verify_login
Authorize.logged_in?(current_user, session)
end
Where the checking is executed in the Authorize service model.
Now in Rspec you just have to mock the response:
before do
current_user = FactoryBot.create(:user)
session = Session.create
expect(Authorize).to receive(:logged_in?).with(current_user, session).and_return(true)
end
it "should respond to logged-in user" do
get '/users'
expect(response).to have_http_status(:success)(
end

Undefined local variable or method params in Rspec

Hi I am implementing a method to delete a user account in my web application. My controller:
class UsersController < ApplicationController
before_filter :set_current_user
def user_params
params.require(:user).permit(:user_id, :first_name, :last_name, :email, :password, :password_confirmation)
end
def delete_account
#user = User.find_by_id(params[:id])
if #user.present?
#user.destroy
flash[:notice] = "User Account Deleted."
end
redirect_to root_path
end
def destroy
User.delete(:user_id)
redirect_to root_path
end
end
My rspec:
require 'spec_helper'
require 'rails_helper'
require'factory_girl'
describe UsersController do
describe "delete account" do
before :each do
#fake_results = FactoryGirl.create(:user)
end
it "should call the model method that find the user" do
expect(User).to receive(:find).with(params[:id]).and_return (#fake_results)
end
it "should destroy the user account from the database" do
expect{delete :destroy, id: #fake_results}.to change(User, :count).by(-1)
end
it "should redirect_to the home page" do
expect(response).to render_template(:home)
end
end
end
The first error is
Failure/Error: expect(User).to receive(:find).with(params[:id]).and_return (#fake_results)
NameError:undefined local variable or method `params' for #<RSpec::ExampleGroups::UsersController::DeleteAccount:0x00000007032e18>
I know what this error means but I don't know how to correct it. How can I pass the user id from the controller to rspec?
The second error is:
Failure/Error: expect(response).to render_template(:home)
expecting <"home"> but rendering with <[]>
I think there is something wrong with my controller method. It should redirect to the home page but it doesn't.
params is not available in your tests, it's available in your controller.
Looks like you create a test user in your test:
#fake_results = FactoryGirl.create(:user)
Then, you can use the id of this test user (#fake_results.id) instead of trying to use params[:id]:
expect(User).to receive(:find).with(#fake_results.id).and_return (#fake_results)
Although, you may want to change the name from #fake_results to something more meaningful e.g. test_user or so.
However, this should fix both of your problems as your second problem is there because of the first problem. As it's failing to delete the user in the first place, it's not being redirected to the root path and hence the home template is not rendering.

How to create a route for testing purposes?

I'm writing tests with rspec for my application controller in my rails app (written in Rails 4) and I'm running into a problem where it doesn't recognize the route for the HTTP request I'm sending. I know there's a way to do this using MyApp::Application.routes but I'm not able to get it working.
#application_controller_spec.rb
require 'spec_helper'
class TestController < ApplicationController
def index; end
end
describe TestController do
before(:each) do
#first_user = FactoryGirl.create(:user)
# this is to ensure that all before_filters are run
controller.stub(:first_time_user)
controller.stub(:current_user)
end
describe 'first_time_user' do
before(:each) do
controller.unstub(:first_time_user)
end
context 'is in db' do
before(:each) do
#user = FactoryGirl.create(:user)
controller.stub(:current_user).and_return(#user)
end
it 'should not redirect' do
get :index
response.should_not be_redirect
end
end
context 'is not in db' do
context 'session[:cas_user] does not exist' do
it 'should return nil' do
get :index
expect(assigns(:current_user)).to eq(nil)
end
end
it "should redirect_to new_user_path" do
controller.stub(:current_user, redirect: true).and_return(nil)
get :index
response.should be_redirect
end
end
end
The error I'm getting right now is
No route matches {:action=>"index", :controller=>"test"}
I would add the test#index route to config/routes.rb, but it doesn't recognize the Test Controller, so I want to do something like
MyApp::Application.routes.append do
controller :test do
get 'test/index' => :index
end
end
but I'm not sure where to add this or if this even works in rspec. Any help would be great!
If you are trying to test your ApplicationController, see this RSpec documentation about it. You will need to define methods like index inside the test, but it works well.

RSpec Test of Custom Devise Session Controller Fails with AbstractController::ActionNotFound

I am currently trying to test a custom Devise session controller with rspec. My controller looks like this:
class SessionsController < Devise::SessionsController
def create
#valid email?
if !(params[:email] =~ /^[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/)
set_flash_message :notice, "Please enter a valid e-mail address!"
end
super
end
end
My RSpec Controller Test is this:
require 'spec_helper'
require 'devise/test_helpers'
describe SessionsController do
it "should put a warning on invalid mail address login attempt" do
post :create, :user => {:email => 'invalidEmailAddress'}
response.should contain "Please enter a valid e-mail address!"
end
it "should put no warning on valid mail address login attempt" do
pending
end
end
If I execute the RSpec Test it fails with the following line:
Failure/Error: post :new, :user => {:email => 'invalidEmailAddress'}
AbstractController::ActionNotFound
# ./spec/controllers/sessions_controller_spec.rb:7
Tips from the plataformatec Devise Wiki as well as this post did not solve this issue. Thanks for your help.
Addition
I investigated further. I was actually able to "remove" the error with the following addition to the controller spec:
before(:each) do
request.env['devise.mapping'] = Devise.mappings[:user]
end
But now a new error appears:
Failure/Error: post :create #currently fails with multiple render warning
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
Even with the create method left out in the inheriting controller the error appears. The error does not appear on get :new for example. It seems to be post :create only.
I am out of ideas? Any help?
Thanks!
I finally fixed my problem by doing including the devise test helpers, calling the method setup_controller_for_warden in my test AND doing request.env["devise.mapping"] = Devise.mappings[:user]. Like so:
require 'test_helper'
class SessionsControllerTest < ActionController::TestCase
include Devise::TestHelpers
test "should reject invalid captcha" do
setup_controller_for_warden
request.env["devise.mapping"] = Devise.mappings[:user]
get :new
assert_response :success
end
end
Not sure about your double render problem though, are you sure your supposed to call post :create then render? i'm not sure how rspec is supposed to work.

User login while testing with rspec and authlogic

I have a spec for testing a controller as below
require 'spec_helper'
describe ProductsController do
setup :activate_authlogic
describe "user not logged in" do
it "should not GET index" do
get :index
response.should redirect_to(login_path)
end
end
describe "user logged in" do
before(:each) do
UserSession.create :username => "rohit", :password => "test123"
end
it "should GET index" do
get :index
response.should redirect_to(products_path)
end
end
end
I have also used this line in spec_helper.rb
require "authlogic/testcase"
The test for "user not logged in passes" but for "user logged in" fails with
'ProductsController user is logged in should GET index' FAILED
expected redirect to "/products", got no redirect
It seems normal, because You fetch the '/products' url with a logged user. Then He see this page. He is not redirect to the page he see.
Each test are independant. No state are save in previous test.

Resources