# frozen_string_literal: true
require "abstract_unit"
require "rails/engine"
require "action_dispatch/routing/inspector"
require "io/console/size"
class MountedRackApp
def self.call(env)
end
end
class Rails::DummyController
end
module ActionDispatch
module Routing
class RoutesInspectorTest < ActiveSupport::TestCase
setup do
@set = ActionDispatch::Routing::RouteSet.new
end
def test_displaying_routes_for_engines
engine = Class.new(Rails::Engine) do
def self.inspect
"Blog::Engine"
end
end
engine.routes.draw do
get "/cart", to: "cart#show"
end
output = draw do
get "/custom/assets", to: "custom_assets#show"
mount engine => "/blog", :as => "blog"
end
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
"custom_assets GET /custom/assets(.:format) custom_assets#show",
" blog /blog Blog::Engine",
"",
"Routes for Blog::Engine:",
" cart GET /cart(.:format) cart#show"
], output
end
def test_displaying_routes_for_engines_without_routes
engine = Class.new(Rails::Engine) do
def self.inspect
"Blog::Engine"
end
end
engine.routes.draw do
end
output = draw do
mount engine => "/blog", as: "blog"
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" blog /blog Blog::Engine",
"",
"Routes for Blog::Engine:"
], output
end
def test_cart_inspect
output = draw do
get "/cart", to: "cart#show"
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" cart GET /cart(.:format) cart#show"
], output
end
def test_articles_inspect_with_multiple_verbs
output = draw do
match "articles/:id", to: "articles#update", via: [:put, :patch]
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" PUT|PATCH /articles/:id(.:format) articles#update"
], output
end
def test_inspect_shows_custom_assets
output = draw do
get "/custom/assets", to: "custom_assets#show"
end
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
"custom_assets GET /custom/assets(.:format) custom_assets#show"
], output
end
def test_inspect_routes_shows_resources_route
output = draw do
resources :articles
end
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
" articles GET /articles(.:format) articles#index",
" POST /articles(.:format) articles#create",
" new_article GET /articles/new(.:format) articles#new",
"edit_article GET /articles/:id/edit(.:format) articles#edit",
" article GET /articles/:id(.:format) articles#show",
" PATCH /articles/:id(.:format) articles#update",
" PUT /articles/:id(.:format) articles#update",
" DELETE /articles/:id(.:format) articles#destroy"
], output
end
def test_inspect_routes_shows_root_route
output = draw do
root to: "pages#main"
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" root GET / pages#main"
], output
end
def test_inspect_routes_shows_dynamic_action_route
output = draw do
ActiveSupport::Deprecation.silence do
get "api/:action" => "api"
end
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" GET /api/:action(.:format) api#:action"
], output
end
def test_inspect_routes_shows_controller_and_action_only_route
output = draw do
ActiveSupport::Deprecation.silence do
get ":controller/:action"
end
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" GET /:controller/:action(.:format) :controller#:action"
], output
end
def test_inspect_routes_shows_controller_and_action_route_with_constraints
output = draw do
ActiveSupport::Deprecation.silence do
get ":controller(/:action(/:id))", id: /\d+/
end
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" GET /:controller(/:action(/:id))(.:format) :controller#:action {:id=>/\\d+/}"
], output
end
def test_rails_routes_shows_route_with_defaults
output = draw do
get "photos/:id" => "photos#show", :defaults => { format: "jpg" }
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
' GET /photos/:id(.:format) photos#show {:format=>"jpg"}'
], output
end
def test_rails_routes_shows_route_with_constraints
output = draw do
get "photos/:id" => "photos#show", :id => /[A-Z]\d{5}/
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" GET /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}"
], output
end
def test_rails_routes_shows_routes_with_dashes
output = draw do
get "about-us" => "pages#about_us"
get "our-work/latest"
resources :photos, only: [:show] do
get "user-favorites", on: :collection
get "preview-photo", on: :member
get "summary-text"
end
end
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
" about_us GET /about-us(.:format) pages#about_us",
" our_work_latest GET /our-work/latest(.:format) our_work#latest",
"user_favorites_photos GET /photos/user-favorites(.:format) photos#user_favorites",
" preview_photo_photo GET /photos/:id/preview-photo(.:format) photos#preview_photo",
" photo_summary_text GET /photos/:photo_id/summary-text(.:format) photos#summary_text",
" photo GET /photos/:id(.:format) photos#show"
], output
end
def test_rails_routes_shows_route_with_rack_app
output = draw do
get "foo/:id" => MountedRackApp, :id => /[A-Z]\d{5}/
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" GET /foo/:id(.:format) MountedRackApp {:id=>/[A-Z]\\d{5}/}"
], output
end
def test_rails_routes_shows_named_route_with_mounted_rack_app
output = draw do
mount MountedRackApp => "/foo"
end
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
"mounted_rack_app /foo MountedRackApp"
], output
end
def test_rails_routes_shows_overridden_named_route_with_mounted_rack_app_with_name
output = draw do
mount MountedRackApp => "/foo", as: "blog"
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" blog /foo MountedRackApp"
], output
end
def test_rails_routes_shows_route_with_rack_app_nested_with_dynamic_constraints
constraint = Class.new do
def inspect
"( my custom constraint )"
end
end
output = draw do
scope constraint: constraint.new do
mount MountedRackApp => "/foo"
end
end
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
"mounted_rack_app /foo MountedRackApp {:constraint=>( my custom constraint )}"
], output
end
def test_rails_routes_dont_show_app_mounted_in_assets_prefix
output = draw do
get "/sprockets" => MountedRackApp
end
assert_no_match(/MountedRackApp/, output.first)
assert_no_match(/\/sprockets/, output.first)
end
def test_rails_routes_shows_route_defined_in_under_assets_prefix
output = draw do
scope "/sprockets" do
get "/foo" => "foo#bar"
end
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" foo GET /sprockets/foo(.:format) foo#bar"
], output
end
def test_redirect
output = draw do
get "/foo" => redirect("/foo/bar"), :constraints => { subdomain: "admin" }
get "/bar" => redirect(path: "/foo/bar", status: 307)
get "/foobar" => redirect { "/foo/bar" }
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" foo GET /foo(.:format) redirect(301, /foo/bar) {:subdomain=>\"admin\"}",
" bar GET /bar(.:format) redirect(307, path: /foo/bar)",
"foobar GET /foobar(.:format) redirect(301)"
], output
end
def test_routes_can_be_filtered
output = draw(grep: "posts") do
resources :articles
resources :posts
end
assert_equal [" Prefix Verb URI Pattern Controller#Action",
" posts GET /posts(.:format) posts#index",
" POST /posts(.:format) posts#create",
" new_post GET /posts/new(.:format) posts#new",
"edit_post GET /posts/:id/edit(.:format) posts#edit",
" post GET /posts/:id(.:format) posts#show",
" PATCH /posts/:id(.:format) posts#update",
" PUT /posts/:id(.:format) posts#update",
" DELETE /posts/:id(.:format) posts#destroy"], output
end
def test_routes_when_expanded
previous_console_winsize = IO.console.winsize
IO.console.winsize = [0, 23]
engine = Class.new(Rails::Engine) do
def self.inspect
"Blog::Engine"
end
end
engine.routes.draw do
get "/cart", to: "cart#show"
end
output = draw(formatter: ActionDispatch::Routing::ConsoleFormatter::Expanded.new) do
get "/custom/assets", to: "custom_assets#show"
get "/custom/furnitures", to: "custom_furnitures#show"
mount engine => "/blog", :as => "blog"
end
assert_equal ["--[ Route 1 ]----------",
"Prefix | custom_assets",
"Verb | GET",
"URI | /custom/assets(.:format)",
"Controller#Action | custom_assets#show",
"--[ Route 2 ]----------",
"Prefix | custom_furnitures",
"Verb | GET",
"URI | /custom/furnitures(.:format)",
"Controller#Action | custom_furnitures#show",
"--[ Route 3 ]----------",
"Prefix | blog",
"Verb | ",
"URI | /blog",
"Controller#Action | Blog::Engine",
"",
"[ Routes for Blog::Engine ]",
"--[ Route 1 ]----------",
"Prefix | cart",
"Verb | GET",
"URI | /cart(.:format)",
"Controller#Action | cart#show"], output
ensure
IO.console.winsize = previous_console_winsize
end
def test_no_routes_matched_filter_when_expanded
output = draw(grep: "rails/dummy", formatter: ActionDispatch::Routing::ConsoleFormatter::Expanded.new) do
get "photos/:id" => "photos#show", :id => /[A-Z]\d{5}/
end
assert_equal [
"No routes were found for this grep pattern.",
"For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
], output
end
def test_not_routes_when_expanded
output = draw(grep: "rails/dummy", formatter: ActionDispatch::Routing::ConsoleFormatter::Expanded.new) {}
assert_equal [
"You don't have any routes defined!",
"",
"Please add some routes in config/routes.rb.",
"",
"For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
], output
end
def test_routes_can_be_filtered_with_namespaced_controllers
output = draw(grep: "admin/posts") do
resources :articles
namespace :admin do
resources :posts
end
end
assert_equal [" Prefix Verb URI Pattern Controller#Action",
" admin_posts GET /admin/posts(.:format) admin/posts#index",
" POST /admin/posts(.:format) admin/posts#create",
" new_admin_post GET /admin/posts/new(.:format) admin/posts#new",
"edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit",
" admin_post GET /admin/posts/:id(.:format) admin/posts#show",
" PATCH /admin/posts/:id(.:format) admin/posts#update",
" PUT /admin/posts/:id(.:format) admin/posts#update",
" DELETE /admin/posts/:id(.:format) admin/posts#destroy"], output
end
def test_regression_route_with_controller_regexp
output = draw do
ActiveSupport::Deprecation.silence do
get ":controller(/:action)", controller: /api\/[^\/]+/, format: false
end
end
assert_equal ["Prefix Verb URI Pattern Controller#Action",
" GET /:controller(/:action) :controller#:action"], output
end
def test_inspect_routes_shows_resources_route_when_assets_disabled
@set = ActionDispatch::Routing::RouteSet.new
output = draw do
get "/cart", to: "cart#show"
end
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
" cart GET /cart(.:format) cart#show"
], output
end
def test_routes_with_undefined_filter
output = draw(controller: "Rails::MissingController") do
get "photos/:id" => "photos#show", :id => /[A-Z]\d{5}/
end
assert_equal [
"No routes were found for this controller.",
"For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
], output
end
def test_no_routes_matched_filter
output = draw(grep: "rails/dummy") do
get "photos/:id" => "photos#show", :id => /[A-Z]\d{5}/
end
assert_equal [
"No routes were found for this grep pattern.",
"For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
], output
end
def test_no_routes_were_defined
output = draw(grep: "Rails::DummyController") {}
assert_equal [
"You don't have any routes defined!",
"",
"Please add some routes in config/routes.rb.",
"",
"For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
], output
end
def test_displaying_routes_for_internal_engines
engine = Class.new(Rails::Engine) do
def self.inspect
"Blog::Engine"
end
end
engine.routes.draw do
get "/cart", to: "cart#show"
post "/cart", to: "cart#create"
patch "/cart", to: "cart#update"
end
output = draw do
get "/custom/assets", to: "custom_assets#show"
mount engine => "/blog", as: "blog", internal: true
end
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
"custom_assets GET /custom/assets(.:format) custom_assets#show",
], output
end
private
def draw(formatter: ActionDispatch::Routing::ConsoleFormatter::Sheet.new, **options, &block)
@set.draw(&block)
inspector = ActionDispatch::Routing::RoutesInspector.new(@set.routes)
inspector.format(formatter, options).split("\n")
end
end
end
end