How to write a test for a nested controller index - ruby-on-rails

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

Related

Rails: Rspec user index admin user not included

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])

Rspec: Creating user before testing method

Hi I am new to rspec (and unit testing in general) and want to test the following method:
class HelloController < ApplicationController
def hello_world
user = User.find(4)
#subscription = 10.00
render :text => "Done."
end
end
I am trying to use Rspec like so:
Describe HelloController, :type => :controller do
describe "get hello_world" do
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
end
I would like to simply test that the method works properly and renders the test "done". I get the following error when I run the test:
Failure/Error: user = User.find(4)
ActiveRecord::RecordNotFound:
Couldn't find User with 'id'=4
But how do I properly create a user with that id before executing it? I have tried the following based on other tutorials and questions but it doesn't work:
describe "get hello_world" do
let(:user) {User.create(id: 4)}
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
Thank you in advance.
Hey so really no action (e.g. def hello_world) should rely on a specific id. So a simple alternative could be to use user = User.last or to find the user by name user = User.find_by(name: "name"). Then in the test you would create any user if you using User.last in the action.
describe "get hello_world" do
let(:user) {User.create!}
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
or if you are searching by name you can make a user with that name;
describe "get hello_world" do
let(:user) {User.create!(name: "name")}
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
Hope this helps, questions welcome.
Do you really mean to use 'user = User.find(4)'? If you really meant to do that, you should stub the User's find method and return a user object.
it "should render the text 'done'" do
u = User.new #a new user, your test database is empty, so there's no user with id 4
User.stub(find: u) #stub the User's find method to return that new user
get :hello_world
expect(response.body).to include_text("Done.")
end
Another option is to send the user_id via params
it "should render the text 'done'" do
u = User.create(.... your user params)
get :hello_world, user_id: u.id
expect(response.body).to include_text("Done.")
end
and
def hello_world
user = User.find(params[:user_id])
#subscription = 10.00
render :text => "Done."
end
Anyway, I don't think you should be doing that, a hardcoded id is a bad sign. If you need to control users registrations and logins you can use something like Devise, and you may need to create an login a user before the spec.

RSpec - Functional Test - Syntax Check

so I'm writing a Test for my UserController, and the associated Devise dependency.
I'm trying to write a test that verify's userA can't access the show page of userB, but is redirected to the root_path instead. I'm guessing syntax errors are my issue, but I'd love another pair of eyes on it!
require 'rails_helper'
describe UsersController, :type => :controller do
# create test user
before do
#userA = User.create!(email: "test#example.com", password: "1234567890")
#userB = User.create!(email: "test2#example.com", password: "1234567890")
end
describe "GET #show" do
before do
sign_in(#userA)
end
context "Loads correct user details" do
get :show
expect(response).to have_http_status(200)
expect(assigns(:user)).to eq #userA
end
context "No user is logged in" do
it "redirects to login" do
get :show, id: #userA.id
expect(response).to redirect_to(root_path)
end
end
end
describe "GET Unauthorized page" do
before do
sign_in(#userA)
end
context "Attempt to access show page of UserB" do
it "redirects to login" do
get :show, id: #userB.id
expect(response).to have_http_status(401)
expect(response).to redirect_to(root_path)
end
end
end
end
You're missing an "it" block in
context "Loads correct user details" do
get :show
expect(response).to have_http_status(200)
expect(assigns(:user)).to eq #userA
end

Testing a before filter in rails controller

I seem to be stuck. I am trying to shore up some rspec testing and want to make sure the the correct before_filter methods are getting called for controllers. However, I am getting feedback saying the method never gets called.
The error:
Failure/Error: expect(controller).to receive(:authorize)
(#<UsersController:0x007fca2fd27110>).authorize(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
The spec:
require "rails_helper"
RSpec.describe UsersController, :type => :controller do
let(:school){ FactoryGirl.create :school }
let(:user){ FactoryGirl.create :teacher}
before(:each){
allow(controller).to receive(:current_user).and_return(user)
school.teachers << user
}
context "Get #show" do
before(:each){ get :show, school_id: school.id, id: user.id }
it "responds successfully with an HTTP 200 status code" do
expect(controller).to receive(:authorize)
expect(response).to have_http_status(200)
end
it "renders the show template" do
expect(response).to render_template("show")
end
end
end
The controller:
class UsersController < ApplicationController
before_filter :authorize
def show
#user = User.find_by_id params[:id]
#school = #user.school
#coordinators = #school.coordinators
#teachers = #school.teachers
#speducators = #school.speducators
#students = #school.students
end
end
Manual testing shows that before is being called, and when I put a p in the authorize method it is called when I run the test, any thoughts on where the test is going wrong?
You must set method expectation before actual call, so your test should look like:
context "Get #show" do
subject { get :show, school_id: school.id, id: user.id }
it "calls +authorize+ befor action" do
expect(controller).to receive(:authorize)
subject
end
end
Check the documentation https://github.com/rspec/rspec-mocks#message-expectations

Rails RSPEC controller testing to count # of users on INDEX page

Working on controller testing and wanted to test that when I go to the index page, I should see the total number of users created and that should equal all the users that were in fact created. Can't get it to work and no errors are coming up, it just freezes and I have to press control c to exit.
describe "GET #index" do
it "show a list of all users" do
total = User.all.count
get :index
expect(response).to eq total
end
rspec controller tests don't render views by default, testing success might be better start
describe "GET #index" do
it "show a list of all users" do
get :index
expect(response).to be_success
end
end
If you really want to check rendering
describe "GET #index" do
render_views
it "show a list of all users" do
total = User.all.count
get :index
expect(response).to contain total.to_s
# OR
expect(response.body).to match total.to_s
end
end
see: https://www.relishapp.com/rspec/rspec-rails/v/2-2/docs/controller-specs/render-views
If you want check displaying of some information on page, it will be better to write integrations test using Capybara.
Purpose of controller tests is to check incoming parameters, variables initialized in controller and controller response (rendering views or redirecting...).
About your question - if you have next controller:
class UsersController < ApplicationController
def index
#users = User.all
end
end
you can write next controller test:
describe UsersController do
it "GET #index show a list of all users" do
User.create(email: 'aaa#gmail.com', name: 'Tim')
User.create(email: 'bbb#gmail.com', name: 'Tom')
get :index
expect(assigns[:users].size).to eq 2
end
end

Resources