I am trying to set up cleaning of my specs using database_cleaner gem. I have the following simple config in my spec_helper.rb:
require 'database_cleaner'
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :suite do
DatabaseCleaner.strategy = :truncation
end
config.before :each do
DatabaseCleaner.start
end
config.after :each do
DatabaseCleaner.clean
end
end
Running the spec though, I'm noticing that my database gets completely wiped out after DatabaseCleaner.clean is executed. I'm sure it's meant to clean up only the effects of the test... Any ideas what may cause such behavior?
It's because you've got the strategy set to :truncation, this does indeed clear the whole thing.
If you want to limit it to just what's done in test, then change the strategy to :transaction
Broadly speaking, truncation is very simple, and shouldn't be a problem in the TEST database.
Related
I have various tests that create models using FactoryGirl in Rails
it "does something" do
user = create(:user)
...
expect(user.name).to eq("foo")
end
I noticed that each time I run the spec suite, it does not reset the table id's on the test schema (using Postgres). So after several executions the user might have an id of something like 2894.
I use Database Cleaner to clean my DB between subsequent runs - see below.
Is there a way to reset table ID's directly between rspec runs? A company I previously worked at did it with their app, but I'm not aware how.
If #1 is not an option, is it possible to drop and recreate the test DB between runs?
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:deletion)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :deletion
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
I am also using DatabaseCleaner gem and don't experience the same issue you do (though I'm using mysql instead).
Not sure if this helps in your case but would be worth trying my configuration:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
Rails.application.load_seed
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
My rails_helper.rb
require 'support/database_cleaner'
RSpec.configure do |config|
config.use_transactional_fixtures = false
I have following line in my rails helper.
config.use_transactional_fixtures = true
But I want to modify it to
config.use_transactional_fixtures = false
But I don't want to modify it for every tests inside spec folder. I just want to apply it to all the tests inside spec/requests folder.
How can I do it ?
After doing a bit more research, it looks like you need to use the DatabaseCleaner gem https://github.com/DatabaseCleaner/database_cleaner. In your rails helper, you would add this:
require 'database_cleaner'
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before type: :request do
DatabaseCleaner.strategy = :truncation
end
config.after type: :request do
DatabaseCleaner.strategy = :transaction
end
config.before :each do
DatabaseCleaner.start
end
config.after do
DatabaseCleaner.clean
end
end
This will set you up so that request specs will use the truncation strategy (removing all data from the database) and everything but request specs use transactions (rollback all changes from runnning scenario).
I have a JS feature spec I'm trying to run with Capybara Webkit. It doesn't seem to be able to find my database records however.
The spec in question looks like this
it "should allow pledging to a Hardback level", js: true do
book = FactoryGirl.create :book
visit book_path(book)
click_link "pledge-btn"
end
Unfortunately, the request to book_path(book) 404s because the book cannot be found.
If I take the :js flag off, the test passes.
I have DatabaseCleaner set up to use :truncation for JS specs as is the recommended method.
# spec/support/database_cleaner.rb
RSpec.configure do |config|
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
DatabaseMetadata.create!(:sanitized_at => DateTime.now)
end
config.after(:each) do
DatabaseCleaner.clean
end
end
I can puts the book in the test and it will be found.
it "should allow pledging to a Hardback level", js: true do
book = FactoryGirl.create :book
visit book_path(book)
p Book.first
# => .. the book instance
click_link "pledge-btn"
end
I've also tried this shared connection method which doesn't seem to fix the problem either.
What else could be wrong?
You may have config.use_transactional_fixtures = true set in your spec_helper.rb. This would override what you have above.
You want to either remove this line from your spec_helper.rb or change it there to be false.
I ran into this same issue and had a very similar config. After looking through the DatabaseCleaner README, I found this small note:
It's also recommended to use append_after to ensure DatabaseCleaner.clean runs after the after-test cleanup capybara/rspec installs.
Source
That means changing your
config.after(:each) do
DatabaseCleaner.clean
end
to
config.append_after(:each) do
DatabaseCleaner.clean
end
Note the append_after instead of after. This fixed my problem.
Working on legacy project I have had such issue, it was caused by switching DatabaseCleaner strategy to :truncation like the following:
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean
Test::Seeder.seed!
DatabaseCleaner.strategy = :transaction
end
so, removing DatabaseCleaner.strategy = :transaction helped in my case
If you create records in a before(:all) block then they will be available.
before :all do
#book = FactoryGirl.create :book
end
it "should allow pledging to a Hardback level", js: true do
visit book_path(#book)
click_link "pledge-btn"
end
Capybara runs the rails server in a separate process from the tests, so they each get their own connection to the database. Therefore, the server does not access to the records created in the transaction for the test.
Because they are not inside a transaction, make sure that you clean them up with DatabaseCleaner in your spec_helper.rb:
config.after(:all, :type => :feature) do
DatabaseCleaner.clean
end
For anyone that lands here in 2019 and beyond, I was caught out by the following code which I copied verbatim from the DatabaseCleaner readme:
config.before(:each, type: :feature) do
# :rack_test driver's Rack app under test shares database connection
# with the specs, so continue to use transaction strategy for speed.
driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test
unless driver_shares_db_connection_with_specs
# Driver is probably for an external browser with an app
# under test that does *not* share a database connection with the
# specs, so use truncation strategy.
DatabaseCleaner.strategy = :truncation
end
end
This is all well and good, but I am using Rails system specs, not RSpec features and therefore this code block was never being run.
Change config.before(:each, type: :feature) to config.before(:each, type: :system) if you're using system specs!
I think your main issue is that your rails_helper.rb has the following line commented out:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
This means your database_cleaner.rb is never getting loaded.
This config worked fine when I was using sqlite:
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
controller.stub(:should_navigate_user?).and_return(false) rescue ""
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
When I switched to PostgreSQL I began getting errors when tests depended on the id number of entries in the database. I looked at the database during the tests and it was never cleaning the database.
If I switch to the following config:
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.clean
controller.stub(:should_navigate_user?).and_return(false) rescue ""
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
All of my tests pass, but I'm having to call clean before and after my methods tests?
I shouldn't have to clean the database before and after each test - right? I feel like I'm misunderstanding something somewhere. What am I failing to understand.
I'm using postgres with the database cleaner. Its working well now, but I remember having trouble at first. I pasted my config below. You can stick this in your spec_helper.rb, or in another file such as /support/database_cleaner.rb
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
Also make sure you turn the transactional fixtures off in the spec_helper:
config.use_transactional_fixtures = false
You used sqlite in non-persistent mode. PostgreSQL doesn't have such options, always persistent. Use drop database/create database to clean it complettely.
i really can't understand why DatabaseCleaner is not cleaning my test database. This is what i get prompting
1.9.2p290 :007 > DatabaseCleaner.clean
--
=> [#<DatabaseCleaner::Base:0x007fa7e4dd8b58 #autodetected=true, #orm=:active_record, #strategy=#<DatabaseCleaner::ActiveRecord::Transaction:0x007fa7e4dc14f8 #db=:default>>]
This seems not to set correctly the database (supposed to be :test), so i got a solution like
DatabaseCleaner[:active_record, :connection => :test].clean
# => nil
The gem seems to be set up correctly:
1.9.2p290 :007 > DatabaseCleaner[:active_record, :connection => :test]
#<DatabaseCleaner::Base:0x007fe8fcfd4868 #orm=:active_record, #strategy=#<DatabaseCleaner::ActiveRecord::Transaction:0x007fe8fcfd2748 #db=:test, #connection_hash={"adapter"=>"sqlite3", "database"=>"db/test.sqlite3", "pool"=>5, "timeout"=>5000}>, #db=:test>
This seems to setup correctly the test database, however it is still not going to clean properly the database. Any suggestions?
Thank you very much.
Even with database cleaner correctly configured it is easy to leave data lying around.
config.before(:suite) do
DatabaseCleaner.clean_with :truncation # clean DB of any leftover data
DatabaseCleaner.strategy = :transaction # rollback transactions between each test
Rails.application.load_seed # (optional) seed DB
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
The configuration above starts & runs the cleaner either side of each test.
If you then use before :all in your specs you can end up with data lying around:
describe User do
# Before all is outside the before :each
before :all do
#user = User.create(:email => 'hello#example.com')
end
...tests here
end
Here's my spec_helper.rb (slightly modified) - maybe that will help you?
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'database_cleaner'
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
Avdi Grimm's had a nice post recently on configuring database cleaner:
http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
$ rails c test
> require 'database_cleaner'
> DatabaseCleaner.strategy = :truncation
> DatabaseCleaner.clean
https://github.com/DatabaseCleaner/database_cleaner