lundi 19 janvier 2015

RSpec Controller tests fail for POST create

My program functions as expected, but there are problems in my RSpec controller test code. I need help troubleshooting the specs, which were created when I ran the scaffold generator. There are three "POST create with valid params" failures:



POST create
with valid params
creates a new Appointment (FAILED - 1)
assigns a newly created appointment as @appointment (FAILED - 2)
redirects to the created appointment (FAILED - 3)

Failures:

1) AppointmentsController POST create with valid params creates a new Appointment
Failure/Error: expect {
expected #count to have changed by 1, but was changed by 0
# ./spec/controllers/appointments_controller_spec.rb:90:in `block (4 levels) in <top (required)>'

2) AppointmentsController POST create with valid params assigns a newly created appointment as @appointment
Failure/Error: expect(assigns(:appointment)).to be_persisted
expected `#<Appointment id: nil, member_id: nil, trainer_id: nil, created_at: nil, updated_at: nil, date: "2020-01-02", starts_at: "2000-01-01 08:00:00", ends_at: "2000-01-01 09:00:00">.persisted?` to return true, got false
# ./spec/controllers/appointments_controller_spec.rb:99:in `block (4 levels) in <top (required)>'

3) AppointmentsController POST create with valid params redirects to the created appointment
Failure/Error: expect(response).to redirect_to(Appointment.last)
Expected response to be a <redirect>, but was <200>
# ./spec/controllers/appointments_controller_spec.rb:104:in `block (4 levels) in <top (required)>'


In the second failure, I notice there are nil values for appointment id, member and trainer, although I have valid factories for member and trainer. Tests for my member and trainer factories pass, and they work as expected. I assume the problem must be caused by the way I set up the "valid attributes" hash in the Controller spec, but I don't know what's wrong. Why are the POST create tests failing? What do I need to do to get them to pass?


Here's the code for the Appointments Controller:



require 'rails_helper'


RSpec.describe AppointmentsController, :type => :controller do

let(:valid_attributes) { {
'date' => '2020-01-02',
'starts_at' => '08:00:00',
'ends_at' => '09:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}


}



let(:invalid_attributes) { {
'date' => '2000-01-02',
'starts_at' => '06:00:00',
'ends_at' => '09:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}

let(:valid_session) { {
'date' => '2020-12-30',
'starts_at' => '15:00:00',
'ends_at' => '17:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}

describe "GET index" do
it "assigns all appointments as @appointments" do
appointment = Appointment.create! valid_attributes
get :index, {}, valid_session
expect(assigns(:appointments)).to eq([appointment])
end
end

describe "GET show" do
it "assigns the requested appointment as @appointment" do
appointment = Appointment.create! valid_attributes
get :show, {:id => appointment.to_param}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end
end

describe "GET new" do
it "assigns a new appointment as @appointment" do
get :new, {}, valid_session
expect(assigns(:appointment)).to be_a_new(Appointment)
end
end

describe "GET edit" do
it "assigns the requested appointment as @appointment" do
appointment = Appointment.create! valid_attributes
get :edit, {:id => appointment.to_param}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end
end

describe "POST create" do
describe "with valid params" do
it "creates a new Appointment" do
expect {
post :create, {:appointment => valid_attributes}, valid_session
}.to change(Appointment, :count).by(1)
save_and_open_page
end

it "assigns a newly created appointment as @appointment" do
post :create, {:appointment => valid_attributes}, valid_session
expect(assigns(:appointment)).to be_a(Appointment)
expect(assigns(:appointment)).to be_persisted
end

it "redirects to the created appointment" do
post :create, {:appointment => valid_attributes}, valid_session
expect(response).to redirect_to(Appointment.last)
end
end

describe "with invalid params" do
it "assigns a newly created but unsaved appointment as @appointment" do
post :create, {:appointment => invalid_attributes}, valid_session
expect(assigns(:appointment)).to be_a_new(Appointment)
end

it "re-renders the 'new' template" do
post :create, {:appointment => invalid_attributes}, valid_session
expect(response).to render_template("new")
end
end
end

describe "PUT update" do
describe "with valid params" do
let(:new_attributes) { {
'date' => '2020-01-02',
'starts_at' => '10:00:00',
'ends_at' => '12:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}

let(:invalid_attributes) { {
'date' => '2005-03-15',
'starts_at' => '04:00:00',
'ends_at' => '09:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}

it "updates the requested appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => new_attributes}, valid_session
appointment.reload
expect(controller.notice).to eq('Appointment was successfully updated.')
end

it "assigns the requested appointment as @appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => valid_attributes}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end

it "redirects to the appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => valid_attributes}, valid_session
expect(response).to redirect_to(appointment)
end
end

describe "with invalid params" do
it "assigns the appointment as @appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => invalid_attributes}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end

it "re-renders the 'edit' template" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => invalid_attributes}, valid_session
expect(response).to render_template("edit")
end
end
end

describe "DELETE destroy" do
it "destroys the requested appointment" do
appointment = Appointment.create! valid_attributes
expect {
delete :destroy, {:id => appointment.to_param}, valid_session
}.to change(Appointment, :count).by(-1)
end

it "redirects to the appointments list" do
appointment = Appointment.create! valid_attributes
delete :destroy, {:id => appointment.to_param}, valid_session
expect(response).to redirect_to(appointments_url)
end
end
end


The code for the Appointment Model:



class Appointment < ActiveRecord::Base

belongs_to :member
belongs_to :trainer

validates_date :date, :on => :create, :on_or_after => :today

validates_time :starts_at, :between => ['06:30', '21:00']
validates_time :starts_at, :after => :now, :if => :today_appointment #scopes validation to current day only
validates_time :ends_at, :after => :starts_at

validate :duration_of_appointment

validates :member, :trainer, presence: true

validates :starts_at, :ends_at, :overlap => {
:exclude_edges => ["starts_at", "ends_at"],
:scope => "date",
:scope => "starts_at",
:scope => "trainer_id"
}

validates :starts_at, :ends_at, :overlap => {
:exclude_edges => ["starts_at", "ends_at"],
:scope => "member_id"
}


private

def today_appointment
Date.current == self.date
end


def duration_of_appointment
length = (ends_at - starts_at) / 60
return if length.between?(30, 120) # stops validation if length falls between the two integers
errors.add(:base, 'Duration must be between 30 and 120 minutes')
end
end

Aucun commentaire:

Enregistrer un commentaire