Rspec NoMethodError: undefined method `errors_on' - ruby-on-rails

I'm testing for validation of entry of a city attribute in an addresses model. My model spec is as follows
require 'rails_helper'
RSpec.describe Address, :type => :model do
before(:each) do
#valid_attributes = {
street: 'rock avenue',
city: 'MSA',
zip: '00100',
person_id: 1
} # runs before each it block
end
context "Validations" do
it 'must have a city' do
a = Address.new
expect(a.errors_on(:city)).not_to be_empty
end
end
end
When I run the spec, i get the following error
1) Address Validations must have a city
Failure/Error: expect(a.errors_on(:city)).not_to be_empty
NoMethodError:
undefined method `errors_on' for #<Address:0xd844538>
# ./spec/models/address_spec.rb:19:in `block (3 levels) in <top (required)>'
My test gems are set up as following in my Gemfile
group :development, :test do
gem 'rspec-rails'
gem 'factory_girl_rails', :require => false
end
group :test do
gem 'capybara'
gem 'guard'
gem 'guard-rspec'
gem 'libnotify'
gem 'rspec-collection_matchers'
end
I have included the rspec collection matchers in my spec_helper, so I don't understand why I am getting this error
My spec_helper.rb
require 'capybara/rspec'
require 'factory_girl_rails'
require 'rspec/collection_matchers'
However I can see that the method, errors_on has been defined in rspec-collection_matchers gem as shown here
My .rspec
--color
--require spec_helper
I have also changed the position of
require 'rspec/collection_matchers'
to rails_helper.rb, but running the test suite again brings up the same error
rails_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require 'rspec/collection_matchers'
require 'capybara/rspec'
require 'factory_girl_rails'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.include Capybara::DSL
config.include FactoryGirl::Syntax::Methods
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
end
My spec_helper.rb is empty with only the block below:
RSpec.configure do |config|
end
I am using Rails 4.1.0, rspec 3.0.0 and rspec-collection_matchers 1.0.0

Without seeing the repo, this is only a guess based on the information. I think this is a load order problem.
It looks like you are loading rspec/collection_matchers in spec_helper, not rails_helper. If you are using the new default configuration, --require spec_helper is in your .rspec file. When you run rspec this will require spec_helper very early on. When that happens it requires rspec/collection_matchers. However, at that point rails_helper has not been loaded. Unfortunately, this also means most of ActiveSupport including ActiveModel are not loaded yet. It also means the Rails autoloading functionality has not been loaded, so those won't get defined when you reference them.
All this to say, the check for ActiveModel here returns false. Which does not load errors_on.
Try moving the require into rails_helper.
Note on testing in isolation:
If you are going for faster testing in isolation this is my suggestion:
spec_helper should be kept very minimal and lightweight, that means for the most part you shouldn't add any require declarations to it
Move the requires you listed from spec_helper into rails_helper, those are mostly Rails specific and do not belong in spec_helper as Rails is not loaded there
If you need access to the other rspec/collection_matchers functionality in specs which do not require Rails, then just add the require 'rspec/collection_matchers' to the top of the spec file; Ruby will handle making sure it is only loaded once

Related

RSpec 3.1 undefined method `feature' for main:Object

I´m going through the rather painful upgrade to RSpec 3.1. I have several feature specs which worked in RSpec 2.99 that raise:
undefined method `feature' for main:Object
I noticed that I have to use RSpec.describe in my other specs since they are are no longer attached to the main object. What would the equivalent call for feature be?
In my features I require 'rails_helper'
require 'rails_helper'
feature 'Facebook Authentiation' do
...
end
spec/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 'rails/application'
# Add additional requires below this line. Rails is not loaded until this point!
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# 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
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location
config.infer_spec_type_from_file_location!
end
spec/spec_helper.rb
#
See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Limits the available syntax to the non-monkey patched syntax that is recommended.
# For more details, see:
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
config.disable_monkey_patching!
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
end
Gemfile
# ...
group :development, :test do
gem 'rspec-rails', '~> 3.1.0'
end
# ...
group :test do
# ...
gem 'capybara', '~> 2.4.3'
end
It looks like your forgot to require capybara at your spec/rails_helper.rb
require 'capybara/rspec'
Also you can try to remove this line:
config.disable_monkey_patching!
Or check if capybara adds feature method to Rspec namespace:
RSpec.feature "My feature" do
...
end
I've faced the same issue with rails 4.2 even though I've had
require 'capybara/rspec' in rails_helper.rb
and
require 'spec_helper' in feature spec.
Solution is to require 'rails_helper' in feature spec as well.
In my case the problem was that I had the
require "spec_helper"
line lower in rails_helper.rb.
When I moved it at the top, everything went back to normal.
For your reference, my rails_helper.rb first lines now are:
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"
I had to use the following in my problem which is a combination of previous answers:
spec/features/visitors/navigation_spec.rb
require 'spec_helper'
require 'capybara/rspec'
RSpec.feature 'Navigation links', :devise do
...
end
spec/rails_helper.rb
require 'capybara/rspec'
spec/spec_helper.rb
config.disable_monkey_patching = false

