Can't get my rspec test to pass - ruby-on-rails

I have a test I'm trying to pass but I can't get it to pass, I am new to this.
Here's a link to my git repository https://github.com/FrankWiebe/nameofapp
The failure message comes up like so:
1) UsersController GET #show No user is logged in redirects to login
Failure/Error: expect(response).to redirect_to(root_path)
Expected response to be a <redirect>, but was <200>
# ./spec/controllers/users_controller_spec.rb:24:in `block (4 levels) in <top (required)>'
This is the code:
require 'rails_helper'
describe UsersController, :type => :controller do
before do
#user = User.create(email: "doe#example.com", password: "1234567890")
end
describe "GET #show" do
context "User is logged in" do
before do
sign_in #user
end
it "loads correct user details" do
get :show, id: #user.id
expect(response).to have_http_status(200)
expect(assigns(:user)).to eq #user
end
end
context "No user is logged in" do
it "redirects to login" do
get :show, id: #user.id
expect(response).to redirect_to(root_path)
end
end
end
end

Perhaps #user is carried on as being logged in from one test to the next, so the 2nd show succeeds. Try to sign off the user whithin the first test.
As this is not the case, check your config/routes.rb.
Resources requiring login should be wrapped within a do...end
authenticate(:user) do
resources :user
...other stuff
end

Related

RSpec sessions controllers - user with invalid params without devise

