web-dev-qa-db-ja.com

カピバラのURLにPOSTするにはどうしますか?

Cucumber + WebratからCucumber + Capybaraに切り替えたところ、POSTコンテンツを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

ただし、カピバラのドキュメントは次のように述べています:

訪問メソッドは単一のパラメーターのみを受け取り、要求メソッドは常にGETです。常にGETです。

Cucumber + CapybaraがPOSTをURLに実行するように、ステップを変更するにはどうすればよいですか?

34
Clinton

最近、私は この素晴らしいブログ投稿 を見つけました。これは、Tonyのような場合や、実際にキューに何かを投稿したい場合に最適です。

私の場合、これは次のようになりました:

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
22
Clinton

あなたはこれを行うことができます:

_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は、アプリの最後のドキュメントを削除します。
22
Mike

ドライバーにpostがない場合(たとえば、Poltergeistにはない)、これを行うことができます。

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

ただし、このリクエストは新しいセッションで発生するため、responseオブジェクトを通過してアサートする必要があることに注意してください。

他の場所で述べたように、カピバラテストでは通常、ユーザーと同じようにフォームを送信してPOSTを実行します。上記を使用して、POSTが別のセッションで(WebSocketsを介して)発生した場合にユーザーに何が起こるかをテストしたため、フォームはそれをカットしませんでした。

ドキュメント:

10
Henrik N

カピバラの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を使用することをお勧めしますが、それは私だけです。

9
Ariejan

回答は既に受け入れられていますが、更新された回答を提供したいと思います。 Anthony Eden および Corey Haines からのテクニックで、Rack :: TestをCucumberのWorldオブジェクトに渡します。

テストREST CucumberおよびRack :: Testを使用したAPI

この手法により、ステップ定義内でポストリクエストを直接送信することができました。ステップ定義を書いているとき、Rack :: Test APIを独自の specs から学ぶことは非常に役に立ちました。

# 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
simeonwillbanks

質問に対する正確な回答ではありませんが、私にとっての最良の解決策は、ユーザーの対話をシミュレートする仕様(visitを使用)にCapybaraを使用し、リクエストのようなテストAPIにラックテストを使用することでした。同じテストスイート内で一緒に使用できます。

以下をスペックヘルパーに追加すると、getpostおよびその他のラックテストメソッドにアクセスできます。

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

ラックテストの仕様をspec/requestsフォルダ。

2
B Seven

RSpec 3+を使用するアプリケーションでは、HTTP POST Capybaraでリクエストを作成する必要はありません。Capybaraは、ユーザーの動作をエミュレートし、JSの動作と結果のページコンテンツを受け入れるためのものです。終了ユーザーがHTTPを形成しないPOSTアプリケーション内のリソースのリクエスト、ユーザーがボタンをクリックする、ajaxリンクをクリックする、要素をドラッグアンドドロップする、Webフォームを送信するなど。

カピバラと他のHTTPメソッドについて このブログ投稿 をチェックしてください。著者は次の主張をします:

Get、post、responseなどのメソッドについて言及しましたか?番号?カピバラには存在しないからです。これについて非常に明確にしましょう... Capybaraは、APIのテストに適したライブラリではありません。そこにあります。 CapybaraでAPIをテストしないでください。それのために設計されていません。

したがって、明示的なHTTP POSTリクエストを行う必要があり、HTML要素と何らかのイベント(クリック、ドラッグ、選択、focusout、何でも)、それはカピバラでテストすべきではありません。いくつかのボタンをクリックして同じ機能をテストできる場合は、カピバラを使用してください。

あなたが望んでいるのは 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
1
Todd