Rspec test to request controller action but seems action wasn't executed - ruby-on-rails

I am new to Rails and Rspec and trying to write spec to test one non RESTful controller action.
Spec code:
require 'rails_helper'
RSpec.describe ReportsController, type: :controller do
describe "GET /full_members" do
context "when current account doesn't have contacts" do
let!(:current_account) { create(:account) }
it "hit full_members action" do
expect(get: '/reports/full_members').to be_routable
expect(:get => "/reports/full_members").to route_to(
controller: "reports",
action: "full_members")
get :full_members
end
end
end
end
Controller code:
class ReportsController < ApplicationController
def full_members
require "pry"
binding.pry
set_select_options_full_members
#members = #current_account.contacts
end
...
I was expecting to execute spec and stop at the breaking point pry. But the actual result is spec passed and pry didn't work.
Finished in 0.17359 seconds (files took 1.16 seconds to load)
1 example, 0 failures
From rails routes I can see the route exists(the spec first two assertions also prove that)
~ยป rails routes | ag full_members
>> full_members_reports GET /reports/full_members(.:format)
My routes.rb
resources :reports, only: [:index] do
collection do
get 'full_members'
end
end
Can not figure out why the pry didn't work in controller action. Can anyone help with that? Thanks

Related

Controll spec ActionController::UrlGenerationError

