I've got a Rails 3.2.21 app on Ruby 2.1.5 that uses Postgres, Redis as the cache store (config.cache_store = :redis_store), background workers (mostly for view cache warming) with sidekiq. Russian doll caching used with the cache_digests gem so you end up with cache keys like views/my_lovely_partial/5506949e3754753ad58190924d5b029f. Running tests with RSpec, Factory Girl and Capybara.
For the test environment I have set up a parallel Redis server, different port to production and dev, and have "config.action_controller.perform_caching = true" in test rb. It's the same redis setup in dev and test apart from the port being different.
Testing through either controller spec or feature spec I see the presence of objects cached in Redis, either through the tests themselves or directly viewing the keys in redis-cli.
When I try to test for view partials in Redis I find they are not being cached e.g. In dev environment on the same machine the view partials appear in the redis cache whereas in test they don't - only cached objects appear; this is confirmed by viewing through the redis-cli for both dev and test redis instances. 'render_template' and 'have_content' together with viewing the tested page (Using the 'capybara-screenshot' gem) confirm the content is being served successfully but the partials are not being cached in test.
Gems used specifically in test : rspec-rails, factory_girl_rails, faker, capybara, capybara-screenshot, capybara-user_agent, pry, guard-rspec, launchy, database_cleaner, shoulda-matchers, redis, turn.
I've checked in the spec.rb's that perform_caching is still true; tried temporarily removing pry, guard-rspec, launchy, shoulda-matchers gems but no difference. Tried removing database_cleaner gem, disabling all test cache clearing and ran tests again to find only object caching present in redis, no partials.
test.rb
SmashingSuperApp::Application.configure do
config.cache_classes = true
config.whiny_nils = true
config.consider_all_requests_local = false
config.action_dispatch.show_exceptions = true
config.action_controller.allow_forgery_protection = false
config.action_mailer.delivery_method = :test
config.active_support.deprecation = :stderr
config.action_controller.perform_caching = true
config.cache_store = :redis_store, "redis://localhost:6378/0/cache", { expires_in: 1176.hours }
ENV["REDIS_URL"] ||= "redis://localhost:6378/0"
config.action_mailer.raise_delivery_errors = false
config.active_support.deprecation = :log
config.action_dispatch.best_standards_support = :builtin
config.active_record.mass_assignment_sanitizer = :strict
config.active_record.auto_explain_threshold_in_seconds = 0.5
config.log_tags = [:uuid, :remote_ip]
config.before_initialize do |app|
app.config.paths.add 'app/models', :eager_load => true
end
config.to_prepare do
Dir["#{Rails.root}/app/models/*"].each do |model_name|
require_dependency model_name unless model_name == "." || model_name == ".."
end
end
Rails.application.routes.default_url_options[:host]= 'smashingsuperapp.co.uk:3000'
end
rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'capybara/rails'
require 'capybara-screenshot/rspec'
require 'shoulda/matchers'
require 'faker'
require 'redis'
RSpec.configure do |config|
config.include Rails.application.routes.url_helpers
config.infer_spec_type_from_file_location!
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
Rails.cache.clear # Clear redis cache
end
config.before(:each) do |example|
DatabaseCleaner.strategy= example.metadata[:js] ? :truncation : :transaction
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
Rails.cache.clear # Clear redis cache
end
config.include FactoryGirl::Syntax::Methods
config.after do |example|
if example.metadata[:type] == :feature and example.exception.present?
save_and_open_page
end
end
end
def set_host (host)
default_url_options[:host] = host
Capybara.app_host = "http://" + host
end
spec_helper.rb
require 'capybara/user_agent'
Capybara::UserAgent.add_user_agents(mechanize: 'Mechanize')
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.include Capybara::UserAgent::DSL
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
=begin
config.filter_run :focus
config.run_all_when_everything_filtered = true
config.disable_monkey_patching!
if config.files_to_run.one?
config.default_formatter = 'doc'
end
config.profile_examples = 10
config.order = :random
Kernel.srand config.seed
=end
end
def get_path(path)
parsed_params = Rails.application.routes.recognize_path path
controller = parsed_params.delete(:controller)
action = parsed_params.delete(:action)
get(action, parsed_params)
end
Feature specs use 'visit' and controller specs use 'get' to the correct URL's and render the correct content.
Any pointers as to why partials wouldn't be being cached in this situation very much appreciated. Thanks in advance.
Thought I'd try adding the 'selenium-webdriver' gem and after lots of irony debugging/trial/error in the test environment I then found cached partials were appearing in Redis.
In case it helps others as I found a information a bit patchy;
Further added
gem 'selenium-webdriver'
into test group of Gem file.
Modified /spec/rails_helper.rb below. Note particularly Capybara.server_port = 10000, Capybara.always_include_port = true, Capybara.javascript_driver = :selenium - default port was not being picked up in js marked tests so had to lock it down there.
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'capybara/rails'
require 'capybara-screenshot/rspec'
require "rack_session_access/capybara"
require 'shoulda/matchers'
require 'faker'
require 'redis'
require 'support/wait_for_ajax'
RSpec.configure do |config|
config.include Rails.application.routes.url_helpers
config.infer_spec_type_from_file_location!
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
Rails.cache.clear # Clear redis cache
# To prevent FactoryGirl creating persons with an id that are reserved for 'special' persons
ActiveRecord::Base.connection.execute("ALTER SEQUENCE persons_id_seq START with 4000 RESTART;")
end
config.before(:each) do |example|
DatabaseCleaner.strategy= example.metadata[:js] ? :truncation : :transaction
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
Rails.cache.clear # Clear redis cache
end
config.include FactoryGirl::Syntax::Methods
config.after do |example|
if example.metadata[:type] == :feature and example.exception.present?
save_and_open_page
end
end
end
Capybara.server_port = 10000
Capybara.always_include_port = true
Capybara.javascript_driver = :selenium
def set_host (host)
# host! host
default_url_options[:host] = host
Capybara.app_host = "http://" + host
end
The "require 'support/wait_for_ajax'" in the above, described here, is something I came across whilst trying to get selenium up and running that looks handy for ajax testing. Although ajax was not playing a role in the cached partials I was testing for this, there are others with ajax calls where this would be handy.
For the feature tests using selenium, have those tests in their own describe block e.g.
describe "special person accesses event with JS tests" do
before(:each) do
Capybara.current_driver = :selenium
end
after(:all) do
Capybara.use_default_driver
end
scenario 'can view persons partial with cache insertion', js: true do
visit some_cached_page_path(id:some_page_id)
...
And then any following tests that use rack_test (default no full browser and no js tests) put them in a separate describe block but without 'js: true' and those before and after blocks. Initially I thought I would only need to mark selenium driven test blocks with "js: true" but found issues then with the basic rack_test based blocks until I took the above describe block approach.
Related
I'm currently running a Rails 6 App with Rspec and Capybara. When running the system specs, rails automatically generates screenshots. This makes my tests slow. I would like to disable the screenshots. How do i disable screenshots?
spec_helper.rb
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
config.shared_context_metadata_behavior = :apply_to_host_groups
end
rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
puts e.to_s.strip
exit 1
end
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
config.include FactoryBot::Syntax::Methods# config.filter_gems_from_backtrace("gem name")
end
Capybara.default_driver = :selenium_chrome_headless
Currently, the only way to disable screenshot is by including a before block like this:
require 'rails_helper'
RSpec.describe 'Hello world', type: :system do
before do
driven_by(:selenium_chrome_headless)
end
describe 'index page' do
it 'shows the right content' do
get hello_world_index_path
expect(page).to have('hello world')
end
end
end
I'm looking for a more sustainable way to disable the screenshots by default.
Rails calls the take_failed_screenshot by default in the teardown phase of the tests https://github.com/rails/rails/blob/c5bf2b4736f2ddafbc477af5b9478dd7143e5466/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb#L8
I don't see any configuration to turn that off.
The method is defined here https://github.com/rails/rails/blob/c5bf2b4736f2ddafbc477af5b9478dd7143e5466/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb#L44-L46
Maybe you can try to override that method to not take the screenshot? something like this is you use minitest:
# test/application_system_test_case.rb
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]
def take_failed_screenshot
end
end
or if you use RSpec:
# spec/rails_helper.rb
module NoFailedScreenshots
def take_failed_screenshot
end
end
RSpec.configure do |config|
config.include(NoFailedScreenshots)
...
But one comment, if these are the screenshots you refer to, then you have a problem with too many failing specs if that slows things down, you should fix the specs instead.
If this is not what's happening to you then you probably have some custom setup taking screenshots that it's not standard Rails
I added selenium webdriver to my test setup to start writing some tests based on javascript. I added
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.javascript_driver = :selenium_chrome
Capybara.configure do |config|
config.default_max_wait_time = 5
config.default_driver = :selenium
end
to my rails helper which now look like this
rails_helper.rb
require "spec_helper"
ENV["RAILS_ENV"] ||= "test"
require File.expand_path("../config/environment", __dir__)
# 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 "capybara/rspec"
Dir[Rails.root.join("spec", "support", "**", "*.rb")].each { |f| require f }
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
puts e.to_s.strip
exit 1
end
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.javascript_driver = :selenium_chrome
Capybara.configure do |config|
config.default_max_wait_time = 5
config.default_driver = :selenium
end
# 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")
# Include Factory Bot syntax methods
config.include FactoryBot::Syntax::Methods
# Configure Database Cleaner
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
end
After these changes, my previous feature tests broke because now they do not use the fixtures created within the tests.
i.e features/article_spec.rb
require "rails_helper"
RSpec.describe "articles", type: :feature do
before :each do
create(:article, published: false)
create(
:article,
name: "Published article",
body_text: "Lorem ipsum",
published_at: Time.now,
published: true
)
end
describe "article feature" do
it "shows only published articles" do
visit("/articles")
expect(page).to have_css(".article-container", count: 1)
end
end
end
The tests are not running headless so I can follow along and see that no articles are present despite the creation within article_spec.rb. I assume the driver executes the tests using another server and/or another database but I'm not sure. In which case don't know how to change that or how to seed that database. You guys have any clue?
You can't use an around hook for database cleaner with RSpec and Capybara because of the order the hooks get run in. If you're going to continue using database cleaner you need to be using closer to the recommended configuration - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example
That being said, since Rails 5.1 assuming you're using a normal configuration (testing with local app, normal DB config, up to date rspec-rails, etc) you don't need to use database cleaner at all, just set config.use_transactional_fixtures = true in your RSpec configuration, remove all references to database cleaner, and the DB connection should be safely shared between your tests and the app under test.
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
I have an RSpec feature spec that tests the login for my app. It passes when I run it in RSpec with Capybara, but when I try to run it flagged with js: true using Capybara-webkit, it fails. This is a problem because my entire app is behind the login, and if I can't get this bit to run I don't know how to do feature specs for the rest of the app.
Here's what I have tried:
Installing all the Capybara-webkit dependencies listed here. I'm running my app in a Docker container built on the ruby:2.3 image, which is built on Jessie.
Setting up DatabaseCleaner per this blog post. My database_cleaner.rb file is below.
Using the Headless gem (headless.rb below)
Running RSpec like so: xvfb-run -a bin/rspec spec/features/log_in_spec.rb (seems no different than running it normally with Headless)
How do I get my login specs to work under Capybara-webkit? Some of my specs will need to be flagged for JS and some won't, but they'll all need the user to be logged in. Thank you.
log_in_spec.rb
require 'rails_helper'
RSpec.feature "Log in", type: :feature do
scenario "as admin" do
user = create(:admin)
# Tried this instead of with Capybara, works with Capybara but not capybara-webkit
# login_as user, scope: :user, run_callbacks: false
visit root_path
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
find('.btn-primary').click
expect(page).to have_content('Admin')
end
end
spec_helper.rb
require 'capybara/rspec'
require 'paperclip/matchers'
RSpec.configure do |config|
Capybara.javascript_driver = :webkit
Capybara.app_host = 'https://192.168.99.101'
config.include Paperclip::Shoulda::Matchers
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
mocks.verify_doubled_constant_names = true
end
config.filter_run :focus
config.run_all_when_everything_filtered = true
config.disable_monkey_patching!
if config.files_to_run.one?
config.default_formatter = 'doc'
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 'spec_helper'
require 'rspec/rails'
require 'capybara/rails'
require 'devise'
require 'support/controller_macros'
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.filter_rails_from_backtrace!
config.include Warden::Test::Helpers
config.before :suite do
Warden.test_mode!
end
config.after :each do
Warden.test_reset!
end
end
# Added headless gem and this code thanks to this post: http://stackoverflow.com/a/28706535/3043668
if ENV['HEADLESS']
require 'headless'
headless = Headless.new
headless.start
at_exit { headless.stop }
end
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
spec/support/headless.rb
RSpec.configure do |config|
config.around type: :feature do |example|
Headless.ly do
example.run
end
end
end
spec/support/capybara.rb
Capybara::Webkit.configure do |config|
config.debug = true
config.allow_unknown_urls
config.timeout = 5
config.ignore_ssl_errors
config.skip_image_loading
end
Here is a gist of the debug output from Capybara-webkit when I run the test. It looks like it's trying the same thing over and over.
UPDATE
I removed my Capybara.app_host setting, and the non-JS test still passes, but when I run it under capybara-webkit, I see this in the debig output:
Received 0 from "https://127.0.0.1:37193/login"
Page finished with false
Load finished
Page load from command finished
Wrote response false "{"class":"InvalidResponseError","message":"Unable to load URL: http://127.0.0.1:37193/login because of error loading https://127.0.0.1:37193/login: Unknown error"}"
Received "Reset()"
Started "Reset()"
undefined|1|SecurityError: DOM Exception 18: An attempt was made to break through the security policy of the user agent.
It's trying to visit("/login") and it is being redirected to the https version, and this is making it fail. How do I make it succeed?
The first reason is that the record after save procedure c=keep not the password in plain view, but seems that it is good in this case:
user = create(:admin)
# ...
user = User.first # wrong way
#...
fill_in 'Password', with: 'password'
The second reason in fail to login is that factory girl and capybara uses separate connections, so and data created in one session isn't available in another. To fix it use single connection patch (put it to spec/support) as described here.
This was a hard one. But the issue was that I had set force_ssl = true in my application.rb, stupidly, instead of putting it in production.rb and development.rb like a normal person.
I also had set Capybara-webkit's app_host, which, as it turned out, I did not need to do. After removing that, and running capybara-webkit with debug on, I saw that it was trying to redirect from http://localhost:45362/login (or whatever port) to https://localhost:45362/login (note the https!) and that this was causing a DOM 18 security error or whatever, and this was making it choke. I turned off force_ssl and now it works like a champ. Hope this helps you not tear your hair out.
For a while I was using Selenium / Spork / Rspec, with cache_classes on false, and everything seemed to be working.
In switching over to webkit, I've started to get errors related to cache_classes (e.g. Expected User, got User), so I've been fighting with it to try to get cache_classes set to true.
However no matter what I do, I end up with the following error:
Capybara::Driver::Webkit::WebkitInvalidResponseError:
Unable to load URL: http://127.0.0.1:56398/login
I have tried all kinds of things... including:
ActiveSupport::Dependencies.clear in both the prefork and each _run blocks
The code here: http://my.rails-royce.org/2012/01/14/reloading-models-in-rails-3-1-when-usign-spork-and-cache_classes-true/
Starting to wonder if I should just live with cache_classes = false, and figure out how to avoid the Factory girl errors. Any help would be appreciated. My spork file is as follows:
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rails'
require 'capybara/rspec'
require 'database_cleaner'
require 'factory_girl'
require 'authlogic/test_case'
require 'email_spec'
include Authlogic::TestCase
require File.expand_path("../../config/environment", __FILE__)
RSpec.configure do |config|
# == Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
config.mock_with :rspec
ApplicationController.skip_before_filter :activate_authlogic
config.include(EmailSpec::Helpers)
config.include(EmailSpec::Matchers)
config.include Capybara::DSL
# 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
# 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.before(:suite) do
DatabaseCleaner.strategy = :truncation, {:except => %w[ages coefficients weights1 weights2 weights3 weights4 weights5 weights6 weights7 weights8 etfs]}
DatabaseCleaner.clean
end
config.before(:each) do
DatabaseCleaner.start
Capybara.current_driver = :webkit if example.metadata[:js]
#Capybara.current_driver = :selenium if example.metadata[:js]
activate_authlogic
ActiveRecord::Base.instantiate_observers
end
config.after(:each) do
DatabaseCleaner.clean
Capybara.use_default_driver if example.metadata[:js]
end
Capybara.default_selector = :css
end
# 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}
## SUPPORT METHODS ##
## (erased for clarity) ##
## ##
ActiveSupport::Dependencies.clear
end
Spork.each_run do
#FactoryGirl.reload
# Required to fix a recurring error when testing Active_Admin stuff
# See here: http://railsgotchas.wordpress.com/2012/01/31/activeadmin-spork-and-the-infamous-undefined-local-variable-or-method-view_factory/
# Delete at some point if active admin or whoever fixes this
ActionView::Template.register_template_handler :arb, lambda { |template|
"self.class.send :include, Arbre::Builder; #_helpers = self; self.extend ActiveAdmin::ViewHelpers; #__current_dom_element__ = Arbre::Context.new(assigns, self); begin; #{template.source}; end; current_dom_context"
}
#ActiveSupport::Dependencies.clear
end
UPDATE : Adding an example spec just in case it helps....
describe "Items" do
before(:each) do
#user = Factory.create(:user)
activate_authlogic
b = # something not important
end
describe "usage paths" do
it "the form directly from the basic_simulation show page should have correctly functioning javascript validation", :js => true do
request_sign_in(#user) # This is a helper method which goes through the login form
visit '/basic_simulation'
fill_in "amount", :with => "-5000"
click_button "Calculate"
page.should have_selector("label.jquery-validator.amount-error", :text => "Please enter a value greater than or")
fill_in "amount", :with => "5000"
click_button "Calculate"
page.should have_selector("input#amount", :value => "5000")
end
end
You are having issues due to threading problems with Capybara-webkit and the test suite.
Jose Valim explains it much more clearly in a recent blog post.
If you follow his recommendations then you should be able to turn on transactional fixtures, remove database cleaner altogether and no longer have issues with your data during tests while using capybara-webkit. You'll get a nice boost in testing performance as well.
The trick though is to make sure that Jose's suggestion is in the Spork.each_run block or it will not work. For clarity here are the relevant parts of my spec_helper.rb.
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
Capybara.default_driver = :rack_test
Capybara.default_selector = :css
Capybara.javascript_driver = :webkit
end
end
Spork.each_run do
if Spork.using_spork?
ActiveRecord::Base.instantiate_observers
end
require 'factory_girl_rails'
# Forces all threads to share the same connection, works on Capybara because it starts the web server in a thread.
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
end
A few other small suggestions:
If you are using the latest version of factory_girl_rails then you
should be using require factory_girl_rails in the Spork.each_run
block and require factory_girl should be removed from the prefork
The latest factory_girl_rails also no longer requires ActiveSupport::Dependencies.clear at all, although some people are still having issues without it so you should test removing it.
I'm still not sure about the need for ActiveRecord::Base.instantiate_observers but in any case you would only need it if you are using observers and I understand that it should be in the each_run block.
Try all that and see if it works for you.