web-dev-qa-db-fra.com

Définir le format de requête GET par défaut Rspec sur JSON

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)

47
Drazen Mokic
before :each do
  request.env["HTTP_ACCEPT"] = 'application/json'
end
50
Pratik Khadloya

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
24
knoopx

Ce qui suit fonctionne pour moi avec rspec:

before :each do
  request.headers["accept"] = 'application/json'
end

Cela définit HTTP_ACCEPT.

16
schmijos

Voici une solution qui

  1. fonctionne pour les spécifications de la demande,
  2. fonctionne avec Rails 5, et
  3. n'implique pas d'API privée de Rails (comme 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:

  1. 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/.

  2. Directement dans spec/Rails_helper.rb.

  3. (mon préféré) Dans spec/support/default_format.rb, et être chargé explicitement dans spec/Rails_helper.rb avec

    require 'support/default_format'
    
  4. 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 .

11
Franklin Yu

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

7
Dan Kohn

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).

6
zw963

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
2
settheline

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)
1
mpospelov

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
0
DBrown