Rspec param is missing or the value is empty: user - ruby-on-rails

Hello i'm testing the Update action the User Controller using Rspec.
I get this error
1) UsersController POST #update user updated
Failure/Error: patch :update, {id: user.id }, { user_id: user.id }, user: user_params
ActionController::ParameterMissing:
param is missing or the value is empty: user
# /Users/joseph/.rvm/gems/ruby-2.1.2/gems/actionpack-4.2.0/lib/action_controller/metal/strong_parameters.rb:249:in `require'
# ./app/controllers/users_controller.rb:60:in `user_params'
# ./app/controllers/users_controller.rb:39:in `update'
Weird thing is i used a binding.pry to test whats going on. There is a user and there are user_params. So i don't understand why i receive the above error.
Please see below for the user and user params.
From: /Users/joseph/Documents/Safsy/Website/Safsy/Safsy/spec/controllers/users_controller_spec.rb # line 76 :
71: end
72: end
73:
74: describe "POST #update" do
75: it "user updated" do
=> 76: binding.pry
77: patch :update, {id: user.id }, { user_id: user.id }, user: user_params
78: expect(response).to redirect_to(assigns(:user))
79: expect(assigns(:user)).to eq(user)
80: end
81: end
[1] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)> patch :update, {id: user.id }, { user_id: user.id }, user: user_params
ActionController::ParameterMissing: param is missing or the value is empty: user
from /Users/joseph/.rvm/gems/ruby-2.1.2/gems/actionpack-4.2.0/lib/action_controller/metal/strong_parameters.rb:249:in `require'
[2] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)> user
=> #<User:0x007fd91fe40458
id: 2,
username: "username2",
email: "user2#factory.com",
created_at: Thu, 08 Oct 2015 11:09:54 UTC +00:00,
updated_at: Thu, 08 Oct 2015 11:09:54 UTC +00:00,
password_digest: "$2a$04$YsvGZ05kdqMoa5fhJlkh1Oa9ISN6wuO7TBCT23vVDS.UO1k.vKTA2",
remember_digest: nil,
admin: false,
activation_digest: "$2a$04$GzFp9Otdlo7l1JBPOTeiQu7NUZELLQSIkLZUd7df1h2p4XpqNXLMm",
activated: true,
activated_at: nil,
reset_digest: nil,
>: nil,
reset_sent_at: nil,
avatar_file_name: nil,
avatar_content_type: nil,
avatar_file_size: nil,
avatar_updated_at: nil,
description: "Corporis odio magni repellendus.",
header_image_file_name: nil,
header_image_content_type: nil,
header_image_file_size: nil,
header_image_updated_at: nil>
[3] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)> user_params
=> {:username=>"username512",
:email=>"user463#factory.com",
:password=>"Password123",
:password_confirmation=>"Password123",
:admin=>false,
:description=>"Nihil eligendi ab debitis iure."}
[4] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)>
here is the User controller
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(
:username,
:email,
:password,
:password_confirmation,
:avatar,
:header_image,
:description
)
end
Here is the complete test
require "rails_helper"
RSpec.describe UsersController, type: :controller do
let!(:admin) { create(:user, password: "Password123", admin: true) }
let!(:user) { create(:user, password: "Password456", admin: false) }
let!(:users) do
[admin, user] + 3.times.map { create(:user) }
end
let!(:user_params) { user_params = { username: "username#{rand(1000)}",
email: "user#{rand(1000)}#factory.com",
password: "Password123",
password_confirmation: "Password123",
admin: false,
description: "Nihil eligendi ab debitis iure.",
} }
let!(:category) { create(:category, name: "Shirt") }
let!(:category1) { create(:category, name: "Short") }
describe "GET #index" do
it "admin user renders template and shows users" do
get :index, {}, { user_id: admin.id }
expect(response).to render_template(:index)
expect(response).to have_http_status(:success)
expect(assigns(:users).map(&:id)).to eq users.map(&:id)
end
it "user renders template and shows users" do
get :index, {}, { user_id: user.id }
expect(response).to redirect_to(root_path)
end
it "redirects visitor" do
get :index
expect(response).to redirect_to(root_path)
end
end
describe "GET #show" do
it "user renders template and shows user" do
get :show, id: user.id
expect(response).to render_template(:show)
expect(response).to have_http_status(:success)
expect(assigns(:user)).to eq(user)
end
end
describe "GET #new" do
it "renders template" do
get :new
expect(response).to render_template(:new)
expect(response).to have_http_status(:success)
end
end
describe "POST #create" do
it "user created" do
post :create, user: user_params
expect(assigns(:user)).to be_persisted
end
end
describe "GET #edit" do
it "user edit" do
get :edit, {id: user.id }, { user_id: user.id }
expect(response).to render_template(:edit)
expect(response).to have_http_status(:success)
expect(assigns(:user)).to eq(user)
end
end
describe "POST #update" do
it "user updated" do
patch :update, {id: user.id }, { user_id: user.id }, user: user_params
expect(response).to redirect_to(assigns(:user))
expect(assigns(:user)).to eq(user)
end
end
describe "DELETE #destroy" do
it "user destroy" do
delete :destroy, {id: user.id }, { user_id: user.id }, user: user_params
expect(response).to redirect_to(users_path)
end
end
end
User controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :update, :edit]
before_action :logged_in_user, only: [:edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:destroy, :index]
def index
#users = User.paginate(page: params[:page])
end
def new
#user = User.new
end
def show
#items = #user.items.paginate(page: params[:page])
end
def show_user_items
#user = User.find(current_user)
#items = #user.items.paginate(page: params[:page])
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_path
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(
:username,
:email,
:password,
:password_confirmation,
:avatar,
:header_image,
:description
)
end
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.try(:admin?)
end
end
Here is my log_in method
def log_in(user)
session[:user_id] = user.id
end
def logged_in?
!current_user.nil?
end
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end

Change this:
patch :update, {id: user.id }, { user_id: user.id }, user: user_params
to this:
patch :update, id: user.id, user: user_params, { user_id: user.id }

Related

NoMethodError:undefined method `employee' for nil:NilClass for RSPEC test Rails

