Reputation: 5251
It is super simple, yet I can't figure out how to make the test pass.
I have a friendships
controller that I wanted to test (I am building Rails app similar to this railscast). It works on localhost. This is the test that I created. POST #create
passed.
require 'rails_helper'
RSpec.describe FriendshipsController, type: :controller do
login_user
before :each do
@friend1 = FactoryGirl.create(:user)
end
describe "POST #Create" do
it "adds new friend" do
expect {
post :create, params: { friend_id: @friend1.id}
}.to change(Friendship, :count).by(1)
end
end
describe "DELETE #destroy" do
it "removes a friend =(" do
expect {
delete :destroy, id: @friend1.id
}.to change(Friendship, :count).by(1)
end
end
end
This is the actual controller:
class FriendshipsController < ApplicationController
def create
@friendship = current_user.friendships.build(friend_id: params[:friend_id])
if @friendship.save
flash[:notice] = "New friend added!"
redirect_to root_url
else
flash[:error] = "Error adding friend"
redirect_to root_url
end
end
def destroy
@friendship = current_user.friendships.find(params[:id])
@friendship.destroy
flash[:notice] = "Remove friendship"
redirect_to current_user
end
end
I also made sure that routes.rb
have Friendships: resources :friendships
The problem I am having is to pass the ID.I can't figure out how to pass the id
params. I think it has something to do with my factory...?
1) FriendshipsController DELETE #destroy removes a friend =(
Failure/Error: @friendship = current_user.friendships.find(params[:id])
ActiveRecord::RecordNotFound:
Couldn't find Friendship with 'id'=159 [WHERE "friendships"."user_id" = $1]
I search for other SO destroy
related posts, like this one, this, but they are different case from mine.
How can I pass down ID params for my destroy action?
EDIT: (Source)
module ControllerMacros
def login_user
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
#user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the "confirmable" module
sign_in user
end
end
end
As suggested by answer below, I did:
describe "DELETE #destroy" do
it "removes a friend =(" do
friendship = user.friendships.create!(friend_id: @friend1.id)
expect {
delete :destroy, id: friendship.id
}.to change(Friendship, :count).by(1)
end
end
But it is now returning this error:
FriendshipsController DELETE #destroy removes a friend =(
Failure/Error: friendship = user.friendships.create!(friend_id: @friend1.id)
NameError:
undefined local variable or method `user' for #<RSpec::ExampleGroups::FriendshipsController::DELETEDestroy:0x007fee1ce68c70>
Upvotes: 0
Views: 951
Reputation: 3984
As you're looking for the friendship, not the user in the controller, you need to create the friendship first. Before that you also need to know the user to be logged in. Try sending that first:
module ControllerMacros
def login_user(user)
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
user ||= FactoryGirl.create(:user)
sign_in user
end
end
end
Now the test would look something like this:
let(:current_user) { FactoryGirl.create(:user) }
login_user(current_user)
describe "DELETE #destroy" do
it "removes a friend =(" do
friendship = current_user.friendships.create!(friend_id: @friend1.id)
expect {
delete :destroy, id: friendship.id
}.to change(Friendship, :count).by(1)
end
end
You should be good to go now.
Upvotes: 1