Ruby-on-rails 你如何在 Capybara 中 POST 到一个 URL?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4084212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:32:36  来源:igfitidea点击:

How do you POST to a URL in Capybara?

ruby-on-railscucumberwebratcapybara

提问by Clinton

Just switched from Cucumber+Webrat to Cucumber+Capybara and I am wondering how you can POST content to a URL in Capybara.

刚刚从 Cucumber+Webrat 切换到 Cucumber+Capybara,我想知道如何将内容发布到 Capybara 中的 URL。

In Cucumber+Webrat I was able to have a step:

在 Cucumber+Webrat 我能够有一个步骤:

When /^I send "([^\"]*)" to "([^\"]*)"$/ do |file, project|
  proj = Project.find(:first, :conditions => "name='#{project}'")
  f = File.new(File.join(::Rails.root.to_s, file))
  visit "project/" + proj.id.to_s + "/upload",
        :post, {:upload_path => File.join(::Rails.root.to_s, file)}
end

However, the Capybara documentation mentions:

但是,Capybara 文档中提到:

The visit method only takes a single parameter, the request method is always GET.always GET.

visit 方法只带一个参数,请求方法总是 GET。always GET。

How do I modify my step so that Cucumber+Capybara does a POST to the URL?

如何修改我的步骤,以便 Cucumber+Capybara 对 URL 执行 POST?

采纳答案by Clinton

More recently I found this great blog post. Which is great for the cases like Tony and where you really wantto post something in your cuke:

最近我发现了这篇很棒的博客文章。这对于像托尼这样的案例以及你真的在你的库克中发布一些东西的情况非常有用:

For my case this became:

就我而言,这变成了:

def send_log(file, project)
  proj = Project.find(:first, :conditions => "name='#{project}'")
  f = File.new(File.join(::Rails.root.to_s, file))
  page.driver.post("projects/" + proj.id.to_s + "/log?upload_path=" + f.to_path)
  page.driver.status_code.should eql 200
end

回答by Mike

You could do this:

你可以这样做:

rack_test_session_wrapper = Capybara.current_session.driver
rack_test_session_wrapper.submit :post, your_path, nil
  • You can replace :postwhich whatever method you care about e.g. :putor :delete.
  • Replace your_pathwith the Rails path you want e.g. rack_test_session_wrapper.submit :delete, document_path(Document.last), nilwould delete the last Document in my app.
  • 您可以替换:post您关心的任何方法,例如:put:delete
  • 替换your_path为您想要的 Rails 路径,例如rack_test_session_wrapper.submit :delete, document_path(Document.last), nil删除我的应用程序中的最后一个文档。

回答by Henrik N

If your driver doesn't have post(Poltergeist doesn't, for example), you can do this:

如果您的驱动程序没有post(例如,Poltergeist 没有),您可以这样做:

session = ActionDispatch::Integration::Session.new(Rails.application)
response = session.post("/mypath", my_params: "go_here")

But note that this request happens in a new session, so you will have to go through the responseobject to assert on it.

但请注意,此请求发生在新会话中,因此您必须遍历response对象才能对其进行断言。

As has been stated elsewhere, in a Capybara test you typically want to do POSTs by submitting a form just like the user would. I used the above to test what happens to the user if a POST happens in another session (via WebSockets), so a form wouldn't cut it.

正如其他地方所述,在 Capybara 测试中,您通常希望像用户一样通过提交表单来执行 POST。我使用上面的方法来测试如果 POST 发生在另一个会话中(通过 WebSockets)对用户会发生什么,因此表单不会切断它。

Docs:

文档:

回答by Ariejan

Capybara's visitonly does GET requests. This is by design.

Capybaravisit只做 GET 请求。这是设计使然。

For a user to perform a POST, he must click a button or submit a form. There is no other way of doing this with a browser.

用户要执行POST,他必须单击按钮或提交表单。使用浏览器没有其他方法可以做到这一点。

The correct way to test this behaviour would be:

测试此行为的正确方法是:

visit "project/:id/edit" # This will only GET
attach_file "photo", File.open('cute_photo.jpg')
click_button 'Upload' # This will POST

If you want to test an API, I recommend using spec/requestinstead of cucumber, but that's just me.

如果你想测试一个 API,我建议使用spec/request而不是黄瓜,但这只是我。

回答by simeonwillbanks

I know the answer has already been accepted, but I'd like to provide an updated answer. Here is a technique from Anthony Edenand Corey Haineswhich passes Rack::Test to Cucumber's World object:

我知道答案已被接受,但我想提供更新的答案。这是Anthony EdenCorey Haines 的一项技术,它将 Rack::Test 传递给 Cucumber 的 World 对象:

Testing REST APIs with Cucumber and Rack::Test

使用 Cucumber 和 Rack::Test 测试 REST API

With this technique, I was able to directly send post requests within step definitions. While writing the step definitions, it was extremely helpful to learn the Rack::Test API from it's own specs.

