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'
In config/routes.rb:
match 'app_config/:version' => "application#appconfig"
test/functional/application_controller_test.rb:
require 'test_helper'
class ApplicationControllerTest < ActionController::TestCase
test "app config" do
get "/app_config/v2"
assert_response :success
end
end
rake test:
1) Error:
test_app_config(ApplicationControllerTest):
ActionController::RoutingError: No route matches {:controller=>"application", :action=>"/app_config/v2"}
but $ curl localhost:3000/app_config/v2 works, and returns the response I expect, and rake routes shows the route as expected. Any idea what's going on, or how to investigate further? This is basically the only code in the project.
The get method does not take a route. It takes an action name and a parameter's hash.
If you want to test the action, your tests should look like this:
test "for success" do
get :appconfig, :version => "v2"
assert_response :success
end
If you want to test routing there is a tutorial here in the documentation.
test "should route to appconfig" do
assert_routing '/app_config/v2', { :controller => "application", :action => "appconfig", :version => "v2" }
end
I am doing homework but I have problem with non-RestFul routes.
My spec is:
require 'spec_helper'
describe MoviesController do
describe 'searching TMDb' do
before :each do
#fake_results = [mock('Movie'), mock('Movie')]
end
it 'should call the model method that performs TMDb search' do
Movie.should_receive(:find_in_tmdb).with('Star Wars').
and_return(#fake_results)
get :search_similar_movies, { :search_terms => 'Star Wars' }
end
end
end
In config/routes.rb I have:
resources :movies
'movies/search_similar_movies/:search_terms'
But when I run autotest it gives me error that begins with:
/usr/local/lib/ruby/gems/1.9.1/gems/actionpack-3.1.0/lib/action_dispatch/routing/mapper.rb:181:in `default_controller_and_action': missing :action (ArgumentError)
It's obvious that something is wrong is config/routes.rb. How to solve this?
Your route should be something like
resources :movies do
get 'search_similar_movies', :on => :collection
end
or
match 'movies/search_similar_movies/:search_terms' => 'movies#search_similar_movies', :via => :get
I am trying to write some routing specs for a mountable rails 3.1 engine. I have working model and controller specs, but I cannot figure out how to specify routes.
For a sample engine, 'testy', every approach I try ends with the same error:
ActionController::RoutingError:
No route matches "/testy"
I've tried both Rspec and Test::Unit syntax (spec/routing/index_routing_spec.rb):
describe "test controller routing" do
it "Routs the root to the test controller's index action" do
{ :get => '/testy/' }.should route_to(:controller => 'test', :action => 'index')
end
it "tries the same thing using Test::Unit syntax" do
assert_routing({:method => :get, :path => '/testy/', :use_route => :testy}, {:controller => 'test', :action => 'index'})
end
end
I've laid out the routes correctly (config/routes.rb):
Testy::Engine.routes.draw do
root :to => 'test#index'
end
And mounted them in the dummy app (spec/dummy/config/routes.rb):
Rails.application.routes.draw do
mount Testy::Engine => "/testy"
end
And running rails server and requesting http://localhost:3000/testy/ works just fine.
Am I missing anything obvious, or is this just not properly baked into the framework yet?
Update: As #andrerobot points out, the rspec folks have fixed this issue in version 2.14, so I've changed my accepted answer accordingly.
Since RSpec 2.14 you can use the following:
describe "test controller routing" do
routes { Testy::Engine.routes }
# ...
end
Source: https://github.com/rspec/rspec-rails/pull/668
Try adding a before block with the following:
before(:each) { #routes = Testy::Engine.routes }
That worked for me, as the routing specs use that top level instance variable to test their routes.
The answer from Steven Anderson got me most of the way there, but the requests need to be made relative to the engine, rather than the app - probably because this technique replaces the app's routes with the engine's routes, so everything is now relative to the engine. It seems a little fragile to me, but I haven't seen another way that works. If someone posts a cleaner way of doing this, I'll be happy to accept that answer instead.
In the 'dummy' app, if the engine is mounted as follows (spec/dummy/config/routes.rb):
Rails.application.routes.draw do
mount Testy::Engine => "/testy"
end
The following spec will correctly test the root route of the engine using both rspec and test::unit syntax (spec/routing/index_route_spec.rb):
require 'spec_helper'
describe "test controller routing" do
before(:each) { #routes = Testy::Engine.routes }
it "Routes the root to the test controller's index action" do
{ :get => '/' }.should route_to(:controller => 'testy/test', :action => 'index')
end
it "tries the same thing using Test::Unit syntax" do
assert_routing({:method => :get, :path => '/'}, {:controller => 'testy/test', :action => 'index'})
end
end
This worked for me:
# spec_helper.rb
RSpec.configure do |config|
config.include MyEngine::Engine.routes.url_helpers
end
For me, it was a combination of comments by pretty much everybody involved so far.
First, I started with this simple test:
it "routes / to the widgets controller" do
get('/').should route_to("mozoo/widget#index")
end
This resulted in:
Failures:
1) Mozoo::WidgetController GET widget index routes / to the widgets controller
Failure/Error: get('/').should route_to("mozoo/widget#index")
ActionController::RoutingError:
No route matches {:controller=>"mozoo/widget", :action=>"/"}
# ./spec/controllers/mozoo/widget_controller_spec.rb:9:in `block (3 levels) in <module:Mozoo>'
So I switched from get('/') to { :get => '/' } and things started working great. Not sure why. According to lib/rspec/rails/matchers/routing_matchers.rb L102-105, there is no difference, but it makes a difference to me. Regardless, thanks #cameron-pope.
Next, I added another pretty simple and very similar test as that above:
it "routes root_path to the widgets controller" do
{ :get => root_path }.should route_to("mozoo/widget#index")
end
And was getting this error:
Failures:
1) Mozoo::WidgetController GET widget index routes root_path to the widgets controller
Failure/Error: { :get => '/mozoo' }.should route_to("mozoo/widget#index")
No route matches "/mozoo"
# ./spec/controllers/mozoo/widget_controller_spec.rb:14:in `block (3 levels) in <module:Mozoo>'
So I added this:
before(:each) { #routes = Mozoo::Engine.routes }
And got a better/different error:
Failures:
1) Mozoo::WidgetController GET widget index routes root_path to the widgets controller
Failure/Error: { :get => root_path }.should route_to("mozoo/widget#index")
The recognized options <{"controller"=>"mozoo/widget", "action"=>"index", "section"=>"mozoo"}> did not match <{"controller"=>"mozoo/widget", "action"=>"index"}>, difference: <{"section"=>"mozoo"}>.
<{"controller"=>"mozoo/widget", "action"=>"index"}> expected but was
<{"controller"=>"mozoo/widget", "action"=>"index", "section"=>"mozoo"}>.
# ./spec/controllers/mozoo/widget_controller_spec.rb:14:in `block (3 levels) in <module:Mozoo>'
From there, I changed my test to include the section (the namespace my engine is under):
{ :get => root_path }.should route_to(:controller => "mozoo/widget", :action => "index", :section => "mozoo")
And viola, it passed. Thanks #steven-anderson.
This next part is odd. After adding another test for a specific widget which used the widget_path url helper for a named route:
it "will successfully serve the widget show page" do
visit widget_path(:foobar)
response.should be_success
end
The test promptly blowd up on me with:
Failures:
1) GET bubble_summary_row widget will have the content section properly scoped
Failure/Error: visit widget_path(:bubble_summary_row)
NoMethodError:
undefined method `widget_path' for #<RSpec::Core::ExampleGroup::Nested_3:0x0000010748f618>
# ./spec/views/mozoo/widgets/show.html.haml_spec.rb:7:in `block (2 levels) in <module:Mozoo>'
So I added the following spec_helper config entry:
RSpec.configure do |config|
config.include Testy::Engine.routes.url_helpers
end
And BAM! It passed. Thanks #sam-soffes. What makes this odd is that later on when creating this comment, I removed that config entry to try and get the error back and I was unable to reproduce the error simply by removing the config entry. Oh well, I'm moving on. Hopefully this long-winded account helps somebody.
Based on this answer I chose the following solution:
#spec/spec_helper.rb
RSpec.configure do |config|
# other code
config.before(:each) { #routes = MyEngine::Engine.routes }
end
The additional benefit is, that you don't need to have the before(:each) block in every controller-spec.
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