How can I test Rails Routes with Minitest? - ruby-on-rails

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

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

Rails route without controller

In my routes file, I have this random route without a controller
match "/ping" => lambda{ |env| [200, {'Content-Type' => 'text/plain'}, ['ACK']] }
Using Test::Unit / MiniTest, how would I go about testing, that yes the route /ping return 'ACK'
When you create a route without a controller, you cannot use ActionController::TestCase to test it. Instead, you should use ActionDispatch::IntegrationTest. Create a file at test/integration/ping_test.rb that includes the following:
require "test_helper"
class PingTest < ActionDispatch::IntegrationTest
def test_ping
get "/ping"
assert_response :success
assert_equal "ACK", response.body
end
end
Definitely using integration tests. See details here: http://guides.rubyonrails.org/testing.html#integration-testing

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

How to use rspec to test named routes?

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

Resources