Rails Spec Controller Test failing with custom route - ruby-on-rails

Rails 5.1
RSpec 3.6
I have a Controller:
class SessionController < ApplicationController
def new
end
end
A custom route:
get 'login' => 'sessions#new'
RSpec Test:
require 'rails_helper'
RSpec.describe SessionController, type: :controller do
describe "GET #new" do
before do
routes.draw { get "login" => "sessions#new" }
end
it "returns http success" do
get :login
expect(response).to have_http_status(:success)
end
end
end
and get error:
ActionController::UrlGenerationError: No route matches {:action=>"login", :controller=>"session"}
So "get" within a controller test seems always map to the action not the route. What should i do to get this test run? thanks in advance.

ActionController::UrlGenerationError: No route matches
{:action=>"login", :controller=>"session"}
Your controller name is SessionController, so your route should be
get 'login' => 'session#new' not get 'login' => 'sessions#new'
require 'rails_helper'
RSpec.describe SessionController, type: :controller do
describe "GET #new" do
before do
routes.draw { get "login" => "session#new" }
end
it "returns http success" do
get :login
expect(response).to have_http_status(:success)
end
end
end
Change it in your routes.rb as well.

When you are writing tests and you use the methods get, post, delete, etc., those methods assume that any parameter you pass them is the name of an action within the controller being tested. So, this works:
get :new
because it generates url_for(:controller => :sessions, :action => :new).
This doesn't work:
get '/login'
because it generates url_for(:controller => :sessions, :action => '/login').

Related

How to test session constrained routes with rspec routing specs?

I have such code in my routes.rb:
Rails.application.routes.draw do
authorized = ->(request) { request.session[:user_id].present? }
not_authorized = ->(request) { request.session[:user_id].blank? }
constraints authorized do
resources :users
end
constraints not_authorized do
get 'login' => 'auth#login_page'
post 'login' => 'auth#create_session'
get '*unmatched_route', to: 'auth#login_page'
root 'auth#login_page'
end
end
And I have such users_routing_spec.rb file:
require "rails_helper"
RSpec.describe UsersController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(:get => "/users").to route_to("users#index")
end
end
end
This test fails as it routes to 'auth#login_page' because there is no user_id
in session.
How can I call auth#create_session in advance to the expectation?
There is no request or #request object and I also can't make a manual request to 'auth#create_session'

Rspec route matching - same expected vs actual, yet error

1) ExampleController routes for Example routes
Failure/Error: expect( post: '/api/application').to route_to( format: 'json', action: 'create_application', controller: 'example')
The recognized options <{"format"=>"json", "action"=>"create_application", "controller"=>"example"}> did not
match <{"format"=>"json", "action"=>"create_application",
"controller"=>"example"}>,
difference:.
<{"format"=>"json", "action"=>"create_application",
"controller"=>"example"}>
expected but was
<{"format"=>"json", "action"=>"create_application",
"controller"=>"example"}>.
Am I missing something here? I feel as if expected and actual are the same.
#charles
routes.rb:
scope '/api', :defaults => { format: 'json' } do
resource :application, only:[] do
post :create, to: 'example#create_application'
end
end
rake routes:
application POST /api/application(.:format) example#create_application
{:format=>"json"}
Working now with:
describe "routes for Example" do
it "routes" do
expect( post: '/api/application').to route_to( "example#create_application", :format=>"json" )
end
end
I was Having same issue.
You just need to add hash in route_to function like.
it 'routes to /v1/auth to user_token#create' do
expect(:post => '/v1/users/auth.json').to route_to({"format"=>"json", "controller"=>"v1/sessions", "action"=>"create"})
end
Like above.
I had the same issue.
My controller was: api/v1/users
My route was defined this was:
Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :users
end
end
end
And I was defining my spec route this way:
RSpec.describe Api::V1::UsersController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(get: "api/v1/users").to route_to(controller: :api/v1/users, action: :index)
end
end
end
But each time I ran into the error:
The recognized options <{"format"=>"json", "action"=>"index", "controller"=>"api/v1/users"}> did not match <{"action"=>"index", "controller"=>"api/v1/users"}>
Here's how I fixed it:
I simply modified the spec route from this:
RSpec.describe Api::V1::UsersController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(get: "api/v1/users").to route_to(controller: :api/v1/users, action: :index)
end
end
end
to this:
RSpec.describe Api::V1::UsersController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(get: "api/v1/users").to route_to(format: :json, controller: "api/v1/users", action: "index")
end
end
end
That's all.
I hope this helps

Rspec "No route matches" error

