RSpec + DatabaseCleaner + PhantomJS: database get randomly erased during example with js - ruby-on-rails

I have a simple scenario in my rspec feature:
require 'spec_helper'
feature 'CLIENT views results page' do
context 'from welcome/index form' do
let!(:location) { FactoryGirl.create :location, name: 'town' }
before :each do
visit '/'
end
scenario 'successfully', js: true do
expect(Location.count).to eq 1
fill_in 'from_address', with: 'Some address'
fill_in 'to_address', with: 'Another address'
click_button 'Search'
expect(page).to have_content 'Some address → Another address'
end
end
end
spec_helper:
require 'rubygems'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'factory_girl'
require 'database_cleaner'
require 'capybara/poltergeist'
FactoryGirl.reload
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.infer_base_class_for_anonymous_controllers = true
config.order = "random"
config.tty = true
config.mock_with :rspec
config.filter_run focus: true
config.run_all_when_everything_filtered = true
config.treat_symbols_as_metadata_keys_with_true_values = true
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
Capybara.javascript_driver = :poltergeist
Capybara.asset_host = "http://localhost:3000"
Capybara.server_port = 9887 + ENV['TEST_ENV_NUMBER'].to_i
And my scenario fails on some random step (after expect(Location.count).to eq 1) due to the fact, that there are no Location records:
(byebug) Location.all
[]
I think it might be one of two cases:
Either DatabaseCleaner cleans database before an example finishes
Or there are actually two threads with two databases, one of which (the one that is used by the app) is really empty
Gem versions:
rspec (2.14.1)
rspec-core (2.14.8)
rspec-rails (2.14.0)
phantomjs (1.9.7.1)
rails (3.2.21)
database_cleaner (0.9.1)

I remember having issues with this as well. My config for DB cleaning looks like this:
config.before(:each) do
if Capybara.current_driver == :rack_test
DatabaseCleaner.strategy = :transaction
else
DatabaseCleaner.strategy = :truncation
end
DatabaseCleaner.start
end
config.after do
DatabaseCleaner.clean
end
Maybe it has something to do with the order your before blocks are called. So if DatabaseCleaner.start is called before you wanted strategy is set, you might see such results.

Managed to solve this issue by migrating to
config.use_transactional_fixtures = true
instead of using DatabaseCleaner. Some workarounds are suggested to make transactional cleaning work with javascript tests. I chose this one:
(adding somewhere in the beginning of spec/spec_helper)
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
cause it seemed to work faster, still leaving some spontaneously failing tests (might not be the problem related to database).

Related

Capybara not holding user session after one page visit -- Rails 4.2

I can't get Capybara to hold a session beyond one page visit within one spec. I am familiar with the concept that Capybara's driver might be using a different database connection, but anything I do (including not using :js => true) doesn't seem to change anything.
I am just trying to visit a page that requires user authentication. It succeeds on first visit. It fails when I visit it a second time. (This of course all works when I manually test in development.) Code:
activity_areas_spec.rb
require "rails_helper"
RSpec.feature "Activity areas", :type => :feature do
user = FactoryGirl.create(:user)
before(:each) do
login_as(user, :scope => :user)
end
after(:each) do
Warden.test_reset!
end
...
feature "displays activities shared", :js => true do
scenario "to public" do
visit area_activities_path
expect(page).to have_content I18n.t('pages.activity.areas.title') #passes
visit area_activities_path
expect(page).to have_content I18n.t('pages.activity.areas.title') #fails -- user is redirected to login page.
end
end
end
#rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'spec_helper'
require 'capybara/rails'
require 'devise'
require 'support/controller_macros'
include Warden::Test::Helpers
Warden.test_mode!
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Factory girl
config.include FactoryGirl::Syntax::Methods
# Make routes available in specs
config.include Rails.application.routes.url_helpers
# Capybara
config.include Capybara::DSL
# To get Devise test helpers
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros::DeviseHelper, :type => :controller
config.include ControllerMacros::AttributeHelper, :type => :controller
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
# Database cleaner gem configurations
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
Since I was sensitive to the fact that Capy might be using a different database connection, I have tried following DatabaseCleaner's suggested code to the tee in the place of the above DatabaseCleaner commands:
config.before(:suite) do
if config.use_transactional_fixtures?
raise(<<-MSG)
Delete line `config.use_transactional_fixtures = true` from rails_helper.rb
(or set it to false) to prevent uncommitted transactions being used in
JavaScript-dependent specs.
During testing, the app-under-test that the browser driver connects to
uses a different database connection to the database connection used by
the spec. The app's database connection would not be able to access
uncommitted transaction data setup over the spec's database connection.
MSG
end
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, type: :feature) do
driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test
if !driver_shares_db_connection_with_specs
DatabaseCleaner.strategy = :truncation
end
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
See here.
#spec_helper.rb
require 'factory_girl_rails'
require "capybara/rspec"
require 'sidekiq/testing'
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
I'm confused easily, so much appreciated for any help that is provided in simple terms. And let me know if you need any other files.
As a quick guess your user = FactoryGirl.create(:user) needs to be inside your before block - otherwise it would only be run once when the feature is loaded - and then removed from the database before the first feature is run

