-
Notifications
You must be signed in to change notification settings - Fork 4
/
methods.rb
86 lines (71 loc) · 3.39 KB
/
methods.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
require "route_mechanic/testing/route_wrapper"
require "route_mechanic/testing/error_aggregator"
require "route_mechanic/testing/minitest_assertion_adopter"
require "action_controller"
require "action_controller/test_case"
module RouteMechanic
module Testing
module Methods
include MinitestAssertionAdapter if defined?(RSpec)
include ActionDispatch::Assertions
# @param [Rails::Application] application
# @raise [Minitest::Assertion]
def assert_all_routes(application=Rails.application)
@application = application
# Instead of including ActionController::TestCase::Behavior, set up
# https://github.com/rails/rails/blob/5b6aa8c20a3abfd6274c83f196abf73cacb3400b/actionpack/lib/action_controller/test_case.rb#L519-L520
@controller = nil unless defined? @controller
aggregator = ErrorAggregator.new(target_routes, controllers).aggregate
aggregator.all_routes.each { |wrapper| assert_routes(wrapper) }
assert(aggregator.no_error?, ->{ aggregator.error_message })
end
private
def routes
# assert_routing expect @routes to exists as like this class inherits ActionController::TestCase.
# If user already defines @routes, do not override
@routes ||= @application.routes
return @routes if @routes.routes.size > 0
# If routes setting is not loaded when running test, it automatically loads config/routes as Rails does.
load_path = "#{Rails.root.join('config/routes.rb')}"
@application.routes_reloader.paths << load_path unless @application.routes_reloader.paths.include? load_path
@application.reload_routes!
@routes
end
# @param [RouteMechanic::Testing::RouteWrapper] wrapper
# @raise [Minitest::Assertion]
def assert_routes(wrapper)
required_parts = wrapper.required_parts.reduce({}) do |memo, required_part|
memo.merge({ required_part => '1' }) # '1' is pseudo id
end
base_option = { controller: wrapper.controller, action: wrapper.action }
url = routes.url_helpers.url_for(
base_option.merge({ only_path: true }).merge(required_parts))
expected_options = base_option.merge(required_parts)
assert_routing({ path: url, method: wrapper.verb }, expected_options)
end
# @return [Array<Controller>]
def controllers
eager_load_controllers
ApplicationController.descendants
end
# In RAILS_ENV=test, eager load is false and `ApplicationController.descendants` might be empty.
# So it needs to load all controllers. To shorten loading time, it loads only controllers.
# If complicated controllers path is used, use Rails.application.eager_load! instead.
def eager_load_controllers
load_path = "#{Rails.root.join('app/controllers')}"
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file
end
end
# @return [Array<ActionDispatch::Journey::Route>]
def target_routes
routes.routes.reject do |journey_route|
# Skip internals, endpoints that Rails adds by default
# Also Engines should be skipped since Engine's tests should be done in Engine
wrapper = RouteWrapper.new(journey_route)
wrapper.internal? || wrapper.required_defaults.empty? || wrapper.path.start_with?('/rails/')
end
end
end
end
end