I am attempting to test my sessions_controller in Rails 3 app with rspec, but keep coming across this error when I run rspec on my sessions_controller_spec.rb:
ActionController::RoutingError:
No route matches {:controller=>"sessions", :action=>"create"}
Here are all the relevant files:
routes.rb
match 'event' => 'event#create', via: [:post]
match 'event/agenda' => 'event#agenda', via: [:get]
match 'testLogin' => 'application#test_login', via: [:get]
post 'session' => 'session#create'
sessions_controller.rb
class SessionsController < ApplicationController
def create
#MY CODE HERE
end
end
sessions_controller_spec.rb
require 'spec_helper'
describe SessionsController, :type => :controller do
describe "POST #create" do
context "invalid params" do
it "returns a response with status failed if all required parameters are not passed in" do
post "create"
response.body.status.should eq("failed")
end
end
end
end
If there's any other info I can provide to help let me know. Thanks a lot!
post 'session' => 'session#create'
Your route definition is looking for a SessionController, but you have defined a SessionsController. Fix your route.
post 'session' => 'sessions#create'

Rails 3 Tutorial Section 7.3.1 Routing Error

I get the following error when running rspec spec/controllers/users_controller_spec.rb in section 7.3.1 of Michael Hartl's Rails Tutorial:
Failure/Error: get :show, :id => #user
ActionController::RoutingError:
No route matches {:id=>#<User id: 1, #rest is data from the factories.rb file....
Here's my code for the users_controller_spec.rb file:
require 'spec_helper'
require 'factories'
describe UsersController do
render_views
describe "GET 'show'" do
before(:each) do
#user = Factory(:user)
end
it "should be successful" do
get :show, :id => #user
response.should be_success
end
it "should find the right user" do
get :show, :id => #user
assigns(:user).should == #user
end
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the right title" do
get 'new'
response.should have_selector("title", :content => "Sign up")
end
end
end
Here is my factories.rb code:
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
I inserted these lines in Spec_Helper in regards to 'factory_girl':
require 'factory_girl'
Factory.find_definitions
Any idea what's causing the routing error?
Here is my routes.rb code:
SampleApp::Application.routes.draw do
get "users/new"
match '/signup', :to => 'users#new'
match '/contact', :to => 'pages#contact'
match '/about', :to => 'pages#about'
match '/help', :to => 'pages#help'
root :to => 'pages#home'
The author's note regarding using - get :show, :id => #user instead of using - get :show, :id => #user.id:
" Second, note that the value of the hash key :id, instead of being the user’s id attribute #user.id, is the user object itself:
get :show, :id => #user
We could use the code:
get :show, :id => #user.id
to accomplish the same thing, but in this context Rails automatically converts the user object to the corresponding id. It does this by calling the to_param method on the #user variable.
You are missing a route to the show action for users. You can add something like this to the routes.rb file.
match "/users/:id" => "users#show"
If you want the normal CRUD actions, you can get rid of your users/new route and instead of the match line above, just declare them all with a single line:
resources :users
I believe your code is telling Rails that the id is the user, which of course doesn't make sense. That's creating a path like /users/#user, for which no route exists. As you probably know, you want a path like /users/1.
So I think you code should look like
get :show, :id => #user.id
or possibly
get :show, #user

Testing an RSpec controller action that can't be accessed directly

I've got a controller that can't be accessed directly, in the traditional RESTful way, but rather only through a particular url.
Normally I'm used to using get and post in my controller specs to call controller actions. Is there a way that I can exercise my controller by visiting a particular url?
EDIT:
Here is my route:
Larzworld::Application.routes.draw do
match '/auth/:provider/callback' => 'authentications#create'
devise_for :users, :controllers => {:registrations => "registrations"}
root :to => 'pages#home'
end
Here is my spec:
require 'spec_helper'
describe AuthenticationsController do
before(:each) do
request.env["omniauth.auth"] = {"provider" => "twitter", "uid" => "12345678"}
end
describe 'POST create' do
it "should find the Authentication using the uid and provider from omniauth" do
Authentication.should_receive(:find_by_provider_and_uid)
post 'auth/twitter/callback'
end
end
end
and here is the error I receive:
Failures:
1) AuthenticationsController POST create should find the Authentication using the uid and provider from omniauth
Failure/Error: post 'auth/twitter/callback'
No route matches {:action=>"auth/twitter/callback", :controller=>"authentications"}
# ./spec/controllers/authentications_controller_spec.rb:13
Finished in 0.04878 seconds
1 example, 1 failure
Controller tests use the four HTTP verbs (GET, POST, PUT, DELETE), regardless of whether your controller is RESTful. So if you have a non-RESTful route (Rails3):
match 'example' => 'story#example'
the these two tests:
require 'spec_helper'
describe StoryController do
describe "GET 'example'" do
it "should be successful" do
get :example
response.should be_success
end
end
describe "POST 'example'" do
it "should be successful" do
post :example
response.should be_success
end
end
end
will both pass, since the route accepts any verb.
EDIT
I think you're mixing up controller tests and route tests. In the controller test you want to check that the logic for the action works correctly. In the route test you check that the URL goes to the right controller/action, and that the params hash is generated correctly.
So to test your controller action, simply do:
post :create, :provider => "twitter"`
To test the route, use params_from (for Rspec 1) or route_to (for Rspec 2):
describe "routing" do
it "routes /auth/:provider/callback" do
{ :post => "/auth/twitter/callback" }.should route_to(
:controller => "authentications",
:action => "create",
:provider => "twitter")
end
end

Resources