I have a rails 4 api application in which I capture all missing routes like this:
namespace :api, defaults: {format: :json} do
namespace :v1 do
# matchers ...
end
# catch all undefined paths and redirect them to the errors controller
match "*path", to: "errors#routing_error", via: :all
end
With a simple click through test, this seems to work like a charm, however I'd like to write
an rspec test for this behaviour.
In my Rspec spec I try the following:
it "should capture non existing action" do
get '/api/non-existing-action', format: :json #Note that non-existing-action is not defined in the routes.rb
#expectations come here
end
The problem is that Rspec seem to catch the routing error before the router and raises a default error like this one
ActionController::UrlGenerationError:
No route matches {:action=>"/api/non-existing-action", :controller=>"api/api", :format=>:json}
So my question is: Is there a way to tell Rspec that it should let my router handle the non existing path, so that I can expect the error response from my errors controller?
Related
I'm trying to write a controller test and Rspec isn't finding routes that I know exist and work fine on a development server.
In my routes I have a catch-all route that should redeirect to a generic controller if someone goes to a route that isn't predefined.
routes.rb
namespace :tools do
match '*unmatchedpath' => "generic#show", :via => :get
end
generic_controller.rb
def show
# do stuff
end
generic_controller_spec.rb
require 'spec_helper'
describe Tools::GenericController do
describe 'GET show' do
it 'does stuff' do
get :show
end
end
Here is the error I get from rspec when I run the test above
1) Tools::GenericController GET show does stuff
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"tools/generic", :action=>"show"}
All routes work as expected on my development server so I'm not sure why Rspec isn't finding the route.
Try:
get '*unmatchedpath' => 'tools/generic#show'
After an upgrade from Rails 3.0 to 3.2.21 and RSpec from 2.14 to 3.1, my API routes (namespaced, see below) aren't working any more. Specifically, they appear in rake routes and work in the browser in development mode, but they cause "Route not found" exceptions in tests and I cannot get them recognized in the console (but this might be my ignorance... any help appreciated).
Other (non-namespaced) routes work fine.
Here are the route definitions:
namespace :api, path: '', defaults: { format: :json }, constraints: { format: :json, subdomain: 'api' } do
namespace :v1 do
resources :foos, only: [:index] do
post :bar, on: :collection
end
end
end
match '*path' => 'application#route_not_found' # default 404 route
Here is the rake routes output:
bar_api_v1_foo_index POST /v1/foo/bar(.:format) api/v1/foo#bar {:format=>:json, :subdomain=>"api"}
api_v1_foo DELETE /v1/foo/:id(.:format) api/v1/foo#destroy {:format=>:json, :subdomain=>"api"}
Here is my spec (in spec/integration/api_v1_foo_controller_spec.rb):
require "spec_helper"
describe Api::V1::FooController do
before do
host! "api.#{host}" # set subdomain, see http://elia.schito.me/2011/09/15/set-subdomain-in-rails-3-request-specs/
end
describe "POST" do
it "should bar" do
post "/v1/foo/bar"
end
end
end
Here is the spec output:
Failures:
1) Api::V1::FooController POST should bar
Failure/Error: post "/v1/foo/bar"
ActionController::RoutingError:
No route matches [POST] "/v1/foo/bar"
# /opt/local/lib/ruby2.1/gems/2.1.0/gems/actionpack-3.2.21/lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
# /opt/local/lib/ruby2.1/gems/2.1.0/gems/actionpack-3.2.21/lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
My feeble attempts at getting the routes to work in the console also fail, but for all Rails versions. It's probably the syntax (how do you use this?).
Rails.application.routes.recognize_path '/v1/foo/bar', method: :post, subdomain: 'api', format: :json
=> {:controller=>"application", :action=>"route_not_found", :path=>"v1/foo/bar"}
Why does the test above fail after the upgrade to Rails 3.2 and Rspec 3.1?
Update
This is probably an effect of a RoR bug: https://github.com/rails/rails/issues/8679
If I remove subdomain: 'api' inside the constraints block of the routes definition, all of Rails 3.2.21, 4.1.9 and 4-2-stable will accept the routes and work. If I force the spec to be a request spec and change the host! "api.#{host}" to host! "api.example.com", the routing also works.
Is this intentional? Is there an alternate way of restricting a route to a specific subdomain?
I have this line of code in my routes
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
match '/auth/:provider/callback', to: 'sign_in#authenticate'
end
end
And my test as
require 'spec_helper'
describe "Routing" do
it "should route to sign_in#authenticate" do
expect(post: 'api/v1/auth/:provider/callback').to route_to({ controller: 'api/v1/sign_in', action: 'authenticate', format: 'json' })
end
end
However, no matter what I do I keep getting the error
No route matches "/api/v1/auth/:provider/callback"
What am I missing here in order to make this test pass?
I believe the error you're getting is because match defaults to a GET request, but you are testing a POST request in your spec. You should be able to fix the issue by changing the route to:
match '/auth/:provider/callback', to: 'sign_in#authenticate', via: :post
My personal preference is to use the post method instead of match, it just reads better to me:
post '/auth/:provider/callback' => 'sign_in#authenticate'
I'm trying to test my namespaced controller and not having much luck. I have the following route setup:
namespace :api do
get 'organization/:id/questions/:number', controller: 'questions', action: 'index', as: 'organization_questions'
end
which produces the following route:
api_organization_questions GET /api/organization/:id/questions/:number(.:format) {:controller=>"api/questions", :action=>"index"}
that route works, and I'm able to successfully make a request to it with the following url: http://localhost:3000/api/organization/1/questions/1234567890
However when I try to make a get request to it in my unit test I get the following error:
No route matches {:controller=>"api/questions", :action=>"/api/organization/1/questions/1234567890"}
my get request looks like this:
get api_organization_questions_path(#organization.id, '1234567890')
Not sure what I'm doing wrong!?
What are you using for testing ? RSpec? The first parameter for the get method is the action. The code below should make the request you want:
describe Api::QuestionsController do
it "should do something" do
get :index, :id => #organization.id, :number => '1234567890'
end
end
Anyone know how to get RSpec to call a singular route when testing controller?
It can't find the route b/c it doesn't know to look for a singular controller so I need a way to specify it.
routes.rb
resource :settings_group, :path => "/settings/scheduling/"
settings_groups_controller_spec.rb
describe SettingsGroupsController do
describe "GET show" do
let(:describe_action) { get :show }
it "sets #settings_group" do
describe_action
assigns(:settings_group).should be_kind_of(SettingsGroup)
end
end
end
...
ActionController::RoutingError:
No route matches {:controller=>"settings_groups"}
Just out of curiosity, but why does settings_group_controller.rb have
describe SettingsGroupsController (with an s)
Shouldn't they match?