使用这种技术,我能够在步骤定义中直接发送发布请求。在编写步骤定义时,从它自己的规范中学习 Rack::Test API 非常有帮助。

# feature
  Scenario: create resource from one time request
    Given I am an admin
    When I make an authenticated request for a new resource
    Then I am redirected  
    And I see the message "Resource successfully created" 

# step definitions using Rack::Test
When /^I make an authenticated request for a new resource$/ do
  post resources_path, :auth_token => @admin.authentication_token
  follow_redirect!
end

Then /^I am redirected$/ do
  last_response.should_not be_redirect
  last_request.env["HTTP_REFERER"].should include(resources_path)
end

Then /^I see the message "([^"]*)"$/ do |msg|
  last_response.body.should include(msg)
end

回答by B Seven

Although, not an exact answer to the question, the best solution for me has been to use Capybara for specs that simulate user interaction (using visit), and Rack Test for test API like requests. They can be used together within the same test suite.

虽然不是这个问题的确切答案,但对我来说最好的解决方案是将 Capybara 用于模拟用户交互的规范(使用visit),并将 Rack Test 用于测试 API 之类的请求。它们可以在同一个测试套件中一起使用。

Adding the following to the spec helper gives access to get, postand other Rack test methods:

将以下内容添加到规范帮助程序可以访问get,post和其他 Rack 测试方法:

RSpec.configure do |config|
  config.include Rack::Test::Methods

You may need to put the Rack Test specs in a spec/requestsfolder.

您可能需要将机架测试规范放在一个spec/requests文件夹中。

回答by Todd

With an application using RSpec 3+, you would not want to make an HTTP POST request with Capybara. Capybara is for emulating user behavior, and accepting the JS behavior and page content that results. An end user doesnt form HTTP POST requests for resources in your application, a user clicks buttons, clicks ajax links, drags n drops elements, submits web forms, etc.

对于使用 RSpec 3+ 的应用程序,您不希望使用 Capybara 发出 HTTP POST 请求。Capybara 用于模拟用户行为,并接受由此产生的 JS 行为和页面内容。最终用户不会对您的应用程序中的资源形成 HTTP POST 请求,用户单击按钮、单击 ajax 链接、拖放 n 个元素、提交 Web 表单等。

Check out this blog poston Capybara and other HTTP methods. The author makes the following claim:

查看这篇关于 Capybara 和其他 HTTP 方法的博客文章。作者提出以下主张:

Did you see any mention of methods like get, post or response? No? That's because those don't exist in Capybara. Let's be very clear about this...Capybara is not a library suited to testing APIs. There you have it. Do not test APIs with Capybara. It wasn't designed for it.

您是否看到任何提及诸如 get、post 或 response 之类的方法?不?那是因为这些在水豚中不存在。让我们非常清楚这一点……Capybara 不是一个适合测试 API 的库。你有它。不要使用 Capybara 测试 API。它不是为它设计的。

So, developing an API or not, if you have to make an explicit HTTP POST request, and it does not involve an HTML element and some sort of event (click, drag, select, focusout, whatever), then it shouldn't be tested with Capybara. If you can test the same feature by clicking some button, then do use Capybara.

因此,无论是否开发 API,如果您必须发出明确的 HTTP POST 请求,并且它不涉及 HTML 元素和某种事件(单击、拖动、选择、聚焦等),那么它不应该是用水豚测试。如果您可以通过单击某个按钮来测试相同的功能,那么请使用 Capybara。

What you likely want is RSpec Request specs. Here you can make postcalls, and any other HTTP method as well, and assert expectations on the response. You can also mock n stub objects and methods to assert expectations in regards to side effects and other behaviors that happen in between your request and the response.

您可能想要的是RSpec Request specs。您可以在此处进行post调用以及任何其他 HTTP 方法,并对响应断言期望值。您还可以模拟 n 个存根对象和方法,以断言对请求和响应之间发生的副作用和其他行为的期望。

# spec located in spec/requests/project_file_upload_spec.rb
require "rails_helper"

RSpec.describe "Project File Upload", type: :request do

  let(:project) { create(:project) }
  let(:file)    { File.new(File.join(::Rails.root.to_s, 'path/to/file.ext')) } # can probably extract this to a helper...

  it "accepts a file uploaded to a Project resource" do

    post "project/#{project.id}/upload", upload_path: file

    expect(response).to be_success
    expect(project.file?).to eq(true)
    # expect(project.file).not_to eq(nil)
    expect(response).to render_template(:show)
  end

end

回答by Marnen Laibow-Koser

As others have said, there's no direct way of doing a POST with Capybara because it's all about browser interaction. For API testing, I'd veryhighly recommend the rspec_api_documentationgem.

正如其他人所说,没有使用 Capybara 进行 POST 的直接方法,因为这完全与浏览器交互有关。对于API的测试,我会强烈推荐rspec_api_documentation宝石。