95

I can't get capybara working with rspec. It gives me this error:

undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1:0x16529f8 @example=nil>

I know there are lots of posts about this but non of the solutions are working for me. Most of them involve the specs not being in /spec/features - which mine is in.

First the error:

$bundle exec rspec spec
F

Failures:

  1) security signs users in
     Failure/Error: visit "/sessions/new"
     NoMethodError:
       undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1:0x16529f8 @example=nil>
     # ./spec/features/security_spec.rb:4:in `(root)'

 Finished in 0.006 seconds
 1 example, 1 failure

Failed examples:

rspec ./spec/features/security_spec.rb:3 # security signs users in

I think its important to note that at first I was using the URL Helper 'new_sessions_path' and it kept giving me an error undefined local variable or method 'new_sessions_path'. I know it is valid because:

$ rake routes
logout_sessions GET    /sessions/logout(.:format) sessions#logout
       sessions POST   /sessions(.:format)        sessions#create
   new_sessions GET    /sessions/new(.:format)    sessions#new
      contracts POST   /contracts(.:format)       contracts#create
  new_contracts GET    /contracts/new(.:format)   contracts#new
 edit_contracts GET    /contracts/edit(.:format)  contracts#edit
                GET    /contracts(.:format)       contracts#show
                PUT    /contracts(.:format)       contracts#update
                DELETE /contracts(.:format)       contracts#destroy
           root        /                          contracts#index

My Gemfile:

source 'https://rubygems.org'

gem 'rails', '3.2.11'
gem 'execjs'

group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'uglifier', '>= 1.0.3'
end

gem 'jquery-rails'
gem 'activerecord-oracle_enhanced-adapter', '~> 1.4.1'
gem 'jruby-openssl'
gem 'therubyrhino'
gem 'kaminari'
gem 'nokogiri'

group :development do
  gem 'warbler'
end

group :test do
  gem 'rspec-rails'
  gem 'capybara'
  gem 'activerecord-jdbcsqlite3-adapter'
end

spec_helper.rb inside of my_app/spec:

# 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 'rspec/autorun'

# Capybara integration
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}

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 = true
  config.infer_base_class_for_anonymous_controllers = false
  config.order = "random"
  # Include path helpers
  config.include Rails.application.routes.url_helpers
end

my_app/spec/features/security_spec.rb:

describe "security", :type => :feature do
  it "signs users in" do
    visit "/sessions/new"
    fill_in "username", :with => "user"
    fill_in "password", :with => "pass"
    click_button "Sign In"

    page.should have_content('Login Successful')
  end
end

I've tried defining the test above both with and without :type => :feature. It makes no difference either way. Any ideas what I should try next?

