Andy Harvey
Andy Harvey

Reputation: 12663

How to verify json response in controller tests?

I have a rails controller that returns only json

def index
  if params[:filtered] = 'someValue'
    @json = Model.where(some_conditions).to_json 
  else
    @json = Model.where(some_other_conditions).to_json 
  end
  render json: @json
end

What is the correct way to test that the action is returning the expected @json objects?

I've tried the following

describe "GET #index" do  
  before :each do
    get :index, filtered: 'someValue'
  end
  it { expect( response.body ).to eq 'my expected response' }
end

But I'm getting

Failure/Error: it { expect( response.body ).to eq 'my expected response' }
expected: 'my expected response'
got: "[]"

I'm having trouble determining whether there is a problem in the underlying controller, or whether I've simply written a bad test.

Is response.body the correct way to get the json payload?

Help appreciated!

Upvotes: 2

Views: 4373

Answers (1)

max
max

Reputation: 102423

Both your controller and spec are somewhat off.

You don't need to call to_json on the object that you want to render. If you use the :json option, render will automatically call to_json for you.
http://guides.rubyonrails.org/layouts_and_rendering.html

The reason your spec is giving you "[]" is that Model.where(some_conditions) is returning an empty collection. An empty collection renders as an empty array in JSON.

Either the scope does not work as intended or your test setup is flawed. Remember that let variables are lazy loading and you either need to use let! or reference the variable for records to be inserted into the test db.

# polyfill for Rails 4. Remove if you are using Rails 5.
let(:parsed_response) { response.body.to_json }

describe "GET #index" do  
  # or use fixtures / factories
  let!(:model) { Model.create!(foo: 'bar') }
  before :each do
    get :index, filtered: 'someValue'
  end
  expect(parsed_response.first["id"].to_i).to eq model.id
end

Upvotes: 4

Related Questions