Set Rspec default GET request format to JSON

35,626

Solution 1

before :each do
  request.env["HTTP_ACCEPT"] = 'application/json'
end

Solution 2

Put this in 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

And then simply override default_params:

describe FooController do
    let(:default_params) { {format: :json} }
    ...
end

Solution 3

The following works for me with rspec 3:

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

This sets HTTP_ACCEPT.

Solution 4

Here is a solution that

  1. works for request specs,
  2. works with Rails 5, and
  3. does not involve private API of Rails (like process).

Here's the RSpec configuration:

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

Verified with

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, The RSpec configuration can be placed:

  1. Directly in spec/spec_helper.rb. This is not suggested; the file will be loaded even when testing library methods in lib/.

  2. Directly in spec/rails_helper.rb.

  3. (my favorite) In spec/support/default_format.rb, and be loaded explicitly in spec/rails_helper.rb with

    require 'support/default_format'
    
  4. In spec/support, and be loaded by

    Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
    

    which loads all the files in spec/support.

This solution is inspired by knoopx's answer. His solution doesn't work for request specs, and alias_method_chain has been deprecated in favor of Module#prepend.

Solution 5

In RSpec 3, you need make JSON tests be request specs in order to have the views render. Here is what I use:

# 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

As for setting the format on all tests, I like the approach from this other answer: https://stackoverflow.com/a/14623960/1935918

Share:
35,626
Drazen
Author by

Drazen

Updated on December 18, 2021

Comments

  • Drazen
    Drazen over 2 years

    I am doing functional tests for my controllers with Rspec. I have set my default response format in my router to JSON, so every request without a suffix will return JSON.

    Now in rspec, i get an error (406) when i try

    get :index
    

    I need to do

    get :index, :format => :json
    

    Now because i am primarily supporting JSON with my API, it is very redundant having to specify the JSON format for every request.

    Can i somehow set it to default for all my GET requests? (or all requests)