36

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

在 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

但是,Capybara 文档提到:

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

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

4

8 回答 8

24

最近我发现了这篇很棒的博客文章。这对于像 Tony 这样的案例以及您真正在您的 cuke 中发布内容的情况非常有用:

就我而言,这变成了:

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
于 2011-04-11T01:53:39.070 回答
21

你可以这样做:

rack_test_session_wrapper = Capybara.current_session.driver
rack_test_session_wrapper.submit :post, your_path, nil
  • 您可以替换:post您关心的任何方法,例如:put:delete.
  • 替换your_path为您想要的 Rails 路径,例如rack_test_session_wrapper.submit :delete, document_path(Document.last), nil将删除我的应用程序中的最后一个文档。
于 2012-03-08T11:48:32.207 回答
13

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

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

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

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

文件:

于 2014-06-22T16:50:19.410 回答
9

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

用户要执行POST,他必须单击按钮或提交表单。没有其他方法可以使用浏览器执行此操作。

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

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

如果你想测试一个 API,我推荐使用spec/request而不是 cucumber,但这只是我。

于 2010-11-03T10:24:06.630 回答
5

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

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

使用这种技术,我能够在步骤定义中直接发送发布请求。在编写步骤定义时,从自己的规范中学习 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
于 2011-10-31T20:05:33.337 回答
3

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

将以下内容添加到 spec 帮助程序可以访问getpost其他 Rack 测试方法:

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

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

于 2015-05-27T21:31:04.487 回答
1

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

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

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

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

您可能想要的是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
于 2017-04-08T21:51:40.310 回答
0

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

于 2020-04-22T16:10:54.150 回答