Je fais des tests fonctionnels pour mes contrôleurs avec Rspec. J'ai défini mon format de réponse par défaut dans mon routeur sur JSON, donc chaque demande sans suffixe retournera JSON.
Maintenant dans rspec, j'obtiens une erreur (406) quand j'essaye
get :index
J'ai besoin de faire
get :index, :format => :json
Maintenant, parce que je supporte principalement JSON avec mon API, il est très redondant de spécifier le format JSON pour chaque demande.
Puis-je le définir par défaut pour toutes mes demandes GET? (ou toutes les demandes)
before :each do
request.env["HTTP_ACCEPT"] = 'application/json'
end
Mettez ceci dans spec/support
:
require 'active_support/concern'
module DefaultParams
extend ActiveSupport::Concern
def process_with_default_params(action, parameters, session, flash, method)
process_without_default_params(action, default_params.merge(parameters || {}), session, flash, method)
end
included do
let(:default_params) { {} }
alias_method_chain :process, :default_params
end
end
RSpec.configure do |config|
config.include(DefaultParams, :type => :controller)
end
Et puis simplement remplacer default_params
:
describe FooController do
let(:default_params) { {format: :json} }
...
end
Ce qui suit fonctionne pour moi avec rspec:
before :each do
request.headers["accept"] = 'application/json'
end
Cela définit HTTP_ACCEPT
.
Voici une solution qui
process
).Voici la configuration RSpec:
module DefaultFormat
extend ActiveSupport::Concern
included do
let(:default_format) { 'application/json' }
prepend RequestHelpersCustomized
end
module RequestHelpersCustomized
l = lambda do |path, **kwarg|
kwarg[:headers] = {accept: default_format}.merge(kwarg[:headers] || {})
super(path, **kwarg)
end
%w(get post patch put delete).each do |method|
define_method(method, l)
end
end
end
RSpec.configure do |config|
config.include DefaultFormat, type: :request
end
Vérifié avec
describe 'the response format', type: :request do
it 'can be overridden in request' do
get some_path, headers: {accept: 'text/plain'}
expect(response.content_type).to eq('text/plain')
end
context 'with default format set as HTML' do
let(:default_format) { 'text/html' }
it 'is HTML in the context' do
get some_path
expect(response.content_type).to eq('text/html')
end
end
end
FWIW, La configuration RSpec peut être placée:
Directement dans spec/spec_helper.rb
. Ce n'est pas suggéré; le fichier sera chargé même lors du test des méthodes de bibliothèque dans lib/
.
Directement dans spec/Rails_helper.rb
.
(mon préféré) Dans spec/support/default_format.rb
, et être chargé explicitement dans spec/Rails_helper.rb
avec
require 'support/default_format'
Dans spec/support
, et être chargé par
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
qui charge tous les fichiers dans spec/support
.
Cette solution est inspirée de réponse de knoopx . Sa solution ne fonctionne pas pour les spécifications de la demande, et alias_method_chain
est déconseillé au profit de Module#prepend
.
Dans RSpec 3, vous devez faire en sorte que les tests JSON soient des spécifications de demande afin que les vues soient rendues. Voici ce que j'utilise:
# spec/requests/companies_spec.rb
require 'Rails_helper'
RSpec.describe "Companies", :type => :request do
let(:valid_session) { {} }
describe "JSON" do
it "serves multiple companies as JSON" do
FactoryGirl.create_list(:company, 3)
get 'companies', { :format => :json }, valid_session
expect(response.status).to be(200)
expect(JSON.parse(response.body).length).to eq(3)
end
it "serves JSON with correct name field" do
company = FactoryGirl.create(:company, name: "Jane Doe")
get 'companies/' + company.to_param, { :format => :json }, valid_session
expect(response.status).to be(200)
expect(JSON.parse(response.body)['name']).to eq("Jane Doe")
end
end
end
Quant à la définition du format sur tous les tests, j'aime l'approche de cette autre réponse: https://stackoverflow.com/a/14623960/1935918
Vous pourriez peut-être ajouter la première réponse dans spec/spec_helper ou spec/Rails_helper avec ceci:
config.before(:each) do
request.env["HTTP_ACCEPT"] = 'application/json' if defined? request
end
s'il est dans le test de modèle (ou dans un contexte de méthodes de demande qui n'existe pas), ce code ignore simplement. cela a fonctionné avec rspec 3.1.7 et Rails 4.1.0 il devrait être travaillé avec toutes les versions Rails 4 en général).
En cours d'exécution Rails 5 et Rspec 3.5 j'ai dû définir les en-têtes pour accomplir cela.
post '/users', {'body' => 'params'}, {'ACCEPT' => 'application/json'}
Cela correspond à ce que l'exemple dans le docs ressemble:
require "Rails_helper"
RSpec.describe "Widget management", :type => :request do
it "creates a Widget" do
headers = {
"ACCEPT" => "application/json", # This is what Rails 4 accepts
"HTTP_ACCEPT" => "application/json" # This is what Rails 3 accepts
}
post "/widgets", { :widget => {:name => "My Widget"} }, headers
expect(response.content_type).to eq("application/json")
expect(response).to have_http_status(:created)
end
end
Pour les personnes qui travaillent avec des tests de demande, la méthode la plus simple que j'ai trouvée consiste à remplacer #process
méthode dans ActionDispatch::Integration::Session
et définissez le paramètre par défaut as
sur :json
comme ça:
module DefaultAsForProcess
def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: :json)
super
end
end
ActionDispatch::Integration::Session.prepend(DefaultAsForProcess)
Selon le Rspec docs , la méthode prise en charge est à travers les en-têtes:
require "Rails_helper"
RSpec.describe "Widget management", :type => :request do
it "creates a Widget" do
headers = {
"ACCEPT" => "application/json", # This is what Rails 4 and 5 accepts
"HTTP_ACCEPT" => "application/json", # This is what Rails 3 accepts
}
post "/widgets", :params => { :widget => {:name => "My Widget"} }, :headers => headers
expect(response.content_type).to eq("application/json")
expect(response).to have_http_status(:created)
end
end