I have a callback in my user.rb model something like:
class User
include Mongoid::Document
include Mongoid::Timestamps::Created
.
.
.
.
#add a first board for user
after_create :first_board
def first_board
board = self.boards.new(:title => self.username, :category_id => Category.find_or_create_by(slug: "other"))
board.save!
end
end
When a user is created, the app create a new board with above callback.
In my spec/factories/users.rb I have:
FactoryGirl.define do
factory :user do
name 'Test User'
username 'test username'
password 'please'
password_confirmation 'please'
# required if the Devise Confirmable module is used
confirmed_at Time.now
end
end
In my spec/controllers/users_controller_spec.rb I have:
require 'spec_helper'
describe UsersController do
before :each do
request.env['devise.mapping'] = Devise.mappings[:user]
end
include Devise::TestHelpers
before (:each) do
#user = FactoryGirl.create(:user)
sign_in #user
end
describe "GET 'show'" do
it "should be successful" do
get :show, :id => #user.id
response.should be_success
end
it "should find the right user" do
get :show, :id => #user.slug
assigns(:user).should == #user
end
end
end
How can I run my callback with factorygirl?
I get 2 errors:
Failures:
1) UsersController GET 'show' should be successful
Failure/Error: #user = FactoryGirl.create(:user)
Errno::ECONNREFUSED:
Connection refused - connect(2)
# (eval):2:in `post'
# ./app/models/user.rb:190:in `first_board'
# ./spec/controllers/users_controller_spec.rb:10:in `block (2 levels) in <top (required)>'
2) UsersController GET 'show' should find the right user
Failure/Error: #user = FactoryGirl.create(:user)
Errno::ECONNREFUSED:
Connection refused - connect(2)
# (eval):2:in `post'
# ./app/models/user.rb:190:in `first_board'
# ./spec/controllers/users_controller_spec.rb:10:in `block (2 levels) in <top (required)>'
The find_or_create_by method can't be called like that, afaik. It uses method_missing and expects an activerecord attribute tacked on the end. Try:
Category.find_or_create_by_slug("other")
Related
I am trying to validate that the current_user's organization matches that of the organization they are trying to view.
Here's the part of the controller that's failing this test (#organization is being defined in an earlier method):
if current_user.organization != #organization
redirect_to root_path, notice: "Not authorized to edit this organization"
end
Here's the failing test:
require 'rails_helper'
RSpec.describe Admin::PagesController, :type => :controller do
describe 'GET #home' do
login_user
before do
#organization = FactoryGirl.create(:organization)
end
context "valid params" do
it "renders the home template and returns http 200" do
get :home, name: #organization.name
expect(response).to render_template("home")
expect(response.status).to eq(200)
end
end
end
Here's my factory:
factory :user do
email { Faker::Internet.email }
organization_id 1
password "foobarfoobar"
password_confirmation { |u| u.password }
end
...And here's where login_user is being defined:
module ControllerMacros
def login_user
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
Stacktrace:
1) Admin::PagesController GET #home valid params renders the home template and returns http 200
Failure/Error: it "renders the home template and returns http 200" do
expecting <"home"> but rendering with <[]>
# ./spec/controllers/admin/pages_controller_spec.rb:15:in `block (4 levels) in <top (required)>'
However:
[2] pry(#<RSpec::ExampleGroups::AdminPagesController::GETHome::ValidParams>)> subject.current_user.organization == #organization
=> true
Not sure what is going wrong here, seems like pretty standard stuff. Any ideas?
Turns out the issue was that I was sending in the wrong parameter - should have been sending #organization.subdomain, not #organization.name. :(
I'm currently doing rspec testing on two files and I got these failures regarding undefined methods. I need more calcification on how to exactly fixes these errors,Thanks!
Failures:
1) FavoritesController#create creates a favorite for the current user and specified post
Failure/Error: #post = create(:post)
NoMethodError:
undefined method `create' for #<RSpec::ExampleGroups::FavoritesController::Create:0x007fdabc84f7f8>
# /Users/bryanporras/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/testing/assertions/routing.rb:171:in `method_missing'
# ./spec/controllers/favorites_controller_spec.rb:8:in `block (2 levels) in <top (required)>'
2) FavoritesController#destroy destroys the favorite for the current user and post
Failure/Error: #post = create(:post)
NoMethodError:
undefined method `create' for #<RSpec::ExampleGroups::FavoritesController::Destroy:0x007fdabfe0f3e8>
# /Users/bryanporras/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/testing/assertions/routing.rb:171:in `method_missing'
# ./spec/controllers/favorites_controller_spec.rb:8:in `block (2 levels) in <top (required)>'
3) VotesController#up_vote adds an up-vote to the post
Failure/Error: sign_in #user
NoMethodError:
undefined method `sign_in' for #<RSpec::ExampleGroups::VotesController::UpVote:0x007fdabfe26fe8>
# /Users/bryanporras/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/testing/assertions/routing.rb:171:in `method_missing'
# ./spec/controllers/votes_controller_spec.rb:12:in `block (3 levels) in <top (required)>'
4) Vote after_save calls `Post#update_rank` after save
Failure/Error: vote = Vote.new(value: 1, post: post)
NameError:
undefined local variable or method `post' for #<RSpec::ExampleGroups::Vote::AfterSave:0x007fdabdb8b0b0>
# ./spec/models/vote_spec.rb:25:in `block (3 levels) in <top (required)>'
Finished in 0.78639 seconds (files took 2.82 seconds to load)
15 examples, 4 failures, 2 pending
Failed examples:
rspec ./spec/controllers/favorites_controller_spec.rb:14 # FavoritesController#create creates a favorite for the current user and specified post
rspec ./spec/controllers/favorites_controller_spec.rb:24 # FavoritesController#destroy destroys the favorite for the current user and post
rspec ./spec/controllers/votes_controller_spec.rb:8 # VotesController#up_vote adds an up-vote to the post
rspec ./spec/models/vote_spec.rb:24 # Vote after_save calls `Post#update_rank` after save
This is the favorites_controller_spec.rb file:
require 'rails_helper'
describe FavoritesController do
include Devise::TestHelpers
before do
#post = create(:post)
#user = create(:user)
sign_in #user
end
describe '#create' do
it "creates a favorite for the current user and specified post" do
expect( #user.favorites.find_by(post_id: #post.id) ).to be_nil
post :create, { post_id: #post.id }
expect( #user.favorites.find_by(post_id: #post.id) ).not_to be_nil
end
end
describe '#destroy' do
it "destroys the favorite for the current user and post" do
favorite = #user.favorites.where(post: #post).create
expect( #user.favorites.find_by(post_id: #post.id) ).not_to be_nil
delete :destroy, { post_id: #post.id, id: favorite.id }
expect( #user.favorites.find_by(post_id: #post.id) ).to be_nil
end
end
end
and this is the votes_controller_spec.rb file:
require 'rails_helper'
describe VotesController do
include TestFactories
describe '#up_vote' do
it "adds an up-vote to the post" do
request.env["HTTP_REFERER"] = '/'
#user = authenticated_user
#post = associated_post
sign_in #user
expect {
post( :up_vote, post_id: #post.id )
}.to change{ #post.up_votes }.by 1
end
end
end
Check if you have config.include FactoryGirl::Syntax::Methods inside rails_helper.rb
If you have above line in rails_helper.rb file you can always use FactoryGirl.create :user
You didn't probably include include Devise::TestHelpers in specs for VotesController that's why it does not see sign_in method
I'm having problems with FactoryGirl, I'm using sequence to avoid duplicating fields, but validations are failing anyway.
Output:
1) CustomersController anonymous user GET #edit is redirected to signin when accessing edit form
Failure/Error: get :edit, id: create(:customer)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken, Email has already been taken
# ./spec/controllers/customers_controller_spec.rb:25:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
3) Customer public class methods executes its methods correctly #find_by_id_or_name finds customer by name
Failure/Error: let(:john) {create(:customer, name: 'John Doe X')}
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken, Email has already been taken
# ./spec/models/customer_spec.rb:25:in `block (3 levels) in <top (required)>'
# ./spec/models/customer_spec.rb:38:in `block (5 levels) in <top (required)>'
# -e:1:in `<main>'
Factories:
FactoryGirl.define do
factory :customer do
user
name {Faker::Name.name}
sequence(:mail) { |n| "person#{n}#example.com" }
address {Faker::Address.street_address}
phone {Faker::PhoneNumber.phone_number}
end
end
FactoryGirl.define do
factory :user do
sequence(:email) {|i| "example#{i}#example.com"}
password {Faker::Internet.password(10)}
end
end
These are the tests that are failing:
RSpec.describe Customer, type: :model do
describe "public class methods" do
let(:john) {create(:customer, name: 'John Doe X')}
let(:frank) {create(:customer)}
context "responds to its methods" do
it "responds to #find_by_id_or_name" do
expect(Customer).to respond_to(:find_by_id_or_name)
end
end
context "executes its methods correctly" do
context "#find_by_id_or_name" do
it "finds customer by name" do
customer = Customer.find_by_id_or_name('John Doe X')
expect(customer).to eq john
end
it "finds customer by id" do
customer = Customer.find_by_id_or_name(frank.id)
expect(customer).to eq frank
end
end
end
end
end
RSpec.describe CustomersController, type: :controller do
context "signed in user" do
before :each do
#user = create(:user)
end
describe "GET #edit" do
it "renders :edit view" do
get :edit, id: create(:customer).id
expect(response).to render_template(:edit)
end
end
describe "DELETE #destroy" do
before :each do
#customer = create(:customer, user: #user)
end
it "deletes record" do
expect {delete :destroy, id: #customer.id}.to change(Customer, :count).by(-1)
end
end
end
end
This is happening to me all over my app. I just copied some tests that apply to Customer.
Thanks
My problem was related to not appropiately configuring database_cleaner. The configuration in this post solves the problem: How can I clean my database between erroneous rspec specs?
I'm trying to create a controller spec for a contact form. All I want is to test that the :new template is rendered when invalid attributes are submitted. I've tried various configurations of the factory, as well as changing it to a trait, instead of factory to no avail. The error message doesn't get very specific, just Invalid Factory. Any ideas would be appreciated!
# blog_app/spec/factories/inquiries.rb
FactoryGirl.define do
factory :inquiry do
name "TestName"
email "test#test.com"
phone "123-456-7890"
message "TestMessage"
end
factory :invalid_inquiry, parent: :inquiry do
name nil
end
end
#/app/controllers/inquiries_controller.rb
class InquiriesController < ApplicationController
def new
#inquiry = Inquiry.new
end
def create
#inquiry = Inquiry.new(params[:inquiry])
if #inquiry.deliver
render :thank_you
else
render :new
end
end
end
# spec/controllers/inquiries_controller_spec.rb
require 'spec_helper'
describe InquiriesController do
it "has a valid factory" do
FactoryGirl.build(:inquiry).should be_valid
end
describe "POST #create" do
context "with valid attributes" do
it "delivers inquiry" #pending
it "renders the :thank_you page template" do
post :create, inquiry: FactoryGirl.attributes_for(:inquiry)
response.should render_template :thank_you
end
end
context "with invalid attributes" do
it "does not deliver inquiry" do #pending
it "renders :new page template" do
post :create, inquiry: FactoryGirl.attributes_for(:invalid_inquiry)
response.should render_template :new
end
end
end
describe "GET #new" do
it "renders :new page template" do
get :new
response.should render_template :new
end
end
end
Finished in 0.31244 seconds
0 examples, 0 failures
/Users/.../.rvm/gems/ruby-2.0.0-p353/gems/factory_girl-4.4.0/lib/factory_girl.rb:73:in `lint': The following factories are invalid: (FactoryGirl::InvalidFactoryError)
* invalid_inquiry
from /Users/.../Documents/blog_app/spec/support/factory_girl.rb:8:in `block (2 levels) in <top (required)>'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:21:in `instance_eval'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:21:in `run'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `block in run'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `each'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `run'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:418:in `run_hook'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:27:in `block in run'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/reporter.rb:34:in `report'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:25:in `run'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/runner.rb:80:in `run'
from /Users/.../.rvm/gems/ruby-2.0.0-p353/gems/rspec-core-2.13.1/lib/rspec/core/runner.rb:17:in `block in autorun'
Does this work?
FactoryGirl.define do
factory :inquiry do
name "TestName"
email "test#test.com"
phone "123-456-7890"
message "TestMessage"
factory :invalid_inquiry do
name nil
end
end
end
Alternatively you might try replacing:
post :create, inquiry: FactoryGirl.attributes_for(:invalid_inquiry)
with:
post :create, inquiry: FactoryGirl.attributes_for(:inquiry, name: nil)
and getting rid of the invalid_inquiry factory altogether.
I can't figure out why this RSpec test fails. Any advice? I'm new-ish to FactoryGirl, RSpec, and TDD in general.
Controller:
def update
#vendor = current_user.vendors.find(params[:id])
if #vendor.update_attributes(params[:vendor])
redirect_to vendor_path(#vendor)
else
render 'edit'
end
end
Test:
require 'spec_helper'
describe VendorsController do
login_user
before :each do
#user = subject.current_user
#vendor = FactoryGirl.create(:vendor, :user => #user)
end
[...]
describe 'POST update' do
def do_update
post :update, :id => #vendor.id, :vendor => FactoryGirl.attributes_for(:vendor)
end
[...]
it 'should update a given vendor' do
do_update
#vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
end
end
end
Factory:
FactoryGirl.define do
factory :vendor do
name 'Widget Vendor'
user
end
end
The Failure:
Failures:
1) VendorsController POST update should update a given vendor
Failure/Error: #vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
(#<Vendor:0x007faeb75e77d0>).update_attributes({:name=>"Widget Vendor"})
expected: 1 time
received: 0 times
# ./spec/controllers/vendors_controller_spec.rb:108:in `block (3 levels) in <top (required)>'
Update:
I'm a little closer, now. I changed the test to the following:
it 'should update a given vendor' do
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
do_update
end
And the new error is:
Failures:
1) VendorsController POST update should update a given vendor
Failure/Error: post :update, :id => #vendor.id, :vendor => FactoryGirl.attributes_for(:vendor)
#<Vendor:0x007ff30d765900> received :update_attributes with unexpected arguments
expected: ({:name=>"Widget Vendor"})
got: ({"name"=>"Widget Vendor"})
# ./app/controllers/vendors_controller.rb:33:in `update'
# ./spec/controllers/vendors_controller_spec.rb:98:in `do_update'
# ./spec/controllers/vendors_controller_spec.rb:108:in `block (3 levels) in <top (required)>'
Answer...?
Well, this worked. There has to be a better way of doing this, though:
Vendor.any_instance.should_receive(:update_attributes).with(JSON.parse(FactoryGirl.attributes_for(:vendor).to_json)).and_return(true)
I think you are doing it wrong.
The #vendor object in specs is another one that in your controller, so it doesn't receive "update_attributes" method.
You can try this (rspec 2.5+ probably):
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
Or you can check if object attributes has changed:
expect{
do_update
}.to change(...)
I believe you need to set your expectations before posting the request; otherwise, by the time it hits your expectation the object has already been set. So move do_update after your should_receive line:
it 'should update a given vendor' do
#vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
do_update
end
You can use the Hash stringify keys method in rails:
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor).stringify_keys)