I want to run the rspec of Tickets controllers, I Have used scaffold and I have made some changes according to my project.
but I am getting some errors. I also have a login (using Devise).
How do I go ahead?
This is the controller-
class TicketsController < ApplicationController
before_action :set_ticket, only: %i[ show edit update destroy assign]
before_action :set_assign_ticket, only: %i[assignid]
# shows the landing page of employee
def landing
#tickets = current_user.employee.tickets.order('tstatus_id, id desc')
end
# Service engineer index showing the tickets which are assinged to him
def slanding
#tickets = Ticket.where(service_id: current_user.employee.service_id).order('tstatus_id, id desc')
end
# Showing tickets list based on the user type
def index
#tickets = if current_user.employee.designation.role == "ADMIN"
Ticket.all.order('tstatus_id ,id desc ')
else
Ticket.where(employee: current_user.employee)
end
end
def show
#tickets = Ticket.all
end
def new
#ticket = Ticket.new
end
#creating a new ticket
def create
#ticket = Ticket.new(ticket_params)
#ticket.employee = current_user.employee
respond_to do |format|
if #ticket.save
format.html { redirect_to landing_path}
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
# updating a ticket
def update
respond_to do |format|
if #ticket.update(ticket_params)
if current_user.employee.designation.role == "ADMIN"
format.html { redirect_to tickets_url }
else
format.html { redirect_to slanding_path }
end
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
private
def set_ticket
#ticket = Ticket.where(id: params[:id]).first
end
def ticket_params
params.require(:ticket).permit(:kind, :description, :dev_id, :service_id,:tstatus_id)
end
def set_assign_ticket
#ticket = Ticket.find(params[:id])
end
end
This is the model -
class Ticket < ApplicationRecord
belongs_to :service, optional: true
belongs_to :employee
belongs_to :tstatus
before_validation(on: :create) do
self.service_id = 4 # this will assign the service engineer to NONE
self.tstatus_id = 1 # this will assign the status to logged
end
validates :description, presence: true
end
My test cases are:
require 'rails_helper'
describe TicketsController, type: :controller do
# describe 'GET show' do
it 'gets show based on ID' do
#ticket = Ticket.new(id: 1,kind: "Example Ticket", description: "Ticket#example.com", service_id: 1, employee_id: 1,tstatus_id:1)
get :show, params: { id: #ticket.id }
expect(response.status).to eq(200)
end
# describe 'GET edit' do
it 'has 200 status code' do
get :new
expect(response.status).to eq(200)
end
describe 'POST create' do
it 'has 200 status code' do
mock = double('Employee')
expect(mock).to receive(:employee_id)
post :create, params: {
ticket: {
id: 1,kind: "Example Ticket", description: "Ticket#example.com", service_id: 1, employee_id: 1,tstatus_id:1
}
}
expect(response.status).to eq 302
end
end
end
I am a newbie to rails,
Can someone tell me how to write test cases for the controller above?

How to convert database calls with mocks/doubles, in Rails and Rspec?

I am working on a reminder scheduler and used rails scaffold to create the models and views for the reminder. So far I have the controller looks like this:
class RemindersController < ApplicationController
before_action :set_reminder, only: [:show, :edit, :update, :destroy]
##reminder_hash = {}
##scheduler = Rufus::Scheduler.singleton
def index
#reminders = Reminder.all
end
def new
#reminder = Reminder.new
end
def edit
end
def create
#reminder = Reminder.new(reminder_params)
respond_to do |format|
if #reminder.save
format.html { redirect_to reminders_url, notice: I18n.t('Reminder was successfully created.') }
format.json { render :show, status: :created, location: #reminder }
schedule_reminder #reminder.id, #reminder.reminder_day, #reminder.reminder_time
else
format.html { render :new }
format.json { render json: #reminder.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #reminder.update(reminder_params)
# Unschedule the job.
jobs = ##scheduler.jobs(tag: #reminder.id)
jobs.each { |job| ##scheduler.unschedule(job) }
# Reschedule the job at the new time.
schedule_reminder #reminder.id, #reminder.reminder_day, #reminder.reminder_time
format.html { redirect_to reminders_url, notice: I18n.t('Reminder was successfully updated.') }
format.json { render :show, status: :ok, location: #reminder }
else
format.html { render :edit }
format.json { render json: #reminder.errors, status: :unprocessable_entity }
end
end
end
def destroy
#reminder.destroy
respond_to do |format|
jobs = ##scheduler.jobs(tag: #reminder.id)
jobs.each { |job| ##scheduler.unschedule(job) }
format.html { redirect_to reminders_url, notice: I18n.t('Reminder was successfully destroyed.') }
format.json { head :no_content }
end
end
# Internal: Schedule reminder to be sent at appropriate time.
#
# id - The Reminder id used to uniquely identify the job associated with that reminder.
# reminder day - The day when the reminder will be sent.
# reminder time - The time when the reminder will be sent.
#
# Returns nothing.
def schedule_reminder(tag, reminder_day, reminder_time)
minute = reminder_time.strftime('%M')
hour = reminder_time.strftime('%H')
day = reminder_day[0...3].upcase
cron_string = '0 ' + minute + ' ' + hour + ' * * ' + day
##scheduler.cron cron_string, tag: tag do
EmailController.mentor_reminder_email_sender
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_reminder
#reminder = Reminder.find(params[:id])
end
# Whitelist the paramters.
def reminder_params
params.fetch(:reminder, {}).permit(:reminder_day, :reminder_time)
end
end
The spec looks like this:
require 'rails_helper'
RSpec.describe RemindersController, type: :controller do
let(:valid_attributes) {
{ id: 1, reminder_day: :monday, reminder_time: Time.now}
}
let(:invalid_attributes) {
{ id: nil, reminder_day: nil, reminder_time: nil}
}
let(:valid_session) { {} }
describe 'DELETE #destroy' do
it 'destroys the requested reminder' do
reminder = Reminder.create! valid_attributes
expect {
delete :destroy, {id: reminder.to_param}, valid_session
}.to change(Reminder, :count).by(-1)
end
it 'does not call reminder scheduler function' do
post :create, {reminder: valid_attributes}, valid_session
expect(controller).to_not receive(:schedule_reminder)
end
it 'redirects to the reminders list' do
reminder = Reminder.create! valid_attributes
delete :destroy, {id: reminder.to_param}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
describe '#create' do
let(:reminder) { Reminder.new(id: 1, reminder_day: 1, reminder_time: Time.now) }
let(:reminders_controller) { RemindersController.new }
context 'with valid params' do
before do
allow(controller).to receive(:schedule_reminder)
end
it 'creates a new Reminder' do
expect {
post :create, {reminder: valid_attributes}, valid_session
}.to change(Reminder, :count).by(1)
end
it 'assigns a newly created reminder as #reminder' do
post :create, {reminder: valid_attributes}, valid_session
expect(assigns(:reminder)).to be_a(Reminder)
expect(assigns(:reminder)).to be_persisted
end
it 'calls schedule_reminder with correct parameters' do
expect(reminders_controller).to receive(:schedule_reminder)
.with(reminder.id, reminder.reminder_day, reminder.reminder_time)
reminders_controller.schedule_reminder(reminder.id, reminder.reminder_day, reminder.reminder_time)
end
end
context 'with invalid params' do
it 'assigns a newly created but unsaved reminder as #reminder' do
post :create, {reminder: invalid_attributes}, valid_session
expect(assigns(:reminder)).to be_a_new(Reminder)
end
it 're-renders the "new" template' do
post :create, {reminder: invalid_attributes}, valid_session
expect(response).to render_template('new')
end
it 'does not call schedule_reminder' do
expect(controller).to_not receive(:schedule_reminder)
end
end
end
describe 'PUT #update' do
context 'with valid params' do
let(:new_attributes) {
{ id: 2, reminder_day: :tuesday, reminder_time: Time.now}
}
let(:reminders_controller) { RemindersController.new }
let(:reminder) { Reminder.new(id: 1, reminder_day: 1, reminder_time: Time.now) }
it 'updates the requested reminder' do
reminder = Reminder.create! valid_attributes
put :update, { id: reminder.to_param, reminder: new_attributes}, valid_session
reminder.reload
end
it 'calls reminder scheduler function with correct parameters' do
post :create, {reminder: valid_attributes}, valid_session
expect(reminders_controller).to receive(:schedule_reminder)
.with(reminder.id, reminder.reminder_day, reminder.reminder_time)
reminders_controller.schedule_reminder(reminder.id, reminder.reminder_day, reminder.reminder_time)
end
it 'assigns the requested reminder as #reminder' do
reminder = Reminder.create! valid_attributes
put :update, { id: reminder.to_param, reminder: valid_attributes}, valid_session
expect(assigns(:reminder)).to eq(reminder)
end
it 'redirects to the reminder' do
reminder = Reminder.create! valid_attributes
put :update, { id: reminder.to_param, reminder: valid_attributes}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
context 'with invalid params' do
it 'assigns the reminder as #reminder' do
reminder = Reminder.create! valid_attributes
put :update, {id: reminder.to_param, reminder: invalid_attributes}, valid_session
expect(assigns(:reminder)).to eq(reminder)
end
it 're-renders the "edit" template' do
reminder = Reminder.create! valid_attributes
put :update, {id: reminder.to_param, reminder: invalid_attributes}, valid_session
expect(response).to render_template('edit')
end
it 'does not call schedule_reminder' do
expect(controller).to_not receive(:schedule_reminder)
end
end
end
describe 'GET #index' do
it 'assigns all reminders as #reminders' do
reminder = Reminder.create! valid_attributes
get :index, {}, valid_session
expect(assigns(:reminders)).to eq([reminder])
end
end
describe 'GET #new' do
it 'assigns a new reminder as #reminder' do
get :new, {}, valid_session
expect(assigns(:reminder)).to be_a_new(Reminder)
end
end
describe 'GET #edit' do
context 'when reminder is found' do
it 'assigns the requested reminder as #reminder' do
reminder = Reminder.create! valid_attributes
get :edit, {id: reminder.to_param}, valid_session
expect(assigns(:reminder)).to eq(reminder)
end
end
context 'when reminder is not found' do
it 're-renders the "edit" template' do
reminder = Reminder.create! valid_attributes
put :update, {id: reminder.to_param, reminder: invalid_attributes}, valid_session
expect(response).to render_template('edit')
end
end
end
end
I am trying to replace all the create statements with a mock/double to eliminate database calls. I have tried replacing all create statements with this:
reminder = double('Reminder', id: 1, reminder_day: :monday, reminder_time: Time.now)
and other variations.
I replaced this :
describe 'DELETE #destroy' do
it 'destroys the requested reminder' do
reminder = Reminder.create! valid_attributes
expect {
delete :destroy, {id: reminder.to_param}, valid_session
}.to change(Reminder, :count).by(-1)
end
it 'does not call reminder scheduler function' do
post :create, {reminder: valid_attributes}, valid_session
expect(controller).to_not receive(:schedule_reminder)
end
it 'redirects to the reminders list' do
reminder = Reminder.create! valid_attributes
delete :destroy, {id: reminder.to_param}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
with this:
describe 'DELETE #destroy' do
let(:reminder){double('Reminder', id: 1, reminder_day: :monday, reminder_time: Time.now)}
before do
allow(Reminder).to receive(:create).and_return(reminder)
end
it 'destroys the requested reminder' do
reminder = Reminder.create
expect {
delete :destroy, {id: reminder.to_param}, valid_session
}.to change(Reminder, :count).by(-1)
end
it 'does not call reminder scheduler function' do
post :create, {reminder: valid_attributes}, valid_session
expect(controller).to_not receive(:schedule_reminder)
end
it 'redirects to the reminders list' do
reminder = Reminder.create
delete :destroy, {id: reminder.to_param}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
I'm getting these errors:
Failure/Error: expect(response).to redirect_to(reminders_path)
Expected response to be a , but was <404>
Failure/Error: expect {
expected #count to have changed by -1, but was changed by 0

Failure/Error: specify { expect(response).to redirect_to(root_url) }

I can not understand, why not pass the tests, it performs the first redirect and not the second, as described in the controller code itself works correctly, redirections occur exactly as described.
Rspec 3.5.1
Rails 5
Ruby 2.3.1
spec/features/authentication_pages_spec.rb
describe "autorization", type: :request do
describe "for non-signed-in users" do
let(:user) { FactoryGirl.create(:user) }
describe "in the Users controller" do
describe "visiting the edit page" do
before { visit edit_user_path(user) }
it { should have_title('Log in') }
end
describe "submitting to the update action" do
before { patch user_path(user) }
specify { expect(response).to redirect_to(login_path) }
end
end
end
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { log_in user, no_capybara: true }
describe "submitting a GET request to the Users#edit action" do
before { get edit_user_path(wrong_user) }
specify { expect(response.body).not_to match(full_title('Edit user')) }
specify { expect(response).to redirect_to(root_url) }
end
describe "submitting a PATCH request to the User#update action" do
before { patch user_path(wrong_user) }
specify { expect(response).to redirect_to(root_url) }
end
end
end
end
The test fails with the following error:
1) AuthenticationPages autorization as wrong user submitting a GET request to the Users#edit action should redirect to "http://www.example.com/"
Failure/Error: specify { expect(response).to redirect_to(root_url) }
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/login>.
Expected "http://www.example.com/" to be === "http://www.example.com/login".
2) AuthenticationPages autorization as wrong user submitting a PATCH request to the User#update action should redirect to "http://www.example.com/"
Failure/Error: specify { expect(response).to redirect_to(root_url) }
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/login>.
Expected "http://www.example.com/" to be === "http://www.example.com/login".
I cannot fathom why it's redirecting to the signin url when it should redirect to the root url - the user is signed in in the spec.
Here is the UserController:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# Before filters
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in."
redirect_to login_url
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
Here are the relevant bits of my sessions_helper.rb file:
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
# Returns the current logged-in user (if any).
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(id: session[:user_id])
end
def current_user?(user)
user == current_user
end
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
def log_out
session.delete(:user_id)
#current_user = nil
end
end
User class:
class User < ApplicationRecord
has_secure_password
before_save { self.email = email.downcase }
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.encrypt(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.encrypt(User.new_remember_token)
end
end
spec/support/utilities.rb
include ApplicationHelper
def valid_login(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
end
RSpec::Matchers.define :have_error_message do |message|
match do |page|
expect(page).to have_selector('div.alert.alert-error', text: message)
end
end
def log_in(user, options={})
if options[:no_capybara]
# Sign in when not using Capybara.
remember_token = User.new_remember_token
cookies[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
else
visit login_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
end
end
I suspect your issue is related to
before { log_in user, no_capybara: true }
try changing it to
before { session[:user_id] = user.id }
The problem is with your log_in method (in the spec, not the helper code), which is not actually logging anybody in. That's why you hit the login error. You mention that this code "creates a user with a different email address from the default", but this is not what it should be doing; it should be setting the session.
Simply creating a user will not set the session, and without the session being set, logged_in? will be false and you will get redirected to the login page.
Try something like this instead:
before { #request.session[:user_id] = user.id }
This sets the session explicitly on the request to the user'd id, so that logged_in? will return true in your controller.

Why does my rspec test fail?

I have problem with my "POST create" action. Test passed successfully, when attributes are valid, but when they are invalid, player is also saved. It's strange because, only :invalid_player, can be saved with invalid attributes. If I change for example, wins to -1 or "string", player with attributes :invalid_player is saved. But if I change attributes for :player, like wins = -1, validators prevent player, from being saved.
Console output with error message:
Failures:
1) PlayersController user is signed in POST create with invalid attributes does not save the new player
Failure/Error:
expect{
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:invalid_player) }
}.to_not change(Player, :count)
expected #count not to have changed, but did change from 1 to 2
# ./spec/controllers/players_controller_spec.rb:111:in `block (5 levels) in <top (required)>'
This is my Player model:
class Player < ActiveRecord::Base
belongs_to :user
belongs_to :tournament
validates :wins, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :loses, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :draws, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
end
Factory file for players:
FactoryGirl.define do
factory :player do
wins 0
loses 0
draws 0
end
factory :invalid_player, parent: :player do
wins -1
loses 0
draws 0
end
end
Spec test:
context "user is signed in" do
before do
#tournament = create(:tournament)
#player = create(:player)
#user = create(:user)
#request.env["devise.mapping"] = Devise.mappings[:user]
sign_in(#user)
controller.stub(:current_user).and_return(#user)
end
describe "GET new" do
end
describe "GET index" do
it "renders the :index view" do
get :index, tournament_id: #tournament
expect(response).to render_template :index
end
end
describe "GET show" do
it "renders the :show view" do
get :show, { id: #player, tournament_id: #tournament }
expect(response).to render_template :show
end
end
describe "POST create" do
context "with valid attributes" do
it "creates a new player" do
expect{
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:player) }
}.to change(Player,:count).by(1)
end
it "redirects to the tournament" do
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:player) }
expect(response).to redirect_to #tournament
end
end
context "with invalid attributes" do
it "does not save the new player" do
expect{
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:invalid_player) }
}.to_not change(Player, :count)
end
it 're-renders the new method' do
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:invalid_player) }
response.should render_template :new
end
end
end
end
Controller:
class PlayersController < ApplicationController
before_action :set_tournament
before_action :set_admin, only: [:edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
def index
#players = #tournament.players.all
end
def show
#player = Player.find(params[:id])
end
def new
#player = #tournament.players.new
end
def create
if current_user.player.nil? == false
flash[:error] = "You're already in tournament."
redirect_to tournaments_url
else
#player = #tournament.players.new
#player.user_id = current_user.id
if #player.save
redirect_to #tournament
else
render 'new'
end
end
end
def edit
if current_user == #admin
#player = #tournament.players.find(params[:id])
else
redirect_to tournaments_url
end
end
def update
if current_user == #admin
#player = #tournament.players.find(params[:id])
if #player.update_attributes(game_params)
flash[:success] = "Player was updated successful"
redirect_to #tournament
end
else
redirect_to tournaments_url
end
end
def destroy
#player = Player.find(params[:id])
flash[:success] = "Player deleted"
redirect_to #tournament
end
private
def set_tournament
#tournament = Tournament.find(params[:tournament_id])
end
def set_admin
#tournament = Tournament.find(params[:tournament_id])
#admin = #tournament.user
end
end
You are not assigning any attributes to your model in your create method. You need to do the following (I assume it's rails 4):
#player = #tournament.players.new(player_params)
#...
private
def player_params
params.require(:player).permit(:wins, :loses, :draws)
end
Without any assignment you most likely falling back onto database default value of zero, which is valid.

expecting <"index"> but render with <[]>

I'm having problems to pass a test in rails with rspec. This is what console tells me when I ran the tests.
The fail is ControlsController GET index logged in renders the index template
Failure/Error: expect(response). to render_template(:index)
expecting <"index"> but rendering with <[]>
And this is my code
require "rails_helper"
RSpec.describe ControlsController, :type => :controller do
render_views
describe "GET index" do
let(:user) {
FactoryGirl.create(:user)
}
let(:control) {
FactoryGirl.create(:control, user: user)
}
context "logged in" do
before :each do
sign_in :user, user
end
it "loads all controls into #controls" do
get :index, { user_id: user.id}
expect(assigns(:controls)).to eq([control])
end
it "assigns a new control to #control" do
get :index, { user_id: user.id}
expect(assigns(:control)).to be_a_new(Control)
end
it "renders the index template" do
get :index, { user_id: user.id}
expect(response). to render_template(:index)
end
it "a user can't see the controls from other user" do
new_user = User.create(name: "Juan",
email: "juan#gmail.com",
password: "123456789",
password_confirmation: "123456789")
get :index, { user_id: new_user.id}
expect(response).to redirect_to root_path
end
class ControlsController < ApplicationController
before_action :authenticate_user!
def index
#user= current_user
#control= Control.new
# #control_last = Control.lastcontrol (current_user.id)
# #controls_average = Control.controls_average (current_user.id)
# #controls_average_day = Control.controls_day_average (current_user.id)
#controls = Control.all
if params[:user_id] != current_user.id
redirect_to root_path
end
end
The answer is to make a private method and redirect_to user_controls_path current_user.name
This is the new code of the controller
controlsController.rb
class ControlsController < ApplicationController
before_action :authenticate_user!
before_action :redirect_if_not_current_user, only: :index
private
def control_params
params.require(:control).permit(:level, :period, :day)
end
def redirect_if_not_current_user
if params[:user_id] != current_user.name
redirect_to user_controls_path current_user.name
end
end

Resources