Rails - Singleton class troubles with rspec feature - ruby-on-rails

I have a problem testing a functionality that depends of a Singleton class. That class (ERPDao) is a suite with diferent methods that helps application to connect with external ERP vía REST services using Faraday gem. URLMaker is a helper class for build requests strings. When i try to run a feature spec that depends of one of this methods i have the following message in rspec:
Failure/Error: result = ERPDao.instance.get_credit_info(erp_id)
NoMethodError:
undefined method `instance' for ERPDao:Class
Did you mean? instance_of?
Did you mean? instance_of?
My class ERPDao
class ERPDao
def initialize
#end_points = EndPoint.first
#connection = Faraday.new(:url => #end_points.url_base, request: {
open_timeout: 10, # opening a connection
timeout: 10 # waiting for response
})
end
##instance = ERPDao.new
def self.instance
return ##instance
end
def get_credit_info(erp_id)
begin
return #connection.get URLMaker.instance.get_uri('credit_info', erp_id)
rescue Faraday::Error::ConnectionFailed => e
puts "Connection failed: #{e}"
return 0, false, 0
end
end
...
end
My rails_helper.rb
require 'spec_helper'
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 'rspec/rails'
require 'support/factory_bot'
require 'support/wait_for_ajax'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.before :suite do
DatabaseCleaner.strategy = :truncation
end
config.before :each do
DatabaseCleaner.clean
end
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
config.include Warden::Test::Helpers
config.include Devise::TestHelpers, type: :controller
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
Capybara.javascript_driver = :webkit
Capybara::Webkit.configure do |config|
config.debug = false
config.allow_unknown_urls
config.skip_image_loading
config.timeout = 15
config.raise_javascript_errors = false
end
end
My version of rails is 4.2.6, ruby 2.3.1, factory_bot 4.8.2 and rspec-rails 3.7.
Someone knows about this error?
Thanks!

ERPDao is [also] being defined somewhere else. Maybe someone decided to add a method to it by re-opening the class like
class ERPDao
def some_new_method
...
end
end
Don't do that. Use modules and prepend instead.
module HasMyNewMethod
def some_new_method
...
end
end
ERPDau.prepend HasMyNewMethod
Otherwise you end up accidentally referencing the re-opening of the class and that becomes the definition - so the autoloader doesn't load it since it's already defined.
Search your codebase for 'class ERPDao'. Modify the ones that are not the initial declaration.

Related

How to disable screenshot in rails 6 rspec app

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

Attempted to assign to readonly property on Capybara

I'm working on updating a rails 3.2 app to rails 4.2.10, I've got almost everything worked out, unit tests and integration tests passing.
I'm having some issues with feature tests, I'm using capybara 3.3.0 and poltergeist 1.18.1 and it throws me error on visit '/'
I've looked at lots of issues on Stack regarding Attemped to assign to readonly property but none of them apply to my case here,
This is my stripped down spec file
require 'vcr'
Capybara.default_max_wait_time = 10
feature "Create something" do
include SpecHelpers
include Acceptance
before do
setup_database
end
after do
teardown_database
end
scenario "Creating a Consignment", :js => true do
puts "Running with #{Capybara.current_driver}"
VCR.use_cassette('cassette_name.yml') do
page.driver.resize(1000,2200) unless Capybara.current_driver == :selenium
visit '/'
expect(page).to have_content 'EMAIL'
expect(page).to have_content 'PASSWORD'
end
end
end
This is my stripped down spec helper file
ENV["RAILS_ENV"] ||= 'test'
require_relative '../config/environment.rb'
require 'rspec/rails'
require 'capybara/rails'
require 'capybara/poltergeist'
require 'shoulda/matchers'
require 'redis'
require 'redis-namespace'
require 'resque'
require 'mock_redis'
require 'bcrypt'
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
# rspec
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
RSpec.configure do |config|
config.deprecation_stream = 'log/deprecations.log'
end
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, :type => :controller
end
RSpec::Expectations.configuration.on_potential_false_positives = :nothing
BCrypt::Engine.cost = 1
if (ENV['DEBUG_CAP'])
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
else
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, {js_errors: true})
end
Capybara.javascript_driver = :poltergeist
end
Capybara.server_port = 31337
Capybara.server = :webrick
module SpecHelpers
def setup_database
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start
end
def teardown_database
DatabaseCleaner.clean
end
end
module Acceptance
VCR.configure do |c|
require 'webmock'
c.hook_into :webmock
c.cassette_library_dir = 'fixtures/vcr_cassettes'
c.allow_http_connections_when_no_cassette = true
c.default_cassette_options = {:record => :new_episodes}
c.ignore_request do |request|
URI(request.uri).port == Capybara.server_port || request.uri=~/shutdown/ || request.uri=~/session/
end
end
def wait_until(timeout = Capybara.default_max_wait_time)
require "timeout"
begin
Timeout.timeout(timeout) do
sleep(0.3) until value = yield
value
end
rescue => e
save_screenshot "capybara_#{Time.now.to_i}.png"
puts e.message
puts e.backtrace
raise e
end
end
end
require "rspec/mocks/standalone"
....
This is the error stack trace
Running with poltergeist
Error: Attempted to assign to readonly property.
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:22:3139
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:3551
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:19730
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12707
s#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:20964
g#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12573
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:16265
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:22205
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4884
$digest#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:7801
$apply#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:9410
http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26430
a#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26340
Z#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26051
http://127.0.0.1:31337/lib/bfd57c67.components.js:7:28112
d#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:18351
fireWith#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:19152
ready#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:13970
wt#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:11347
Error: Attempted to assign to readonly property.
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:22:3139
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:3551
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:19730
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12707
s#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:20964
g#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12573
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:16265
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:22205
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4884
$digest#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:7801
$apply#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:9410
http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26430
a#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26340
Z#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26051
http://127.0.0.1:31337/lib/bfd57c67.components.js:7:28112
d#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:18351
fireWith#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:19152
ready#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:13970
wt#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:11347
Error: Attempted to assign to readonly property.
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:22:3139
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:3551
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:19730
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12707
s#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:20964
g#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12573
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:16265
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:22205
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4884
$digest#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:7801
$apply#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:9410
http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26430
a#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26340
Z#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26051
http://127.0.0.1:31337/lib/bfd57c67.components.js:7:28112
d#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:18351
fireWith#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:19152
ready#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:13970
wt#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:11347
Update 1
Upon some debugging, it turns out that error gets thrown from angularjs-bootstrap-datetimepicker package when it tries to set $render to a function,
var ngModelController = $element.controller('ngModel')
var configuration = createConfiguration()
$scope.screenReader = configuration.screenReader
// Behavior
$scope.changeView = changeView
ngModelController.$render = $render --> in this line

Factories not loading with single test but loads with all tests

I am following the rails api book but building the code in an engine. The test is at spec/controllers/concerns/handicap/authenticable_spec.rb and looks like this
require 'spec_helper'
require_relative '../../../../app/controllers/concerns/handicap/authenticable.rb'
class Authentication
include Handicap::Authenticable
end
module Handicap
describe Authenticable, type: :controlller do
let(:authentication) { Authentication.new }
subject { authentication }
describe "#current_user" do
before do
#user = FactoryGirl.create :handicap_user
request.headers["Authorization"] = #user.auth_token
authentication.stub(:request).and_return(request)
end
it "returns the user from the authorization header" do
expect(authentication.current_user.auth_token).to eql #user.auth_token
end
end
end
end
When I run the test directly i.e. rspec ./spec/controllers/concerns/handicap/authenticable_spec.rb I get an error:
uninitialized constant Handicap::FactoryGirl
However, when I run all the tests i.e. rspec spec, it does find the FactoryGirl constant and the test fails with
undefined local variable or method `request' for #<RSpec::ExampleGroups::HandicapAuthenticable::CurrentUser:0x007ff276ad5988>.
According to this github issue, I need to add < ActionController::Base to the Authentication class i.e.
class Authentication < ActionController::Base
but if I add this in, I get
uninitialized constant ActionController
I have also tried adding < Handicap::ApplicationController but get
uninitialized constant Handicap::ApplicationController
There appears to be something wrong with my namespacing. There are three symptoms, the fact that FactoryGirl cannot be found if I run the test by itself, but is found when all the tests are run. The second is that it cannot find ActionController even when all the tests are run. The third is that I need to add the line:
require_relative '../../../../app/controllers/concerns/handicap/authenticable.rb'
to find the module that is being tested.
How do I fix my namespacing?
The rails_helper.rb file is
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../dummy/config/environment.rb', __FILE__)
require 'rspec/rails'
require 'capybara'
require 'capybara/rails'
require 'capybara/rspec'
require 'capybara-screenshot'
require 'capybara-screenshot/rspec'
require 'capybara/poltergeist'
require 'capybara/email/rspec'
require 'pp'
require 'chris_api_helpers'
# 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 'factory_girl_rails'
ActiveRecord::Migration.maintain_test_schema!
Shoulda::Matchers.configure do |config|
config.integrate do |with|
# Choose a test framework:
with.test_framework :rspec
with.library :rails
end
end
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# force test migrations for db:migrate
ActiveRecord::Migration.maintain_test_schema!
Capybara::Screenshot.prune_strategy = { keep: 20 }
Capybara::Screenshot.append_timestamp = false
config.include FactoryGirl::Syntax::Methods
FactoryGirl.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
FactoryGirl.find_definitions
config.include Devise::Test::ControllerHelpers, type: :controller
end
and the spec_helper.rb is
require 'simplecov' if ENV["COVERAGE"]
SimpleCov.start do
add_filter '/spec/'
add_filter '/config/'
add_filter '/lib/'
add_filter '/vendor/'
add_group 'Controllers', 'app/controllers'
add_group 'Models', 'app/models'
add_group 'Helpers', 'app/helpers'
add_group 'Mailers', 'app/mailers'
add_group 'Views', 'app/views'
end if ENV["COVERAGE"]
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
#http://stackoverflow.com/questions/30859037/suppress-backtrace-for-rspec-3
config.backtrace_exclusion_patterns = [
/\/lib\d*\/ruby\//,
/bin\//,
/gems/,
/spec\/spec_helper\.rb/,
/lib\/rspec\/(core|expectations|matchers|mocks)/
]
end
You should not be putting specs into modules. This is the cause of problem here. If you need to reference a namespaced class, reference it like RSpec.describe Handicap::Authenticatable.
In general, when you are within a namespace and need to reference something explicitly from the 'root' scope, you can prepend it with double-colons. Such as:
module Handicap
class Something
def do_stuff
::FactoryGirl.create(:person)
end
end
end
It turns out that at the top of my file I should have had require 'rails_helper', not require 'spec_helper'``. All my other files hadrequire 'rails_helper'`` so when I ran the whole test suite, the rails_helper was being loaded anyway.
Embarrassing, but this Q&A might help someone else that has trouble spotting simple errors.