Can't get rspec working with Zeus

I've read all the recommendations about how to get rspec on rails working with zeus. In particular, I've commented out "require 'rspec/autorun'" in spec/spec_helper.rb:
# require 'rspec/autorun'
I start up zeus in one terminal:
zeus start
Then in another terminal run rspec:
zeus rspec spec/controllers/source_configs_controller_spec.rb
And get... nothing. No output, no response, nada - just dumps me back to command line. However, if I uncomment require 'rspec/autorun' in spec_helper.rb, and run it again, I get:
Failure/Error: post :create, {:account_id => #account.id, :source_config => valid_attributes.except(:account_id)}, {}
NoMethodError:
undefined method `post' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_1::Nested_1:0x007fbdff3032d8>
Any ideas? I feel like I've lost more time trying to figure this out than I'll ever recover with speedier rspec runs... so frustrating.
After more digging and experimentation, it looks like rr (mocking framework) in spec_helper.rb was the culprit. I had
RSpec.configure do |config|
config.mock_with :rr
#...
end
To fix it:
Upgrade rr ("bundle update rr").
Initialize rr in a different manner:
In Gemfile
group :development, :test do
gem "rr", :require => false # important to specify ":require => false"
gem "rspec-rails"
# (any other appropriate gems)
end
In spec_helper.rb
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
# vvvv NOTE: this is how you enable rr now
require 'rr'
#require 'rspec/autorun'
# 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}
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
# vvvv NOTE: Make sure this line is commented out
# config.mock_with :rr
# ... other rspec config
end
Would love to hear anyone else's thoughts - is there a better way?
So I was having the same issue and using some debugging I found that the tests were being run, but there was no output.
What worked so far is putting config.reset at the top of the RSpec.configure block. I got that idea from here: https://github.com/burke/zeus/issues/461 which got the idea from here: How can I configure rspec to show output with spork?
As a warning, one of the comments in the first link mentions that putting config.reset has undesirable side effects, but I have not run into any .... yet.

How to put RSpec/Capybara tests outside of the spec/requests directory?

For some reason my team does not want our acceptance tests to exist in the spec/requests directory. Instead, they would like them placed in a new directory called acceptance that exists outside of the spec directory structure. So, my first question is, using RSpec, Capybara and capybara-webkit, is this even possible?
Here is my acceptance_spec_helper.rb file
require 'rubygems'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
require 'capybara/rails'
# 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}
# Capybara.javascript_driver = :webkit
RSpec.configure do |config|
config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
:file_path => config.escaped_path(%w[acceptance])
}
# 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 = true
# 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
end
However, it does not seem that the application is actually being run in order to be tested.
And please, do not just say to put the tests back in the spec/requests directory without some very strong arguments to back up why that is the only option.
I've done something similar where I had my specs in spec/acceptance, tagged them with :acceptance => true, and ran them with a separate rake task rake spec:acceptance
Check out this gist- https://gist.github.com/3858851.
Hope it helps

Capybara: undefined method 'visit'

When running my specs with rspec & capybara, it can't find capybara's visit method. Is there another initialization step I need to do?
$bundle exec rspec spec
/home/brian/projects/expense_track/expense_track/spec/requests/homepage_spec.rb:6:in `block (2 levels) in <top (required)>': undefined method `visit' for #<Class:0xb6572b8> (NoMethodError)
Gemfile:
group :test, :development do
gem "rspec-rails"
gem "capybara"
end
top of my spec_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__)
require 'rspec/rails'
require 'capybara/rspec'
require 'rspec/autorun'
homepage_spec.rb:
require 'spec_helper'
describe "The home page" do
context "home page exists" do
visit "/"
page.should have_content("elephants")
end
end
Just ran into this issue myself.
So the reason for this is there has been a somewhat undocumented change in Capybara. Capybara now makes the assumption that anything using it needs to be in the spec/features folder and it will make the proper assumptions. Anything left in the spec/requests folder will no longer work. Though there are workarounds.
For a context block you can add the parameter :type => :feature and this will fix that issue or you can change the name of a describe method at the beginning of a spec to feature and this should change it as well.
They announced this change in their Google group: https://groups.google.com/forum/?fromgroups=#!topic/ruby-capybara/5KfxezI-U0Q
Notably, we changed the :type that Capybara assumes your specs run under in RSpec to :feature (previously it was :request). The latest release of spec/features. Alternatively you can use the Capybara Feature DSL (feature instead of describe), which should work without any additional tweaking. If you see errors like undefined method visit, then you're probably encountering this issue. If you're including modules into :request specs, you will probably need to change that to :feature.
This was further discussed in the github issue: https://github.com/jnicklas/capybara/issues/814
A few things to note here :
The changes in Capybara 2.0.x are documented here https://github.com/rspec/rspec-rails/blob/master/Capybara.md . There are changes in the spec directory structure : spec/features, spec/controllers, spec/views, spec/helpers, spec/mailers.
load Capybara dsl explicitly inside your spec_helper
require 'capybara/rails'
require 'capybara/rspec'
include Capybara::DSL
This worked for me.
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
require 'capybara/rails'
RSpec.configure do |config|
config.include Capybara::DSL, :type => :request
end
This enables you to use Capybara's helpers inside spec/requests.
Because RSpec.configure not including capybara DSL in spec_helper.rb
It is an ugly solution, but you can add this to your spec_helper.rb.
module ::RSpec::Core
class ExampleGroup
include Capybara::DSL
include Capybara::RSpecMatchers
end
end
The git issue for this:
https://github.com/rspec/rspec-rails/issues/503
Unfortunately this workaround doesn't do it for me. I still get
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1::Nested_1:0x007fbfeb535298>
The repo is public under: https://github.com/ikusei/Goldencobra_Newsletter
You need to look at the branch '28817499-subscribe'
edit: If i put include Capybara::DSL inside my describe block it works.
but including Capybara::DSL in the global scope is not recommended!
Because I do not know a good way.
For rspec 3 and rails, make sure you are using require "rails_helper", instead of require "spec_helper".
Otherwise, review the latest changes to rspec 3 & rspec-rails and Capybara 2.0.x.

