Rails: Rspec user index admin user not included - ruby-on-rails

Factory user.rb
FactoryGirl.define do
factory :user do
username "Matin"
password "123456"
factory :admin do
admin true
end
end
end
user_controller_spec.rb
before :each do
session[:user_id] = create(:admin).id
end
describe "user access to orders" do
describe "GET#index" do
it " populates an array of all users" do
smith = create(:user,username:'smith')
jones = create(:user,username:'jones')
get :index
expect(assigns(:users)).to match_array([smith, jones])
end
it "render the :index template" do
get :index
expect(response).to render_template :index
end
end
This can not pass test and show error
expected collection contained:[User id: 2, username: "smith"] actual
collection contained: [User id: 1, username: "Matin"] the extra
elements were: [User id: 1, username: "Matin"]
I think error happens because I did not put admin user into match_array. How to add admin user into match_array?

You can save admin user to variable and then use it:
before :each do
#admin = create(:admin)
session[:user_id] = #admin.id
end
...
get :index
expect(assigns(:users)).to match_array([#admin, smith, jones])

Related

RSpec with Devise: subject.current_user is nil when used in second method in a context

I am currently using RSpec to test my Rails 4 application and when testing, I found this strange problem: subject.current_user is nil in the second method in a context. Code snippet:
describe 'GET #register_as_team:' do
context 'user logged in but not admin:' do
login_user
it 'should redirect_to user_path if user is not student' do
get :register_as_team, id: subject.current_user.id
expect(response).to redirect_to(user_path(subject.current_user))
expect(flash[:danger]).not_to be_nil
end
it 'should redirect_to student_path if user is a non-pending student' do
student = FactoryGirl.create(:student, user: subject.current_user, is_pending: false)
get :register_as_team, id: subject.current_user.id
expect(response).to redirect_to(student_path(student))
end
end
end
So when subject.current_user is used first time, it is OK and I can just get the logged user but in the second method it returns nil.
For background information, login_user is like this:
module ControllerMacros
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
In an example, subject can only be resolved once.
When you did, get :register_as_team, id: subject.current_user.id, you essentially resolved subject already and subject.current_user is not resolved in next line.
Try this:
describe 'GET #register_as_team:' do
context 'user logged in but not admin:' do
login_user
it 'should redirect_to user_path if user is not student' do
user = subject.current_user
get :register_as_team, id: user.id
expect(response).to redirect_to(user_path(user))
expect(flash[:danger]).not_to be_nil
end
it 'should redirect_to student_path if user is a non-pending student' do
student = FactoryGirl.create(:student, user: subject.current_user, is_pending: false)
user = subject.current_user
get :register_as_team, id: user.id
expect(response).to redirect_to(student_path(student))
end
end

How to write a test for a nested controller index

Right now my organizations controller lists all organizations where the current user has a membership. I know that my test is wrong, but I just can't figure out how it would be correct.
organizations_controller.rb
def index
#user = current_user
#organizations = #user.organizations.all
end
This is working fine, the model is ok and the views show the correct organizations.
I am trying to write a test for it, but somehow I am stuck. Here's my factory:
factory :organization do
name "example"
website "www.aquarterit.com"
after(:create) {|organization| organization.users = [create(:admin)]}
end
Here's my test:
describe "GET #index" do
it "populates an array of organizations where the user has membership" do
organization = create(:organization)
get :index
expect(assigns(:organizations)).to eq([organization])
end
it "renders the :index view" do
get :index
expect(response).to render_template ("index")
end
end
The result is naturally:
expected: [#<Organization id: 1, name: "example", website: "www.aquarterit.com", created_at: "2014-02-20 22:10:17", updated_at: "2014-02-20 22:10:17">]
got: nil
(compared using ==)
That's because the organization you create in the test is not associated with the user that is returned on calling current_user. stub the current_user method to return your user
describe "GET #index" do
it "should populate an array of organizations where the user has membership" do
organization = create(:organization)
controller.stub(:current_user).and_return(organization.user)
get :index
expect(assigns(:organizations)).to eq([organization])
end
it "renders the :index view" do
get :index
expect(response).to render_template ("index")
end
end

Using FactoryGirl for a controller test

I want to test my Users#show controller. How can I use FactoryGirl to create test data to be passed into my controller?
In "spec/controllers/users_controller_spec.rb":
describe UsersController do
describe "GET #show" do
it "assigns the requested user to #user" do
user = Factory(:user) # How do I do this using FactoryGirl?
get :show, id: user
assigns(:user).should eq(user)
end
end
end
In "spec/factories/users.rb"
require 'faker'
FactoryGirl.define do
factory :user do
email { Faker::Internet.email }
end
# Replace email with nil. Apparently all other attributes defer to the
# original :user factory.
factory :invalid_user do
email nil
end
end
To wrap things up:
Use create(:user) or build(:user) as shown in latest docs instead of Factory(:user).
build(:user) does not save the object to database therefore you will probably have to stub controller's queries. It's faster though.
To pass the id of not persisted user you'll have to do get :show, id: user.id instead of get :show, id: user

How to create an article of the user

I am testing the controllers with RSpec, FactoryGirls.
It is my factories.rb
FactoryGirl.define do
factory :user do |user|
user.sequence(:name) { Faker::Internet.user_name }
user.email Faker::Internet.email
user.password "password"
user.password_confirmation "password"
end
factory :article do
user
title Faker::Lorem.sentence(5)
content Faker::Lorem.paragraph(20)
end
end
How can i create an article of the user here
And this is articles_controller_spec
describe ArticlesController do
let(:user) do
user = FactoryGirl.create(:user)
user.confirm!
user
end
describe "GET #index" do
it "populates an array of articles of the user" do
#how can i create an article of the user here
sign_in user
get :index
assigns(:articles).should eq([article])
end
it "renders the :index view" do
get :index
response.should render_template :index
end
end
end
The older version, instead of traits, is this:
describe ArticlesController do
..
describe "GET #index" do
it "populates an array of articles of the user" do
article = FactoryGirl.create(:article, :user => user)
sign_in user
get :index
assigns(:articles).should eq([article])
end
..
end
describe ArticlesController do
let(:user) do
user = FactoryGirl.create(:user)
user.confirm!
user
end
describe "GET #index" do
it "populates an array of articles of the user" do
#how can i create an article of the user here
sign_in user
get :index
assigns(:articles).should eq([article])
end
it "renders the :index view" do
get :index
response.should render_template :index
end
it "assign all atricles to #atricles" do
get :index
assigns(:atricles).your_awesome_test_check # assigns(:articles) would give you access to instance variable
end
end
end
you can specify an User factory with articles already
FactoryGirl.define do
factory :user do |user|
user.sequence(:name) { Faker::Internet.user_name }
user.email Faker::Internet.email
user.password "password"
user.password_confirmation "password"
end
factory :article do
user
title Faker::Lorem.sentence(5)
content Faker::Lorem.paragraph(20)
end
trait :with_articles do
after :create do |user|
FactoryGirl.create_list :article, 2, :user => user
end
end
end
then in your controller test
FactoryGirl.create :user, :with_articles # => returns user with 2 articles
UPDATE
i think you want to see all articles per user.. if thats the case use
get :index, {:id => user.id}
that way you look for the user and get all articles in your controller
#user = User.find(params[:id]);
#articles = #user.articles
if thats not the case then just doing
#articles = Article.all
after using the trait :with_articles should display at least 2 Articles
you can test this with a simply asserting like
expect(#article.size).to eq(2)

How to test after_sign_in_path_for(resource)?

I have devise authentication and registration set up on my Rails app. I'm using after_sign_in_path_for() to customise the redirect when the user signs in based on various scenarios.
What I'm asking is how to test this method? It seems hard to isolate since it is called automatically by Devise when the user signes in. I want to do something like this:
describe ApplicationController do
describe "after_sign_in_path_for" do
before :each do
#user = Factory :user
#listing = Factory :listing
sign_in #user
end
describe "with listing_id on the session" do
before :each do
session[:listing_id] = #listing.id
end
describe "and a user in one team" do
it "should save the listing from the session" do
expect {
ApplicationController.new.after_sign_in_path_for(#user)
}.to change(ListingStore, :count).by(1)
end
it "should return the path to the users team page" do
ApplicationController.new.after_sign_in_path_for(#user).should eq team_path(#user.team)
end
end
end
end
end
but that's obviously not the way to do it because I just get an error:
Failure/Error: ApplicationController.new.after_sign_in_path_for(#user)
RuntimeError:
ActionController::Metal#session delegated to #_request.session, but #_request is nil: #<ApplicationController:0x00000104581c68 #_routes=nil, #_action_has_layout=true, #_view_context_class=nil, #_headers={"Content-Type"=>"text/html"}, #_status=200, #_request=nil, #_response=nil>
So, how can I test this method?
Oddly, I was wondering this very thing today. Here's what I came up with. I created an anonymous subclass of ApplicationController. In this anonymous subclass, I exposed the protected methods that I wanted to test as public methods. Then I tested them directly.
describe ApplicationController do
controller do
def after_sign_in_path_for(resource)
super resource
end
end
before (:each) do
#user = FactoryGirl.create(:user)
end
describe "After sigin-in" do
it "redirects to the /jobs page" do
controller.after_sign_in_path_for(#user).should == jobs_path
end
end
end
On a similar note - if you want to test the redirect after sign-up, you have two options.
First, you can follow a pattern similar to above and very directly test the method in RegistrationsController:
require 'spec_helper'
describe RegistrationsController do
controller(RegistrationsController) do
def after_sign_up_path_for(resource)
super resource
end
end
describe "After sign-up" do
it "redirects to the /organizations/new page" do
#user = FactoryGirl.build(:user)
controller.after_sign_up_path_for(#user).should == new_organization_path
end
end
end
Or, you can take a more integration-testing sort of approach and do the following:
require 'spec_helper'
describe RegistrationsController do
describe "After successfully completing the sign-up form" do
before do
#request.env["devise.mapping"] = Devise.mappings[:user]
end
it "redirects to the new organization page" do
post :create, :user => {"name" => "Test User", "email" => "test#example.com", "password" => "please"}
response.should redirect_to(new_organization_path)
end
end
end
For the newcomers, I would recommend doing this way:
RSpec.describe ApplicationController, type: :controller do
let(:user) { create :user }
describe "After sing-in" do
it "redirects to the /yourpath/ home page" do
expect(subject.after_sign_in_path_for(user)).to eq(yourpath_root_path)
end
end
end
I found this answer through Google recently and thought I would add my solution. I didn't like the accepted answer because it was testing the return value of a method on the application controller vs testing the desired behavior of the app.
I ended up just testing the call to create a new sessions as a request spec.
RSpec.describe "Sessions", type: :request do
it "redirects to the internal home page" do
user = FactoryBot.create(:user, password: 'password 123', password_confirmation: 'password 123')
post user_session_path, params: {user: {email: user.email, password: 'password 123'}}
expect(response).to redirect_to(internal_home_index_path)
end
end
(Rails 5, Devise 4, RSpec 3)
context "without previous page" do
before do
Factory.create(:user, email: "junior#example.com", password: "123456", password_confirmation: "123456")
request.env["devise.mapping"] = Devise.mappings[:user]
post :create, user: { email: "junior#example.com", password: "123456" }
end
end
it { response.should redirect_to(root_path) }
context "with previous page" do
before do
Factory.create(:user, email: "junior#example.com", password: "123456", password_confirmation: "123456")
request.env["devise.mapping"] = Devise.mappings[:user]
request.env['HTTP_REFERER'] = 'http://test.com/restaurants'
post :create, user: { email: "junior#example.com", password: "123456" }
end
it { response.should redirect_to("http://test.com/restaurants") }
end

Resources