Rails - Testing ApplicationController with rspec - ruby-on-rails

I want to put the common controller actions, index, show, create etc. in the ApplicationController like this:
class ApplicationController < ActionController::Base
respond_to :json
def index
#implementation
end
def show
#implementation
end
def update
#implementation
end
end
The app will only return JSON.
I have written the following spec to test this with RSPEC's annonymous controller
describe ApplicationController do
controller do ; end
describe 'Get :index' do
it 'should respond to index' do
get :index
response.code.should eq "200"
end
end
end
The above spec gives the following error:
ActionView::MissingTemplate: Missing template anonymous/index,
application/index with {:locale=>[:en], :formats=>[:json],
:handlers=>[:erb, :builder]}. Searched in: *
"#"
Can anyone suggest a way to make this work with the anonymous controller?

try this may be it helpful
your controller like
def index
end
your rspec testing like
describe "GET index" do
it "should respond to index" do
get :index
response.code.should eq "200"
end
end
create index.html.erb in your application/ folder
then test it.

describe "GET index" do
it "returns correct JSON" do
# #groups.should have(2).items
get :index, :format => :json
response.should be_success
body = JSON.parse(response.body)
body.should include('group')
groups = body['group']
groups.should have(2).items
groups.all? {|group| group.key?('customers_count')}.should be_true
groups.any? {|group| group.key?('customer_ids')}.should be_false
end
end

Related

Expected response to be a <redirect>, but was <200>

Hi guys i have a controller code with the following :
class FeedbacksController < ApplicationController
def create
#feedback = Feedback.create(feedback_params)
if #feedback.errors.any?
flash[:error] = #feedback.errors
render 'new'
else
redirect_to :back
end
end
test spec
require "rails_helper"
RSpec.describe FeedbacksController do
describe "POST create" do
context 'when param[:name] is present' do
it 'should redirect to homepage' do
#feedback = Feedback.create(:name => "Hah")
#feedback.save
is_expected.to redirect_to new_feedback_path
debugger
end
end
end
end
However when i run localhost, the output is exactly what i want but as of the unit test, it's not passing but returning me
"Expected response to be a m was was <200> ."
May i know why is it so and how should i pass my test case ?
You are missing the actual post request to your controller.
Please read this: rspec documentation
So this:
#feedback = Feedback.create(:name => "Hah")
#feedback.save
Should not be there. The second line is superfluous anyway, create already saves the object.
You are looking for code like this:
it 'should redirect to homepage' do
post feedback_path, params: { name: 'hah' }
expect(response).to redirect_to(new_feedback_path)
end

Test controller method. Rspec