Why do I receive this RSpec error when I try to create a factory?

**Update*: Scroll to very bottom for reproducible error in bare minimum rails app*
I am testing a rails task with Rspec, the fantaskspec gem, and the Factory Girl. When I try to run tests I receive this error:
1) update_account_reverification_table update_account_reverification_table
Failure/Error: account = create(:account, twitter_id: 1234567890)
NoMethodError:
undefined method `create' for #<RSpec::ExampleGroups::UpdateAccountReverificationTable:0x007fda1bd07710>
# ./spec/lib/tasks/account_reverification_spec.rb:18:in `block (2 levels) in <top (required)>'
On line, 18 of my account_reverification_spec.rb file I have this test.
it 'update_account_reverification_table' do
# binding.pry
account = create(:account, twitter_id: 1234567890)
Account.first.reverification.twitter_reverification_sent_at.must_equal Time.now
Account.first.reverification.twitter_reverified.must_equal true
end
I have also tried this variation but the test continues to fail:
account = FactoryGirl.create(:account, twitter_id: 1234567890)
However I receive a different error:
1) update_account_reverification_table update_account_reverification_table
Failure/Error: account = FactoryGirl.create(:account, twitter_id: 1234567890)
ArgumentError:
Factory not registered: account
Here is my spec_helper.rb and my rails_helper.rb
require 'fantaskspec'
require 'factory_girl_rails'
require 'pry-rails'
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.infer_rake_task_specs_from_file_location!
end
and 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'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.include FactoryGirl::Syntax::Methods
FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
FactoryGirl.find_definitions
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
end
Note that I have these lines in my rails_helper.rb file:
config.include FactoryGirl::Syntax::Methods
FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
FactoryGirl.find_definitions
I grabbed this from a previous answer on a different problem referenced here Specific config problem Any ideas?
-----EDIT #2------
I have created a brand new basic example app to help figure out where this problem could potentially be. I have followed the instructions to set up my directory and tree structure using these documentation links.
Rspec
Factory Girl Rails
Fantaskspec
Tutorial on Rspec and Fantaskspec
Directory tree structure:
spec
- factories
- accounts.rb
- lib
- tasks
- account_reverification_spec.rb
- support
- factory_girl.rb
- rails_helper.rb
- spec-helper.rb
Contents of spec/support/factory_girl.rb
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
Contents of spec/factories/accounts.rb
FactoryGirl.define do
sequence :account_login do |n|
"login-#{ n }"
end
factory :account do
sequence :email do |n|
"someone#{n}#gmail.com"
end
email_confirmation { |account| account.send :email }
url { Faker::Internet.url }
login { generate(:account_login) }
password { Faker::Internet.password }
password_confirmation { |account| account.send(:password) }
current_password { |account| account.send(:password) }
twitter_account 'openhub'
name { Faker::Name.name + rand(999_999).to_s }
about_raw { Faker::Lorem.characters(10) }
activated_at { Time.current }
activation_code nil
country_code 'us'
email_master true
email_kudos true
email_posts true
end
end
Contents of spec/lib/tasks/account_reverification_spec.rb
require 'rails_helper'
RSpec.describe 'update_account_reverification_table' do
let(:task_name) { 'update_account_reverification_table' }
it 'correct task is called' do
expect(subject).to be_a(Rake::Task)
expect(subject.name).to eq("update_account_reverification_table")
expect(subject).to eq(task)
end
it 'update_account_reverification_table' do
account = create(:account, twitter_id: 1234567890)
end
end
Contents of 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 'fantaskspec'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
Rails.application.load_tasks
config.infer_rake_task_specs_from_file_location!
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
end
Contents of 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
end
Try adding the following line to your spec_helper.rb file:
require 'factory_girl'
Also, add these lines to your spec_helper.rb:
FactoryGirl.definition_file_paths.clear
FactoryGirl.definition_file_paths << File.expand_path('../factories', __FILE__)
FactoryGirl.find_definitions
and remove them from RSpec.configure do |config| block.
Also, make sure you defined your factories in the correct file. It should be defined in factories.rb in your test folder (spec) if you use rspec.
Update
FactoryGirl.definition_file_paths.clear
FactoryGirl.definition_file_paths << "./spec/factories"
FactoryGirl.find_definitions
These lines should go to your spec/support/factory_girl.rb file and remove them from anywhere else.
Also, add the following in your spec_helper.rb:
config.before(:all) do
FactoryGirl.reload
end
In your spec_helper.rb the Rspec.configure block should look like this:
RSpec.configure do |config|
config.mock_with :rspec
config.run_all_when_everything_filtered = true
config.filter_run :focus
config.include FactoryGirl::Syntax::Methods
end
Update
Add this to your rails_helper.rb:
require_relative 'support/factory_girl.rb'
And then it should work.

Having Issues with cache_classes / Spork after changing to Capybara-Webkit from Selenium

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.

Resources