Rewrite tests for ActionController::RouteMatcher

Why:

* We recently added Routing::RouteMatcher; the tests for those were
  roughly copied from those for ActionController::RouteMatcher but were
  rewritten, so we want to make the tests consistent between the two.
* The names of the existing tests weren't descriptive enough.
* The tests involving globs inside of routes should have been run
  twice -- once in the case that controller and action are separate
  options, another in the case that controller and action are specified
  together.
This commit is contained in:
Elliot Winkler 2015-09-25 16:53:40 -06:00
parent dcf2f4a1be
commit 07e740d24f
1 changed files with 284 additions and 117 deletions

View File

@ -1,163 +1,330 @@
require 'unit_spec_helper'
describe 'Shoulda::Matchers::ActionController::RouteMatcher', type: :controller do
shared_examples_for 'a controller with a defined route' do
context 'when controller and action are specified as explicit options' do
shared_examples_for 'tests involving expected route parts' do |args|
include_controller_in_expected_route_options =
args.fetch(:include_controller_in_expected_route_options)
context 'when all parts of the expected route match an existing route' do
it 'accepts' do
expect(controller_with_defined_routes).
to route(:get, "/#{controller_path}").
to(action: 'index')
define_route :get, '/', action: 'index'
assert_accepts add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'index'
)
)
end
it 'accepts a symbol controller' do
expect(controller_with_defined_routes).
to route(:get, "/#{controller_path}").
to(controller: controller_path.to_sym, action: 'index')
end
if include_controller_in_expected_route_options
context 'and the expected controller is specified as a symbol' do
it 'accepts' do
define_route :get, '/', action: 'index'
it 'accepts a symbol action' do
expect(controller_with_defined_routes).
to route(:get, "/#{controller_path}").
to(action: :index)
end
it 'rejects an undefined route' do
expect(controller_with_defined_routes).
not_to route(:get, '/non_existent_route').
to(action: 'non_existent')
end
it 'rejects a route for another controller' do
define_controller_with_defined_routes
other_controller = define_controller('Other').new
expect(other_controller).
not_to route(:get, "/#{controller_path}").
to(action: 'index')
end
context 'when route has parameters' do
it 'accepts a non-string parameter' do
expect(controller_with_defined_routes).
to route(:get, "/#{controller_path}/1").
to(action: 'show', id: 1)
end
it 'rejects a route for different parameters' do
expect(controller_with_defined_routes).
not_to route(:get, "/#{controller_path}/1").
to(action: 'show', some: 'other', params: 'here')
assert_accepts add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'index'
)
)
end
end
end
context 'when route has a default format' do
context 'and the expected action is specified as a symbol' do
it 'accepts' do
expect(controller_with_defined_routes).
to route(:post, "/#{controller_path}").
to(action: 'create', format: 'json')
end
define_route :get, '/', action: 'index'
it 'accepts when format is specified as a symbol' do
expect(controller_with_defined_routes).
to route(:post, "/#{controller_path}").
to(action: 'create', format: :json)
end
it 'rejects when format is unspecified' do
expect(controller_with_defined_routes).
not_to route(:post, "/#{controller_path}").
to(action: 'create')
assert_accepts add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: :index
)
)
end
end
end
context 'when controller and action are specified as a joined string' do
it 'accepts' do
expect(controller_with_defined_routes).
to route(:get, "/#{controller_path}").
to("#{controller_path}#index")
context 'when no parts of the expected route 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 route has parameters' do
it 'accepts a non-string parameter' do
expect(controller_with_defined_routes).
to route(:get, "/#{controller_path}/1").
to("#{controller_path}#show", id: 1)
end
context 'when all parts of the expected route but the method match an existing route' do
it 'rejects' do
define_route :post, '/', action: 'index'
assert_rejects add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'index'
)
)
end
end
context 'when route has the format' do
it 'accepts' do
expect(controller_with_defined_routes).
to route(:post, "/#{controller_path}").
to("#{controller_path}#create", format: 'json')
end
context 'when all parts of the expected route but the path match an existing route' do
it 'rejects' do
define_route :get, '/', action: 'index'
it 'rejects when format is unspecified' do
expect(controller_with_defined_routes).
not_to route(:post, "/#{controller_path}").
to(action: 'create')
assert_rejects add_target_to(
route(:get, '/different_path'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'index'
)
)
end
end
if include_controller_in_expected_route_options
context 'when all parts of the expected route but the controller match an existing route' do
it 'rejects' do
define_route :get, '/', controller: 'another_controller', action: 'index'
assert_rejects add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'index'
)
)
end
end
end
def controller_with_defined_routes
@_controller_with_defined_routes ||= begin
controller_class = define_controller(controller_name)
_controller_path = controller_path
context 'when all parts of the expected route but the action match an existing route' do
it 'rejects' do
define_route :get, '/', action: 'index'
setup_rails_controller_test(controller_class)
define_routes do
get "/#{_controller_path}", to: "#{_controller_path}#index"
get "/#{_controller_path}/:id", to: "#{_controller_path}#show"
post "/#{_controller_path}",
to: "#{_controller_path}#create",
defaults: { format: :json }
end
controller
assert_rejects add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'another_action'
)
)
end
end
def controller_path
controller_name.sub(/Controller$/, '').underscore
end
alias_method :define_controller_with_defined_routes,
:controller_with_defined_routes
end
context 'given a controller with a defined glob url' do
it 'accepts glob route' do
controller_class = define_controller('Examples')
setup_rails_controller_test(controller_class)
shared_examples_for 'tests involving params' do
context 'when the actual route has a param' do
context 'and the expected params include that param' do
it 'accepts' do
define_route :get, "/#{controller_name}/:id", action: 'show'
define_routes do
get '/examples/*id', to: 'examples#example'
assert_accepts add_target_to(
route(:get, "/#{controller_name}/1"),
controller: controller_name,
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_route :get, "/#{controller_name}/:id", action: 'show'
assert_accepts add_target_to(
route(:get, "/#{controller_name}/1"),
controller: controller_name,
action: 'show',
id: 1
)
end
end
end
expect(controller).to route(:get, '/examples/foo/bar').
to(action: 'example', id: 'foo/bar')
context 'and the expected params do not match the actual params' do
it 'rejects' do
define_route :get, "/#{controller_name}/:id", action: 'show'
params = {
controller: controller_name,
action: 'show',
some: 'other',
params: 'here'
}
assert_rejects add_target_to(
route(:get, "/#{controller_name}/: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_route :post, "/#{controller_name}/(.:format)",
action: 'create',
defaults: { format: :json }
assert_accepts add_target_to(
route(:post, "/#{controller_name}"),
controller: controller_name,
action: 'create',
format: :json
)
end
end
context 'as a string' do
it 'accepts' do
define_route :post, "/#{controller_name}/(.:format)",
action: 'create',
defaults: { format: :json }
assert_accepts add_target_to(
route(:post, "/#{controller_name}"),
controller: controller_name,
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_route :get, "/#{controller_name}/*id", action: 'whatever'
assert_accepts add_target_to(
route(:get, "/#{controller_name}/foo/bar"),
controller: controller_name,
action: 'whatever',
id: 'foo/bar'
)
end
end
context 'and no param is given which represents the segment' do
it 'rejects' do
define_route :get, "/#{controller_name}/*id", action: 'whatever'
assert_rejects add_target_to(
route(:get, "/#{controller_name}"),
controller: controller_name,
action: 'whatever'
)
end
end
end
end
shared_examples_for 'core tests' do
context 'given a controller and action specified as individual options' do
include_examples 'tests involving expected route parts',
include_controller_in_expected_route_options: true
include_examples 'tests involving params'
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 'tests involving expected route parts',
include_controller_in_expected_route_options: true
include_examples 'tests involving params'
def add_target_to(route_matcher, args)
controller = args.fetch(:controller)
action = args.fetch(:action)
route_matcher.to("#{controller}##{action}", args)
end
end
context 'given just an action' do
include_examples 'tests involving expected route parts',
include_controller_in_expected_route_options: false
include_examples 'tests involving params'
def add_target_to(route_matcher, params)
route_matcher.to(params)
end
end
end
before do
setup_rails_controller_test(controller_class)
end
context 'given a controller that is not namespaced' do
it_behaves_like 'a controller with a defined route' do
def controller_name
'ExamplesController'
end
include_examples 'core tests'
def controller_class_name
'ExamplesController'
end
end
context 'given a controller that is namespaced' do
it_behaves_like 'a controller with a defined route' do
before do
define_module('Admin')
end
def define_controller_under_test
define_module('Admin')
super
end
def controller_name
'Admin::ExamplesController'
include_examples 'core tests'
def controller_class_name
'Admin::ExamplesController'
end
end
let(:controller_class) do
define_controller_under_test
end
def define_controller_under_test
define_controller(controller_class_name)
end
def controller_name
controller_class_name.sub(/Controller$/, '').underscore
end
def define_route(method, path, args)
action = args.fetch(:action)
controller = args.fetch(:controller) { controller_name }
define_routes do
public_send(
method,
path,
args.merge(controller: controller, action: action)
)
end
end
def build_expected_route_options(include_controller_in_expected_route_options, default_options)
default_options.dup.tap do |options|
if include_controller_in_expected_route_options
options[:controller] = controller_name
end
end
end
def assert_accepts(matcher)
expect(controller).to matcher
end
def assert_rejects(matcher)
expect(controller).not_to matcher
end
end