forked from rspec/rspec-rails
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathview_rendering.rb
166 lines (137 loc) · 4.54 KB
/
view_rendering.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
require 'action_view/testing/resolvers'
module RSpec
module Rails
# @api public
# Helpers for optionally rendering views in controller specs.
module ViewRendering
extend ActiveSupport::Concern
# @!attribute [r]
# Returns the controller object instance under test.
attr_reader :controller
# @private
attr_writer :controller
private :controller=
# DSL methods
module ClassMethods
# @see RSpec::Rails::ControllerExampleGroup
def render_views(true_or_false = true)
@render_views = true_or_false
end
# @api private
def render_views?
return @render_views if defined?(@render_views)
if superclass.respond_to?(:render_views?)
superclass.render_views?
else
RSpec.configuration.render_views?
end
end
end
# @api private
def render_views?
self.class.render_views? || !controller.class.respond_to?(:view_paths)
end
# @private
class EmptyTemplateResolver
def self.build(path)
if path.is_a?(::ActionView::Resolver)
ResolverDecorator.new(path)
else
FileSystemResolver.new(path)
end
end
def self.nullify_template_rendering(templates)
templates.map do |template|
::ActionView::Template.new(
"",
template.identifier,
EmptyTemplateHandler,
virtual_path: template.virtual_path,
format: template_format(template),
locals: []
)
end
end
def self.template_format(template)
template.format
end
# Delegates all methods to the submitted resolver and for all methods
# that return a collection of `ActionView::Template` instances, return
# templates with modified source
#
# @private
class ResolverDecorator < ::ActionView::Resolver
(::ActionView::Resolver.instance_methods - Object.instance_methods).each do |method|
undef_method method
end
(::ActionView::Resolver.methods - Object.methods).each do |method|
singleton_class.undef_method method
end
def initialize(resolver)
@resolver = resolver
end
def method_missing(name, *args, &block)
result = @resolver.send(name, *args, &block)
nullify_templates(result)
end
private
def nullify_templates(collection)
return collection unless collection.is_a?(Enumerable)
return collection unless collection.all? { |element| element.is_a?(::ActionView::Template) }
EmptyTemplateResolver.nullify_template_rendering(collection)
end
end
# Delegates find_templates to the submitted path set and then returns
# templates with modified source
#
# @private
class FileSystemResolver < ::ActionView::FileSystemResolver
private
def find_templates(*args)
templates = super
EmptyTemplateResolver.nullify_template_rendering(templates)
end
end
end
# @private
class EmptyTemplateHandler
def self.call(_template, _source = nil)
::Rails.logger.info(" Template rendering was prevented by rspec-rails. Use `render_views` to verify rendered view contents if necessary.")
%("")
end
end
# Used to null out view rendering in controller specs.
#
# @private
module EmptyTemplates
def prepend_view_path(new_path)
super(_path_decorator(*new_path))
end
def append_view_path(new_path)
super(_path_decorator(*new_path))
end
private
def _path_decorator(*paths)
paths.map { |path| EmptyTemplateResolver.build(path) }
end
end
# @private
RESOLVER_CACHE = Hash.new do |hash, path|
hash[path] = EmptyTemplateResolver.build(path)
end
included do
before do
unless render_views?
@_original_path_set = controller.class.view_paths
path_set = @_original_path_set.map { |resolver| RESOLVER_CACHE[resolver] }
controller.class.view_paths = path_set
controller.extend(EmptyTemplates)
end
end
after do
controller.class.view_paths = @_original_path_set unless render_views?
end
end
end
end
end