I've got routes setup so that they work as expected in my controllers; I can use both room_path and rooms_path as expected.
However when I try to use the same routes in a controller spec for some reason then I get an error:
ActionController::UrlGenerationError:
No route matches {:action=>"/1", :controller=>"rooms"}
My routes.rb file:
root "rooms#index"
resources :rooms, :path => '/', only: [:index, :create, :show] do
resources :connections, only: [:create,:destroy]
end
And if I rake routes:
room_connections POST /:room_id/connections(.:format) connections#create
room_connection DELETE /:room_id/connections/:id(.:format) connections#destroy
rooms GET / rooms#index
POST / rooms#create
room GET /:id(.:format) rooms#show
However my test fails:
describe "GET room_path(room)" do
it "renders show" do
#room = Room.create
get room_path(#room)
expect(response.status).to eq(200)
expect(response).to render_template(:show)
end
end
While my controllers can use the same route helpers without issue:
class RoomsController < ApplicationController
def index
end
def create
#room = Room.create
redirect_to room_path(#room)
end
def show
#room = Room.find(params[:id])
end
end
I'm not sure why in my tests it seems to go looking for a "/1" action rather than rooms#show like I would expect.
Update
So continuing to play this I've been able to get the test green by changing to the following:
describe "GET room_path(room)" do
it "renders show" do
#room = Room.create
get :show, params: { id: #room.id }
expect(response.status).to eq(200)
expect(response).to render_template(:show)
end
end
I would still love to understand why my helpers aren't working though. Is this to be expected? Manually writing the Parameters hash is kind of a PITA.
I don't know what version of Rails and RSpec you're on. This works for me on Rails 4.2 and Rspec 3.4.4:
describe "my neat test description", type: :routing do
it "can use path helper" do
puts whatever_path
end
end
The type: :routing pulls in the path and url helpers.
I believe the reason you don't have that by default is that rspec is replicating a lot of the environment for the different types of tests. For controller tests, it's pulling in the various path and url helpers because generally speaking they're used there often enough to be worth pulling in. In model tests, for example, they aren't used there often so they aren't pulled in by default.
These helpers live on the app object.

No route matches for inherited (create) action

I have 2 versions of my API(1&2) the controller of api version 2 inherits from the controller of api version 1. The problem is, specs for version 1 are running fine, but when i run specs in version 2, it tells me
ActionController::UrlGenerationError: No route matches {:action=>"create", :controller=>"api/mobile/v2/samples"}
#version 1
class Api::Mobile::V1::SamplesController < ApplicationController
def create
#dummy
end
end
#version 2
require "meta_data"
class Api::Mobile::V2::SamplesController < Api::Mobile::V1::SamplesController
include MetaData
end
#spec for version 1
require 'rails_helper'
RSpec.describe Api::Mobile::V1::SamplesController, type: :controller do
describe "POST #create" do
it "performs a post" do
post :create
end
end
end
#spec for version 2
require 'rails_helper'
RSpec.describe Api::Mobile::V2::SamplesController, type: :controller do
describe "POST #create" do
it "performs a post" do
post :create
end
end
end
RSpec is looking for SamplesController (plural). Make sure you are specifying your routes using singular resource if that's what you have. Otherwise, specify plural form of sample as sample in an initializer.
I would just go with the flow and user plural form. But, obviously with the public API that's a real headache.

Rails Test w/ Minitest Reporter - NoMethodError: undefined method + ActionController::UrlGenerationError: No route matches

I am learning Rails and very new to testing but so far I've managed to build something with minimal errors. However, the issue I am running into is that my tests are complaining for methods that cannot be found and no route matching.
To my understanding tests should be run frequently based Hartl's - Railstutorial 3.3. Many StackO threads and online articles seem to pertain to utilizing test suites I don't use like RSpec, etc...so the test configurations are confusing. My testing suite is set up similiar to Hartl's - Railstutorial 3.3 and below are the gems loaded for testing.
gem 'better_errors', '~> 2.1.1'
gem 'binding_of_caller'
gem 'minitest-reporters', '1.0.5'
gem 'mini_backtrace', '0.1.3'
gem 'guard-minitest', '2.3.1'
gem 'ruby-prof'
NoMethodError: undefined method
Error: (_I have two error similar errors to below_)
ServicesControllerTest#test_should_get_index:
NoMethodError: undefined method 'services' for nil:NilClass
app/controllers/services_controller.rb:6:in 'index'
test/controllers/services_controller_test.rb:9:in 'block in <class:ServicesControllerTest>"
Services Controller
def index
#services = current_tech.services
end
services_controller_test.rb
require 'test_helper'
class ServicesControllerTest < ActionController::TestCase
setup do
#service = services(:one)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:services)
end
end
I believe the reason I am receiving this error is because of Devise.
If I were to setup the following index action below, the test will pass.
def index
#services = Tech.first.services
end
How do I correct this so that this test passes?
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"tech"}
Error:
CarsControllerTest#test_should_get_show:
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"cars"}
test/controllers/cars_controller_test.rb:5:in `block in <class:CarsControllerTest>
Rake routes pertaining to cars
tech_cars POST - /techs/:tech_id/cars(.:format) - cars#create
car GET - /cars/:id(.:format) - cars#show
Routes
Rails.application.routes.draw do
devise_for :customers, controllers: { sessions: 'customers/sessions' }
devise_for :techs, controllers: { sessions: 'techs/sessions' }
resources :techs, :only => [:index, :show], shallow: true do
resources :cars, only: [:show, :create]
end
resources :services, :garages
root "home#index"
end
cars_controller.rb
class CarsController < ApplicationController
before_action :set_car
def show
#garage = Garage.find(params[:id])
#tech = #tech.service.car.id
end
def create
#garage = Garage.create(tech_first_name: #car.service.tech.first_name,
customer_id: current_customer.id,
customer_street_address: current_customer.street_address,
customer_city: current_customer.city,
customer_state: current_customer.state,
customer_zip_code: current_customer.zip_cod)
if #garage.save
redirect_to techs_path, notice: "Working"
else
redirect_to techs_path, notice: "Uh oh, flat tire"
end
end
private
def set_car
#car = Car.find(params[:id])
end
def car_params
params.permit(:service_name, :garage_photo)
end
end
cars_controller_test.rb
require 'test_helper'
class CarControllerTest < ActionController::TestCase
test "should get show" do
get :show
assert_response :success
end
end
cars.html.erb (only links on page)
<%= button_to 'View Garage', tech_cars_path(tech_id: #car.service.tech.id, id: #car) %>
<%= link_to 'Back to tech', tech_path(#car.service.tech.id) %>
As you may gather, I am building a Garage not a Car object within the Cars controller. Would this be a problem for tests? My application functions fine as is. On a side note, I am also having difficulty trying to associate car_params strong params for instance variables but that's another StackO post.
*test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end
class ActionController::TestCase
include Devise::TestHelpers
end
Is there something I am missing or haven't configured correctly?
Please know my application appears to be working fine, it's just I would like to suppress these tests errors.
Please advise on how to get these test errors to pass.
Thanks
First issue: Your feeling is correct. Devise comes with Devise::TestHelpers which you've mixed into ActionController::TestCase in your test helper file. One of the methods it provides is sign_in which lets you spoof a logged in user as part of your test. Assuming you've got a model called Tech and you're following standard Rails conventions, you'll need to add something like:
sign_in techs(:some_tech)
to either your setup block or directly into your test body before the call to get :index. That will ensure that current_tech returns something non-nil and remove the immediate NoMethodError.
Second issue: Your :show action expects to receive the ID of a known Car as part of the URL. Replace your current invocation of the controller with:
require 'test_helper'
class CarControllerTest < ActionController::TestCase
setup do
#car = cars(:some_car)
end
test "should get show" do
get :show, id: #car.id
assert_response :success
end
end

Specs for controller inside a module (versionist)

I'm creating an API in Rails and I use versionist to handle versions. I want to test API controllers, but I'm unable to create a valid request.
My controller:
class Api::V1::ItemsController < Api::V1::BaseController
def index
render json:'anything'
end
end
My spec:
describe Api::V1::ItemsController do
describe "#create" do
it "shows items" do
get :index, format: :json
end
end
end
routes.rb:
scope '/api' do
api_version(:module => "Api::V1", :path => {:value => "v1"}, :default => true) do
resources :items
end
end
The test doesn't check anything. Still, it raises an error:
Failure/Error: get :index, format: :json
ActionController::RoutingError:
No route matches {:format=>:json, :controller=>"api/v1/items", :action=>"index"}
I suppose that there is something wrong with the :controller key in the request, but I don't know how to fix it...
I was able to reproduce this locally. You need to move this to a request spec instead of a controller spec for this to work:
# spec/requests/api/v1/items_controller_spec.rb
describe Api::V1::ItemsController do
describe "#index" do
it "shows items" do
get '/api/v1/items.json'
# assert something
end
end
end
The versionist documentation says you need to do this when using the HTTP header or request parameter versioning strategies (https://github.com/bploetz/versionist#a-note-about-testing-when-using-the-http-header-or-request-parameter-strategies) but that's clearly not the case here. I'll file an issue to get this clarified in the documentation that you need to do this for all versioning strategies.

How to test refinery sessions controller

I've overridden Refinery's session controller and not even modified it yet, as I'm trying to write some specs for it.
The controller lives in app/controllers/refinery/sessions_controller:
module Refinery
class SessionsController < Devise::SessionsController
....
def create
super
rescue ::BCrypt::Errors::InvalidSalt, ::BCrypt::Errors::InvalidHash
flash[:error] = t('password_encryption', :scope => 'refinery.users.forgot')
redirect_to refinery.new_refinery_user_password_path
end
.....
I then am trying to write a spec against this in spec/controllers/refinery/sessions_controller_spec.rb:
require 'spec_helper'
describe Refinery::SessionsController do
it "should post ok" do
post :create
response.should be_success
end
end
However this is giving me an error
No route matches {:action=>"create", :controller=>"refinery/sessions"}
This confuses me as when I run rake routes, I get the following line:
refinery_user_session POST /refinery/users/login(.:format) refinery/sessions#create
Could anyone help?
Rails 3.2.8, refinery 2.0.8

Resources