Empty response body in controllers specs RSpec - ruby-on-rails

There is the following code of RSpec controllers spec:
require 'spec_helper'
describe Api::PostsController do
let!(:post) { create(:post) }
describe 'index' do
it 'should return a json array of posts' do
get :index, format: :json
puts "response=#{ response.body }"
result = JSON.parse(response.body)
expect(result[0][:title]).to eq(post.title)
end
end
end
Code of the controller:
class Api::PostsController < ApplicationController
def index
#posts = Post.all
end
end
But I got the following error:
Failure/Error: result = JSON.parse(response.body)
JSON::ParserError:
A JSON text must at least contain two octets!
The body of the response is empty. So, tell me please, how can I fix it? Thanks in advance.

Try adding
def index
#posts = Post.all
render :json => #posts
end

Related

wrong response status in rspec + devise + factory_girl

so i've been trying to make a basic response test - with 200 and 403. I'm not sure i need to add anything else ..
accounts_spec.rb
RSpec.describe Api::V1::AccountsController, :type => :controller do
describe "GET index no account" do
it "has a 403 status code" do
get :index
expect(response.status).to eq(403)
end
end
describe "GET index with account" do
login_user
it "has a 200 status code" do
get :index
expect(response.status).to eq(200)
end
end
end
Accounts Controller #index
def index
#show user details
raise if not current_user
render json: { :user => current_user.as_json(:except=>[:created_at, :updated_at, :authorization_token, :provider, :uid, :id])}
rescue
render nothing: true, status: 403
end
I keep getting
1)Api::V1::AccountsController GET index with account has a 200 status code
expected: 200
got: 403
Any thoughts on where i'm doing it wrong ?
UPDATE
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in :user, user
end
end
end
Much cleaner implementation
class SomeController < ApplicationController
before_action :authenticate
skip_before_action :verify_authenticity_token, if: :json_request?
def index
render json: { user: current_user...
end
protected
def json_request?
request.format.json?
end
def authenticate
head :unauthorized unless current_user
end
end
I also recommend in using ActiveModel Serializer https://github.com/rails-api/active_model_serializers. This will separate logic of render json and oy will have a separate class under serializer that defines the json output. So your render method will look like this:
render json: current_user, status: :ok
app/serializers/user.rb
class UserSerializer < ActiveModel::Serializer
attribute :id, :email #list your attributes for json output
end
If you want to test json response in your rspec what I find best is testing against json schema like this library https://github.com/sharethrough/json-schema-rspec.
Hope it helps

Empty response when rendering RABL template with RSPEC

I'm having a perplexing problem where my controller is working fine. However, when I'm testing it with RSPEC it's returning an empty string as the response body.
Here is the controller:
class Api::UsersController < Api::ApplicationController
def show
#user = User.find(params[:id])
render 'show', status: 200
# render json: #user
end
end
And the RABL template I'm rendering:
object #user
attributes :id, :name, :email, :phone_number, :invite_token
Finally here is my spec:
require "spec_helper"
describe Api::UsersController do
it "returns user attributes" do
user = FactoryGirl.create(:user, name: "Mark", email: "foo#bar.com")
get :show, id: user.id
expect(response.status).to eq(200)
output = JSON.parse(response.body)
end
end
When I use render 'show' to render the RABL template my test fails as the response.body is an empty string. However, if I CURL to that endpoint, the body returns just fine.
When I change the controller to: render json: #user the test passes.
Can anyone tell me what's going on here?
Thanks in advance!
try to add render_views at the top of the tests
describe Api::UsersController do
render_views
it "returns user attributes" do
user = FactoryGirl.create(:user, name: "Mark", email: "foo#bar.com")
get :show, id: user.id
output = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(output).to eq(expected_hash)
end
end
Possible reason: RSpec do not render views by default to speed up tests.

rspec not accepting custom http header

My spec is like so:
describe SomeController do
before(:each) do
#request.env["HTTP_ACCEPT"] = 'application/vnd.apple.mpegurl'
end
describe 'GET #index' do
it "returns response" do
get 'index', format: :m3u8
puts response.code # prints 406
response.should be_success # fails
end
end
end
The controller:
class SomeController < AuthenticatedController
def index
Mime::Type.register "application/vnd.apple.mpegurl", :m3u8
# do some stuff
respond_to do |format|
format.m3u8 { render :m3u8 => #some_variable.html_safe }
end
end
What am I missing to get it to respond with status 200? Right now, the status returned is 406. Thanks.
Drop the #.
before(:each) do
request.env["HTTP_ACCEPT"] = 'application/vnd.apple.mpegurl'
end

testing "create" method in ruby with rspec

I have written this controller code in Ruby on Rails
class PostsController < ApplicationController
before_filter :authenticate_user!
def index
#posts = Post.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#post = Post.create(:message => params[:message])
respond_to do |format|
if #post.save
format.html { redirect_to posts_path }
format.js
else
flash[:notice] = "Message failed to save."
format.html { redirect_to posts_path }
end
end
end
end
and corresponding to this I have written the following test case :-
require 'spec_helper'
describe PostsController do
describe "GET 'index'" do
it "returns http success" do
get 'index'
response.should be_success
end
end
describe "#create" do
it "creates a successful mesaage post" do
#post = Post.create(message: "Message")
#post.should be_an_instance_of Post
end
end
end
I am getting failures on both. Please take a look on the code and help me figure out.
I suspect you are not logged in since you are using Devise?
Maybe you need to include the devise testhelpers:
describe PostsController do
include Devise::TestHelpers
before(:each) do
#user = User.create(...)
sign_in #user
end
#assertions go here
end
As Tigraine states, it appears as though you probably are not logged in (with Devise) when the tests get executed. However, showing the failures would help in narrowing down the problem further.
On top of that, the second test isn't really an integration test and I would probably prefer something like the following to test the same condition. There are two types of test you could do:
# inside 'describe "#create"'
let(:valid_params) { {'post' => {'title' => 'Test Post'} }
it 'creates a new Post' do
expect {
post :create, valid_params
}.to change(Post, :count).by(1)
end
# and / or
it 'assigns a new Post' do
post :create, valid_params
assigns(:post).should be_a(Post)
assigns(:post).should be_persisted
end
Don't forget to add this line into your spec_helper.rb
require "devise/test_helpers"
include Devise::TestHelpers
Nevertheless, here is link for Devise wiki - How to test Controllers where you can find more info about this approach. I recommend writing the before method without (:each), what I remember it sometimes causes problems.
before do
#user = FactoryGirl.create(:user)
sign_in #user
end
Can always use:
puts response.inspect
To see how your response looks like.

Why is my Ruby on Rails RSpec test passing with both #plugin and #plugins?

I'm in Chapter 10 of the Foundation Rails 2 book. We're working with RSpec.
We're testing the 'index' action of the 'PluginsController'.
Here's the code for the controller:
class PluginsController < ApplicationController
# GET /plugins
# GET /plugins.xml
def index
#plugins = Plugin.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #plugins }
end
end
Here's the code for the tests for that controller:
require File.dirname(__FILE__) + '/../spec_helper'
describe PluginsController, " GET to /plugins" do
before do
#plugin = mock_model(Plugin)
Plugin.stub!(:find).and_return([#plugin])
end
it "should be successful" do
get :index
response.should be_success
end
it "should find a list of all plugins" do
Plugin.should_receive(:find).with(:all).and_return([#plugin])
get :index
end
it "should assign the list of plugins to a variable to be used in the view"
it "should render the index template"
end
When we were writing our test, I thought that this line
Plugin.should_receive(:find).with(:all).and_return([#plugin])
should have had
#plugins
and not
#plugin
because in the controller we have
def index
#plugins = Plugin.find(:all)
I wanted to see what would happen if I changed
Plugin.should_receive(:find).with(:all).and_return([#plugin])
to
Plugin.should_receive(:find).with(:all).and_return([#plugins])
and the test passed.
So...why is it #plugin and not #plugins? And...why does the test pass with both?
Cheers!
When you have an undefined variable, as #plugins is since you don't define it earlier in the test, it will show up as nil.
What Plugin.should_receive(:find).with(:all).and_return([#plugins]) actually do in this case is that it tells Plugin.find(:all) to return [nil], which according to your test is valid.

Resources