Skip to content

Instantly share code, notes, and snippets.

@wincent
Created July 5, 2010 06:50
Show Gist options
  • Save wincent/464081 to your computer and use it in GitHub Desktop.
Save wincent/464081 to your computer and use it in GitHub Desktop.
require File.expand_path('../../spec_helper', File.dirname(__FILE__))
describe Admin::ForumsController do
describe 'routing' do
# controller only implements #index, #show and #update
specify { get('/admin/forums').should have_routing('admin/forums#index') }
specify { get('/admin/forums/foo').should have_routing('admin/forums#show', :id => 'foo') }
specify { put('/admin/forums/foo').should have_routing('admin/forums#update', :id => 'foo') }
# the remaining RESTful actions aren't recognized
specify { get('/admin/forums/foo/edit').should_not be_recognized }
specify { delete('/admin/forums/foo').should_not be_recognized }
specify { post('/admin/forums').should_not be_recognized }
# note how in the absence of a admin/forums#new route,
# /admin/forums/new is interpreted as admin/forums#show
specify { get('/admin/forums/new').should have_routing('admin/forums#show', :id => 'new') }
describe 'helpers' do
before do
@forum = Forum.stub :permalink => 'foo'
end
describe 'admin_forums_path' do
it { admin_forums_path.should == '/admin/forums' }
end
describe 'admin_forum_path' do
it { admin_forum_path(@forum).should == '/admin/forums/foo' }
end
end
end
end
# rspec -f s output
IssuesController
routing
should route GET /issues as issues#index
should route GET /issues/new as issues#new
should route GET /issues/123 as issues#show with {:id=>"123"}
should route GET /issues/123/edit as issues#edit with {:id=>"123"}
should route PUT /issues/123 as issues#update with {:id=>"123"}
should route DELETE /issues/123 as issues#destroy with {:id=>"123"}
should route POST /issues as issues#create
index pagination
should route GET /issues/page/2 as issues#index with {:page=>"2"}
rejects non-numeric :page params
non-RESTful routes
should route GET /issues/search as issues#search
should route POST /issues/search as issues#search
comments
should map GET /issues/123/comments/new to comments#new with {:issue_id=>"123"}
should map POST /issues/123/comments to comments#create with {:issue_id=>"123"}
should not recognize GET /issues/123/comments
should not recognize GET /issues/123/comments/456
should not recognize GET /issues/123/comments/456/edit
should not recognize PUT /issues/123/comments/456
should not recognize DELETE /issues/123/comments/456
helpers
issues_path
should == "/issues"
new_issue_path
should == "/issues/new"
issue_path
should == "/issues/123"
edit_issue_path
should == "/issues/123/edit"
edit_issue_path
should == "/issues/123/edit"
Finished in 0.11541 seconds
23 examples, 0 failures
# rspec -f s output
Admin::ForumsController
routing
should route GET /admin/forums as admin/forums#index
should route GET /admin/forums/foo as admin/forums#show with {:id=>"foo"}
should route PUT /admin/forums/foo as admin/forums#update with {:id=>"foo"}
should not recognize GET /admin/forums/foo/edit
should not recognize DELETE /admin/forums/foo
should not recognize POST /admin/forums
should route GET /admin/forums/new as admin/forums#show with {:id=>"new"}
helpers
admin_forums_path
should == "/admin/forums"
admin_forum_path
should == "/admin/forums/foo"
Finished in 0.02475 seconds
9 examples, 0 failures
require File.expand_path('../spec_helper', File.dirname(__FILE__))
describe IssuesController do
describe 'routing' do
specify { get('/issues').should have_routing('issues#index') }
specify { get('/issues/new').should have_routing('issues#new') }
specify { get('/issues/123').should have_routing('issues#show', :id => '123') }
specify { get('/issues/123/edit').should have_routing('issues#edit', :id => '123') }
specify { put('/issues/123').should have_routing('issues#update', :id => '123') }
specify { delete('/issues/123').should have_routing('issues#destroy', :id => '123') }
specify { post('/issues').should have_routing('issues#create') }
describe 'index pagination' do
specify { get('/issues/page/2').should have_routing('issues#index', :page => '2') }
it 'rejects non-numeric :page params' do
get('/issues/page/foo').should_not be_recognized
end
end
describe 'non-RESTful routes' do
specify { get('/issues/search').should have_routing('issues#search') }
specify { post('/issues/search').should have_routing('issues#search') }
end
describe 'comments' do
# only #new and #create are implemented while nested
# Rails assert_routing limitation?: only map_to works here; map_from (and therefore also have_routing) do not
specify { get('/issues/123/comments/new').should map_to('comments#new', :issue_id => '123') }
specify { post('/issues/123/comments').should map_to('comments#create', :issue_id => '123') }
# all other RESTful actions are no-ops
specify { get('/issues/123/comments').should_not be_recognized }
specify { get('/issues/123/comments/456').should_not be_recognized }
specify { get('/issues/123/comments/456/edit').should_not be_recognized }
specify { put('/issues/123/comments/456').should_not be_recognized }
specify { delete('/issues/123/comments/456').should_not be_recognized }
end
describe 'helpers' do
before do
@issue = Issue.stub :id => 123
end
describe 'issues_path' do
specify { issues_path.should == '/issues' }
end
describe 'new_issue_path' do
specify { new_issue_path.should == '/issues/new' }
end
describe 'issue_path' do
specify { issue_path(@issue).should == '/issues/123' }
end
describe 'edit_issue_path' do
specify { edit_issue_path(@issue).should == '/issues/123/edit' }
end
describe 'edit_issue_path' do
specify { edit_issue_path(@issue).should == '/issues/123/edit' }
end
end
end
end
module RoutingSpecHelpers
extend ActiveSupport::Concern
extend RSpec::Matchers::DSL
module DestinationParser
def parse_destination destination
string_or_hash, options_hash = destination[0], destination[1]
case string_or_hash
when String
controller, action = string_or_hash.split('#')
options = options_hash || {}
options.merge({ :controller => controller, :action => action })
when Hash
string_or_hash
else
raise ArgumentError.new "unexpected argument of class #{destination.class}"
end
end
end
included do
include Rails.application.routes.url_helpers
end
def delete path
{ :method => :delete, :path => path }
end
def get path
{ :method => :get, :path => path }
end
def post path
{ :method => :post, :path => path }
end
def put path
{ :method => :put, :path => path }
end
matcher :map_to do |*destination|
extend DestinationParser
match_unless_raises Test::Unit::AssertionFailedError do |request|
@request = request
@method = @request.delete :method
@path = @request.delete :path
@destination = parse_destination destination
assert_recognizes(@destination, { :method => @method, :path => @path })
end
failure_message_for_should do
rescued_exception.message
end
description do
controller = @destination.delete(:controller)
action = @destination.delete(:action)
result = "map #{@method.to_s.upcase} #{@path} "
result << " with #{@request.inspect} " unless @request.empty?
result << "to #{controller}\##{action}"
result << " with #{@destination.inspect}" unless @destination.empty?
result
end
end
matcher :map_from do |*destination|
extend DestinationParser
match_unless_raises Test::Unit::AssertionFailedError do |request|
@request = request
@method = @request.delete :method # ignored
@path = @request.delete :path
@destination = parse_destination destination
assert_generates @path, @destination
end
failure_message_for_should do
rescued_exception.message
end
description do
controller = @destination.delete(:controller)
action = @destination.delete(:action)
result = "map #{@path} "
result << " with #{@request.inspect} " unless @request.empty?
result << "from #{controller}\##{action}"
result << " with #{@destination.inspect}" unless @destination.empty?
result
end
end
matcher :have_routing do |*destination|
extend DestinationParser
match_unless_raises Test::Unit::AssertionFailedError do |request|
@request = request
@method = @request.delete :method
@path = @request.delete :path
@destination = parse_destination destination
assert_routing({ :method => @method, :path => @path}, @destination)
end
failure_message_for_should do
rescued_exception.message
end
description do
controller = @destination.delete(:controller)
action = @destination.delete(:action)
result = "route #{@method.to_s.upcase} #{@path} "
result << " with #{@request.inspect} " unless @request.empty?
result << "as #{controller}\##{action}"
result << " with #{@destination.inspect}" unless @destination.empty?
result
end
end
matcher :be_recognized do
match do |request|
@method = request[:method]
@path = request[:path]
@result = true
# we need to do this because recognize_path() can still "recognize"
# paths which aren't actually routable:
#
# route:
# resource :issues, :except => :index
#
# assertion:
# recognize_path('/issues', :method => :get)
#
# "routes" to:
# {:controller => 'issues', :action => 'new'}
begin
assert_recognizes({}, { :method => @method, :path => @path })
rescue ActionController::RoutingError => e
@result = e.message
rescue Test::Unit::AssertionFailedError => e
# routable but we didn't supply an expected destination
end
@result == true
end
failure_message_for_should do
@result
end
failure_message_for_should_not do
"expected #{@method.to_s.upcase} #{@path} to not be routable, but it is"
end
description do
"recognize #{@method.to_s.upcase} #{@path}"
end
end
end
ENV['RAILS_ENV'] = ENV['RSPEC_RAILS_ENV'] || 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
RSpec.configure do |config|
config.include RoutingSpecHelpers, :example_group => { :file_path => %r{\bspec/routing/} }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment