Comment envoyer des données post brutes dans un test fonctionnel Rails?

Je cherche à envoyer des données de publication brutes (par exemple, JSON non paramétrable) à l’un de mes contrôleurs pour les tests:

class LegacyOrderUpdateControllerTest < ActionController::TestCase test "sending json" do post :index, '{"foo":"bar", "bool":true}' end end 

mais cela me donne un NoMethodError: undefined method `symbolize_keys' for # erreur NoMethodError: undefined method `symbolize_keys' for # .

Quelle est la bonne façon d’envoyer des données post brutes dans ActionController::TestCase ?

Voici un code de contrôleur:

 def index post_data = request.body.read req = JSON.parse(post_data) end 

J’ai rencontré le même problème aujourd’hui et j’ai trouvé une solution.

Dans votre test_helper.rb définissez la méthode suivante dans ActiveSupport::TestCase :

 def raw_post(action, params, body) @request.env['RAW_POST_DATA'] = body response = post(action, params) @request.env.delete('RAW_POST_DATA') response end 

Dans votre test fonctionnel, utilisez-le comme la méthode post mais transmettez le corps de publication brut comme troisième argument.

 class LegacyOrderUpdateControllerTest < ActionController::TestCase test "sending json" do raw_post :index, {}, {:foo => "bar", :bool => true}.to_json end end 

Je l’ai testé sur Rails 2.3.4 lors de la lecture du corps du message brut en utilisant

 request.raw_post 

au lieu de

 request.body.read 

Si vous regardez le code source, vous verrez que raw_post justement request.body.read avec une vérification pour ce RAW_POST_DATA dans le hash de request env.

J’ai en fait résolu les mêmes problèmes en ajoutant une seule ligne avant de simuler la post-requête rspec. Ce que vous faites est de remplir le “RAW_POST_DATA”. J’ai essayé de supprimer les atsortingbuts var sur le post: create, mais si je le fais, il ne trouve pas l’action.

Voici ma solution

 def do_create (atsortingbuts)
   request.env ['RAW_POST_DATA'] = atsortingbuts.to_json
   post: créer, atsortingbuts
 fin 

Dans le contrôleur, le code que vous devez lire le JSON est quelque chose de similaire

   @property = Property.new (JSON.parse (request.body.read))

En regardant la trace de la stack exécutant un test, vous pouvez acquérir plus de contrôle sur la préparation de la demande: ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: Session.env_for

Vous pouvez transmettre json ssortingng en tant que: params ET spécifier un type de contenu “application / json”. Dans d’autres cas, le type de contenu sera défini sur “application / x-www-form-urlencoded” et votre json sera analysé correctement.

Il suffit donc de spécifier “CONTENT_TYPE”:

 post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json' 

Si vous utilisez RSpec (> = 2.12.0) et que vous écrivez des spécifications de requête, le module inclus est ActionDispatch::Integration::Runner . Si vous examinez le code source, vous pouvez remarquer que la méthode post appelle un processus qui accepte un paramètre rack_env .

Tout cela signifie que vous pouvez simplement faire ce qui suit dans vos spécifications:

 #spec/requests/articles_spec.rb post '/articles', {}, {'RAW_POST_DATA' => 'something'} 

Et dans le contrôleur:

 #app/controllers/articles_controller.rb def create puts request.body.read end 

Pour ceux qui utilisent les tests d’intégration Rails5 +, la manière (non documentée) de faire cela est de passer une chaîne dans l’argument params, donc:

 post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' } 

Version pour Rails 5:

 post :create, body: '{"foo": "bar", "bool": true}' 

Voir ici – le paramètre de chaîne de body est traité comme corps de requête brut.

En utilisant Rails 4, je cherchais à le faire pour tester le traitement du fichier XML brut envoyé au contrôleur. J’ai pu le faire en fournissant simplement la chaîne au message:

 raw_xml = File.read("my_raw.xml") post :message, raw_xml, format: :xml 

Je pense que si le paramètre fourni est une chaîne, il est simplement transmis au contrôleur en tant que corps.

La méthode post attend un hachage des paires nom-valeur, vous devrez donc faire quelque chose comme ceci:

 post :index, :data => '{"foo":"bar", "bool":true}' 

Ensuite, dans votre contrôleur, obtenez les données à parsingr comme ceci:

 post_data = params[:data] 

A partir de Rails 4.1.5, c’était la seule chose qui fonctionnait pour moi:

 class LegacyOrderUpdateControllerTest < ActionController::TestCase def setup @request.headers["Content-Type"] = 'application/json' end test "sending json" do post :index, '{"foo":"bar", "bool":true}'.to_json, { account_id: 5, order_id: 10 } end end 

pour une url chez / accounts / 5 / orders / 10 / items. Cela récupère les parameters d'URL ainsi que le corps JSON. Bien sûr, si les commandes ne sont pas intégrées, vous pouvez laisser de côté le paramètre hash params.

 class LegacyOrderUpdateControllerTest < ActionController::TestCase def setup @request.headers["Content-Type"] = 'application/json' end test "sending json" do post :index, '{"foo":"bar", "bool":true}'.to_json end end 

Dans les rails, 5.1, ce qui suit fonctionne pour moi lorsque vous effectuez une demande de suppression nécessitant des données dans le corps:

 delete your_app_url, as: :json, env: { "RAW_POST_DATA" => {"a_key" => "a_value"}.to_json } 

REMARQUE: Cela ne fonctionne que lors d’un test d’intégration.

Je cherchais très longtemps à publier du contenu JSON brut dans un test d’intégration (Rails 5.1). Je suppose que ma solution pourrait également aider dans ce cas. J’ai recherché la documentation et le code source de la méthode post : https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers.html#method-i-post

Cela m’a orienté vers la méthode process pour plus de détails: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process

Grâce à cela, j’ai finalement trouvé quels parameters sont acceptés par le process et donc la méthode post . Voici à quoi ressemblait ma solution finale:

 post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json 
 post :index, {:foo=> 'bar', :bool => 'true'}