Définir Rspec par défaut obtenir le format de requête à 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 à JSON, ainsi chaque requête sans suffixe retournera JSON.

maintenant dans rspec, je reçois une erreur (406) quand j'essaie

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 d'avoir à spécifier le format JSON pour chaque requête.

est-ce que je peux le définir par défaut pour toutes mes requêtes GET? (ou toutes les demandes)

41
demandé sur Drazen Mokic 2012-06-14 00:30:14

9 réponses

before :each do
  request.env["HTTP_ACCEPT"] = 'application/json'
end
45
répondu Pratik Khadloya 2013-05-05 08:02:49

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 ensuite simplement remplacer default_params :

describe FooController do
    let(:default_params) { {format: :json} }
    ...
end
24
répondu knoopx 2013-01-31 10:50:32

les travaux suivants pour moi avec rspec 3 :

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

cet ensemble HTTP_ACCEPT .

13
répondu schmijos 2015-01-15 16:57:05

dans RSpec 3, vous avez besoin de faire des tests JSON être Request specs 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

pour ce qui est de définir le format sur tous les tests, j'aime l'approche de cette autre réponse: https://stackoverflow.com/a/14623960/1935918

7
répondu dankohn 2017-05-23 12:26:12

Voici une solution qui

  1. fonctionne pour les specs de requête,
  2. travaille avec des 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 . Ceci n'est pas suggéré; le fichier sera chargé même si l'on teste les méthodes de la 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 de spec/support .

cette solution est inspirée de knoopx's answer . Sa solution ne fonctionne pas pour les spécifications de demande, et alias_method_chain a été déprécié en faveur de Module#prepend .

4
répondu Franklin Yu 2017-05-23 12:26:12

peut-être pourriez-vous 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

si dans le contexte de l'essai sur modèle (ou de toute méthode de requête inexistante), ce code ne tient pas compte. il a travaillé avec rspec 3.1.7 et rails 4.1.0 il doit être travaillé avec tous les rails 4 version Généralement parlant.

3
répondu zw963 2014-10-31 14:29:35

Running Rails 5 et Rspec 3.5 J'ai dû régler les en-têtes pour accomplir ceci.

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
répondu settheline 2017-02-12 21:49:56

pour les gens qui travaillent avec des tests de requêtes la façon la plus facile que j'ai trouvée est de surcharger #process méthode dans ActionDispatch::Integration::Session et définir le paramètre par défaut as à :json comme ceci:

module DefaultAsForProcess
  def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: :json)
    super
  end
end

ActionDispatch::Integration::Session.prepend(DefaultAsForProcess)
0
répondu mpospelov 2017-09-09 08:54:13

pourquoi les méthodes de RSpec, "get", "post", "put", "delete" ne fonctionnent-elles pas dans un contrôleur spec dans un gem (ou des Rails extérieurs)?

basé sur cette question, vous pouvez essayer de redéfinir le processus () dans ActionController::TestCase de https://github.com/rails/rails/blob/32395899d7c97f69b508b7d7f9b7711f28586679/actionpack/lib/action_controller/test_case.rb .

voici ma solution.

describe FooController do
    let(:defaults) { {format: :json} }

    context 'GET index' do
        let(:params) { defaults }
        before :each do
            get :index, params
        end

        # ...
    end

    context 'POST create' do
        let(:params) { defaults.merge({ name: 'bar' }) }
        before :each do
            post :create, params
        end

        # ...
    end
end
-3
répondu Kenneth Cheng 2017-05-23 10:31:25