Rspec/Capybara 找不到表单的提交按钮

Rspec/Capybara Can't Find Submit Button for Form

我正在尝试编写一个创建对象然后保存的测试。我想确保对象在提交后创建并出现在重定向的页面上。但是,我似乎无法点击 "Save" 按钮。

相关测试:

describe 'Create a new contact list', :type => :feature do

  it 'Creates a contact list with a name' do
    visit new_contact_list_url
    expect(page).to have_content("New Contact List")
    fill_in "contact_list_name", with: "Group 1"
    find('#save').click
    expect(page).to have_content("Group 1")
  end

end

我得到的错误:

 1) Create a new contact list Creates a contact list with a name
 Failure/Error: find('#save').click
 NoMethodError:
   undefined method `id' for nil:NilClass

相关的 HAML

=form_for(@contact_list, html: {multipart: true}) do |f| 
  .form-group
    .field
    =f.label "Contact List Name"
    =f.text_field :contact_list_name, :class => 'form-contorl', :id => 'contact_list_name'
  %h3 Contacts
  =f.fields_for :contacts do |contact|
    =render 'contact_fields', f: contact
  .links
    =link_to_add_association 'Add Contact', f, :contacts, :class => 'btn btn-primary', :id => 'add_contact'

  =f.submit :class => 'btn btn-warning', :value => 'Save', :id => 'save'

rspec 启用了 --backtrace

Failures:

1) Create a new contact list Creates a contact list with a name
 Failure/Error: find("#new_contact_list").find("#save").click
 NoMethodError:
   undefined method `id' for nil:NilClass
 # ./app/controllers/contact_lists_controller.rb:17:in `create'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller  /metal/implicit_render.rb:4:in `send_action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/abstract_controller/base.rb:198:in `process_action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/rendering.rb:10:in `process_action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:117:in `call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:117:in `call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:505:in `call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:505:in `call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:92:in `_run_callbacks'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:776:in `_run_process_action_callbacks'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:81:in `run_callbacks'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/abstract_controller/callbacks.rb:19:in `process_action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/rescue.rb:29:in `process_action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/notifications.rb:164:in `block in instrument'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/notifications.rb:164:in `instrument'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
 # ./.bundle/ruby/2.2.0/gems/activerecord-4.2.1/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/abstract_controller/base.rb:137:in `process'
 # ./.bundle/ruby/2.2.0/gems/actionview-4.2.1/lib/action_view/rendering.rb:30:in `process'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal.rb:196:in `dispatch'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal.rb:237:in `block in action'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:74:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:74:in `dispatch'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:43:in `serve'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/journey/router.rb:43:in `block in serve'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/journey/router.rb:30:in `each'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/journey/router.rb:30:in `serve'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:819:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/etag.rb:24:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/conditionalget.rb:38:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/head.rb:13:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/params_parser.rb:27:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/flash.rb:260:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:225:in `context'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:220:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/cookies.rb:560:in `call'
 # ./.bundle/ruby/2.2.0/gems/activerecord-4.2.1/lib/active_record/query_cache.rb:36:in `call'
 # ./.bundle/ruby/2.2.0/gems/activerecord-4.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:649:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:88:in `call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:88:in `_run_callbacks'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:776:in `_run_call_callbacks'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:81:in `run_callbacks'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/callbacks.rb:27:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
 # ./.bundle/ruby/2.2.0/gems/web-console-2.2.1/lib/web_console/middleware.rb:39:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
 # ./.bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/rack/logger.rb:38:in `call_app'
 # ./.bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/rack/logger.rb:20:in `block in call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/tagged_logging.rb:68:in `block in tagged'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/tagged_logging.rb:26:in `tagged'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/tagged_logging.rb:68:in `tagged'
 # ./.bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/rack/logger.rb:20:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/request_id.rb:21:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/methodoverride.rb:22:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/runtime.rb:18:in `call'
 # ./.bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/lock.rb:17:in `call'
 # ./.bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/static.rb:113:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/sendfile.rb:113:in `call'
 # ./.bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/engine.rb:518:in `call'
 # ./.bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/application.rb:164:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb:66:in `block in call'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `each'
 # ./.bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `call'
 # ./.bundle/ruby/2.2.0/gems/rack-test-0.6.3/lib/rack/mock_session.rb:30:in `request'
 # ./.bundle/ruby/2.2.0/gems/rack-test-0.6.3/lib/rack/test.rb:244:in `process_request'
 # ./.bundle/ruby/2.2.0/gems/rack-test-0.6.3/lib/rack/test.rb:67:in `post'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/rack_test/browser.rb:60:in `process'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/rack_test/browser.rb:35:in `process_and_follow_redirects'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/rack_test/browser.rb:26:in `submit'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/rack_test/form.rb:76:in `submit'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/rack_test/node.rb:61:in `click'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/node/element.rb:134:in `block in click'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/node/base.rb:84:in `synchronize'
 # ./.bundle/ruby/2.2.0/gems/capybara-2.5.0/lib/capybara/node/element.rb:134:in `click'
 # ./spec/features/create_contact_list_spec.rb:10:in `block (2 levels) in <top (required)>'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:148:in `instance_exec'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:148:in `block in run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `call'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `block (2 levels) in <class:Procsy>'
 # ./.bundle/ruby/2.2.0/gems/rspec-rails-3.0.2/lib/rspec/rails/adapters.rb:72:in `block (2 levels) in <module:MinitestLifecycleAdapter>'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:294:in `instance_exec'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:294:in `instance_exec'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/hooks.rb:430:in `block (2 levels) in run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `call'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `block (2 levels) in <class:Procsy>'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/hooks.rb:432:in `run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/hooks.rb:485:in `run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:303:in `with_around_example_hooks'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:145:in `run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:494:in `block in run_examples'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:490:in `map'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:490:in `run_examples'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:457:in `run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:112:in `block (2 levels) in run_specs'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:112:in `map'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:112:in `block in run_specs'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/reporter.rb:54:in `report'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:108:in `run_specs'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:86:in `run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:70:in `run'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:38:in `invoke'
 # ./.bundle/ruby/2.2.0/gems/rspec-core-3.0.4/exe/rspec:4:in `<top (required)>'
 # /Users/cowan/.rvm/gems/ruby-2.2.1/bin/rspec:23:in `load'
 # /Users/cowan/.rvm/gems/ruby-2.2.1/bin/rspec:23:in `<main>'
 # /Users/cowan/.rvm/gems/ruby-2.2.1/bin/ruby_executable_hooks:15:in `eval'
 # /Users/cowan/.rvm/gems/ruby-2.2.1/bin/ruby_executable_hooks:15:in `<main>'

编辑相关控制器操作(创建)

def create
  @contact_list = ContactList.new(contact_list_params)
  @contact_list.user_id = current_user.id

  if @contact_list.save
    flash[:success] = "Contact List Created"
    redirect_to contact_lists_url
  else
    render 'contact_lists/new'
  end
end

您是否尝试过使用 click('Save') 而不是 find("#save").click

如果你有,你不成功吗?回答为什么会这样可能会对你有所帮助。

How would I log in a user using rspec? Since my login helper methods are in app/helpers/sessions_helper.rb

只需在您通过 Capybara 登录的地方编写一些函数,即

visit '/auth'
fill_in :login, with: 'John'
fill_in :password, with: '123'
click 'Login'

然后在您的测试中使用它,例如,在 before { } 块中。

如果您有很多测试而这种方法太慢,请查看 Warden::Test::Helpers

另外,看看这个答案: