How to create a route for testing purposes? - ruby-on-rails

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.

Related

Getting a delegation error in the API controller test module in Rspec

I am writing a controller spec to verify this private method and I get the error Module::DelegationError: ActionController::RackDelegation but I am lost as how to fix this. The best example I have found has been http://owowthathurts.blogspot.com/2013/08/rspec-response-delegation-error-fix.html.
How can I get the unverified spec to pass? I want to make sure the 401 is returned.
Method
def validate_api_request
return four_oh_one unless api_request_verified?(request)
end
Current Spec
describe Api::ApiController, type: :controller do
describe '#validate_api_request' do
it 'verified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(true)
expect(subject.send(:validate_api_request)).to be_nil
end
it 'unverified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(false)
allow(controller).to receive(:redirect_to)
binding.pry
end
end
end
I'm using Rails 4.
If anyone is working on a similar issue writing controller specs, here is how I solved this based on these 2 guides: http://codegur.com/22603728/test-user-authentication-with-rspec and https://gayleforce.wordpress.com/2012/12/01/testing-rails-before_filter-method/.
describe Api::ApiController, type: :controller do
describe '#validate_api_request' do
controller(Api::ApiController) do
before_filter :validate_api_request
def fake
render text: 'TESTME'
end
end
before do
routes.draw { get 'fake', to: 'api/api#fake' }
end
it 'verified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(true)
expect(subject.send(:validate_api_request)).to be_nil
end
it 'unverified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(false)
get 'fake'
expect(response.status).to be(401)
end
end
end

How to test subdomain constraint with RSpec & Rails 4

I'm trying to write a controller test which tests a subdomain constraint. However, I'm unable to get RSpec to set the subdomain and return an error if the subdomain isn't accurate.
I'm using Rails 4.2.6 and RSpec ~3.4
routes.rb
namespace :frontend_api do
constraints subdomain: 'frontend-api' do
resources :events, only: [:index]
end
end
events_controller.rb
module FrontendAPI
class EventsController < FrontendAPI::BaseController
def index
render json: []
end
end
end
spec
RSpec.describe FrontendAPI::EventsController do
describe 'GET #index' do
context 'wrong subdomain' do
before do
#request.host = 'foo.example.com'
end
it 'responds with 404' do
get :index
expect(response).to have_http_status(:not_found)
end
end
end
end
Is there some other way of doing this?
You can accomplish this by using the full URL in your tests instead of setting the host in a before block.
Try:
RSpec.describe FrontendAPI::EventsController do
describe 'GET #index' do
let(:url) { 'http://subdomain.example.com' }
let(:bad_url) { 'http://foo.example.com' }
context 'wrong subdomain' do
it 'responds with 404' do
get "#{bad_url}/route"
expect(response).to have_http_status(:not_found)
end
end
end
end
There is a similar question and answer here testing routes with subdomain constraints using rspec

rspec controller test expecting route

I am trying to test that on the creation of a post, the user is redirected to deployments path. I have added in
config.include Rails.application.routes.url_helpers
to extend rails routes to rspec. But my test still fails with the following error
1) Failure/Error: expect(response).to redirect_to(path)
Expected response to be a redirect to <http://test.host/deployments/new> but was a redirect to <http://test.host/deployments/new.1473>.
Expected "http://test.host/deployments/new" to be === "http://test.host/deployments/new.1473".
# -e:1:in `<main>'
Here is the test:
describe "post create" do
before do
allow(model).to receive(:new).and_return(instance)
end
context "where all is not well" do
before do
allow(instance).to receive(:save).and_return(false)
post :create, params_new_instance
end
sets_flash(:error)
it "should render the new form" do
expect(response).to render_template("projects/new")
end
end
context "where all is well" do
before do
allow(instance).to receive(:save).and_return(true)
post :create, params_new_instance
end
sets_flash(:notice)
it "redirects to new_deployments_path" do
expect(controller.controller_path).to eq(new_deployment_path)
end
end
end
project controller
def create
#project=Project.new(params_project)
if #project.save
record_saved
return redirect_to(new_deployment_path(#project))
else
check_for_errors
return render('/projects/new')
end
end
why is this failing? am i approaching this in the right way?
thanks in advance
Are you sure that new_deployments_path instead of new_deployment_path
This is my first suggestion. Them can be more but not enough information: routes.rb and deployments controller for example

How can I determine the subject of an rspec controller test?

So I don't have a great reason for needing to know this other than curiosity - the BEST reason - but I'm not sure what's going on here.
Background:
I'm working through the RSpec book and updating the examples.
On Chapter 24 - Rails Controllers there's a test for a messages controller.
## spec/controllers/messages_controller_spec.rb ##
require 'spec_helper'
describe MessagesController do
describe "POST create" do
let(:message) { mock_model(Message).as_null_object }
before do
Message.stub(:new).and_return(message)
end
# Then a bunch of Tests...
context "when the message fails to save" do
before do
message.stub(:save).and_return(false)
post :create
end
it "assigns #message" do
assigns[:message].should eq(message)
end
it "renders the new template" do
response.should render_template("new")
end
end
end
end
This goes along with the messages controller:
## app/controllers/messages_controller.rb ##
class MessagesController < ApplicationController
def create
#message = Message.new(params[:message])
if #message.save
flash[:notice] = "The message was saved successfully"
redirect_to action: "index"
else
render "new"
end
end
end
When I run the tests:
The test passes with response.
it "renders the new template" do
response.should render_template("new")
end
The test also passes with subject.
it "renders the new template" do
subject.should render_template("new")
end
The test Also passes with page
it "renders the new template" do
page.should render_template("new")
end
The test ALSO passes with NOTHING
it "renders the new template" do
should render_template("new")
end
In case it helps anyone make heads or tails of this, the config/routes.rb just has resources :messages
Why do all those tests pass? What am I actually testing? Are 'page', 'subject', and ' ' just synonyms for response?
Does it matter as long as my tests pass?
By default, the subject would be referencing the class, which is the MessagesController.
Not defining a subject in the last test example, will implicitly set the subject to be MessagesController.
From a binding.pry, it appears that subject is an instance of the controller class:
[2] pry(#<RSpec::ExampleGroups::MyController::DescribeString::ContextString>)> subject.is_a? Class
=> false
[3] pry(#<RSpec::ExampleGroups::MyController::DescribeString::ContextString>)> subject.is_a? Users::SessionsController
=> true

rspec stub current_company

I have a Rails 3 project in which I want to store the current company selected in a session variable.
I'm working with the staff controller spec and would like to stub out current_company for now as I'm isolating my spec example for the staff new controller action.
it "should call current_company" do
company = mock_model(Company, :id => "1")
controller.should_receive(:current_company).and_return(company)
get :new
end
Here is my new action for the staff controller
def new
#staff = Staff.new
#staff.company_id = current_company.id
end
I keep getting error
Failure/Error: get :new
NameError:
undefined local variable or method `current_company' for #<StaffsController:0x000000028d6ad8>
I've also tried just stubbing it out instead of using should_receive
controller.stub!(:current_company).and_return(company)
I get the same error.
Your code looks fine to me, it should work. There must be some other problem we are not seeing. I notice the controller name is "StaffsController" -- is that correct? Double-check the names of the controller and the corresponding spec -- they should be the same.
I think it was bombing out on the 'should be successful' example/test, so I've put my stubbing in a before block.
require 'spec_helper'
describe StaffsController do
describe "GET 'new'" do
let(:staff) { mock_model(Staff, :company_id= => nil)}
let(:company) { mock_model(Company, :id => 1)}
before do
Staff.stub!(:new).and_return(staff)
controller.stub!(:current_company).and_return(company)
end
it "should be successful" do
get :new
response.should be_success
end
it "should call current_company" do
controller.should_receive(:current_company).and_return(company)
get :new
end
end
end
This works for:
class StaffsController < ApplicationController
def new
#staff = Staff.new
current_company.id
end
end

Resources