I've got a simple message app to learn RSpec where one user can create message to another user (only logged users can write messages). I didn't used devise or FactoryBot, this app is as simple as possible just for rspec learning.
I wanted to run these tests for sessions controller, but the second one (when user has invalid params) gives me an error Expected response to be a <3XX: redirect>, but was a <200: OK> and I don't understand why since hours.
RSpec.describe SessionsController, type: :controller do
let(:create_user) { #user = User.create(username: 'John', password: 'test123') }
describe 'POST #create' do
context 'when user is logged in' do
it 'loads correct user details and redirect to the root path' do
create_user
post :create, params: { session: { username: #user.username, password: #user.password } }
expect(response).to redirect_to(root_path)
end
end
context 'when user has invalid params' do
before do
create_user
post :create, params: { session: { username: #user.username, password: 'somepass' } }
end
it 'render new action' do
expect(assigns(:user)).not_to eq create_user
expect(response).to redirect_to(action: 'new')
end
end
end
end
Sessions Controller
class SessionsController < ApplicationController
before_action :logged_in_redirect, only: %i[new create]
def new; end
def create
user = User.find_by(username: params[:session][:username])
if user && user.authenticate(params[:session][:password])
session[:user_id] = user.id
flash[:success] = 'You have successfully logged in'
redirect_to root_path
else
flash.now[:error] = 'There was something wrong with your login'
render 'new'
end
end
end
I'm not quite sure if line expect(assigns(:user)).not_to eq create_user is in line with convention but it doesn't matter for result.
In your test you expect redirect response:
expect(response).to redirect_to(action: 'new')
And in the controller you just render new template:
render 'new'
I think it's a good approach to render new, you should change your spec to expect this.
expect(response).to render_template(:new)

rspec for the controller without factory girl

I am trying to write spec code for my controller it gets failed. And i am not sure where it gets failed.
Controller Code
def index
#users = User.all
end
def update
authorize! :update, #user
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to user_index_path }
else
format.html { render :index }
end
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.permit(:active)
end
Spec Code for the above controller
RSpec.describe UserController, type: :controller do
describe 'GET #index' do
let(:user) {User.create!(name: "hari")}
context 'with user details'do
it 'loads correct user details' do
get :index
expect(response).to permit(:user)
end
end
context 'without user details' do
it 'doesnot loads correct user details' do
get :index
expect(response).not_to permit(:user)
end
end
end
describe 'Patch #update' do
context 'when valid params' do
let(:attr) do
{active: 'true'}
end
before(:each) do
#user = subject.current_user
put :update, params: { user: attr }
#user.reload
end
it 'redirects to user_index_path ' do
expect(response).redirect_to(user_index_path)
end
it 'sets active state' do
expect(#user.active?('true')).to be true
end
end
context 'when invalid param' do
let(:attr) do
{active: 'nil'}
end
before(:each) do
#user = subject.current_user
put :update, params: { user: attr }
#user.reload
end
it 'render index' do
expect(respone.status).to eq(200)
end
it 'doesnot change active state' do
expect(#user.active?(nil)).to be true
end
end
end
end
I am just a beginner and tried the spec code for my controller by checking https://relishapp.com/rspec/rspec-rails/docs/gettingstarted. Can you help me where my spec goes wrong or could anyone give me a few test examples for these methods or could redirect me to an rspec guide? the index method is getting failed
and my
terminal log is
1) UserController GET #index with user details loads correct user details
Failure/Error: expect(response).to permit(:user)
NoMethodError:
undefined method `permit' for #<RSpec::ExampleGroups::UserController::GETIndex::WithUserDetails:0x00005614152406b0>
Did you mean? print
# ./spec/controllers/user_controller_spec.rb:10:in `block (4 levels) in <top (required)>'

Rspec check the template after a redirect

Here is my create action for users:
def create
#user = User.new(user_params)
if #user.save
respond_to do |format|
format.html {
redirect_to edit_admin_user_path(#user)
flash[:success] = "Successfully created"
}
end
else
render :new
flash[:alert] = "Something went wrong"
end
end
My test is looking like this:
context "POST methods" do
describe "#create" do
it "renders the edit template" do
post :create, user: FactoryGirl.attributes_for(:user)
expect(response).to render_template(:edit)
end
end
end
However I'm getting this error:
Failures:
1) Admin::UsersController POST methods #create renders the edit template
Failure/Error: expect(response).to render_template(:edit)
expecting <"edit"> but was a redirect to <http://test.host/admin/users/80/edit>
I want to check if the edit.html.haml file is rendered after creating a user. What am I doing wrong?
Update #1
I do check for redirect in another test, this is my full test suite:
require 'rails_helper'
RSpec.describe Admin::UsersController, type: :controller do
render_views
context "POST methods" do
describe "#create" do
it "using valid params" do
expect{
post :create, user: { email: "something#hello.com", password: "long12345678" }
}.to change(User, :count).by(1)
# get user_path('1')
end
it "redirects to the edit page after saving" do
post :create, user: FactoryGirl.attributes_for(:user)
user = User.last
expect(response).to redirect_to(edit_admin_user_path(user.id))
end
it "renders the edit template" do
post :create, user: FactoryGirl.attributes_for(:user)
user = User.last
expect {
redirect_to(edit_admin_user_path(user.id))
}.to render_template(:edit)
end
context "it redirects to new" do
it "if user has no valid mail" do
post :create, user: { email: "something", password: "long12345678" }
expect(response).to render_template(:new)
end
it "if user has no valid password" do
post :create, user: { email: "something#mail.com", password: "short" }
expect(response).to render_template(:new)
end
end
end
end
end
What I want is to actually check if the edit template is rendered. Because with expect(response).to redirect_to(edit_admin_user_path(user)) it does not check the template. This test passes even if I have no edit.html.haml file at all.
When you're testing create action you should just check correctness of redirect. In this action you're not actually rendering edit template, but you're just making redirect to the edit path of created entity. So this is the thing you should check.
describe "#create" do
it "redirects to the edit path" do
post :create, user: FactoryGirl.attributes_for(:user)
expect(response).to redirect_to(edit_admin_user_path(User.last))
end
end
Then you should have another test for edit action, where you're checking template rendering. That will mean that after redirect in create action you also will see the proper template.
You are redirecting to edit_admin_user_path after successfully saving the User in your controller action. But, you're testing render in the test instead.
Update your test as below.
context "POST methods" do
describe "#create" do
before(:each) do
#user = FactoryGirl.attributes_for(:user)
end
it "renders the edit template" do
post :create, user: #user
expect(response).to redirect_to(edit_admin_user_path(#user))
end
end
end

Rails Rspec - undefined method `session'

Im testing my Session Controller but Im getting this error, the log in feature works, I tested it on the browser but Im new to testing on Rspec and can't get this to work
Failure/Error: expect(response.session[:user_id]).to eq(#user_attr.id)
NoMethodError:
undefined method `session' for #<ActionController::TestResponse:0xd30df10>
# ./spec/controllers/sessions_controller_spec.rb:20:in `block (3 levels) in <top (required)>'
This is the code of my controller:
def new
#user = User.new
end
def create
#user = User.find_by(username: params[:user][:username])
if #user && #user.authenticate(params[:user][:password])
session[:user_id] = #user.id
redirect_to root_path
else
render :new
end
end
Rspec code:
require 'rails_helper'
RSpec.describe SessionsController, type: :controller do
describe "get Login page" do
it "returns http status" do
get :new
expect(response).to have_http_status(:success)
end
end
describe "session" do
before(:each) do
#user = FactoryGirl.create(:user)
#user_attr = FactoryGirl.attributes_for(:user)
end
it "gives session" do
request.session[:user_id] = nil
post :create, user: #user_attr
expect(response.session[:user_id]).to eq(#user_attr.id)
end
end
end
session is a variable that is available without the request/response context as shown in your example. If you want to manipulate it or check the values it contains, you can simply do something like this:
it "gives session" do
session[:user_id] = nil
post :create, user: #user_attr
expect(session[:user_id]).to eq(#user_attr.id)
end

Rspec Test Won't Pass using assigns()

Here is my current users_controller_spec.rb file
require 'spec_helper'
describe UsersController do
render_views
.
.
.
describe "success" do
before(:each) do
#attr = { :name => "New User", :email => "user#example.com",
:password => "foobar", :password_confirmation => "foobar" }
end
it "should create a user" do
lambda do
post :create, :user => #attr
end.should change(User, :count).by(1)
end
it "should redirect to the user show page" do
post :create, :user => #attr
response.should redirect_to(user_path(assigns(:user)))
end
end
end
end
When I run this I get the following:
Failures:
1) UsersController POST 'create' success should redirect to the user show page
Failure/Error: response.should redirect_to(user_path(user))
ActionController::RoutingError:
No route matches {:action=>"show", :controller=>"users"}
# ./spec/controllers/users_controller_spec.rb:95:in `block (4 levels) in <top (required)>'
Which leads me to believe that :user isn't an actual object. How can I test this and how can I change :user into an object that user_path understands.
Thanks in advance for any help.
UPDATED:
def create
#title = "Sign up"
#user = User.new(params[:user])
if #user.save
redirect_to #user, :notice => "Signed Up!"
else
#title = "Sign up"
render "new"
end
end
When I run the following:
it "should redirect to the user show page" do
post :create, :user => #attr
user = assigns(:user)
user.should_not be_blank
puts "user errors are: #{user.errors.full_messages.inspect}" unless user.is_valid?
user.should be_valid
response.should redirect_to(user_path(user))
end
I get:
1) UsersController POST 'create' success should redirect to the user show page
Failure/Error: user.should_not be_blank
expected blank? to return false, got true
# ./spec/controllers/users_controller_spec.rb:94:in `block (4 levels) in <top (required)>'
Try using assigns with brackets instead of parenthesis.
assigns[:user]
(RSpec docs)
EDIT
One pattern I always use when testing controller actions is to ensure that a variable required by the associated view(s) is assigned. For example,
it "should assign an #user variable" do
post :create, :user => #attr
assigns[:user].should_not be_nil
assigns[:user].should be_kind_of(User)
end
You've got a typo
response.should redirect_to(user_path(:user))
should be
response.should redirect_to(user_path(user))
Edit:
Try checking that the user is valid with:
it "should redirect to the user show page" do
post :create, :user => #attr
user = assigns(:user)
user.should_not be_blank
puts "user errors are: #{user.errors.full_messages.inspect}" unless user.is_valid?
user.should be_valid
response.should redirect_to(user_path(user))
end
I know it works on the previous test case... but still worth checking extensively at least once here. You can remove all that guff when you're certain.
In your test:
it "should redirect to the user show page" do
#user = Factory(:user)
post :create, :user => #attr
user = assigns(:user)
response.should redirect_to(user_path(#user))
end
Your #attr hash is different from #user. You are creating user with attributes of #attr, and asserting that it should redirect to #user show (which is different from one created). Change to:
it "should redirect to the user show page" do
post :create, :user => #attr
user = assigns(:user)
response.should redirect_to(user_path(user))
end

Resources