Как вы используете POST для URL-адреса в Capybara?
Просто переключился с Cucumber + Webrat на Cucumber + Capybara, и мне интересно, как вы можете использовать POST-контент для URL-адреса в Capybara.
В огурце + 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 отправил POST в URL?
Ответы
Ответ 1
Совсем недавно я нашел этот отличный пост в блоге. Что отлично подходит для таких случаев, как Тони и где вы действительно хотите опубликовать что-то в своем фильме:
В моем случае это стало:
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
Ответ 2
Вы можете сделать это:
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
удалит последний документ в моем приложении.
Ответ 3
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
вместо огурца, но это только я.
Ответ 4
Если у вашего драйвера нет post
(например, Poltergeist), вы можете сделать это:
session = ActionDispatch::Integration::Session.new(Rails.application)
response = session.post("/mypath", my_params: "go_here")
Но обратите внимание, что этот запрос выполняется в новом сеансе, поэтому вам придется пройти через объект response
, чтобы его утверждать.
Как было сказано в другом месте, в тесте Capybara вы обычно хотите делать POST, отправляя форму так же, как и пользователь. Я использовал приведенное выше, чтобы проверить, что происходит с пользователем, если POST происходит в другом сеансе (через WebSockets), поэтому форма не разрешит его.
Docs:
Ответ 5
Я знаю, что ответ уже принят, но я хотел бы предоставить обновленный ответ. Вот техника из Anthony Eden и Кори Хейнс, которая проходит Rack:: Test to Cucumber World object:
Тестирование API REST с помощью огурца и стойки:: Тест
С помощью этой методики я смог напрямую отправлять почтовые запросы в определениях шагов. При написании определений шагов было чрезвычайно полезно изучить 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
Ответ 6
Хотя, не точный ответ на вопрос, лучшим решением для меня было использование Capybara для спецификаций, которые имитируют взаимодействие с пользователем (с использованием visit
) и Rack Test для тестовых API, таких как запросы. Они могут использоваться вместе в одном наборе тестов.
Добавление следующего в spec-помощник дает доступ к get
, post
и другим методам проверки стойки:
RSpec.configure do |config|
config.include Rack::Test::Methods
Вам может потребоваться установить спецификации Rack Test в папку spec/requests
.
Ответ 7
С помощью приложения, использующего RSpec 3+, вы не захотите делать HTTP POST-запрос с Capybara. Capybara предназначен для эмуляции поведения пользователя и принятия поведения JS и содержимого страницы. Конечный пользователь не формирует HTTP POST-запросы для ресурсов в вашем приложении, пользователь нажимает кнопки, нажимает на ссылки ajax, перетаскивает элементы n капель, отправляет веб-формы и т.д.
Отметьте это сообщение в блоге о Capybara и других методах HTTP. Автор делает следующее выражение:
Вы видели какие-либо упоминания о методах, таких как получение, публикация или ответ? Нет? То потому что они не существуют в Capybara. Давайте будем очень понятны об этом... Capybara не является библиотекой, подходящей для тестирования API. Там у вас это есть. Не проверяйте API с Capybara. Он не был предназначен для этого.
Итак, разрабатывая API или нет, если вам нужно сделать явный HTTP-запрос POST, и он не включает элемент HTML и какое-то событие (щелкните, перетащите, выберите, сконфигурировать, что угодно), тогда он должен Тестировать с Capybara. Если вы можете протестировать одну и ту же функцию, нажав на какую-нибудь кнопку, используйте Capybara.
Скорее всего, вам нужно спецификации RSpec. Здесь вы можете делать вызовы 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