Rspec Controller Testing - Blank Response.Body

RSpec controller testing - blank response.body

By default, rspec-rails hacks into Rails to prevent it from actually rendering view templates. You should only test the behavior of your actions & filters your controller tests, not the outcome of template rendering — that's what view specs are for.

However, if you wish to make your controller specs render templates as the app normally would, use the render_views directive:

describe YourController do
render_views
...
end

RSpec API controllers testing

Given the shape of your response and the characteristics you are interested in testing, you can write your tests as follows:

describe 'advertising_sources' do
let(:parsed_response_body) { JSON.parse(response.body) }
let(:advertising_sources) { parsed_response_body['advertising_sources'] }

it 'returns list of advertising sources' do
expect(advertising_sources.size).to eq(2)
end

%w(id title).each do |attr|
it "returns json with #{attr} included" do
advertising_sources.each { |source| expect(source.keys).to include(attr) }
end
end
end

I would personally simplify this even further to:

describe 'advertising_sources' do
let(:parsed_response_body) { JSON.parse(response.body) }
let(:advertising_sources) { parsed_response_body['advertising_sources'] }

it 'returns list of advertising sources' do
expect(advertising_sources.size).to eq(2)
end

it 'includes an id and title for each source' do
advertising_sources.each { |source| expect(source.keys).to match_array(%w(id title)) }
end
end

Is there a way to test whether a template has properties in an RSpec controller test?

According to Rspec docs for controller tests:

by default, views are not rendered. See views are stubbed by default and render_views for details.

So first things first, you'll want to instruct Rspec to render your controller views by adding a render_views directive in your test suite as mentioned here:

require "rails_helper"

RSpec.describe WidgetsController, :type => :controller do
render_views # <-- This

describe "GET index" do
it "has a widgets related heading" do
get :index
expect(response.body).to match /<h1>.*widgets/im
end
end
end

Finally, you'll be able to match the JSON array with the rendered HTML using somthing like this(code is untested, but it should hopefully drive the point):


RSpec.describe MyController, type: :controller, do
describe "GET my_thing/index" do
it "renders the index template" do
# Can also be added below the `describe` call if view rendering is needed elsewhere.
render_views
select_values = [
{ "name": "foo", "id": "10000" },
{ "name": "bar", "id": "10001" },
{ "name": "baz", "id": "10002" },
]
stub_request(:get, "https://outsideapi.net/endpoint").
to_return(status: 200,
body: {
"values" => select_values,
}.to_json,
headers: {})

get :index, params: { request_identifier: generate_request_identifier() }
expect(response).to have_http_status(:success)
expect(response).to render_template(:index)
# Extract the select value names as an array of strings.
select_value_names = select_values.map {|v| v['name']}
expect(response.body).to include(select_value_names)
end
end

On a related note, if you're running tests against page contents, you might want to consider using acceptance testing frameworks such as Capybara, which integrates well with Rspec.



Related Topics



Leave a reply



Submit