`autodetect': No known ORM was detected

Unable to clean data using database_cleaner.rb; throwing the following issue on running tests.
/Users/prashanth_sams/.rvm/gems/ruby-2.0.0-p598/gems/database_cleaner-1.3.0/lib/database_cleaner/base.rb:147:in
`autodetect': No known ORM was detected! Is ActiveRecord, DataMapper,
Sequel, MongoMapper, Mongoid, Moped, or CouchPotato, Redis or Ohm
loaded? (DatabaseCleaner::NoORMDetected)
spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../config/environment", __FILE__)
require 'rspec/rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
config.use_transactional_fixtures = false
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.color = true
Selenium::Application.reload_routes!
end
database_cleaner.rb
require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :each do
DatabaseCleaner.start
end
config.after :each do
DatabaseCleaner.clean
end
end
I had same issue on controller_spec.
'autodetect': No known ORM was detected! Is ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, Moped, or CouchPotato, Redis or Ohm loaded? (DatabaseCleaner::NoORMDetected)
I resolved by requiring rails_helper file on controller spec.
require 'rails_helper'
In rails_helper.rb require file 'database_cleaner'.
require 'database_cleaner'
I had this issue (on Rails 5.1) and the reason was that I had
config.before(:suite) do
DatabaseCleaner.clean_with :truncation
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
in my spec_helper.rb.
I put require 'database_cleaner in spec_helper.rb as well.
So eventually I moved both things to rails_helper.rb and that fixed the issue for me.
Use my setup, seems to work fine for RDBMS (checked on MySQL and Postgres), put it into your 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
# this may be needed for Capybara tests and for testing after_commit hooks
config.before(:each, strategy: :truncation) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
If you want to use truncation strategy, just use
describe 'something', strategy: :truncation or it 'something', strategy: truncation.

Problems with rspec 3, capybara and machinist 2

I have this feature test (Store model have a uniqueness validation):
feature "Index" do
before do
3.times { Store.make! }
end
scenario "User visit index" do
visit stores_path
within("table.table") do
Store.all.each do |store|
expect(page).to have_content(store.name)
end
end
end
end
When i run the test, randomly fails:
Failure/Error: 3.times { Store.make! }
ActiveRecord::RecordInvalid:
Validation failed: name has already been taken
My blueprint is (follow the machinist documentation to generate a unique record):
Store.blueprint do
name { "store #{sn}" }
end
I use DatabaseCleaner gem, then my config rails_spec:
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'shoulda/matchers'
require 'capybara/rails'
require 'capybara/rspec'
require 'pundit/rspec'
require 'database_cleaner'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.before(:each) do |example|
DatabaseCleaner.strategy = if example.metadata[:js]
:truncation
else
:transaction
end
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
DatabaseCleaner.logger = Rails.logger
config.infer_spec_type_from_file_location!
That errors are driving me crazy
Try to replace the following in your spec/spec_helper.rb:
config.before :suite do |example|
DatabaseCleaner.strategy = example.metadata[:js] ? :truncation : :transaction
end
config.before do
DatabaseCleaner.clean
end

Object is created. (RoR, Database Cleaner, Factory Girl)

I'm a beginner in Rails, help me, I do not understand what the problem is. It seems like something else is written before(:each)...
And How can I write a test in test_spac.rb in which no Card object is created. That the method before(:each) did not work for this test.
This is work:
test_spec.rb:
require 'rails_helper'
describe "Index Page" do
before(:each) do
#card = FactoryGirl.create(:card)
DatabaseCleaner.start
end
it "shows error messages if translation is wrong" do
visit root_path
fill_in 'translated_text', with: 'wqww'
click_on 'Проверить'
expect(page).to have_content('Неверно!')
end
after(:each) do
DatabaseCleaner.clean
end
end
rails_helper.rb:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/poltergeist'
require 'database_cleaner'
Capybara.javascript_driver = :poltergeist
Capybara.default_driver = :poltergeist
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.before(:each) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each, type: :features) do
DatabaseCleaner.strategy = :truncation
end
config.infer_spec_type_from_file_location!
end
This is NOT Work:
test_spec.rb:
require 'rails_helper'
describe "Index Page" do
before(:each) do
#card = FactoryGirl.create(:card)
end
it "shows error messages if translation is wrong" do
visit root_path
fill_in 'translated_text', with: 'wqww'
click_on 'Проверить'
expect(page).to have_content('Неверно!')
end
end
rails_helper.rb:
config.use_transactional_fixtures = false
config.before(:each) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each, type: :features) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
Problem solved:
I make this: (test_spec.rb)
require 'rails_helper'
describe "Index Page" do
it "check behavior then translation is wrong" do
FactoryGirl.create(:card) #################
visit root_path
fill_in 'translated_text', with: 'some text'
click_on 'Проверить'
expect(page).to have_content('Неверно!')
end
it "check page then object is not created" do
visit root_path
expect(page).to have_content('Непросмотренных')
end
end
Could you post what you mean by not working? Are you getting any error messages?
By the way, why do you have config.use_transactional_fixtures disabled? If you stick to using before(:each) hooks, RSpec will reset the database for you and you shouldn't need to use the DatabaseCleaner.

Clear database after testing a rake task using RSpec

I'm trying to test my rake task using rspec and it runs fine, but the problem is that the records aren't being deleted afterwards.
I've put config.use_transactional_fixtures = true in the config file to no affect. In other tests it's was working fine.
Here's my code:
require 'rspec'
require 'spec_helper'
require 'rake'
describe 'my_app rake tasks' do
describe 'rake_task_1' do
before { MyApp::Application.load_tasks }
it 'should test it!' do
10.times { create(:record) }
Rake::Task["rake_task_1"].invoke
Record.count.should == 10
end
end
end
In my rake task I'm executing a query using ActiveRecord::Base.connection.execute.
I'm sure it has something with SQL transitions in RSepc....
any ideas?
Have you tried using database_cleaner gem?
You can check the great article by Avdi Grimm about how to configure it.
config.use_transactional_fixtures = false
In file spec/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

Resources