So I have read how to solve this problem:
RSpec Test of Custom Devise Session Controller Fails with AbstractController::ActionNotFound
and
http://lostincode.net/blog/testing-devise-controllers
But under which file do I add these changes is my problem:
Under the rspec folder for my
registrations_controller
I tried this
before :each do
request.env['devise.mapping'] = Devise.mappings[:user]
end
require 'spec_helper'
describe RegistrationsController do
describe "GET 'edit'" do
it "should be successful" do
get 'edit'
response.should be_success
end
end
end
Which didn't work, any help with the specific files to change to make this work would be greatly appreciated.
EDIT
So I also tried -
https://github.com/plataformatec/devise/wiki/How-To:-Controllers-and-Views-tests-with-Rails-3-(and-rspec)
so I made a folder with spec/support and made a file called controllers_macros.rb
module ControllerMacros
def login_admin
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:admin]
sign_in Factory.create(:admin) # Using factory girl as an example
end
end
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = Factory.create(:user)
user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
sign_in user
end
end
end
And my registrations_controller is now this:
require 'spec_helper'
describe RegistrationsController do
describe "GET 'edit'" do
before :each do
request.env['devise.mapping'] = Devise.mappings[:user]
end
it "should be successful" do
get 'edit'
response.should be_success
end
end
end
I have other controllers in rspec do I need to change every single one? Or I'm confused on where to make the changes.
Just take the first version you tried, but move the before block inside the first describe block like this:
require 'spec_helper'
describe RegistrationsController do
before :each do
request.env['devise.mapping'] = Devise.mappings[:user]
end
describe "GET 'edit'" do
it "should be successful" do
get 'edit'
response.should be_success
end
end
end
Related
I am using Devise for my user logins and stuff and rspec for testing. I have looked at the Devise testing guide for rspec and mixined ControllerMicros to controller specs.
And actually things are all working fine if I have tests organized like this:
describe 'GET #index' do
context 'user logged in but not admin' do
login_user
it 'should redirect to root_path for non_user' do
get :index
// I have asserted that the current_user here is not nil
expect(response).to redirect_to(root_path)
end
end
end
However, if I have 2 tests in the context and I got current_user is nil for the non-first test.
describe 'GET #index' do
context 'user logged in but not admin' do
login_user
it 'should redirect to root_path for non_user' do
get :index
// I have asserted that the current_user here is not nil
expect(response).to redirect_to(root_path)
end
it 'should do some other thing' do
get :index
// the current_user method returns nil here
expect(response).to redirect_to(root_path)
end
end
end
And the worst part is that it seems this problem is not deterministic: happens somewhat randomly--cause after several failed runs the suite just passed on my computer(but still fails on Travis my build)
Some additional information:
the ControllerMacro.rb
module ControllerMacros
def login_admin
before(:each) do
# #request.env["devise.mapping"] = Devise.mappings[:user]
user = User.find_by(email: 'default_admin#controller.spec')
user ||= FactoryGirl.create(:user, email: 'default_admin#controller.spec', uid: 'default_admin.controller.spec')
admin = Admin.find_by(user_id: user.id)
FactoryGirl.create(:admin, user: user) if not admin
sign_in user
end
end
def login_user(user = nil)
before(:each) do
# #request.env["devise.mapping"] = Devise.mappings[:user]
user ||= User.find_by(email: 'default_user#controller.spec')
user ||= FactoryGirl.create(:user, email: 'default_user#controller.spec', uid: 'default_user.controller.spec')
sign_in user
end
end
end
the rails_helper.rb
RSpec.configure do |config|
# for loading devise in test
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
end
Your login_user method is run when the test suite load, you should put it in a before :each block to run it once for each test.
describe "GET index" do
before do
login_user
end
it 'blabla' do
get :index
expect(response).to redirect_to(root_path)
end
end
PS : Don't know what you do in your login_user method, but Devise have some nice helpers you can include as follow
#rails_helper.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
#then in you test
before do
sign_in user_instance
end
UPDATE from comment
If you have multiple type of user / devise login entry, maybe try to specify the devise mapping you're trying to sign in the user to , as follow :
sign_in :user, user_instance
sign_in :admin, admin_user_instance
please help solve the problem. i use gem 'devise', gem 'rspec' and this tutorial:
Authentication with Devise in Rspec tests
.i need #user output in console.
emails_controller_spec.rb:
RSpec.describe EmailsController, type: :controller do
let(:valid_attributes) {
{
email: Faker::Internet.email,
description: Faker::Lorem.paragraph(7),
user_id: 1
}
}
describe "GET #index" do
login_user
it "assigns all emails as #emails" do
email = Email.create! valid_attributes
get :index
binding.pry
expect(assigns(:emails)).to eq([email])
#expect(assigns(#user)).to eq(#user)
end
end
end
spec/factories/users.rb:
FactoryGirl.define do
factory :user do
sequence(:email){ |i| "us#{i}#ad.ad" }
password 'qwertyui'
password_confirmation{ |u| u.password }
role :none
end
end
spec/support/controller_macros.rb:
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
end
i user gem 'pry' for see on variables from console after run the test. but i see follow:
kalinin#kalinin ~/rails/mailer $ rspec spec/controllers
From: /home/kalinin/rails/mailer/spec/controllers/emails_controller_spec.rb # line 56 :
[1] pry(#<RSpec::ExampleGroups::EmailsController::GETIndex>)> #user
=> nil
[2] pry(#<RSpec::ExampleGroups::EmailsController::GETIndex>)> user
NameError: undefined local variable or method `user' for #<RSpec::ExampleGroups::EmailsController::GETIndex:0x00000007c4e670>
from /home/kalinin/.rvm/gems/ruby-2.0.0-p598/gems/rspec-expectations-3.3.1/lib/rspec/matchers.rb:966:in `method_missing'
[3] pry(#<RSpec::ExampleGroups::EmailsController::GETIndex>)> puts page.html
=> nil
i need displays user-object or displays html-code of page. please help
I hope you have included your ControllerMacros module somewhere. If not add that to top of your emails_controller_spec.rb file as include ControllerMacros
Add login_user in a before block -
describe "GET #index" do
before { login_user }
it "assigns all emails as #emails" do
email = Email.create! valid_attributes
get :index
binding.pry
expect(assigns(:emails)).to eq([email])
expect(assigns(#user)).to eq(#user)
end
end
Also change your ControllerMacros to:
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = FactoryGirl.create(:user)
sign_in #user
end
end
end
Im writing a simple rspec for a controller. The sign_in function does not seem to work however (although I included the rails_helper).
Any thoughts on what goes wrong here?
require 'rails_helper'
describe WikisController do
include Devise::TestHelpers
before do
#user = build(:user)
#wiki = build(:wiki)
sign_in #user
end
describe "#create" do
expect(#user.votes).to be_nil
post :create, {wiki_id: #wiki.id}
expect {#user.wikis}.to be (1)
end
end
You need to create the user, not build it, change
#user = build(:user)
to
#user = create(:user)
I have started rspec coding recently and i am new to rails framework, rspec fails where i am using 'current_user' in controller. Please check below for my controller and rspec code. Thanks in advance.
Controller code:
def task
#tasks = current_user.alerts.where(kind: "TASK")
end
rspec code:
describe "get #task" do
it "assigns a task" do
sign_in(#user)
get :task
expect(response).to have_http_status(200)
end
You can do it like this:
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user) # Don't forget to create a factory for user
user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the "confirmable" module
sign_in user
It is better to put it in support/devise.rb:
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the "confirmable" module
sign_in user
end
end
end
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
end
you can say login_user instead of sign_in(#user)
I found that there are not enough posts about this subject so I decide to post the question ones again.
I am simply trying to test my controllers that use devise with rspec .
I did add in rails_helper.rb
config.include Devise::TestHelpers, :type => :controller
I wrote this test:
describe AlbumsController do
render_views
let(:user) { User.create!(email: "rspec#example.com", password: "password") }
before(:each) do
sign_in(user)
end
it "should have a current_user" do
subject.current_user.should_not be_nil
end
describe "get ALBUM index" do
describe "for a registred user" do
it "should => index page" do
get :index
response.should have_selector('div#photos')
end
end
end
end
and my index method is really executed! I added some puts to follow the execution.
The subject.current_user is not null. everything should be good.
But I get a message:
<html><body>You are being redirected.</body></html>
There is No particular redirect_to or render method in my index action. It just render the default.
What is the problem here?
I'm using gem 'devise', "2.2.8" and gem 'rails', "3.2.1". It is old I know. I try to add tests before the migration to Rails 4 :-/
EDIT 1:
The current_user is valid in my index method.
It means it is not a Devise problem. but the view that is rendered
Try to use such construction
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
sign_in user
end
Source: https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-%28and-RSpec%29
Try adding:
before { request.env['HTTPS'] = 'on' }