lightswitch05
  • 9,058
  • 7
  • 52
  • 75
  • Possible duplicate of [Capybara: undefined method 'visit'](http://stackoverflow.com/questions/9059854/capybara-undefined-method-visit) – mlt Dec 28 '16 at 22:16
  • 2
    @mlt in the first paragraph I said: "I know there are lots of posts about this but non of the solutions are working for me. Most of them involve the specs not being in /spec/features - which mine is in." This paragraph is specifically referencing the question you link to. This question not only has higher votes, but also comes with a solution - which is different than the highest voted answer (not solution) posted on your linked question. – lightswitch05 Dec 28 '16 at 22:24

7 Answers7

213

Try to add:

  config.include Capybara::DSL

to your config block.

# 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 '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|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  # config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.use_transactional_fixtures = true
  config.infer_base_class_for_anonymous_controllers = false
  config.order = "random"
  # Include path helpers
  config.include Rails.application.routes.url_helpers

  config.include Capybara::DSL

end
Kocur4d
  • 6,701
  • 8
  • 35
  • 53
  • Nope, exact same issue, no apparent change – lightswitch05 Mar 01 '13 at 01:42
  • 11
    This worked for me -- thanks a ton. I didn't need to do this though in my other projects. What circumstances would make this necessary in one project, but not another? Also, what exactly is this doing? – Peter Berg Jun 09 '13 at 21:39
  • My file already had the require 'spec_helper' that was checked asthe answer to this problem, but this worked for me. Thanks! – sixty4bit Mar 08 '14 at 16:54
  • That doesn't work for me: I get an error message that `Capybara` is an undefined constant. My Cucumber tests are using Capybara just fine. – digitig Oct 09 '14 at 14:00
56

Adding require 'rails_helper' at the top of my feature ended up fixing my problem:

require 'rails_helper'

describe "security", :type => :feature do

  it "signs users in" do
    visit new_sessions_path
    fill_in "username", :with => "user"
    fill_in "password", :with => "pass"
    click_button "Sign In"

    page.should have_content('Login Successful')
  end
end

This seems odd to me since every example I've seen for rspec and capybara didn't have that require, but oh well. Problem solved.

Original Answer (older versions of rspec)

require 'spec_helper' is used by older versions of RSpec. The better answer would be require 'rails_helper'.

Kris Khaira
  • 132
  • 11
lightswitch05
  • 9,058
  • 7
  • 52
  • 75
  • 4
    You should put the update part in the top of your post. – nistvan Sep 11 '14 at 11:00
  • It is really bad manner to accept ones own answer, even though Kocur4d's answer is more precise (and forgetting to include the rails_helper.rb would not be the more common problem). You should change the accepted answer, as without the configuration change done before including it, you would still have the same error. – randmin Apr 05 '20 at 15:30
37

Since Capybara 2.0 one has to use folder spec/features Capybara commands don't work in folder spec/requests anymore.

Thillai Narayanan
  • 4,766
  • 5
  • 32
  • 39
  • 2
    As my question states, my capybara test **was** already located under `spec/features`. But that is a valid point for other people who might be having issues. – lightswitch05 May 19 '13 at 21:41
  • I find it helpful to create the directory `mkdir spec/features` and create a symbolic link `ln -s spec/features spec/requests`. This way any generated tests will be placed in the features directory. – omarshammas Sep 21 '13 at 20:41
  • Thanks @ThillaiNarayanan, this was my issue following an older setup guide, but on a more recent Capybara version – VegaStudios Jul 29 '19 at 18:25
  • this happens because of the setting `config.infer_spec_type_from_file_location!` inside of your Rspec configure. see https://github.com/rspec/rspec-rails/blob/main/lib/rspec/rails/configuration.rb#L7 – Jason FB Feb 14 '22 at 11:36
6

Try performing all your setup in a before block:

spec/features/security_spec.rb

describe "security" do
  before do
    visit "/sessions/new"
    fill_in "username", :with => "user"
    fill_in "password", :with => "pass"
    click_button "Sign In"
  end

  it "signs users in" do
    page.should have_content('Login Successful')
  end
end
Paul Fioravanti
  • 16,423
  • 7
  • 71
  • 122
  • 2
    This is actually a common **cause** of the error. The `visit` function is only available within a `it` block. [Source](http://stackoverflow.com/a/11911471/912563) – lightswitch05 Mar 01 '13 at 02:14
  • 4
    Not true -- code in a `before` block runs in the example context, so `visit` will work there as well as in an `it` block. – zetetic Mar 01 '13 at 02:46
  • 2
    @user912563, ultimately, since you solved your own problem, my answer just really becomes a style suggestion more than anything else (set up code in `before` blocks is how I write my specs, and they work without error ;-) ), so I think it's fair to accept your own answer. – Paul Fioravanti Mar 01 '13 at 03:30
  • Thanks @zetetic and @Paul-Firavanti - I did not know `before` was still inside the `it` context. Using this will make my other tests that require login much cleaner – lightswitch05 Mar 01 '13 at 03:36
  • This helped me because I'm a noob and didn't have test wrapped in it "" do ... end. – Danny Feb 06 '14 at 22:56
4

I also had this problem,

Adding require 'rails_helper' at the top of my feature ended up fixing my problem:

require 'rails_helper'

RSpec.describe "Products", type: :request do
 describe "GET /products" do
 it "display tasks" do
  Product.create!(:name => "samsung")
  visit products_path
  page.should have_content("samsung")
  #expect(response).to have_http_status(200)
  end
 end
end

And add the 'config.include Capybara::DSL' in rails_helper.rb

RSpec.configure do |config|

 config.fixture_path = "#{::Rails.root}/spec/fixtures"

 config.use_transactional_fixtures = true

 config.infer_spec_type_from_file_location!

 config.include Capybara::DSL

end
Sathibabu P
  • 649
  • 1
  • 7
  • 15
  • Adding that Config line worked for me. It's strange because I was getting the error in one of my spec files but not in another spec file, and both called the same capy methods (and both required rails_helper) – Jonathan Tuzman Jan 24 '19 at 15:54
  • adding only config.include Capybara::DSL inside rails_helper.rb would resolved the issue. – vidur punj Jan 29 '23 at 14:51
2

Other than the upgrading issue which you would run into when ugprading from an older Rails app with require 'spec_helper.rb' instead of require 'rails_helper.rb', this happens for 3 known reasons:

1. Your spec isn't of type "feature" which means Capybara doesn't know how to run it using Javascript or a browser. You want to do one of two things: 1) Typically, you want config.infer_spec_type_from_file_location! set in your RSpec.configure and that will mean that what's in the features folder will be a feature.

if you have something non-standard, you can add type: :feature to the spec describe block to turn that spec in a feature, but typically it's easier just to put them into the /features folder and let the infer setting do its job.

2. You accidentally put the visit outside of the it block

The visit must be within the it, which is within the describe. Be sure not to put the visit directly within the describe.

3. Some other kernal panic you can't see has caused Capy to shut down the spec.

This is a nasty one to diagnose but I have seen it. It means that Capy didn't actually parse this file correctly, and so somehow isn't in the right scope when it gets to the visit block. Carefully pick apart your Capy spec to figure out where you introduced it.

I induced the kernal panic today but have a let block be called page (whoops). page appears to be a reserved word for Rspec or Capy here, and it causes the kernal panic, thus leading to the spec not to parse thus leading to the visit method not being found.

in my case, it was simply changing this:

let(:page) {Page.new()} 

to

let(:content_page) {Page.new()} 

Notice that the word page is not reserved by Rails, and works fine as a database name and also a model name, but the specific construction of using page here as the let variable name seemed to cause Capy to get kind of crappy.

Jason FB
  • 4,752
  • 3
  • 38
  • 69
0

One of the reasons might be if you defined page variable using let:

RSpec.describe "something" do
  let(:page) { some_page }

  it do
    visit "/"
  end
end

Results in the following error:

  1) something
     Failure/Error: visit "/"

     NameError:
       undefined method `visit' for class `#<Class:0x00007ffca6221898>'
       Did you mean?  visible

To fix it, rename page variable.

kolen
  • 2,752
  • 2
  • 27
  • 35