Add a new Routing module

Why:

* The `route` matcher can not only be used within controller example
  groups but also routing example groups.
* Now that we are mixing matchers into specific example groups, `route`
  is no longer available in routing example groups.

To satisfy the above:

* Create a new module that contains a `route` method and returns a new
  instance of RouteMatcher. (RouteMatcher still lives in the
  ActionController namespace.)
* Mix this module into routing example groups when the gem configuration
  block is run.
This commit is contained in:
Elliot Winkler 2015-09-24 14:09:35 -06:00
parent af98a23091
commit 8cf449b4ca
6 changed files with 283 additions and 1 deletions

View File

@ -12,6 +12,7 @@ require 'shoulda/matchers/warn'
require 'shoulda/matchers/action_controller'
require 'shoulda/matchers/active_model'
require 'shoulda/matchers/active_record'
require 'shoulda/matchers/routing'
module Shoulda
module Matchers

View File

@ -3,6 +3,7 @@ require 'shoulda/matchers/integrations/libraries/active_model'
require 'shoulda/matchers/integrations/libraries/active_record'
require 'shoulda/matchers/integrations/libraries/missing_library'
require 'shoulda/matchers/integrations/libraries/rails'
require 'shoulda/matchers/integrations/libraries/routing'
module Shoulda
module Matchers

View File

@ -11,7 +11,8 @@ module Shoulda
SUB_LIBRARIES = [
:active_model,
:active_record,
:action_controller
:action_controller,
:routing
]
def integrate_with(test_framework)

View File

@ -0,0 +1,27 @@
module Shoulda
module Matchers
module Integrations
module Libraries
# @private
class Routing
Integrations.register_library(self, :routing)
include Integrations::Inclusion
include Integrations::Rails
def integrate_with(test_framework)
test_framework.include(matchers_module, type: :routing)
include_into(::ActionController::TestCase, matchers_module)
end
private
def matchers_module
Shoulda::Matchers::Routing
end
end
end
end
end
end

View File

@ -0,0 +1,10 @@
module Shoulda
module Matchers
module Routing
# @private
def route(method, path)
ActionController::RouteMatcher.new(method, path, self)
end
end
end
end

View File

@ -0,0 +1,242 @@
require 'unit_spec_helper'
describe 'Shoulda::Matchers::Routing::RouteMatcher', type: :routing do
before do
define_controller('ThingsController')
end
shared_examples_for 'core tests' do
context 'when the given method, path, controller, and action match an existing route' do
it 'accepts' do
define_routes { get '/', to: 'things#index' }
assert_accepts add_target_to(
route(:get, '/'),
controller: 'things',
action: 'index'
)
end
context 'and the expected controller is specified as a symbol' do
it 'accepts' do
define_routes { get '/', to: 'things#index' }
assert_accepts add_target_to(
route(:get, '/'),
controller: :things,
action: 'index'
)
end
end
context 'and the expected action is specified as a symbol' do
it 'accepts' do
define_routes { get '/', to: 'things#index' }
assert_accepts add_target_to(
route(:get, '/'),
controller: 'things',
action: :index
)
end
end
end
context 'when the given method, path, controller, and action do not match an existing route' do
it 'rejects' do
assert_rejects add_target_to(
route(:get, '/non_existent_route'),
controller: 'no_controller',
action: 'no_action'
)
end
end
context 'when the given path, controller, and action match an existing route but the method does not' do
it 'rejects' do
define_routes { post '/', to: 'things#index' }
assert_rejects add_target_to(
route(:get, '/'),
controller: 'things',
action: 'index'
)
end
end
context 'when the given method, controller, and action match an existing route but the path does not' do
it 'rejects' do
define_routes { get '/', to: 'things#index' }
assert_rejects add_target_to(
route(:get, '/different_path'),
controller: 'things',
action: 'index'
)
end
end
context 'when the given method and path match an existing route but the controller does not' do
it 'rejects' do
define_routes { get '/', to: 'another_controller#index' }
assert_rejects add_target_to(
route(:get, '/'),
controller: 'things',
action: 'index'
)
end
end
context 'when the given method, path, and controller match an existing route but the action does not' do
it 'rejects' do
define_routes { get '/', to: 'things#index' }
assert_rejects add_target_to(
route(:get, '/'),
controller: 'things',
action: 'another_action'
)
end
end
context 'when the actual route has a param' do
context 'and the expected params include that param' do
it 'accepts' do
define_routes { get '/things/:id', to: 'things#show' }
assert_accepts add_target_to(
route(:get, '/things/1'),
controller: 'things',
action: 'show',
id: '1'
)
end
context 'but its value was not specified as a string' do
it 'accepts, treating it as a string' do
define_routes { get '/things/:id', to: 'things#show' }
assert_accepts add_target_to(
route(:get, '/things/1'),
controller: 'things',
action: 'show',
id: 1
)
end
end
end
context 'and the expected params do not match the actual params' do
it 'rejects' do
define_routes { get '/things/:id', to: 'things#show' }
params = {
controller: 'things',
action: 'show',
some: 'other',
params: 'here'
}
assert_rejects add_target_to(
route(:get, '/things/:id'),
params
)
end
end
end
context 'when the actual route has a default param whose value is a symbol' do
context 'and the expected params include a value for it' do
context 'as a symbol' do
it 'accepts' do
define_routes do
post '/things(.:format)',
to: 'things#create',
defaults: { format: :json }
end
assert_accepts add_target_to(
route(:post, '/things'),
controller: 'things',
action: 'create',
format: :json
)
end
end
context 'as a string' do
it 'accepts' do
define_routes do
post '/things(.:format)',
to: 'things#create',
defaults: { format: :json }
end
assert_accepts add_target_to(
route(:post, '/things'),
controller: 'things',
action: 'create',
format: 'json'
)
end
end
end
end
context 'when the existing route has a glob segment' do
context 'and a param is given which represents the segment' do
it 'accepts' do
define_routes { get '/things/*id', to: 'things#whatever' }
assert_accepts add_target_to(
route(:get, '/things/foo/bar'),
controller: 'things',
action: 'whatever',
id: 'foo/bar'
)
end
end
context 'and no param is given which represents the segment' do
it 'rejects' do
define_routes { get '/things/*id', to: 'things#whatever' }
assert_rejects add_target_to(
route(:get, '/things'),
controller: 'things',
action: 'whatever'
)
end
end
end
end
context 'given a controller and action specified as individual options' do
include_examples 'core tests'
def add_target_to(route_matcher, params)
route_matcher.to(params)
end
end
context 'given a controller and action joined together in a string' do
include_examples 'core tests'
def add_target_to(route_matcher, args)
controller = args.fetch(:controller)
action = args.fetch(:action)
route_matcher.to(
"#{controller}##{action}",
args.except(:controller, :action)
)
end
end
def assert_accepts(matcher)
should(matcher)
end
def assert_rejects(matcher)
should_not(matcher)
end
end