在Rails中使用RSpec和Capybara时出现“undefined method 'visit'”错误方法。

95
我无法让capybara在rspec中正常工作。它给出了以下错误信息:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1:0x16529f8 @example=nil>

我知道有很多关于这个问题的帖子,但是没有一个解决方案适用于我。大部分解决方案都涉及规格不在/spec/features目录中 - 而我的规格文件就在其中。
首先是错误信息:
$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

我认为需要注意的是,一开始我使用了URL Helper中的'new_sessions_path',但它不断出现错误undefined local variable or method 'new_sessions_path'。我知道这是有效的,因为:

$ 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

我的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

在my_app/spec目录下的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 '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

我已经尝试过使用:type => :feature和不使用来定义上述测试,但两种方式都没有区别。你有什么建议我接下来该尝试什么吗?


可能是重复问题:Capybara: undefined method 'visit' - mlt
2
在第一段中,我说:“我知道有很多关于这个问题的帖子,但是没有一个解决方案适用于我。大多数解决方案都涉及规格不在/spec/features目录下 - 而我的规格文件就在那里。”这一段特别提到了你链接的问题。这个问题不仅有更高的投票数,而且还附带了一个解决方案 - 这与你链接的问题上最高投票的答案(不是解决方案)不同。 - lightswitch05
7个回答

213
尝试添加:
  config.include Capybara::DSL

添加到您的配置块中。

# 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

没有,完全相同的问题,没有明显的改变。 - lightswitch05
11
这对我有用 - 非常感谢。但在我的其他项目中,我并不需要这样做。是什么情况会使得在一个项目中需要这样做而在另一个项目中不需要呢?此外,这到底是在做什么? - Peter Berg
1
也适用于我。非常感谢你! - Marian Zagoruiko
我的文件已经有了require 'spec_helper',这被检查为这个问题的答案,但这对我有用。谢谢! - sixty4bit
这对我不起作用:我收到一个错误消息,指出“Capybara”是未定义的常量。我的 Cucumber 测试正常使用 Capybara。 - digitig

56
在我的功能代码顶部添加require 'rails_helper'最终解决了我的问题。
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

这对我来说似乎很奇怪,因为我看到的每个rspec和capybara的例子都没有那个require,但是没关系。问题解决了。

原始答案(旧版本的rspec)

require 'spec_helper'被旧版本的RSpec使用。更好的答案应该是require 'rails_helper'


4
您应该将更新部分放在您的帖子顶部。 - nistvan
接受自己的答案是非常不好的行为,即使Kocur4d的答案更精确(而忘记包含rails_helper.rb并不是更常见的问题)。你应该更改已接受的答案,因为如果在包含它之前没有进行配置更改,你仍然会遇到相同的错误。 - randmin

37
自从Capybara 2.0版本以后,必须在spec/features文件夹中使用Capybara命令,而在spec/requests文件夹中则不再适用。

2
正如我的问题所述,我的capybara测试已经位于spec/features下。但对于其他可能遇到问题的人来说,这是一个有效的观点。 - lightswitch05
我发现创建目录 mkdir spec/features 并创建符号链接 ln -s spec/features spec/requests 很有帮助。这样任何生成的测试都将放置在 features 目录中。 - omarshammas
感谢@ThillaiNarayanan,这是我的问题,我遵循了一个较旧的设置指南,但在更近期的Capybara版本上。 - VegaStudios
这是因为在你的 Rspec 配置中设置了 config.infer_spec_type_from_file_location!。请参见 https://github.com/rspec/rspec-rails/blob/main/lib/rspec/rails/configuration.rb#L7。 - Jason FB

6
尝试在before块中完成所有设置:

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

2
这实际上是错误的一个常见原因visit函数只能在it块内使用。来源 - lightswitch05
4
不正确 - before块中的代码在示例上下文中运行,因此visit在那里和在it块中一样有效。 - zetetic
2
@user912563,最终,由于您解决了自己的问题,我的答案只是一个风格建议而已(在before块中设置代码是我编写规范的方式,它们可以无错误运行;-)),因此我认为接受您自己的答案是公平的。 - Paul Fioravanti
感谢@zetetic和@Paul-Firavanti - 我不知道before仍然在it上下文中。使用它将使我需要登录的其他测试更加清晰。 - lightswitch05
这对我很有帮助,因为我是一个新手,没有在它里面包含测试 "" do ... end。 - Danny

4

我也遇到了这个问题,

在我的功能特性顶部添加 require 'rails_helper' 最终解决了我的问题:

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

在rails_helper.rb中添加'config.include Capybara :: DSL'。
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

添加那个配置行对我有用。很奇怪,因为我在一个规范文件中遇到了错误,但在另一个规范文件中没有遇到错误,而且两个文件都调用了相同的capy方法(并且都需要rails_helper)。 - Jonathan Tuzman
只需在rails_helper.rb中添加config.include Capybara :: DSL,问题就会得到解决。 - vidur punj

2
除了在从旧的Rails应用程序升级时遇到需要使用require 'rails_helper.rb'而不是require 'spec_helper.rb'的问题外,这还有三个已知的原因: 1. 您的规范不是“feature”类型 这意味着Capybara不知道如何使用Javascript或浏览器运行它。你想要做以下两件事情:1)通常,你希望在Rspec.configure中设置config.infer_spec_type_from_file_location!,这将意味着features文件夹中的内容都是一个特性。
如果您有一些非标准的内容,可以在规范描述块中添加type: :feature来将该规范转换为特性,但通常最好只是将它们放入/features文件夹中,让推断设置完成工作。 2. 您错误地将visit方法放在it块之外 visit必须在it块内部调用,而it块则位于describe块内部。确保不要直接将visit放在describe块内部。 3. 你看不到的其他内核恐慌导致Capy关闭规范。 这是一个棘手的问题,但我已经见过它。这意味着Capy实际上没有正确解析此文件,因此在到达visit块时不在正确的范围内。仔细分析您的Capy规范以确定您在哪里引入了它。
今天我发生了内核恐慌,但却调用了一个名为pagelet块(糟糕)。这里page似乎是Rspec或Capy的保留字,它导致了内核恐慌,从而导致无法解析该规范,进而导致找不到visit方法。
在我的情况下,只需要将以下内容更改即可:
let(:page) {Page.new()} 

to

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

注意,单词page并不是Rails保留的词汇,可以作为数据库名称和模型名称使用,但在此处使用page作为let变量名的特定构造似乎导致Capy表现不佳。

0
可能的原因之一是您使用let定义了page变量。
RSpec.describe "something" do
  let(:page) { some_page }

  it do
    visit "/"
  end
end

以下是出现的错误结果:
  1) something
     Failure/Error: visit "/"

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

为了修复它,请将page变量重新命名。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接