"PGError: no connection to the server" on running specs with Spork

I'm using Ruby 1.9.2, Rails 3.1, Rspec, Postgres and Spork, but I can't get them to play nicely together.
Running the specs for the first time (with Spork running in the background) works fine. However, when I run the specs a second time, it fails with:
Failure/Error: Unable to find matching line from backtrace
PGError:
no connection to the server
# /Users/tom/.rvm/gems/ruby-1.9.2-p180#grapi/gems/activerecord-3.1.0.rc4/lib/active_record/connection_adapters/postgresql_adapter.rb:272:in `exec'
etc....
Any tips appreciated!
You probably also have Devise enabled.
Your problem is described here: https://github.com/sporkrb/spork/wiki/Spork.trap_method-Jujutsu
And more specifically for rails 3.1 here: https://gist.github.com/1054078
The beginning of your prefork block in spec_helper.rb and env.rb should looks like:
Spork.prefork do
Spork.trap_method(Rails::Application, :reload_routes!)
Spork.trap_method(Rails::Application::RoutesReloader, :reload!)
...
Good luck!
If you're using Factory Girl, don't use the 'factory_girl_rails' gem, just use 'factory_girl'.
Spork.each_run do
FactoryGirl.definition_file_paths = [
File.join(Rails.root, 'spec', 'factories')
]
FactoryGirl.find_definitions
end
For anyone using Factory Girl, Machinist, or Shoulda Matchers, make sure you read about Spork's trap_method at: https://github.com/timcharper/spork/wiki/Spork.trap_method-Jujutsu
It solved my problems with Spork and the dropped PostgreSQL connections while testing.
you have to run spork --bootstrap
and after insert some configuration to your spec_helper.rb file, so spork knows about your rails configuration.
As you use RSpec, you can try adding the following code to your spec_helper file:
require 'rubygems'
require 'spork'
Spork.prefork do
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.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
# Needed for Spork
ActiveSupport::Dependencies.clear
end
end
Spork.each_run do
load "#{Rails.root}/config/routes.rb"
Dir["#{Rails.root}/app/**/*.rb"].each { |f| load f }
end
Could you try adding this to Spork.each_run callback and check if it solves the problem?
ActiveRecord::Base.connection_pool.verify_active_connections!
I read the instructions on https://github.com/timcharper/spork/wiki/Spork.trap_method-Jujutsu and found the following.
In my case the solution was to change how machinist blueprints was loaded. My prefork block had this line:
Spork.prefork do
...
require Rails.root.join 'spec/support/blueprints'
...
I removed that from the prefork block and instead added this line to each_run:
Spork.each_run do
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
...
The two lines basically does the same thing, so the main thing seams to be not to load the blueprints in the prefork, but rather in each_run.
Hope it helps!

Resources