FactoryGirl has many trait creation not working - ruby-on-rails

I'm trying to get FactoryGirl to create quiz_question. But it's only creating the belongs to factory(quiz_campaign) in the test DB environment, not the has many factory(quiz_question).
quiz_campaign.rb
FactoryGirl.define do
trait :with_quiz_questions do
after_create do |campaign|
FactoryGirl.create(:quiz_question, quiz_campaign: campaign)
end
end
end
factory :quiz_campaign do
subdomain "macy"
end
quiz_question.rb
FactoryGirl.define do
factory :quiz_question do
message "What's your question"
end
end
quiz_home_page.feature
Given(/^there's a subdomain for a quiz campaign$/) do
#quiz_campaign = create(:quiz_campaign)
end
When(/^I visit the quiz campaign microsite subdomain url$/) do
visit_with_subdomain microsite_home_path, subdomain: #quiz_campaign.subdomain
end

Resolved it by not using traits. It seems like using traits causes more complex solution than needed

Related

RSpec not recognizing deleted association

In my rails application, a user has many baskets, and a basket belongs to a user. The User class also contains an instance method that removes the user's id from all associated baskets. I am having issues testing that method using RSpec, FactoryGirl and Faker.
class Basket
belongs_to :user, optional: true
end
class User
has_many: baskets
def disassociate_baskets
baskets.each { |b| b.update(user: nil) }
end
end
The disassociate_baskets method works with real data, my RSpec test fails because in the test environment because the basket-user association persists even after running the method. Here's my testing code:
#Basket Factory
FactoryGirl.define do
factory :basket do
date { Faker::Date.backward }
end
end
#User Factory
FactoryGirl.define do
factory :user do
name { Faker::Name.name }
end
end
#user_spec.rb
describe "When deleting purchase history" do
before do
#user = create(:user)
#user1 = create(:user)
#basket = create(:basket, user: #user)
#basket1 = create(:basket, user: #user)
#basket2 = create(:basket, user: #user1)
end
it "disassociates the user from the basket" do
#user.disassociate_baskets
expect(#basket.user).to eq nil
end
end
I've inspected the objects inside the it block, and they are fine, but #basket is still associated to #user even after running disassociate_baskets method, so my test fails. What am I missing here?
Possible solution:
expect(#basket.reload.user).to eq nil
Why you need to reload it:
When you create the new basket and assign it to #basket, it will have an associated User assigned to it. Then, you call #user.disassociate_baskets, which loops over all the baskets of that user by instantiating them one by one, and updating their user attribute.
But since #user.disassociate_baskets instantiated brand new Basket instances, the user attribute will be set to nil only in these new instances. #basket has no idea that another instance got modified, and has to be reloaded manually.

MiniTest parent and child from factory in test

I'm getting the following error when running my test.
NoMethodError: undefined method 'departure_date' for nil:NilClass
Here is the test.
test "successful disbursement should respond with success" do
post :disbursement, {id: #invoice.invoice_id, trip: attributes_for(:trip)}
assert_response :success
end
In the setup portion of the test I'm creating the following.
setup do
#controller = Api::V1::InvoicesController.new
#invoice = create(:invoice)
#trip = create(:trip)
end
The trip factory looks like this.
FactoryGirl.define do
factory :trip do
depart_airport "MCI"
arrive_airport "ORD"
passenger_first_name "Joe"
passenger_last_name "Business"
passenger_count 1
departure_date {10.days.from_now}
invoice
end
end
The invoice factory looks like this.
FactoryGirl.define do
factory :invoice do
sequence(:invoice_id) { |n| "INV#{n}"}
merchant
amount 500.00
item_count 5
paid false
currency "GBP"
invoice_type "pre-flight"
end
end
Can't quite figure out how to make sure the invoice has a trip. I'm guessing this is why the test can't find the departure_date it should.
From what I understand, you are trying to associate the trip and invoice. If my understanding is correct, try this.
setup do
#controller = Api::V1::InvoicesController.new
#invoice = create(:invoice)
#trip = create(:trip, invoice: #invoice)
end

Rails Factory Girl RSpec Testing Has-Many Relationship of Nested Resources

Note: A business has many catalogs and has products, and a catalog has many products. The associations are properly defined and they are working in the application front end. But I can't make this test pass. I am using friendly_id so you will see me using #model.slug on some of the find methods
I am trying this test out:
describe "GET 'show'" do
before do
#business = FactoryGirl.create(:business)
#catalog = FactoryGirl.create(:catalog, :business=>#business)
#product1 = FactoryGirl.create(:product, :business=>#business, :catalog=>#catalog)
#product2 = FactoryGirl.create(:product, :business=>#business, :catalog=>#catalog)
end
def do_show
get :show, :business_id=>#business.slug, :id=>#catalog.slug
end
it "should show products" do
#catalog.should_receive(:products).and_return([#product1, #product2])
do_show
end
end
with this factory (note that a business and catalog factory is define somewhere else, and they are associations):
FactoryGirl.define do
sequence :name do |n|
"product#{n}"
end
sequence :description do |n|
"This is description #{n}"
end
factory :product do
name
description
business
catalog
end
end
with this show action:
def show
#business = Business.find(params[:business_id])
#catalog = #business.catalogs.find(params[:id])
#products = #catalog.products.all
respond_with(#business, #catalog)
end
but I am getting this error:
CatalogsController GET 'show' should show products
Failure/Error: #catalog.should_receive(:products).and_return([#product1, #product2])
(#<Catalog:0x000001016185d0>).products(any args)
expected: 1 time
received: 0 times
# ./spec/controllers/catalogs_controller_spec.rb:36:in `block (3 levels) in <top (required)>'
furthermore, this code block will also indicate that Business model has not received the find method:
Business.should_receive(:find).with(#business.slug).and_return(#business)
The problem here is that the #catalog instance variable you set up in the spec is not the same as the #catalog instance variable in the controller.
#catalog in the spec will never receive any messages sent to #catalog in the controller.
What you need to do instead is to change this in your spec:
#catalog.should_receive(:products).and_return([#product1, #product2])
to
Catalog.any_instance.should_receive(:products).and_return([#product1, #product2])
Check out the RSpec documentation on any_instance.should_receive here: https://www.relishapp.com/rspec/rspec-mocks/v/2-6/docs/message-expectations/expect-a-message-on-any-instance-of-a-class

undefined method `stringify_keys' while using Factory Girl

I have the following block of code in my User_spec.rb:
#user = { username:'newuser',
email:'new#user.com',
fname:'new',
lname:'user',
password:'userpw',
password_confirmation:'userpw'}
for creating a using using these attributes. However while I moved all these attributes to Factories.rb:
require 'factory_girl'
Factory.define :user do |u|
u.username 'newuser'
u.email 'new#user.com'
u.fname 'new'
u.lname 'user'
u.password 'newuserpw'
u.password_confirmation 'newuserpw'
end
and replace the line in user_spec.rb with:
#user = Factory(:user)
all my tests that related to the User model failed(such as tests for email, password, username etc), all were giving me
"undefined method `stringify_keys' for…"
the new user object
I had a similar problem, and it was because I was passing a FactoryGirl object to the ActiveRecord create/new method (whoops!). It looks like you are doing the same thing here.
The first/top #user you have listed is a hash of values, but the second/bottom #user is an instance of your User ojbect (built by FactoryGirl on the fly).
If you are calling something like this in your specs:
user = User.new(#user)
The first (hashed) version of #user will work, but the second (objectified) version will not work (and throw you the 'stringify_keys' error). To use the second version of #user properly, you should have this in your specs:
user = Factory(:user)
Hope that helps.
We need to see an example of a failing test to diagnose, but here is one thing that can cause it – sending an object when attributes are required. I once fixed one of my failing tests by changing:
post :create, organization: #organization
to
post :create, organization: #organization.attributes
#rowanu Answered your question, but let me layout my example too for future reference:
What was failing in my case was:
#user = User.new user_attr
#user.bookings_build(Booking.new booking_attr)
Note that I am trying to build with a booking instance and not hash of attributes
The working example:
user_attr_hash = FactoryGirl.attributes_for(:user)
booking_attr_hash = FactoryGirl.attributes_for(:booking)
#user = User.new user_attr_hash
#user.bookings.build(booking_attr_hash)
And in spec/factories/domain_factory.rb I have
FactoryGirl.define do
factory :user do
# DEFAULT USER...
password "123123123"
email "factory_girl#aaa.aaa"
# there rest of attributes set...
end
factory :booking do
start_date Date.today
end_date Date.today+3
# the rest of attributes
end
end

How to test a before_save method including accossioations with rspec

I'm having a problem testing the following model:
class Bill < ActiveRecord::Base
belongs_to :consignee
before_save :calc_rate
def calc_rate
self.chargeableweight = self.consignee.destination.rate * self.weight
end
end
The consignee model:
class Consignee < ActiveRecord::Base
belongs_to :destination
has_many :bills
end
The controllers are not touched yet.
The behavior of the app is correct (follow up question: are there any performance problems with that solution?) - but the the test break.
You have a nil object when you didn't
expect it! You might have expected an
instance of Array. The error occurred
while evaluating nil.*
Thank you in advice,
Danny
update:
This bill test breaks using factory girl:
describe Bill do
it "should call the calc_rate method" do
bill = Factory.build(:bill)
bill.save!
bill.should_receive(:calc_rate)
end
end
You have a nil object when you didn't expect it!
Factories:
Factory.define :destination do |f|
f.airport_code "JFK"
end
Factory.define :consignee do |f|
...
f.association :destination
end
Factory.define :bill do |f|
f.association :consignee
f.weight 10
f.chargeableweight 20.0
f.after_create do |bill|
bill.calc_rate
end
describe Consignee do
it "should calculate the rate" do
#pending
#make sure this spec is passing first, so you know your calc_rate method is fine.
end
it "should accept calc_rate before save" do
cosignee = mock("Consignee")
consignee.should_receive(:calc_rate).and_return(2) # => stubbing your value
end
end
I didn't spool up a rails app to test this code, but this should get you close. also, assuming that the columns chargeable_rate, weight, etc are columns on the model, you dont need to call self. Ruby will implicitly expect self if there is no instance method or variable of that name available it will automatically look for class methods.

Resources