Reputation: 2253
I'm working through Michael Hartl's Rails tutorial and can't get one Rspec test to pass when refactoring with a matcher.
terminal output
Failures:
1) Authentication login with invalid information
Failure/Error: it { should have_error_message('Invalid') }
NoMethodError:
undefined method `has_error_message?' for #<Capybara::Session>
# ./spec/requests/authentication_pages_spec.rb:21:in `block (4 levels) in <top (required)>'
spec/support/utilities.rb
RSpec::Matchers.define :have_error_message do |m|
match do |page|
page.should have_selector('div.alert.alert-error', text: m)
end
end
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "login page" do
before { visit login_path }
it { should have_selector('h1', text: 'Login') }
it { should have_selector('title', text: 'Login') }
end
describe "login" do
before { visit login_path }
describe "with invalid information" do
before { click_button "Login" }
it { should have_selector('title', text: 'Login') }
it { should have_error_message('Invalid') }
end
describe "after visiting after page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { valid_login(user) }
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Logout', href: logout_path) }
it { should_not have_link('Login', href: login_path) }
describe "followed by logout" do
before { click_link "Logout" }
it { should have_link('Login') }
end
end
end
end
Why is it complaining about a has_error_message?
method that's not defined anywhere?
spec/spec_helper.rb
require 'rubygems'
require 'spork'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
Spork.prefork do
# Loading more in this block will cause your tests to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect.
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
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
# config.mock_with :rr
config.mock_with :rspec
# 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
end
Spork.each_run do
# This code will be run each time you run your specs.
end
Upvotes: 3
Views: 837
Reputation: 16793
If you're using a later version of Capybara or RSpec (ie not the ones explicitly specified in the tutorial), if I recall correctly the way that those custom matchers needed to be written changed (though I could be wrong about that) Nevertheless, try changing your method from
RSpec::Matchers.define :have_error_message do |m|
match do |page|
page.should have_selector('div.alert.alert-error', text: m)
end
end
to:
RSpec::Matchers.define :have_error_message do |m|
match do |page|
page.has_selector?('div.alert.alert-error', text: m)
end
end
This will then hopefully enable you to write tests like:
it { should have_error_message("Invalid") }
it { should_not have_error_message("Invalid") }
I had a similar issue that I outlined in this StackOverflow Q&A.
Upvotes: 2
Reputation: 11588
Are you require
'ing your spec/support/utilities.rb
file? You may need something like this in your spec/spec_helper.rb
file to actually load the file where you define the custom matcher:
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
Update: If you're using Spork, your utilities.rb
file may be getting cached by the Spork server, meaning you would need to restart your master Spork process before the new matcher could be used by RSpec (see details on the Spork wiki).
Some people use this trick to force Spork to always reload support files:
Spork.each_run do
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
end
Upvotes: 3