I'm new in rails. In my project i use rspec + capybara + poltergeist + selenium + database_cleaner.
Source code github link
I have postgresql 9.5.5, ubuntu 16.04 LTS.
When run test
rspec spec/controllers # everything work fine
When run
rspec spec/features # everything work fine too
But when i run all tests
rspec # part of tests fail
When run first acceptance test with :selenium -> question_id in browser 28, but must be 1, because it use database_cleaner.
Why database_cleaner not clean my database? What i do wrong? I spent a day to find a solution, but not found nothing.
Help me please.
P.S. It's a training project.
My Database_Cleaner configuration is:
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
Warden.test_reset!
if Rails.env.test?
FileUtils.rm_rf(Dir["#{Rails.root}/public/uploads"])
end
end
Cleaning the tables means it deletes all records, it doesn't necessarily mean it resets the index counters - just like if you delete record 3 and then add a new record - the new one would be 4. So in your case it's possible 27 records have been deleted and the next one you create would be 28 even though there's only 1 actual record. Query the database to see how many actual records are there to verify that.
Next, your database cleaner config should be more like the recommended config - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example . append_after vs after is important for stability and checking the driver name vs just the :js metadata is too.
When checking for the href '/uploads/attachment/file/1/test_file.dat' in your tests you shouldn't be checking for a hardcoded '1' there you should check based on the record id number of the record you created. So "/uploads/attachment/file/#{question.id}/test_file.dat" (obviously question.id will depend on what objects you've created and your variable names, but that matches at least one of your tests I think.
Additionally after a quick look at your specs - anywhere you're doing expect(current_path).to eq ... is wrong. You should be doing expect(page).to have_current_path(...). The first way disables the retrying behavior of Capybara and will lead to flaky tests.
And finally - where you have expect(page).not_to have_content t('common.button.ready'), I'm guessing that should be expect(page).not_to have_button t('common.button.ready')
Here you could read how to config a database_cleaner with RSpec and Capybara - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example
Related
I have a test like this, which fails after the first run
it 'should have a login count of 1' do
... (creates a user with 'test#example.com' as the email)
expect(user.login_count).to eq 1
end
The test fails because each time I run it, that user is still in the database and the login count keeps incrementing.
The login_count keeps incrementing because of a method in my program which either finds or creates the user, each time though, it increments the login_count by 1
What's the best way to have the test think the database is clear each time it runs?
In order to have a clean state in the database among each test execution you may want to use the database cleaner gem: https://github.com/DatabaseCleaner/database_cleaner
Rspec example setup (Extracted from github)
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
I populate a database that I want to run rspec tests against.
Rspec seems to delete the db before it starts the tests. How can I tell Rspec not to delete this test_db?
I populate the db outside of Rails / Rspec environment. To build all the factories needed to build up the DB is just not practical for the scope of the project but I would like to test against existing DB.
You can manage clean your database using database cleaner gem, and The documentation recommends the following configuration for rspec as this link, but you change as the following:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
end
But, I prefer to create your database in test environment before scenario, as example:
describe "specific name for this scenario" do
before do
#object = create(:object) # using factory girl as example
end
end
so, this data'll be generate for each time you run your test-case, read more about creating data for rspec-test.
I used the advice given in this question: Rspec don't delete 2 specific tables
In spec_helper.rb:
Commented out call to truncate_all_tables.
Then changed line:
config.use_transactional_fixtures = true
to
config.use_transactional_fixtures = false
I'm using rspec-rails to test a controller in my rails application. In one instance, I'm creating new objects to test that they're properly assigned to instance variables.
describe MainController do
describe "GET #index" do
it "properly assigns a colored ball" do
ball1 = Ball.create(color: 'red')
get :index
expect(assigns(:red_balls)).to eq([ball1])
end
end
end
When I run the test, does rspec access the database to create ball1 and then delete it once the test is run?
From the snippet in your question, Yes Rspec access the DB configured as test in the database.yml file, if you want to clean out the DB/Records created by Rspec you can use the database_cleaner gem you can configure it as you deem fit.
e.g:
add gem database_cleaner to your Gemfile
and the below to your spec_helper.rb file as specified by the database_cleaner documentation:
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
Then database_cleaner would truncate the tables in the test db and leave them in a pristine state
To add to what bjhaid said above - Rspec should only be accessing you 'test' database. Check out the config/database.yml to see the configuration of your different databases.
So you do not have to worry about things in your development or production databases interfering with your testing database.
Yes, RSpec allows your database calls to go through, but with the rspec-rails gem under the default configuration, it will execute each test within a database transaction and will roll back that transaction at the end of each example with no action required on your part. No additional gem is required. See https://relishapp.com/rspec/rspec-rails/docs/transactions.
I would like to increase the speed of my tests.
Should I use use_transactional_fixtures or go with the database_cleaner gem?
Which database_cleaner strategy is the best? I noticed that after migration from :truncation to :transaction my more than 800 examples run about 4 times faster!
Should I turn off use_transactional_fixtures when I use database_cleaner :transaction?
Is it true that the best strategy for rack_test is :transaction?
What is the best practices for changing strategy on the fly from :transaction to :truncation when using selenium or akephalos?
P.S. Mysql, Rails 3, Rspec2, Cucumber
P.P.S. I know about spork and parallel_test and using them. But they are offtopic. For example, Spork save about 15-20 sec on whole suite run, but changing from :transaction to :truncation dramatically increase running time from 3.5 to 13.5 minutes (10 minutes difference).
1., 2. & 4., You should use transactions (either with use_transactional_fixtures or transactions support from the database_cleaner gem) if you are using capybara's default engine, rack_test. As you noted, using transactions are substantially faster than using a truncation strategy. However, when database writes can go through different threads (as with selenium) transactions won't work. So you'll need to use truncation (or force everything to go through one db thread--another option).
3. Yes, you should turn off use_transactional_fixtures when using the database_cleaner gem since the gem natively support transactions. If you only need transactions then just use_transactional_fixtures and never load the database_cleaner gem.
5. The following code will switch between :transaction and :truncation on the fly. (Tested this with rspec, capybara, rails3.)
Features This should give you the best of both worlds. The speed of rack_test when you don't need to test javascript stuff and the flexibility of selenium when you do.
Also this code takes care of repopulating seed data in cases where it is needed (this method assumes you use seeds.rb to load your seed data--as is the current convention).
Add the following code to spec_helper.
config.use_transactional_fixtures = false
RSpec.configure do |config|
config.before(:suite) do
require "#{Rails.root}/db/seeds.rb"
end
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
Thanks Jo Liss for pointing the way.
PS: How to switch drivers on the fly
The above solution assumes you already know how to switch drivers on the fly. In case some who come here don't, here's how:
As above let's assume that you normally will use the default capybara driver rack_test, but need to use selenium to test some Ajaxy stuff. When you want to use the selenium driver use :js => true or #javascript for Rspec or cucumber respectively. For example:
Rspec example:
describe "something Ajaxy", :js => true do
Cucumber example:
#javascript
Scenario: do something Ajaxy
Using transactional fixtures will be faster since the DBMS doesn't commit changes (and therefore no heavy IO occurs resetting the database between tests) but as you know won't always work.
We have had some success using SQLite in-memory databases in the test environment so tests run super fast while leaving transactional fixtures off. This option is also available for MySQL (use :options to set "ENGINE=MEMORY") but I've never done it personally and if you search you'll find a few threads about caveats involved. Might be worth a look. Depending on your testing methodology it may not be acceptable to use a different DB engine though.
I suggest you enable transactional fixtures and use the DatabaseCleaner gem to selectively disable transactional fixtures per example group. I can't say that I've tried this but since you didn't have any answers I figured anything might potentially help you out.
before(:all) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
before(:each) do
DatabaseCleaner.start
end
after(:each) do
DatabaseCleaner.clean
end
If it were me I'd factor this out into a helper and call it as a one-line macro from each example group that needs transactional fixtures turned off.
Seems like there really should be a better way, though.... best of luck.
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
This is from Avdi Grimm's post about database cleaner and Rspec. Step-by-step analysis of the code is in the article.
Have you used Spork ? It greatly enhances speed.
I'm running rails 3.0.3 and using rspec-rails 2.4.1 with a postgresql database. Whenever I run my RSpec tests, the data remains at the end. Does anyone know how to get rails or rspec to wipe the test environment's data between each use?
Please tell me if there's any further information that could make answering my question easier.
Thanks!Tristan
Install the database_cleaner gem and then add this to your spec_helper.rb.
Spec::Runner.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
Use transactional examples to rollback the data after every test run
RSpec.configure do |config|
config.use_transactional_examples = true
end
You don't need any extra gem in order to clean your test DB between runs. In your spec_helper.rb file, configure rspec as follows:
RSpec.configure do |c|
c.around(:each) do |example|
ActiveRecord::Base.connection.transaction do
example.run
raise ActiveRecord::Rollback
end
end
end
Another possibility, that I just put myself through, is using the wrong before block.
I accidentally set a before block as an all instead of an each:
before :all do
user = FactoryGirl.create(:user)
sign_in user
end
This caused the user to stick around in the database for the entire rspec run, which caused validation collisions.
Instead, the before should be an each so that everything is kept clean through the rspec run:
before :each do
user = FactoryGirl.create(:user)
sign_in user
end
If you've made this mistake, then you will probably need to manually clean up your test database before things go back to normal. The simplest way to do that is probably to truncate each of the tables (aside from schema_migrations).