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に実行するように、ステップを変更するにはどうすればよいですか?
最近、私は この素晴らしいブログ投稿 を見つけました。これは、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
あなたはこれを行うことができます:
_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
は、アプリの最後のドキュメントを削除します。ドライバーにpost
がない場合(たとえば、Poltergeistにはない)、これを行うことができます。
session = ActionDispatch::Integration::Session.new(Rails.application)
response = session.post("/mypath", my_params: "go_here")
ただし、このリクエストは新しいセッションで発生するため、response
オブジェクトを通過してアサートする必要があることに注意してください。
他の場所で述べたように、カピバラテストでは通常、ユーザーと同じようにフォームを送信してPOSTを実行します。上記を使用して、POSTが別のセッションで(WebSocketsを介して)発生した場合にユーザーに何が起こるかをテストしたため、フォームはそれをカットしませんでした。
ドキュメント:
カピバラの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
を使用することをお勧めしますが、それは私だけです。
回答は既に受け入れられていますが、更新された回答を提供したいと思います。 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
質問に対する正確な回答ではありませんが、私にとっての最良の解決策は、ユーザーの対話をシミュレートする仕様(visit
を使用)にCapybaraを使用し、リクエストのようなテストAPIにラックテストを使用することでした。同じテストスイート内で一緒に使用できます。
以下をスペックヘルパーに追加すると、get
、post
およびその他のラックテストメソッドにアクセスできます。
RSpec.configure do |config|
config.include Rack::Test::Methods
ラックテストの仕様をspec/requests
フォルダ。
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