thoughtbot--shoulda-matchers/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb

331 lines
9.2 KiB
Ruby

require 'unit_spec_helper'
describe 'Shoulda::Matchers::ActionController::RouteMatcher', type: :controller 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
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
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'
assert_accepts add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'index'
)
)
end
end
end
context 'and the expected action is specified as a symbol' do
it 'accepts' do
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
end
end
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 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 all parts of the expected route but the path match an existing route' do
it 'rejects' do
define_route :get, '/', action: 'index'
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
context 'when all parts of the expected route but the action match an existing route' do
it 'rejects' do
define_route :get, '/', action: 'index'
assert_rejects add_target_to(
route(:get, '/'),
build_expected_route_options(
include_controller_in_expected_route_options,
action: 'another_action'
)
)
end
end
end
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'
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
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
include_examples 'core tests'
def controller_class_name
'ExamplesController'
end
end
context 'given a controller that is namespaced' do
def define_controller_under_test
define_module('Admin')
super
end
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