你如何POST到Capybara的URL?

时间:2010-11-03 04:23:18

标签: ruby-on-rails cucumber webrat capybara

刚刚从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?

8 个答案:

答案 0 :(得分:22)

最近我找到this great blog post。对于像托尼这样的案例以及你真正希望在你的公共场合发布内容的案例来说,这是非常好的:

对于我的情况,这成了:

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

答案 1 :(得分:22)

你可以这样做:

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会删除我应用中的最后一个文档。

答案 2 :(得分:8)

Capybara的visit只做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代替黄瓜,但这只是我。

答案 3 :(得分:8)

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

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

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

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

文档:

答案 4 :(得分:5)

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

Testing REST APIs with Cucumber and Rack::Test

通过这种技术,我能够在步骤定义中直接发送帖子请求。在编写步骤定义时,从它自己的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

答案 5 :(得分:2)

虽然不是这个问题的确切答案,但对我来说最好的解决方案是将Capybara用于模拟用户交互(使用mvn -DdependencyDetailsEnabled=true project-info-reports:dependencies )的规范,以及使用Rack Test测试API(如请求)。它们可以在同一个测试套件中一起使用。

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

post

您可能需要将Rack Test规格放在RSpec.configure do |config| config.include Rack::Test::Methods 文件夹中。

答案 6 :(得分:1)

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

在Capybara和其他HTTP方法上查看this blog post。作者提出以下主张:

  

您是否看到任何提及get,post或response等方法?没有?那是因为Capybara中不存在这些。让我们对此非常清楚...... Capybara不是一个适合测试API的库。你有它。不要使用Capybara测试API。它不是为它而设计的。

所以,开发一个API与否,如果你必须发出一个明确的HTTP POST请求,并且它不涉及HTML元素和某种事件(点击,拖动,选择,聚焦,等等),那么它应该& #49;用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

答案 7 :(得分:0)

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