web-dev-qa-db-fra.com

Comment avez-vous POST à une URL à Capybara?

Vient de passer du concombre + Webrat au concombre + Capybara et je me demande comment vous pouvez POST Contenu à une URL à Capybara.

Dans Cucumber + Webrat, j'ai pu avoir une étape:

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

Cependant, la documentation de Capybara mentionne:

La méthode de visite ne prend qu'un seul paramètre, la méthode de la demande est toujours obtenue.

Comment puis-je modifier mon pas de sorte que le concombre + Capybara ait un POST à l'URL?

34
Clinton

Plus récemment, j'ai trouvé ce grand blog post . Ce qui est génial pour les cas comme Tony et où vous voulez vraiment veux Publier quelque chose dans votre Cuke:

Pour mon cas, cela est devenu:

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

Vous pourriez faire cela:

rack_test_session_wrapper = Capybara.current_session.driver
rack_test_session_wrapper.submit :post, your_path, nil
  • Vous pouvez remplacer :post Quelle quelle que soit la méthode que vous vous souciez de par exemple. :put Ou :delete.
  • Remplacez your_path Avec le Rails Chemin que vous voulez, rack_test_session_wrapper.submit :delete, document_path(Document.last), nil supprimerait le dernier document de mon application.
22
Mike

Si votre pilote n'a pas post (Poltergeist ne peut par exemple), vous pouvez le faire:

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

Mais notez que cette demande se produit lors d'une nouvelle session, vous devrez donc passer par l'objet response pour y affirmer.

Comme cela a été déclaré ailleurs, dans un test de Capybara, vous voulez généralement faire des messages en soumettant une forme comme l'utilisateur. J'ai utilisé ce qui précède pour tester ce qui arrive à l'utilisateur si A POST se produit dans une autre session (via WebSockets), un formulaire ne le couperait pas.

DOCS:

10
Henrik N

Capybara visit _ ne reçoit que des demandes. Ceci est par conception.

Pour qu'un utilisateur effectue un POST, il doit cliquer sur un bouton ou soumettre un formulaire. Il n'y a pas d'autre moyen de le faire avec un navigateur.

La bonne façon de tester ce comportement serait:

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

Si vous voulez tester une API, je recommande d'utiliser spec/request au lieu de concombre, mais c'est juste moi.

9
Ariejan

Je sais que la réponse a déjà été acceptée, mais j'aimerais fournir une réponse mise à jour. Voici une technique à partir de Anthony Eden et Corey Haines qui passe de rack :: Test sur l'objet mondial de concombre:

Test REST API avec concombre et rack :: Test

Avec cette technique, j'ai pu envoyer directement des demandes postales dans les définitions d'étape. Tout en écrivant les définitions de l'étape, il était extrêmement utile d'apprendre le rack :: Test API de ses propres spécifications .

# 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

Bien que, pas une réponse exacte à la question, la meilleure solution pour moi a été d'utiliser Capybara pour des spécifications qui simulent l'interaction utilisateur (à l'aide de visit) et test de rack pour les demandes d'API de test. Ils peuvent être utilisés ensemble dans la même suite de tests.

L'ajout de ce qui suit à la spécification Helper donne accès à get, post et autres méthodes de test de rack:

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

Vous devrez peut-être mettre les spécifications de test de rack dans un spec/requests dossier.

2
B Seven

Avec une application à l'aide de RSPEC 3+, vous ne souhaitez pas créer un fichier http POST avec Capybara. Capybara est destiné à émuler le comportement des utilisateurs et à accepter le contenu du comportement et de la page JS qui résulte. Une fin L'utilisateur ne formule pas http POST Demandes de ressources dans votre application, un utilisateur clique sur les boutons, clique sur les liens Ajax, glisser des éléments de gouttes, soumet des formulaires Web, etc.

Check Out ce blog post sur Capybara et autres méthodes HTTP. L'auteur fait la revendication suivante:

Avez-vous vu une mention de méthodes comme Get, Post ou Réponse? Non? C'est parce que ceux n'existent pas à Capybara. Soyons très clairs à ce sujet ... Capybara n'est pas une bibliothèque adaptée à tester les API. Voilà. Ne testez pas les API avec Capybara. Cela n'a pas été conçu pour cela.

Donc, développer une API ou non, si vous devez faire une demande HTTP POST Demande, et cela n'implique pas un élément HTML et une sorte d'événement (cliquez, faites glisser, sélectionnez, Mise en page, Quoi qu'il en soit), alors il ne devrait pas être testé avec Capybara. Si vous pouvez tester la même fonctionnalité en cliquant sur un bouton, utilisez Capybara.

Ce que vous voulez probablement, c'est spécifications de demande RSPEC . Ici, vous pouvez faire post appels, ainsi que toute autre méthode HTTP, et affirmer les attentes sur la réponse. Vous pouvez également vous moquer des objets et des méthodes d'encrassement pour affirmer les attentes vis-à-vis des effets secondaires et d'autres comportements qui se produisent entre votre demande et la réponse.

# 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