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
Make Map Marker Direct Link Onclick for Gmaps4Rails
Ruby Net-Ssh Calling Bash Script with Interactive Prompts
Ruby: How to Dynamically Replace Parameters in Native Pg Gem
Sending Form Data to Remote Rails Application Using Httparty
Removing All Installed Gems and Starting Over
How to Get the Current Working Directory's Absolute Path from Irb
How to Upgrade My Ruby 1.9.2-P0 to the Latest Patch Level Using Rvm
Check If a Table Exists in Rails
How to Schedule a Function to Execute at a Future Time
Check Whether a Variable Is a String in Ruby
Create .Ruby-Version and .Ruby-Gemset with Rvm
How to Insert Erb-Tags with Vim
Cocoapods Not Working in MACos High Sierra
Randomly Showing Nomethoderror: Undefined Method 'Empty' for 0:Fixnum