aboutsummaryrefslogtreecommitdiffstats
path: root/actionview/test/template/lookup_context_test.rb
blob: 290f8327947bb40f242b5acd7eb841d37550b6cb (plain) (blame)
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# frozen_string_literal: true

require "abstract_unit"
require "abstract_controller/rendering"

class LookupContextTest < ActiveSupport::TestCase
  def setup
    @lookup_context = build_lookup_context(FIXTURE_LOAD_PATH, {})
    ActionView::LookupContext::DetailsKey.clear
  end

  def build_lookup_context(paths, details)
    ActionView::LookupContext.new(paths, details)
  end

  def teardown
    I18n.locale = :en
  end

  test "allows to override default_formats with ActionView::Base.default_formats" do
    formats = ActionView::Base.default_formats
    ActionView::Base.default_formats = [:foo, :bar]

    assert_equal [:foo, :bar], ActionView::LookupContext.new([]).default_formats
  ensure
    ActionView::Base.default_formats = formats
  end

  test "process view paths on initialization" do
    assert_kind_of ActionView::PathSet, @lookup_context.view_paths
  end

  test "normalizes details on initialization" do
    assert_equal Mime::SET.to_a, @lookup_context.formats
    assert_equal :en, @lookup_context.locale
  end

  test "allows me to freeze and retrieve frozen formats" do
    @lookup_context.formats.freeze
    assert_predicate @lookup_context.formats, :frozen?
  end

  test "provides getters and setters for variants" do
    @lookup_context.variants = [:mobile]
    assert_equal [:mobile], @lookup_context.variants
  end

  test "provides getters and setters for formats" do
    @lookup_context.formats = [:html]
    assert_equal [:html], @lookup_context.formats
  end

  test "handles */* formats" do
    @lookup_context.formats = ["*/*"]
    assert_equal Mime::SET.to_a, @lookup_context.formats
  end

  test "handles explicitly defined */* formats fallback to :js" do
    @lookup_context.formats = [:js, Mime::ALL]
    assert_equal [:js, *Mime::SET.symbols], @lookup_context.formats
  end

  test "adds :html fallback to :js formats" do
    @lookup_context.formats = [:js]
    assert_equal [:js, :html], @lookup_context.formats
  end

  test "provides getters and setters for locale" do
    @lookup_context.locale = :pt
    assert_equal :pt, @lookup_context.locale
  end

  test "changing lookup_context locale, changes I18n.locale" do
    @lookup_context.locale = :pt
    assert_equal :pt, I18n.locale
  end

  test "delegates changing the locale to the I18n configuration object if it contains a lookup_context object" do
    begin
      I18n.config = ActionView::I18nProxy.new(I18n.config, @lookup_context)
      @lookup_context.locale = :pt
      assert_equal :pt, I18n.locale
      assert_equal :pt, @lookup_context.locale
    ensure
      I18n.config = I18n.config.original_config
    end

    assert_equal :pt, I18n.locale
  end

  test "find templates using the given view paths and configured details" do
    template = @lookup_context.find("hello_world", %w(test))
    assert_equal "Hello world!", template.source

    @lookup_context.locale = :da
    template = @lookup_context.find("hello_world", %w(test))
    assert_equal "Hey verden", template.source
  end

  test "find templates with given variants" do
    @lookup_context.formats  = [:html]
    @lookup_context.variants = [:phone]

    template = @lookup_context.find("hello_world", %w(test))
    assert_equal "Hello phone!", template.source

    @lookup_context.variants = [:phone]
    @lookup_context.formats  = [:text]

    template = @lookup_context.find("hello_world", %w(test))
    assert_equal "Hello texty phone!", template.source
  end

  test "found templates respects given formats if one cannot be found from template or handler" do
    assert_called(ActionView::Template::Handlers::Builder, :default_format, returns: nil) do
      @lookup_context.formats = [:text]
      template = @lookup_context.find("hello", %w(test))
      assert_equal [:text], template.formats
    end
  end

  test "adds fallbacks to view paths when required" do
    assert_equal 1, @lookup_context.view_paths.size

    assert_deprecated do
      @lookup_context.with_fallbacks do
        assert_equal 3, @lookup_context.view_paths.size
        assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.new("")
        assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.new("/")
      end
    end

    @lookup_context = @lookup_context.with_fallbacks

    assert_equal 3, @lookup_context.view_paths.size
    assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.new("")
    assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.new("/")
  end

  test "add fallbacks just once in nested fallbacks calls" do
    assert_deprecated do
      @lookup_context.with_fallbacks do
        @lookup_context.with_fallbacks do
          assert_equal 3, @lookup_context.view_paths.size
        end
      end
    end

    @lookup_context = @lookup_context.with_fallbacks.with_fallbacks
    assert_equal 3, @lookup_context.view_paths.size
  end

  test "generates a new details key for each details hash" do
    keys = []
    keys << @lookup_context.details_key
    assert_equal 1, keys.uniq.size

    @lookup_context.locale = :da
    keys << @lookup_context.details_key
    assert_equal 2, keys.uniq.size

    @lookup_context.locale = :en
    keys << @lookup_context.details_key
    assert_equal 2, keys.uniq.size

    @lookup_context.formats = [:html]
    keys << @lookup_context.details_key
    assert_equal 3, keys.uniq.size

    @lookup_context.formats = nil
    keys << @lookup_context.details_key
    assert_equal 3, keys.uniq.size
  end

  test "gives the key forward to the resolver, so it can be used as cache key" do
    @lookup_context = build_lookup_context(ActionView::FixtureResolver.new("test/_foo.erb" => "Foo"), {})
    template = @lookup_context.find("foo", %w(test), true)
    assert_equal "Foo", template.source

    # Now we are going to change the template, but it won't change the returned template
    # since we will hit the cache.
    @lookup_context.view_paths.first.data["test/_foo.erb"] = "Bar"
    template = @lookup_context.find("foo", %w(test), true)
    assert_equal "Foo", template.source

    # This time we will change the locale. The updated template should be picked since
    # lookup_context generated a new key after we changed the locale.
    @lookup_context.locale = :da
    template = @lookup_context.find("foo", %w(test), true)
    assert_equal "Bar", template.source

    # Now we will change back the locale and it will still pick the old template.
    # This is expected because lookup_context will reuse the previous key for :en locale.
    @lookup_context.locale = :en
    template = @lookup_context.find("foo", %w(test), true)
    assert_equal "Foo", template.source

    # Finally, we can expire the cache. And the expected template will be used.
    @lookup_context.view_paths.first.clear_cache
    template = @lookup_context.find("foo", %w(test), true)
    assert_equal "Bar", template.source
  end

  test "can disable the cache on demand" do
    @lookup_context = build_lookup_context(ActionView::FixtureResolver.new("test/_foo.erb" => "Foo"), {})
    old_template = @lookup_context.find("foo", %w(test), true)

    template = @lookup_context.find("foo", %w(test), true)
    assert_equal template, old_template

    assert @lookup_context.cache
    template = @lookup_context.disable_cache do
      assert_not @lookup_context.cache
      @lookup_context.find("foo", %w(test), true)
    end
    assert @lookup_context.cache

    assert_not_equal template, old_template
  end

  test "responds to #prefixes" do
    assert_equal [], @lookup_context.prefixes
    @lookup_context.prefixes = ["foo"]
    assert_equal ["foo"], @lookup_context.prefixes
  end
