I need to run some tests and I have come at a stand still here.
I am using before_action in my Appointments controller
Here is the controller
class AppointmentsController < ApplicationController
before_action :set_appointment, only: %i[ show edit update destroy ]
#before we run anything if the user is not signed in show index and show functions
before_action :authenticate_user!, except: [:index,:show]
#only the correct user can edit,update and destroy
before_action :correct_user, only: [:edit, :update , :destroy]
# GET /appointments or /appointments.json
def index
@appointments = Appointment.all.decorate
end
# GET /appointments/1 or /appointments/1.json
def show
end
# GET /appointments/new
def new
#@appointment = Appointment.new
@appointment = current_user.appointments.build
end
# GET /appointments/1/edit
def edit
end
#function to allow for search functionality
def search
@appointments = Appointment.where("date LIKE?", "%" params[:q] "%")
end
# POST /appointments or /appointments.json
def create
#@appointment = Appointment.new(appointment_params)
@appointment = current_user.appointments.build(appointment_params)
#here underneath I am using my custom gem to filter bad words within the notes field when creating an appointment
@appointment.notes = Badwordgem::Base.sanitize(@appointment.notes)
respond_to do |format|
if @appointment.save
format.html { redirect_to appointment_url(@appointment), notice: "Appointment was successfully created." }
format.json { render :show, status: :created, location: @appointment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @appointment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /appointments/1 or /appointments/1.json
def update
respond_to do |format|
if @appointment.update(appointment_params)
format.html { redirect_to appointment_url(@appointment), notice: "Appointment was successfully updated." }
format.json { render :show, status: :ok, location: @appointment }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @appointment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /appointments/1 or /appointments/1.json
def destroy
@appointment.destroy
respond_to do |format|
format.html { redirect_to appointments_url, notice: "Appointment was successfully destroyed." }
format.json { head :no_content }
end
end
#function here that restricts editing so the current logged in user can edit only their records
def correct_user
@appointment = current_user.appointments.find_by(id: params[:id])
redirect_to appointments_path, notice:"NOT ALLOWED TO EDIT THIS" if @appointment.nil?
end
private
# Use callbacks to share common setup or constraints between actions.
def set_appointment
@appointment = Appointment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def appointment_params
params.require(:appointment).permit(:barber, :customer, :notes, :date,:user_id)
end
end
and here is my test controller
require "test_helper"
class AppointmentsControllerTest < ActionDispatch::IntegrationTest
Devise::Test::IntegrationHelpers
setup do
@appointment = appointments(:one)
end
test "should get index" do
get appointments_url
assert_response :success
end
test "should get new" do
get new_appointment_url
assert_response :success
end
test "should create appointment" do
assert_difference('Appointment.count') do
post appointments_url, params: { appointment: { barber: @appointment.barber, customer: @appointment.customer, date: @appointment.date, notes: @appointment.notes } }
end
assert_redirected_to appointment_url(Appointment.last)
end
test "should show appointment" do
get appointment_url(@appointment)
assert_response :success
end
test "should get edit" do
get edit_appointment_url(@appointment)
assert_response :success
end
test "should update appointment" do
patch appointment_url(@appointment), params: { appointment: { barber: @appointment.barber, customer: @appointment.customer, date: @appointment.date, notes: @appointment.notes } }
assert_redirected_to appointment_url(@appointment)
end
test "should destroy appointment" do
assert_difference('Appointment.count', -1) do
delete appointment_url(@appointment)
end
assert_redirected_to appointments_url
end
end
If I comment out the "before actions" in my controller , of course all the tests pass but with them 15 tests fail. How do I make the tests pass with the before_action ?
CodePudding user response:
Just need to set up devise helpers properly. https://github.com/heartcombo/devise#integration-tests
In general you have to set up your requests and your models according to what the controller expects.
For before_action :authenticate_user!
user must be authenticated; have a current session during the test, i.e. a particular cookie must be set or whatever the authentication mechanism expects. This is taken care of by device sign_in
helper. When signed in the current_user
helper will return a user model instance.
For before_action :correct_user
user must be authorized to access a resource. This depends on the logic of correct_user
method—appointment has to belong to the current user. Set this up in a test or in fixtures.
# test/controllers/appointments_controller_test.rb
require "test_helper"
class AppointmentsControllerTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
setup do
@appointment = appointments(:one)
@user = users(:user)
# assign appointment to user to pass :edit, :update, :destroy actions
# TODO: do this in fixtures/factories
@user.appointments << @appointment
sign_in @user
# NOTE: how to sign out
# sign_out @user
# or
# sign_out :user
end
# ...
end
Add a user fixture. Don't use password
attribute, it doesn't exist in the database.
# test/fixtures/users.yml
user:
email: [email protected]
encrypted_password: doesnt-matter
# NOTE: if you need to know the password
# encrypted_password: <%= Devise::Encryptor.digest(User, 'password') %>
CodePudding user response:
I think that the first before_action don't cause problems. I am right? So for the second you need to authenticate a user and send the token or cookie with the request for pass the before_action ":authenticate_user!" and check if the user you authenticate has the right access for pass ":correct_user".
I can see you are using Devise for your authentication methods, so you can use the sign_in method for a user created on your fixtures. The docs here