I'm using Mongoid as my database and have configured my spec_helper.rb file as instructed on other Stackoverflow questions, however I'm still getting an error that the Object exists on subsequent tests. So, database_cleaner isn't cleaning my test db as it should.
Here is my spec_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rails/mongoid'
require 'mongoid-rspec'
require 'database_cleaner'
Mongoid.load!(Rails.root.join("config", "mongoid.yml"))
# Load support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
RSpec.configure do |config|
config.mock_with :rspec
#config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
config.before(:suite) do
DatabaseCleaner[:mongoid].strategy = :truncation
DatabaseCleaner[:mongoid].clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
And my rspec test file is simple:
describe Stock do
it "should get created with only name and symbol" do
stock = Stock.create(name: "Netflix", symbol: "NFLX")
expect(stock.errors.full_messages).to eq []
end
end
The output I'm getting is fine on first run (after I manually reset the db) with rake db:reset RAILS_ENV=test however every run after that I am getting:
Failures:
1) Stock should get created with only name and symbol
Failure/Error: expect(stock.errors.full_messages).to eq []
expected: []
got: ["Symbol is already taken"]
(compared using ==)
# ./spec/models/stock_spec.rb:6:in `block (2 levels) in <top (required)>'
What am I missing?
Well, after alot more reading, I've come to determine that database_cleaner and Mongo aren't playing well together. While it's probably not the cleanest solution, it is simple:
In my spec_helper.rb file, I ended up adding this line to the RSpec.configure block:
config.after(:each) do
Mongoid.purge!
end
Related
I have used RSpec in conjunction with Capybara and Capybara-webkit on many Rails projects and it usually works smoothly. For some reason I'm having problems configuring the js: true feature specs to work this time around. They are not interacting with the database properly. I use factory_girl and database_cleaner to manage the test db content. I have DatabaseCleaner.strategy = :truncation in database_cleaner.rb for the js: true tests but it still doesn't work. Oddly, when I put in ActiveRecord::Base.establish_connection into databse_cleaner.rb the tests work fine. Why??
Here is rails_helper.rb:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if
Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
Capybara::Webkit.configure(&:block_unknown_urls)
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
end
This is the important parts of spec_helper.rb:
ENV['RAILS_ENV'] ||= 'test'
ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup'
Bundler.require
require 'pry-byebug'
require 'capybara/rspec'
require 'capybara/webkit'
require 'database_cleaner'
require 'webmock/rspec'
WebMock.disable_net_connect!(allow_localhost: true)
# use `describe 'Feature', type: :feature, js: true` to use this driver
Capybara.javascript_driver = :webkit
# tests use regular (faster) driver if they don't require js
Capybara.default_driver = :rack_test
Capybara::Webkit.configure do |config|
config.allow_unknown_urls
end
RSpec.configure do |config|
config.after(:suite) do
FileUtils.rm_rf(Dir["#{Rails.root}/spec/test_files/"])
end
config.include Capybara::DSL
...
This is database_cleaner.rb (located in spec/support):
RSpec.configure do |config|
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
end
When I change this, the tests can interact with the db properly:
config.before(:each, js: true) do
ActiveRecord::Base.establish_connection
DatabaseCleaner.strategy = :truncation
end
Why? I shouldn't have to explicitly tell it to establish a db connection.
Your question states that you're using :transaction for your js tests, but the code shows :truncation. Truncation is what you should be using for your js tests so I assume the question is a typo.
You should be using the recommended database_cleaner - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example - which detects whether truncation is needed based on the driver being used rather than the 'js: true' metadata and also uses append_after rather than just after, which is very important for test stability.
I also don't see a require 'capybara/rails' anywhere in your rails_helper or spec_helper
When you set js: true, you're essentially just using Capybara which in essence is a Selenium-driven browser request. Any code running outside the test process (like this Selenium browser request) does not see the database fixture.
Preferable to what you're doing though, is to share the data state across the Selenium web server and test the code itself.
Somewhere in Rspec.config (possibly your database_cleaner.rb), you'll want to set
config.use_transactional_fixtures = false
"Everyday Rails Testing with Rspec" has a trick that was sometimes needed for certain test scenarios where you need to share the same DB connection before Rails 5. Although it can cause other issues as pointed out in comments below:
Make a spec/support/shared_db_connection.rb file and add this content:
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || retrieve_connection
end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
My Turnip test is working normally, but does not work when using spork.
I debugged with pry and I found that a missing User(class constant) causes the error.
What should I do to fix?
# working (good)
bundle exec rspec spec/acceptance/features/*
# not work (bad)
bundle exec rspec spec/acceptance/features/* --drb
Here is the error when I run with the --drb option.
Failure/Error: Give a user logged in:
NameError:
wrong constant name #<Module:0x007fd40a19c680>
# spec/acceptance/steps/user_steps.rb:8:in `block (2 levels) in <module:UserSteps>'
# spec/acceptance/steps/user_steps.rb:7:in `each'
This is my spec_helper.rb.
require 'rubygems'
require 'spork'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/dsl'
require 'capybara/rspec'
require 'capybara/rails'
require 'turnip'
require 'turnip/capybara'
require 'shoulda/matchers/integrations/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
Dir.glob("spec/**/*steps.rb") { |f| load f, true }
WebMock.disable_net_connect!(:allow_localhost => true)
Capybara.run_server = true
Capybara.app_host = 'http://localhost'
Capybara.server_port = 8000
Capybara.default_selector = :css
Capybara.javascript_driver = :webkit
OmniAuth.config.test_mode = true
RSpec.configure do |config|
# ## Mock Framework
config.mock_with :rr
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
config.include FactoryGirl::Syntax::Methods
config.include Capybara::DSL, turnip: true
config.include Rails.application.routes.url_helpers
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.before(:each, js: true) do
headless = Headless.new
headless.start
end
end
end
Spork.each_run do
# This code will be run each time you run your specs.
end
This is user_steps.rb.
1. require_relative 'helper_steps'
2.
3. module UserSteps
4. include HelperSteps
5.
6. step 'users are registered :' do |table|
7. table.hashes.each do |row_hash|
8. create(:user, class_params_by_row_hash(User, row_hash))
9. end
10. end
11. end
rails 3.2.13
rspec-rails 2.11.0
rspec 2.11.0
turnip 1.1.0
spork 1.0.0rc3
I'm not sure why this problem occurs, but you can prevent it from happening. If you're wrapping your steps in modules, you don't need to pass the true wrap parameter to load. Change:
Dir.glob("spec/**/*steps.rb") { |f| load f, true }
to:
Dir.glob("spec/**/*steps.rb") { |f| load f }
This prevents this error for me.
Reference: http://www.ruby-doc.org/core-2.1.2/Kernel.html#method-i-load
Works great for about 5 runs, but then all tests fail with:
ArgumentError: prepare called on a closed database: SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
Doesn't happen without Spork, and works fine if I restart Spork. Doesn't happen after a certain number of runs, but changes each time.
Any ideas what could cause this?
EDIT:
It only happens when changing the controller code.
spec_helper.rb:
require 'spork'
require 'simplecov'
SimpleCov.start
Spork.prefork do
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
end
Spork.each_run do # This code will be run each time you run your specs.
require 'capybara/rspec'
require 'capybara/rails'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
# 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 = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
config.include RequestHelpers, :type => :request
config.before :suite do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with :truncation
end
config.before :each do
DatabaseCleaner.start
end
config.after :each do
DatabaseCleaner.clean
end
config.include(MailerHelpers)
config.before(:each) { reset_email }
end
end
Try removing this line:
config.use_transactional_fixtures = true
Seems to have worked for me. I was guided by the error message, as it was transaction related, but not exactly sure what the deal is. Seems to have something to do with spork's threads and sqlite3
I had this error quite a bit and was able to fix it by updating to the latest version of sqlite3.
bundle update sqlite3
this is my first questions online EVER, so please comment and I'll try to update my questions to clarify.
I am quite new to web development, and is currently working on a test suite for a company project. It was working nicely up to the point when I'm trying to do an integration test on a function, which involves javascript. I tried using both webkit(bundled from git) and selenium. Webkit gave the following error message.
Wrote response false "Unable to load URL: http://127.0.0.1:56618/ because of error loading http://127.0.0.1:56618/: Connection closed"
Cleaning database...done
Received "Reset"
Started "Reset"
Finished "Reset"
Wrote response true ""
should see invalid message (FAILED - 1)
Failures:
1) Users GET /sign_in with invalid account should see invalid message
Failure/Error: visit root_path
Capybara::Webkit::InvalidResponseError:
Unable to load URL: http://127.0.0.1:56618/ because of error loading http://127.0.0.1:56618/: Connection closed
And when using Selenium, the FireFox complain about:
Your Firefox profile cannot be loaded. It may be missing or inaccessible.
Does anybody have some clue as to what might be the problem?
Thanks in advance!
my sepc_helper.rb
Spork.prefork do
...
..
.
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) { require "#{Rails.root}/db/seeds.rb" }
config.before(:each) do
if Capybara.current_driver == :rack_test
DatabaseCleaner.strategy = :transaction
else
DatabaseCleaner.strategy = :truncation
end
DatabaseCleaner.start
end
config.after(:each) do
if Capybara.current_driver == :rack_test
DatabaseCleaner.clean
else
DatabaseCleaner.clean
load "#{Rails.root}/db/seeds.rb"
end
end
end
end
Spork.each_run do
ActiveRecord::Schema.verbose = false
load "#{Rails.root.to_s}/db/schema.rb"
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
end
I am not sure but you can try this,
Add below code in your spec_helper.rb file
require 'spork'
Spork.prefork do
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'email_spec'
# Add this to load Capybara integration:
require 'capybara/rspec'
require 'capybara/rails'
# Database Cleaner
#require 'database_cleaner'
# DatabaseCleaner.strategy = :truncation
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
Spork.each_run do
end
Do one thing uncomment database cleaner.
I'm trying to reset the "sequence" in factory girl between each test I run.
(factory_girl 2.6.0 and factory_girl_rails 1.7.0)
I think that to do so, I have to reload the FactoryGirl definitions. I do it in the last lines of spec_helper.rb:
require 'rubygems'
require 'spork'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
require "rails/application"
Spork.trap_method(Rails::Application::RoutesReloader, :reload!)
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
require 'database_cleaner'
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
config.infer_base_class_for_anonymous_controllers = false
# For mailer
config.include(MailerMacros)
config.before(:each) {reset_email}
end
end
Spork.each_run do
# This code will be run each time you run your specs.
I18n.backend.reload!
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
require 'factory_girl'
FactoryGirl.definition_file_paths = [File.join(Rails.root, 'spec', 'factories')]
FactoryGirl.find_definitions
end
Adding:
FactoryGirl.definition_file_paths = [File.join(Rails.root, 'spec', 'factories')]
FactoryGirl.find_definitions
Leads me to the following error when running rspec spec/
→ bundle exec guard
Guard uses Growl to send notifications.
Guard is now watching at '/Rails/projects/MyRailsProject'
Starting Spork for RSpec
Using RSpec
Preloading Rails environment
Loading Spork.prefork block...
Spork is ready and listening on 8989!
Spork server for RSpec successfully started
Guard::RSpec is running, with RSpec 2!
Running all specs
Exception encountered: #<FactoryGirl::DuplicateDefinitionError: Factory already registered: user>
Which seems to be a duplicated factory error, maybe it's trying to load factory girl twice, but I don't understand why.
It is trying to load all your factories twice, because you're asking it to.
Replace your call to find_definitions with
FactoryGirl.reload
which clear out existing factories, sequences etc and then call find_definitions for you