Currently trying test multiple db's using capybara/rspec/factory girl, though having issues with my DB clearing.
Query error:
': Mysql2::Error: Duplicate entry '1503' for key 'PRIMARY': INSERT INTO `users`
Facilities_spec.rb
feature "User with facilities" do
#current_user = FactoryGirl.create(:user_with_facility)
scenario 'A user can perform a walk-through', :js => true do
login_as
visit '/'
expect(page).to have_text "Our records indicate that you have access to 1 facilities:"
...
end
#current_user = FactoryGirl.create(:user_with_facility)
scenario 'The quick-form requires first_name, last_name, and dob', :js => true do
login_as
visit '/'
expect(page).to have_text "Our records indicate that you have access to 1 facilities:"
...
end
end
rails_helper.rb
cleaner = DatabaseCleaner[:active_record,{:connection => :emp_portal_test}]
rt_cleaner = DatabaseCleaner[:active_record, {connection: :test_rt_treats}]
RSpec.configure do |config|
config.include Capybara::DSL
config.include FactoryGirl::Syntax::Methods
config.use_transactional_fixtures = false
config.before(:suite) do
cleaner.strategy = :truncation
rt_cleaner.strategy = :truncation
end
config.before(:each) do
cleaner.strategy = :truncation
rt_cleaner.strategy = :truncation
cleaner.start
rt_cleaner.start
end
config.before(:each, :js => true) do
cleaner.strategy = :truncation
rt_cleaner.strategy = :truncation
end
config.after(:each) do
cleaner.clean
rt_cleaner.clean
end
user_factory.rb
FactoryGirl.define do
factory :user do
id 33065
first_name "Andrew"
last_name "Larson"
select_id "al44096"
factory :user_with_facility do
after(:create) do |user|
user.facility_assignments << create(:facility)
end
end
end
factory :facility do
id 1550
ref_select_id 1550
status -1
name "St. Paul's Home & Apartments"
name_internal "St Paul's Home"
dept_id "R51"
...
end
When I create a new patient within this test environment, it is wiped before my next use, though I cannot use my same current_user throughout my code.
Ok so a few pieces...
One of my databases' tables did not have an auto-increment feature for it's id which was an issue, so I added auto increment to the table via ...
ALTER TABLE document MODIFY COLUMN document_id INT auto_increment
Once this was resolved my database cleaner was working correctly.
Bonus: I didn't know, but to access #current_user amongst both scenarios I needed
background do
#current_user = FactoryGirl.create(:user_with_facility)
end
I have not seen this until now, and it's great.
2 examples, 0 failures
Related
I have a feature spec to create an order. That order has a callback like so:
class Order
belongs_to :site
before_validation :add_call_number
def add_call_number
self.call_number = self.site.call_number_start
end
end
In the spec, I get a NoMethod error on call_number_start, because self.site doesn't exist.
I discovered that the Site I created in the Rspec before action doesn't exist at all. In other words...
require 'rails_helper'
describe "create successfully", type: :feature, js: true do
before do
#site = create(:site)
visit "/orders"
.... # various actions to build an order using the page's form
puts ">>>>>"
puts "site in before action: #{Site.all.size}"
find("#checkoutModal #submit").click()
sleep(1)
end
it "should create" do
expect(Order.all.size).to equal(1)
expect(Order.last.call_number).to equal(#site.call_number_start)
end
end
# controller action that #submit POSTs to
def create
puts ">>>>>"
puts "site in controller create: #{Site.all.size}"
puts ">>>"
puts "site_id from order_params: #{order_params[:site_id]}"
#order = Order.new(order_params)
#order.save if #order.valid?
end
def order_params
params.require(:order).permit(:site_id)
end
# puts output:
>>>>>
site in before action: 1
>>>>>
site in controller create: 0
>>>
site_id from order_params: 1
I thought this was a database cleaner issue, so I went really pedantically to manually set it up as truncation method like this:
# rails_helper.rb
Rspec.configure do |config|
config.use_transactional_fixtures = false
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each, truncate: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
How can I correctly test this callback?
You created a site but did not give it to order in the controller.
Is the site coming from order_params in Controller? Then figure out in controller why site is not available.
Is the site an association with the order? Then need to create the site for order:
FactoryBot.create(:site, order: order)
This is my spec file, when adding test for context "not as singable updates user balance" I get the error below.
require 'spec_helper'
describe Sale do
context 'after_commit' do
context 'assignable' do
sale = FactoryGirl.create(:sale, earned_cents: 10, assignable: true)
after { sale.run_callbacks(:commit) }
it 'updates user balance' do
sale.user.balance.should == sale.earned
end
end
context 'not assignable' do
sale = FactoryGirl.create(:sale, earned_cents: 10, assignable: false)
after { sale.run_callbacks(:commit) }
it 'does not updates user balance' do
sale.user.balance.should_not == sale.earned
end
end
end
end
And the factories
require 'faker'
FactoryGirl.define do
factory :user do
email Faker::Internet.email
password "mypassword"
end
FactoryGirl.define do
factory :sale do
earned_cents 5
user
end
end
On /spec/spec_helper.rb I also had this
require 'database_cleaner'
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
And this is the error I'm getting.
`save!': Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)
I guess its related to the user reference inside Sale Factory, but I have no idea why it is not generating a new user for the second test or deleting it from the database. Any idea?
In your User factory, try this instead:
factory :user do
email { Faker::Internet.email }
password "mypassword"
end
Why you Must Enclose In Curly Brackets: to Avoid Caching Values
The factory(:user) block is run
when defining the factory, and not every time a record is created. So
if Factory::Internet.email evaluated to foo#bar.com the first time,
then the factory would attempt to create all subsequent users with
that very same email!) (as per #kristinalim, Edited for grammar)
I have a controller sending in a list of vendors to my controller, and on normal view it's working fine.
class VendorsController < ApplicationController
respond_to :html, :json
def index
#vendor_categories = VendorCategory.where(:is_top_level => true)
#vendors = Vendor.includes(:vendor_tier, :vendor_categorizations, :vendor_categories).order('vendor_tier_id DESC, name ASC')
respond_with #vendors
end
end
In my view I have the following two lines:
= debug #vendors
= debug current_user.user_vendor_choices
which, again, are working if I view it in the browser. However, if I test it with Capybara and RSpec, it's empty.
require 'spec_helper'
describe 'Vendors' do
before do
category = create(:vendor_category)
5.times do
vendor = create(:vendor)
vendor_categorization = create(:vendor_categorization, vendor: vendor, vendor_category: category)
p vendor
p category
p vendor_categorization
end
visit signup_path
#new_user = sign_up
end
before(:each) do
visit destroy_user_session_path
visit new_user_session_path
sign_in #new_user
visit vendors_path
end
it 'should save selected vendors', js: true do
p Vendor.includes(:vendor_tier, :vendor_categorizations, :vendor_categories).order('vendor_tier_id DESC, name ASC').count
end
end
Vendor.all and the above Vendor.includes... both return values, but for some reason in my test it's not showing anything... getting a Capybara::Element not found.
UPDATE
For testing purposes, I created the Vendors directly with the controller:
def index
#vendor_categories = VendorCategory.where(:is_top_level => true)
4.times do
Vendor.create({name: 'Test McTesterson', vendor_tier_id: 1})
end
#vendors = Vendor.includes(:vendor_tier, :vendor_categorizations, :vendor_categories).order('vendor_tier_id DESC, name ASC')
respond_with #vendors
end
Spec passes. What the--? This must be a FactoryGirl issue, or for some reason my records are deleted before it can run the test? Consoling the objects after I create them is showing a record with an ID, which I guess doesn't prove that it's putting them in the database...
Turns out my Database Cleaner activities defined in my spec_helper were a little too vigorous. I had:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
I had to get rid of the second chunk, so it now reads:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
end
And it works! Not really sure why... any ideas (aside from the obvious, before it was calling database cleaner before/after each test)?
Hi I cursorily glanced at this question, not sure you even need the help anymore, but I think the reason this is failing is a fundamental set up issue that your answer is just patching around.
When you're running a js: true spec (by the way, js: true should be on the describe line, not the it line), short version, Capybara works in different threads, so instance variables created in a before block, unlike with regular Rspec testing, are not available in the spec. To make them available, you have to use a truncation cleaning strategy.
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
TL;DR when running a js test, truncation is basically required (unless obviously you're running js tests that don't require any database interactions). When running all other tests, use transactions (because it's also much faster). I guess your answer replicated this to some extent =)
Good day. i get this error
1) Subscription
Failure/Error: #subscription = FactoryGirl.create(:subscription)
ActiveRecord::RecordInvalid:
Encountered errors: Email already exists, Login already exists
Although in a FactoryGirl i specify the uniqueness of these fields^
call for factory girl
#subscription = FactoryGirl.create(:subscription)
build can't be implemented, because
should validate_uniqueness_of( :category_id).scoped_to(:user_id)
factories:
factory :subscription do
association :category, factory: :advt_category
user
end
factory :user do
sequence(:login) { |n| "user__#{n}" }
password "password"
sequence(:email) { |n| "example__#{n}#example.com"}
end
How to solve this error? why it appears?
Update
I ended up destroying all records for the User model in this spec
before do
User.destroy_all
end
The problem most likely is, that your test DB is not clean when you start your specs. This can happen when a rspec exits prematurely, or is killed.
Your approach with before { User.destroy_all } works, but is tedious (since you may need to add it in other specs as well), and slow.
I'd suggest you make use of the database_cleaner gem and extend your rspec configuration like this:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :suite do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with :truncation
end
config.before(:each) { DatabaseCleaner.start }
config.after(:each) { DatabaseCleaner.clean }
end
When you are using Capybara for your request specs, change the before :each block to:
config.before :each do
if Capybara.current_driver == :rack_test
DatabaseCleaner.strategy = :transaction
else
DatabaseCleaner.strategy = :truncation
end
DatabaseCleaner.start
end
I think this would work
Call a FactoryGirl for user and pass it into the subscription call
#user = FactoryGirl.create(:user)
#subscription = FactoryGirl.create(:subscription, :user_id => #user.id)
As of why this happends we need to see more of the spec
I have tried getting solutions from the SO questions listed at the bottom but my problem is that I am using Capybara and FactoryGirl and I cannot seem to load seeds.rb from anywhere without causing many tests that are completely separate from the seed data from breaking.
Most of the error messages are variations on page.should_not have_content user.email
after a test where I try delete a user that I made through a factory. These are tests that passed fine until I loaded the seed data.
How to load db:seed data into test database automatically?
Prevent Rails test from deleting seed data
What is the best way to seed a database in Rails?
How to auto-load data in the test database before to test my application?
What I have is a single admin group, assigned the admin permission and an admin user in the seeds.rb linked together
One possibility is calling a factory in my seeds.rb to populate this data but I have not yet figured out how.
seeds.rb
User.find_or_create_by_email(email: "admin#admin.admin",
password: "admin", password_confirmation: "admin")
%w{admin supermod}.each {|w| Group.find_or_create_by_name(w)}
%w{admin mod player}.each {|w| Permission.find_or_create_by_name(w)}
g = Group.find_by_name("admin")
g.permission_id = Permission.find_by_name("admin").id
puts "failed to add admin permission to admin group" unless g.save
u = User.find_by_email("neonmd#hotmail.co.uk")
ug = UserGroup.new
ug.group_id = Group.find_by_name("admin").id
ug.user_id = u.id
puts "failed to add admin group to #{u.name}" unless u.save && ug.save
Failing test
This passes before I load seeds.rb
it "lets you remove user from group" do
user = Factory.create(:user)
admin = admin_login
group = add_group
add_user_to_group user, group
click_link "delete_#{user.email}"
page.should_not have_content user.email
end
def admin_login
admin = Factory.build(:admin)
visit login_path
fill_in "email", :with => admin.email
fill_in "password", :with => admin.password
click_button "Log In"
return admin
end
def add_group
group = Factory.build(:group)
visit new_group_path
fill_in "group_name", :with => group.name
click_button "Submit"
return group
end
def add_user_to_group (user, group)
visit groups_path
click_link "#{group.name}_users"
fill_in "user_email", :with => user.email
click_on "Add User"
end
I do not know the reason but requiring the seeds.rb file instead of loading it in the test environment works and you can just call seed_data on the tests that need it.
spec/helpers.rb
def seed_data
require "#{Rails.root}/db/seeds.rb"
end
better solution
spec/spec_helper.rb
RSpec.configure do |config|
config.before(:suite) do
require "#{Rails.root}/db/seeds.rb"
end
........
end
In Rails 4.2.0 and RSpec 3.x, this is how my rails_helper.rb looks.
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.before(:all) do
Rails.application.load_seed # loading seeds
end
end