I want to test the controller method, but I can not find the example of testing method with order and search .
This is my controller:
class Admin::HotelsController < Admin::BaseController
helper_method :sort_column, :sort_direction
def index
#hotels = Hotel.search(params[:search], params[:search_column]).order(sort_column + ' ' + sort_direction)
end
def show
#hotel = Hotel.find(params[:id])
end
def update
#hotel = Hotel.find(params[:id])
if #hotel.update_attributes(hotel_params)
redirect_to admin_hotels_path
else
render(:edit)
end
end
private
def hotel_params
params.require(:hotel).permit(:title, :description, :user_id, :avatar, :price, :breakfast, :status, address_attributes: [:state, :country, :city, :street])
end
def sort_column
Hotel.column_names.include?(params[:sort]) ? params[:sort] : 'created_at'
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
end
end
This is test for this controller.
require 'rails_helper'
describe Admin::HotelsController do
login_admin
describe 'GET index' do
it 'render a list of hotels' do
hotel1, hotel2 = create(:hotel), create(:hotel)
get :index
expect(assigns(:hotels)).to match_array([hotel1, hotel2])
end
end
describe 'GET show' do
it 'should show hotel' do
#hotel = create(:hotel)
get :show, { id: #hotel.to_param, template: 'hotels/show' }
expect(response).to render_template :show
end
end
end
I don't know how testing index method. Please help or give me a link with information about this. Thanks!
If it may help you, I personally prefer to have minimals tests for the controllers for various reasons:
1) as I was beginning in rails testing I read many articles saying it's a good idea
2) it allows you to tests in isolation model methods:
describe 'GET index' do
it 'render a list of hotels' do
hotel1, hotel2 = create(:hotel), create(:hotel)
get :index
expect(assigns(:hotels)).to match_array([hotel1, hotel2])
end
end
here your test matches the result of your query on the model. You can split it like this:
describe 'GET index' do
it 'render a list of hotels' do
hotel1, hotel2 = create(:hotel), create(:hotel)
Hotel.should_receive(:search).with(YOUR PARAMS)
get :index
response.response_code.should == 200
end
end
and then test the result of Hotel.search in a model test.
3) it allows you to test the feature and not some random things that are not really relevant:
describe 'GET show' do
it 'should show hotel' do
#hotel = create(:hotel)
get :show, { id: #hotel.to_param, template: 'hotels/show' }
expect(response).to render_template :show
end
end
here "expect(response).to render_template :show" seems like testing that rails rendering system is properly working. I assume that's not what you want to test, you may prefer (that's what I would do):
describe 'GET show' do
it 'should show hotel' do
#hotel = create(:hotel)
Hotel.should_receive(:find).with(YOUR PARAMS)
get :show, { id: #hotel.to_param, template: 'hotels/show' }
response.response_code.should == 200
end
end
and then test what is supposed to appear on the web page with a feature test using something like capybara gem unless you're rendering some json: in this case match the json values in the controller.
By the way: "#hotel = create(:hotel)" the # is not necessary here as you're in the "it". Moreover you can create such entry like this:
context "" do
before(:each) do
#hotel = create(:hotel) # here the # is necessary for the variable to be
end # accessible in the it
it "" do
end
end
or even like this:
context "" do
let(:hotel) { create(:hotel) } # you can call it in the test by using hotel and it
it "" do # will be insert in you db only when it's in the "it"
end # if you want it to be created in the "it" without
end # calling hotel for nothing, use let!
I would suggest using
describe 'GET index' do
let(:hotel1) { create(:hotel) }
let(:hotel2) { create(:hotel) }
it 'render index template' do
get :index
expect(response).to render_template :index
end
it 'render asc ordered hotels' do
get :index
# if you are using json responses
json = JSON.parse(response.body)
expect(json['hotels'].first).to eq hotel1
expect(json['hotels'].last ).to eq hotel2
# or any similar approach to get test the hotels in response
end
it 'render desc ordered hotels' do
get :index, {direction: 'desc'}
# if you are using json responses
json = JSON.parse(response.body)
expect(json['hotels'].first).to eq hotel2
expect(json['hotels'].last ).to eq hotel1
# or any similar approach to get test the hotels in response
end
# you can complete these tests yourself
it 'render hotels sorted with different_column_than_created_at asc'
it 'render hotels sorted with different_column_than_created_at desc'
end

How to create a route for testing purposes?

I'm writing tests with rspec for my application controller in my rails app (written in Rails 4) and I'm running into a problem where it doesn't recognize the route for the HTTP request I'm sending. I know there's a way to do this using MyApp::Application.routes but I'm not able to get it working.
#application_controller_spec.rb
require 'spec_helper'
class TestController < ApplicationController
def index; end
end
describe TestController do
before(:each) do
#first_user = FactoryGirl.create(:user)
# this is to ensure that all before_filters are run
controller.stub(:first_time_user)
controller.stub(:current_user)
end
describe 'first_time_user' do
before(:each) do
controller.unstub(:first_time_user)
end
context 'is in db' do
before(:each) do
#user = FactoryGirl.create(:user)
controller.stub(:current_user).and_return(#user)
end
it 'should not redirect' do
get :index
response.should_not be_redirect
end
end
context 'is not in db' do
context 'session[:cas_user] does not exist' do
it 'should return nil' do
get :index
expect(assigns(:current_user)).to eq(nil)
end
end
it "should redirect_to new_user_path" do
controller.stub(:current_user, redirect: true).and_return(nil)
get :index
response.should be_redirect
end
end
end
The error I'm getting right now is
No route matches {:action=>"index", :controller=>"test"}
I would add the test#index route to config/routes.rb, but it doesn't recognize the Test Controller, so I want to do something like
MyApp::Application.routes.append do
controller :test do
get 'test/index' => :index
end
end
but I'm not sure where to add this or if this even works in rspec. Any help would be great!
If you are trying to test your ApplicationController, see this RSpec documentation about it. You will need to define methods like index inside the test, but it works well.

Rspec / Capybara: Testing if a controller method is called

Given I set up a HomeController with an index action
class HomeController < ApplicationController
def index
#users = User.all
end
end
and routed to it via the root path,
root :to => "home#index"
why does this request spec fail
it 'should called the home#index action' do
HomeController.should_receive(:index)
visit root_path
end
with the following message
Failure/Error: HomeController.should_receive(:index)
(<HomeController (class)>).index(any args)
expected: 1 time
received: 0 times
? Is it because the index method is called as a instance method instead of a class method?
I'm not sure exactly what you want to test, and I think there's some confusion as to what methods can be used where, so I'll try and give examples of Routing specs, Request Specs, Controller specs, and Feature specs, and hopefully one of them will be appropriate for you.
Routing
If you want to make sure that your root path gets routed to the home#index action, a routing spec may be appropriate:
spec/routing/routing_spec.rb
describe "Routing" do
it "routes / to home#index" do
expect(get("/")).to route_to("home#index")
end
end
Request
If you want to make sure that the index template gets rendered on a request to your root path, a request spec may be appropriate:
spec/requests/home_requests_spec.rb
describe "Home requests" do
it 'successfully renders the index template on GET /' do
get "/"
expect(response).to be_successful
expect(response).to render_template(:index)
end
end
Controller
If you want to make sure that the index template gets rendered on a request to the index action of your HomeController, a controller spec may be appropriate (and quite similar to a request spec in this case, but focused exclusively on the controller):
spec/controllers/home_controller_spec.rb
describe HomeController do
describe "GET index" do
it "successfully renders the index template" do
expect(controller).to receive(:index) # this line probably of dubious value
get :index
expect(response).to be_successful
expect(response).to render_template(:index)
end
end
end
Feature
If you want to make sure the page rendered by home#index has some specific content, a feature spec may be appropriate (and also the only place you can use Capybara methods like visit, depending on your Rails/RSpec version):
spec/features/home_features_spec.rb
feature "Index page" do
scenario "viewing the index page" do
visit root_path
expect(page).to have_text("Welcome to my awesome index page!")
end
end
class MyController < ApplicationController
def index
my_method
end
def my_method
end
end
describe MyController do
it 'calls my method' do
expect(controller).to receive(:my_method)
get :index
end
end

Trace Rspec's get request routing in controller action spec

I am trying to test a simple controller action in a moduled controller. However, my get :index request returns a 404, instead of a 200 response. Is there a way to trace the routing of this get request?
require "spec_helper"
describe Admin::WidgetsController do
describe "GET index" do
it "has a 200 status code" do
get :index
response.code.should eq("200")
end
end
end
The controller looks like as you would expect:
class Admin::WidgetsController < Admin::ApplicationController
respond_to :html, :xml, :json
def index
respond_with(#content = "content")
end
end
Sounds like something is wrong with your routing. On the console you can run this to see what routes are available to your app:
$> rake routes
I'm pretty sure the following, when it fails, will show you what it's being redirected to
describe Admin::WidgetsController do
describe "GET index" do
it "has a 200 status code" do
get :index
response.should redirect_to(:action => 'other_action')
end
end
end
You can check out these links for more info:
http://guides.rubyonrails.org/routing.html
http://old.rspec.info/rails/writing/controllers.html

Resources