end

class LookupContextWithFalseCaching < ActiveSupport::TestCase
  def setup
    @resolver = ActionView::FixtureResolver.new("test/_foo.erb" => ["Foo", Time.utc(2000)])
    @lookup_context = ActionView::LookupContext.new(@resolver, {})
  end

  test "templates are always found in the resolver but timestamp is checked before being compiled" do
    ActionView::Resolver.stub(:caching?, false) do
      template = @lookup_context.find("foo", %w(test), true)
      assert_equal "Foo", template.source

      # Now we are going to change the template, but it won't change the returned template
      # since the timestamp is the same.
      @resolver.data["test/_foo.erb"][0] = "Bar"
      template = @lookup_context.find("foo", %w(test), true)
      assert_equal "Foo", template.source

      # Now update the timestamp.
      @resolver.data["test/_foo.erb"][1] = Time.now.utc
      template = @lookup_context.find("foo", %w(test), true)
      assert_equal "Bar", template.source
    end
  end

  test "if no template was found in the second lookup, with no cache, raise error" do
    ActionView::Resolver.stub(:caching?, false) do
      template = @lookup_context.find("foo", %w(test), true)
      assert_equal "Foo", template.source

      @resolver.data.clear
      assert_raise ActionView::MissingTemplate do
        @lookup_context.find("foo", %w(test), true)
      end
    end
  end

  test "if no template was cached in the first lookup, retrieval should work in the second call" do
    ActionView::Resolver.stub(:caching?, false) do
      @resolver.data.clear
      assert_raise ActionView::MissingTemplate do
        @lookup_context.find("foo", %w(test), true)
      end

      @resolver.data["test/_foo.erb"] = ["Foo", Time.utc(2000)]
      template = @lookup_context.find("foo", %w(test), true)
      assert_equal "Foo", template.source
    end
  end
end

class TestMissingTemplate < ActiveSupport::TestCase
  def setup
    @lookup_context = ActionView::LookupContext.new("/Path/to/views", {})
  end

  test "if no template was found we get a helpful error message including the inheritance chain" do
    e = assert_raise ActionView::MissingTemplate do
      @lookup_context.find("foo", %w(parent child))
    end
    assert_match %r{Missing template parent/foo, child/foo with .* Searched in:\n  \* "/Path/to/views"\n}, e.message
  end

  test "if no partial was found we get a helpful error message including the inheritance chain" do
    e = assert_raise ActionView::MissingTemplate do
      @lookup_context.find("foo", %w(parent child), true)
    end
    assert_match %r{Missing partial parent/_foo, child/_foo with .* Searched in:\n  \* "/Path/to/views"\n}, e.message
  end

  test "if a single prefix is passed as a string and the lookup fails, MissingTemplate accepts it" do
    e = assert_raise ActionView::MissingTemplate do
      details = { handlers: [], formats: [], variants: [], locale: [] }
      @lookup_context.view_paths.find("foo", "parent", true, details)
    end
    assert_match %r{Missing partial parent/_foo with .* Searched in:\n  \* "/Path/to/views"\n}, e.message
  end
end