¿Cómo PUBLICAS a una URL en Capibara?

Acabo de cambiar de Cucumber + Webrat a Cucumber + Capybara y me pregunto cómo puedes enviar contenido a una URL en Capybara.

En Cucumber + Webrat pude dar un paso:

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 

Sin embargo, la documentación de Capibara menciona:

El método de visita solo toma un solo parámetro, el método de solicitud siempre es GET.always GET.

¿Cómo modifico mi paso para que Cucumber + Capybara haga una POST a la URL?

Más recientemente encontré esta gran publicación de blog . Lo cual es genial para los casos como Tony y donde realmente quieres publicar algo en tu cuke:

Para mi caso, esto se convirtió en:

 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 

Podrías hacer esto:

 rack_test_session_wrapper = Capybara.current_session.driver rack_test_session_wrapper.submit :post, your_path, nil 
  • Puede reemplazar :post cualquier método que le interese, por ejemplo :put o :delete .
  • Reemplace your_path con la ruta de Rails que desee, por ejemplo, rack_test_session_wrapper.submit :delete, document_path(Document.last), nil eliminará el último documento en mi aplicación.

La visit de Capibara solo tiene solicitudes GET. Esto es por diseño.

Para que un usuario realice una POST , debe hacer clic en un botón o enviar un formulario. No hay otra manera de hacer esto con un navegador.

La forma correcta de probar este comportamiento sería:

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

Si quieres probar una API, te recomiendo usar la spec/request lugar de pepino, pero así soy yo.

Si su controlador no tiene post (Poltergeist no, por ejemplo), puede hacer esto:

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

Pero tenga en cuenta que esta solicitud se realiza en una nueva sesión, por lo que tendrá que pasar por el objeto de response para afirmarla.

Como se ha indicado en otro lugar, en una prueba de Capybara, normalmente desea realizar un POST enviando un formulario como lo haría el usuario. Usé lo anterior para probar lo que sucede con el usuario si ocurre un POST en otra sesión (a través de WebSockets), por lo que un formulario no lo cortaría.

Documentos:

Sé que la respuesta ya ha sido aceptada, pero me gustaría brindar una respuesta actualizada. Aquí hay una técnica de Anthony Eden y Corey Haines que pasa el objeto de Rack :: Test to Cucumber’s World:

Prueba de API REST con Cucumber and Rack :: Test

Con esta técnica, pude enviar solicitudes de publicación directamente dentro de las definiciones de pasos. Mientras escribía las definiciones de paso, fue extremadamente útil aprender la API Rack :: Test a partir de sus propias especificaciones .

 # 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 

Aunque no es una respuesta exacta a la pregunta, la mejor solución para mí ha sido utilizar Capybara para las especificaciones que simulan la interacción del usuario (con visit ) y prueba en rack para API de prueba, como solicitudes. Se pueden usar juntos dentro del mismo conjunto de pruebas.

Al agregar lo siguiente al asistente de especificaciones, se proporciona acceso a los métodos de get , post y otros métodos de prueba en rack:

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

Es posible que deba colocar las especificaciones de Prueba de Rack en una carpeta de spec/requests .

Con una aplicación que use RSpec 3+, no querrá hacer una solicitud HTTP POST con Capybara. Capybara es para emular el comportamiento del usuario y aceptar el comportamiento de JS y el contenido de la página resultante. Un usuario final no forma solicitudes HTTP POST para recursos en su aplicación, un usuario hace clic en botones, hace clic en enlaces ajax, arrastra elementos de n gotas, envía formularios web, etc.

Echa un vistazo a esta publicación de blog sobre Capybara y otros métodos HTTP. El autor hace la siguiente afirmación:

¿Has visto alguna mención de métodos como get, post o response? ¿No? Eso es porque esos no existen en Capybara. Seamos muy claros sobre esto … Capybara no es una biblioteca adecuada para probar API. Ahí tienes. No pruebes las API con Capybara. No fue diseñado para eso.

Entonces, desarrollar una API o no, si tienes que hacer una solicitud HTTP POST explícita, y no involucra un elemento HTML y algún tipo de evento (clic, arrastrar, seleccionar, enfocar, lo que sea), entonces no debería ser probado con Capybara. Si puede probar la misma función haciendo clic en algún botón, entonces use Capybara.

Lo que probablemente desee es especificaciones de RSpec Request . Aquí puede realizar llamadas post , y cualquier otro método HTTP, y establecer expectativas en la respuesta. También puede burlarse de objetos y métodos de prueba para afirmar expectativas con respecto a los efectos secundarios y otros comportamientos que ocurren entre su solicitud y la respuesta.

 # 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