rspec-rails: Can't set the Content-Type in specs

I had previously had this in my controller specs:

post :operations, '1': @params, border: [0, 0, '#ffffff'], shave!: [0, 0], format: :json

But that fails to send the content as JSON anymore and I attributed that to the changed behaviour in rails for keyword arguments. So I changed that to this:

post :operations, params: { '1' => @params, 'border' => [0, 0, '#ffffff'], 'shave!' => [0, 0] }, headers: { 'Content-Type' => 'application/json' }

But when I inspect for headers, I still get this:

(byebug) headers
{"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff"}

Is this an issue with rspec?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 19 (9 by maintainers)

Most upvoted comments

I can confirm this issue, and it looks like a problem with RSpec and the way Rails changed controller tests.

Here’s my controller action:

  def create
    @widget = Widget.new(widget_params)

    @boolean_attr = params[:boolean_attr]

    respond_to do |format|
      ...
    end
  end

This TestUnit test passes:

  test "should have access to boolean attributes in JSON request" do
    post widgets_url, params: { widget: {  }, boolean_attr: true }, as: :json
    assert_same(assigns(:boolean_attr), true)
  end

This RSpec spec fails:

  it 'has access to boolean attributes in JSON request' do
    post :create, params: { widget: {  }, boolean_attr: true }, as: :json
    expect(assigns(:boolean_attr)).to be true
  end

(I’m on rails 5.0.0.1, rspec-rails 3.5.1, and rails-controller-testing 1.0.1)

Here is the problem:

Rails controller specs now inherit from ActionDispatch::IntegrationTest instead of ActionController::TestCase. But RSpec controller specs still use ActionController::TestCase which is deprecated.

When I step through in TestUnit, I get here. It’s creating an encoder for the format given by the as attribute, in my case, :json.

But in RSpec, we end up here instead, and it appears that nobody has set the CONTENT_TYPE header at this point.

Here is a workaround that makes my spec pass:

  it 'has access to boolean attributes in JSON request' do
    request.content_type = 'application/json'
    post :create, params: { widget: {  }, boolean_attr: true }
    expect(assigns(:boolean_attr)).to be true
  end

Is RSpec going to follow along with Rails and move to integration tests instead of controller tests?