How to use rspec to test named routes? - ruby-on-rails

Given I have a named route:
map.some_route '/some_routes/:id', :controller => 'some', :action => 'other'
How do I use the routing spec file 'spec/routing/some_routing_spec.rb' to test for that named route?
I've tried this after the "describe SomeRouteController" block and it doesn't work, I get 'undefined method "helper":
describe SomeRouteHelper, 'some routes named routes' do
it 'should recognize some_route' do
helper.some_route_path(23).should == '/some_routes/23'
end
end

If this is in a controller spec, you can call the routing method directly, no helper needed.
describe SomeController do
it 'should recognize ma routes!' do
thing_path(23).should == '/things/23'
end
end

In RSpec-Rails 2.7+ you can create a spec/routing directory and put your routing specs in there. See the rspec-rails docs for more info.

there's a nice shoulda matcher for this too:
it { should route(:get, "/users/23").to(:action => "show", :id => 23)
more information on using shoulda matchers with rspec:
https://github.com/thoughtbot/shoulda-matchers

You can do this in your controller specs with the assert_routing method, like so:
describe UsersController do
it "should recognize a specific users#show route" do
assert_routing("/users/23", {:controller => "users", :action => "show", :id => 23})
end
end
More documentation is here.

This is how I write the specs using RSpec2, Shoulda, and Capybara. You would save this example file in #{Rails.root}/spec/routing/thingz_routing_spec.rb or my preference #{Rails.root}/spec/routing/thingz_controller_spec.rb
require "spec_helper"
describe ThingzController do
describe "routing" do
it "routes to #index" do
get("/thingz").should route_to("thingz#index")
end
end
end

Related

How to write Spec tests for routes - Rails 4

I'm trying to write a test for SessionsController and I wrote the following:
I'm using Spec 3.3
RSpec.describe SessionsController, type: :controller do
describe SessionsController do
describe "POST create" do
it "sign in should have a valid route" do
post('/api/signin').should route_to('api/sessions#create')
end
end
end
end
This app is to work mostly as an API, so for now, there's no need for views.
In my routes I have the following:
match '/api/signin', to: 'api/sessions#create',
Yet the test is not passing.
Any suggestions?
EDIT: The errors:
rspec ./spec/controllers/sessions_controller_spec.rb:27 # SessionsController SessionsController POST create sign in should have a valid route
rspec ./spec/controllers/sessions_controller_spec.rb:31 # SessionsController SessionsController POST create creates a new session
EDIT2: Added full test code
You must specify type: :routing and use assert_routing which has the benefice to test your route in 2 ways (route generation and route matching)
I make my answer general, so other people can take info from it, please adapt to your case
describe MyController, type: :routing do
it 'routing' do
# This is optional, but also a good reminder to tell me when I add a route
# and forgot to update my specs.
# Please see bellow for the helper definition
expect(number_of_routes_for('my_controller')).to eq(8)
# Then test for the routes, one by one
assert_routing({method: :get, path: '/my_controller'}, {controller: 'my_controller', action: 'index'})
assert_routing({method: :get, path: '/my_controller/1'}, {controller: 'my_controller', action: 'show', id: '1'})
# ... And so on, for each route
end
end
Note: If get errors with assert_routing (I guess it will be the case with match, but I can't remember) then have a look at assert_generates and assert_recognizes
And the number_of_routes_for helper
def number_of_routes_for(controller)
Rails.application.routes.routes.to_a.select{ |r| r.defaults[:controller] == controller }.count
end

Where should I put authenticated routes tests using Devise + RSpec?

I'm pretty new to Rails.
We are using Devise to handle user authentication and RSpec for testing the application (Rails 4).
I have an Admin devise model which has access to some authenticated routes. Here's an excerpt from routes.rb:
devise_for :admins
authenticate :admin do
get 'admin', to: 'admin#index'
end
It (obviously) works flawlessly: if I visit /admin, I get redirected to /admins/sign_in and, once I sign in (or if I already am in session) I have direct access to /admin.
Now, as I understand, routes should be tested inside spec/routes/<controller_name>_routes_spec.rb. I like the idea of testing routes (and that the right controller handle each route with the right action etc.) on their own.
We're facing the issue of testing routes when the said routes are authenticated. Including
config.include Devise::TestHelpers[, type: :controller]
inside spec/spec_helper.rb still doesn't make the sign_in (or sign_[out|up]) methods available inside routes specs.
What are we supposed to do? How should we test authenticated routes?
It just feels wrong to me that non authenticated routes are tested as spec/routes, while authenticated routes should be tested inside integration tests, manually filling sign-in forms with Capybara-like stuff.
(note: I read this, but it didn't help at all)
You can include the devise helper in your routes controller by removing the conditional in your spec_helper config. Mine looks like this:
...
RSpec.configure do |config|
config.include Devise::TestHelpers
...
end
def sign_in_user( user=nil )
#user = FactoryGirl.build(:user)
#user.skip_confirmation!
#user.save!
sign_in #user
end
Or if you want to insure that you're not abusing devise in weird place you can include it in just the controller and routing tests.
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.include Devise::TestHelpers, type: :routing
...
end
This is all assuming you're typing your spec files. One of my routing files looks like this:
require "spec_helper"
RSpec.describe WidgetsController, :type => :controller do
describe "routing" do
before(:each) do
sign_in_user
end
it "routes to #index" do
expect(:get => "/widgets").to route_to("widgets#index")
end
it "routes to #new" do
expect(:get => "/widgets/new").to route_to("widgets#new")
end
it "routes to #show" do
expect(:get => "/widgets/1").to route_to("widgets#show", :id => "1")
end
it "routes to #edit" do
expect(:get => "/widgets/1/edit").to route_to("widgets#edit", :id => "1")
end
it "routes to #create" do
expect(:post => "/widgets").to route_to("widgets#create")
end
it "routes to #update" do
expect(:put => "/widgets/1").to route_to("widgets#update", :id => "1")
end
it "routes to #destroy" do
expect(:delete => "/widgets/1").to route_to("widgets#destroy", :id => "1")
end
end
end

How can I test Rails Routes with Minitest?

I'm trying to use Minitest for an existing Rails app (3.2), but not having any luck running routing tests. I've tried rspec syntax (should route_to) and TestUnit syntax (assert_routing) but no luck.
Any advice on getting this to work? Specific modules I need to include, etc?
thanks
If you are using minitest-rails you can create route tests by placing the following in test/routes/homepage_test.rb:
require "minitest_helper"
class HomepageRouteTest < ActionDispatch::IntegrationTest
def test_homepage
assert_routing "/", :controller => "home", :action => "index"
end
end
Alternatively, you can use the Minitest Spec DSL:
require "minitest_helper"
describe "Homepage Route Acceptance Test" do
it "resolves the homepage" do
assert_routing "/", :controller => "home", :action => "index"
end
end
You can run these tests with the following rake task:
rake minitest:routes
#blowmage's answer helped me but it looks like the syntax has changed a bit.
With Rails 4:
require "test_helper"
class HomepageRouteTest < ActionDispatch::IntegrationTest
def test_messages
assert_generates '/messages', :controller => "messages", :action => "index"
end
end

RSpec includes help needed

I'm trying to mimic something similar to http://relishapp.com/rspec/rspec-rails/v/2-2/dir/routing-specs/access-to-named-routes-in-routing-specs
I have a unit test passing:
require 'test_helper'
class RoutesTest < ActionController::TestCase
test "book name is sent to store#index' do
assert_routing 'book/mytitle', {:controller => 'book', :action => 'index', :title => 'mytitle'}
end
end
I'm trying to covert this to an RSpec test (running Rspec 2.2 under Rails3.0.3)
Here's the test:
require 'spec_helper'
include RSpec::Rails::Matchers::RoutingMatchers
include ActionDispatch::Assertions::RoutingAssertions
describe "book specific routes" do
it "should recognize title in path" do
{:get => "book/mytitle"}.should route_to(:controller => "book", :action => "index", :title => "mytitle")
end
end
But this results in:
Failures:
1) book specific routes should recognize title in path
Failure/Error: {:get => "book/mytitle"}.should route_to(:controller => "book", :action => "index", :title => "mytitle")
undefined method `recognize_path' for nil:NilClass
# ./spec/route_spec.rb:9:in `block (2 levels) in <top (required)>'
Any idea where the nilClass is coming from? Any help would be appreciated.
It's the double include of ActionDispatch::Assertions::RoutingAssertions which causes the failure -- not sure why. Remove the two include statements and all should be well. The spec file should live in /spec/routing. You can wrap the example with describe BooksController for style points, but it will work without it.
I'm guessing the matchers need to be used inside a controller spec. They should already be there, so there would be no need to include them manually. Just make sure you're describing a controller.
describe BooksController do
it "should recognize title in path" do
# ...
end
end

Can't get RSpec view spec to pass

I've got the following spec in spec/views/users/new.html.erb_spec.rb:
require 'spec_helper'
describe "users/new.html.erb" do
it "displays the text attribute of the message" do
render
response.should contain("Register")
end
end
But when I run the test it fails with:
ActionView::TemplateError in 'users/new.html.erb displays the text attribute of the message'
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
The line it is failing on is:
<% form_for #user, :url => account_path do |f| %>
In my Users controller for the new method, I have this:
#user = User.new
Any ideas why I'm getting that error?
UPDATE: Per request, here's my routes file...
ActionController::Routing::Routes.draw do |map|
map.resource :account, :controller => "users"
map.resources :users
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
The view specification is run in complete isolation from the Users controller. Thus, you have to initialize the variables needed in the view yourself, as described here. The result would be something like this:
require 'spec_helper'
require 'path/to/user.rb'
describe "users/new.html.erb" do
it "displays the text attribute of the message" do
assigns[:user] = User.new
render
response.should contain("Register")
end
end
If you want to test your view together with your controller, I would suggest looking into integration testing with Cucumber.
Just a more updated answer.
require 'spec_helper'
describe "users/new.html.erb" do
it "displays the text attribute of the message" do
assign(:user, stub_model(User))
render
expect(rendered).to include("Register")
end
end
This should work on rails 3.2.13 and rspec 2.13.0

Resources