wovnrb 3.11.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,454 +1,477 @@
1
- require 'test_helper'
2
- require 'wovnrb'
3
-
4
- class WovnrbTest < Minitest::Test
5
- def setup
6
- Wovnrb::Store.instance.reset
7
- end
8
-
9
- def test_initialize
10
- i = Wovnrb::Interceptor.new(get_app)
11
- refute_nil(i)
12
- end
13
-
14
- def test_switch_lang
15
- body = '<html lang="ja"><body><h1>Mr. Belvedere Fan Club</h1><div><p>Hello</p></div></body></html>'
16
-
17
- expected_body = [
18
- '<html lang="ja"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">',
19
- "<script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=&amp;backend=true&amp;currentLang=ja&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;version=#{Wovnrb::VERSION}\"> </script>",
20
- '<link rel="alternate" hreflang="ja" href="http://ja.page.com/">',
21
- '<link rel="alternate" hreflang="en" href="http://page.com/"></head>',
22
- '<body><h1><!--wovn-src:Mr. Belvedere Fan Club-->ベルベデアさんファンクラブ</h1>',
23
- '<div><p><!--wovn-src:Hello-->こんにちは</p></div>',
24
- '</body></html>'
25
- ].join
26
-
27
- assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
28
- end
29
-
30
- def test_switch_lang_with_input_tags
31
- body = [
32
- '<html lang="ja">',
33
- '<body>',
34
- '<input type="hidden" value="test1">',
35
- '<input type="hidden" value="test2">',
36
- '<input type="hidden" value="">',
37
- '<input value="test3">',
38
- '</body></html>'
39
- ].join
40
-
41
- expected_body = [
42
- '<html lang="ja"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">',
43
- "<script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=&backend=true&currentLang=ja&defaultLang=en&urlPattern=path&langCodeAliases={}&version=#{Wovnrb::VERSION}\"> </script>",
44
- '<link rel="alternate" hreflang="ja" href="http://ja.page.com/">',
45
- '<link rel="alternate" hreflang="en" href="http://page.com/"></head>',
46
- '<body>',
47
- '<input type="hidden" value="test1">',
48
- '<input type="hidden" value="test2">',
49
- '<input type="hidden" value="">',
50
- '<input value="test3">',
51
- '<p><!--wovn-src:Hello-->こんにちは</p>',
52
- '</body></html>'
53
- ].join
54
-
55
- assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
56
- end
57
-
58
- def test_switch_lang_of_html_fragment_with_japanese_translations
59
- bodies = ['<span>Hello</span>'].join
60
- expected_bodies = ['<span><!--wovn-src:Hello-->こんにちは</span>'].join
61
-
62
- assert_switch_lang('en', 'ja', bodies, expected_bodies, api_expected: true)
63
- end
64
-
65
- def test_switch_lang_splitted_body
66
- bodies = ['<html><body><h1>Mr. Belvedere Fan Club</h1>',
67
- '<div><p>Hello</p></div>',
68
- '</body></html>'].join
69
- expected_bodies = ["<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=ja&amp;defaultLang=en&amp;urlPattern=subdomain&amp;langCodeAliases={}&amp;version=WOVN.rb_#{Wovnrb::VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"alternate\" hreflang=\"en\" href=\"http://page.com/\"></head><body><h1>Mr. Belvedere Fan Club</h1><div><p>Hello</p></div></body></html>"].join
70
-
71
- assert_switch_lang('en', 'ja', bodies, expected_bodies, api_expected: true)
72
- end
73
-
74
- def test_switch_lang_of_html_fragment_in_splitted_body
75
- body = ['<select name="test"><option value="1">1</option>',
76
- '<option value="2">2</option></select>'].join
77
- expected_body = ['<select name="test"><option value="1">1</option><option value="2">2</option></select>'].join
78
-
79
- assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
80
- end
81
-
82
- def test_switch_lang_missing_values
83
- body = "<html><body><h1>Mr. Belvedere Fan Club</h1>
84
- <div><p>Hello</p></div>
85
- </body></html>"
86
- expected_body = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=&amp;backend=true&amp;currentLang=ja&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;version=#{Wovnrb::VERSION}\"> </script></head><body><h1>Mr. Belvedere Fan Club</h1>
87
- <div><p>Hello</p></div>
88
- </body></html>
89
- "
90
-
91
- assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
92
- end
93
-
94
- def test_switch_lang_on_fragment_with_translate_fragment_false
95
- body = "<h1>Mr. Belvedere Fan Club</h1>
96
- <div><p>Hello</p></div>"
97
-
98
- Wovnrb::Store.instance.settings['translate_fragment'] = false
99
- assert_switch_lang('en', 'ja', body, body, api_expected: false)
100
- end
101
-
102
- def test_switch_lang_on_fragment_with_translate_fragment_true
103
- body = "<h1>Mr. Belvedere Fan Club</h1>
104
- <div><p>Hello</p></div>"
105
- expected_body = "<h1><!--wovn-src:Mr. Belvedere Fan Club-->ベルベデアさんファンクラブ</h1>
106
- <div><p><!--wovn-src:Hello-->こんにちは</p></div>"
107
-
108
- Wovnrb::Store.instance.settings['translate_fragment'] = true
109
- assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
110
- end
111
-
112
- def test_switch_lang_ignores_amp
113
- body = <<HTML
114
- <html amp>
115
- <head><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript></head>
116
- <body>
117
- <h1>Mr. Belvedere Fan Club</h1>
118
- <div><p>Hello</p></div>
119
- </body>
120
- </html>
121
- HTML
122
-
123
- assert_switch_lang('en', 'ja', body, body, api_expected: false)
124
- end
125
-
126
- def test_switch_lang_ignores_amp_defined_with_symbol_attribute
127
- body = <<HTML
128
- <html ⚡>
129
- <body>
130
- <h1>Mr. Belvedere Fan Club</h1>
131
- <div><p>Hello</p></div>
132
- </body>
133
- </html>
134
- HTML
135
-
136
- assert_switch_lang('en', 'ja', body, body, api_expected: false)
137
- end
138
-
139
- def test_call_without_path_ignored_should_change_environment
140
- settings = {
141
- 'project_token' => '123456',
142
- 'url_pattern' => 'path',
143
- 'default_lang' => 'ja',
144
- 'supported_langs' => %w[ja en],
145
- 'ignore_paths' => ['/en/ignored']
146
- }
147
- env = {
148
- 'rack.input' => '',
149
- 'rack.request.query_string' => '',
150
- 'rack.request.query_hash' => {},
151
- 'rack.request.form_input' => '',
152
- 'rack.request.form_hash' => {},
153
- 'HTTP_HOST' => 'test.com',
154
- 'REQUEST_URI' => '/en/not_ignored',
155
- 'PATH_INFO' => '/en/not_ignored'
156
- }
157
-
158
- assert_call_affects_env(settings, env, mock_api: true, affected: true)
159
- end
160
-
161
- def test_call_with_path_ignored_with_language_code_should_change_environment
162
- settings = {
163
- 'project_token' => '123456',
164
- 'url_pattern' => 'path',
165
- 'default_lang' => 'ja',
166
- 'supported_langs' => %w[ja en],
167
- 'ignore_paths' => ['/en/ignored']
168
- }
169
- env = {
170
- 'rack.input' => '',
171
- 'rack.request.query_string' => '',
172
- 'rack.request.query_hash' => {},
173
- 'rack.request.form_input' => '',
174
- 'rack.request.form_hash' => {},
175
- 'HTTP_HOST' => 'test.com',
176
- 'REQUEST_URI' => '/ignored',
177
- 'PATH_INFO' => '/ignored'
178
- }
179
-
180
- assert_call_affects_env(settings, env, mock_api: false, affected: true)
181
- end
182
-
183
- def test_call_with_path_ignored_without_language_code_should_change_environment
184
- settings = {
185
- 'project_token' => '123456',
186
- 'url_pattern' => 'path',
187
- 'default_lang' => 'ja',
188
- 'supported_langs' => %w[ja en],
189
- 'ignore_paths' => ['/ignored']
190
- }
191
- env = {
192
- 'rack.input' => '',
193
- 'rack.request.query_string' => '',
194
- 'rack.request.query_hash' => {},
195
- 'rack.request.form_input' => '',
196
- 'rack.request.form_hash' => {},
197
- 'HTTP_HOST' => 'test.com',
198
- 'REQUEST_URI' => '/en/ignored',
199
- 'PATH_INFO' => '/en/ignored'
200
- }
201
-
202
- assert_call_affects_env(settings, env, mock_api: false, affected: true)
203
- end
204
-
205
- def test_call_with_path_ignored_without_language_code_in_original_language_should_change_environment
206
- settings = {
207
- 'project_token' => '123456',
208
- 'url_pattern' => 'path',
209
- 'default_lang' => 'ja',
210
- 'supported_langs' => %w[ja en],
211
- 'ignore_paths' => ['/ignored']
212
- }
213
- env = {
214
- 'rack.input' => '',
215
- 'rack.request.query_string' => '',
216
- 'rack.request.query_hash' => {},
217
- 'rack.request.form_input' => '',
218
- 'rack.request.form_hash' => {},
219
- 'HTTP_HOST' => 'test.com',
220
- 'REQUEST_URI' => '/ignored',
221
- 'PATH_INFO' => '/ignored'
222
- }
223
-
224
- assert_call_affects_env(settings, env, mock_api: false, affected: true)
225
- end
226
-
227
- def test_call_with_path_ignored_should_not_change_environment
228
- settings = {
229
- 'project_token' => '123456',
230
- 'url_pattern' => 'path',
231
- 'default_lang' => 'ja',
232
- 'supported_langs' => %w[ja en],
233
- 'ignore_paths' => ['/en/ignored']
234
- }
235
- env = {
236
- 'rack.input' => '',
237
- 'rack.request.query_string' => '',
238
- 'rack.request.query_hash' => {},
239
- 'rack.request.form_input' => '',
240
- 'rack.request.form_hash' => {},
241
- 'rack.request.form_pairs' => [],
242
- 'rack.request.cookie_hash' => {},
243
- 'HTTP_HOST' => 'test.com',
244
- 'REQUEST_URI' => '/en/ignored',
245
- 'PATH_INFO' => '/en/ignored'
246
- }
247
-
248
- assert_call_affects_env(settings, env, mock_api: false, affected: false)
249
- end
250
-
251
- def test_call__with_use_cookie_lang_true__cookie_lang_is_target_lang__should_redirect
252
- settings = {
253
- 'project_token' => '123456',
254
- 'url_pattern' => 'path',
255
- 'default_lang' => 'ja',
256
- 'supported_langs' => %w[ja en],
257
- 'use_cookie_lang' => true
258
- }
259
- env = Wovnrb.get_env(
260
- {
261
- 'url' => 'http://test.com/foo',
262
- 'HTTP_COOKIE' => 'wovn_selected_lang=en'
263
- }
264
- )
265
-
266
- sut = Wovnrb::Interceptor.new(get_app, settings)
267
- status, res_headers, _body = sut.call(env)
268
-
269
- assert_equal(302, status)
270
- assert_equal('http://test.com/en/foo', res_headers['location'])
271
- end
272
-
273
- def test_call__with_use_cookie_lang_true__cookie_lang_is_default_lang__should_not_redirect
274
- settings = {
275
- 'project_token' => '123456',
276
- 'url_pattern' => 'path',
277
- 'default_lang' => 'ja',
278
- 'supported_langs' => %w[ja en],
279
- 'use_cookie_lang' => true
280
- }
281
- env = Wovnrb.get_env(
282
- {
283
- 'url' => 'http://test.com/foo',
284
- 'HTTP_COOKIE' => 'wovn_selected_lang=ja'
285
- }
286
- )
287
-
288
- sut = Wovnrb::Interceptor.new(get_app, settings)
289
- status, res_headers, _body = sut.call(env)
290
-
291
- assert_equal(200, status)
292
- assert_nil(res_headers['location'])
293
- end
294
-
295
- def test_call__with_use_cookie_lang_true__cookie_lang_is_different_target_lang__should_not_redirect
296
- settings = {
297
- 'project_token' => '123456',
298
- 'url_pattern' => 'path',
299
- 'default_lang' => 'ja',
300
- 'supported_langs' => %w[ja en fr],
301
- 'use_cookie_lang' => true
302
- }
303
- env = Wovnrb.get_env(
304
- {
305
- 'url' => 'http://test.com/en/foo',
306
- 'HTTP_COOKIE' => 'wovn_selected_lang=fr'
307
- }
308
- )
309
-
310
- mock_translation_api_response('', '')
311
- sut = Wovnrb::Interceptor.new(get_app, settings)
312
- status, res_headers, _body = sut.call(env)
313
-
314
- assert_equal(200, status)
315
- assert_nil(res_headers['location'])
316
- end
317
-
318
- def test_call__with_use_cookie_lang_true__cookie_lang_is_empty__should_not_redirect
319
- settings = {
320
- 'project_token' => '123456',
321
- 'url_pattern' => 'path',
322
- 'default_lang' => 'ja',
323
- 'supported_langs' => %w[ja en],
324
- 'use_cookie_lang' => true
325
- }
326
- env = Wovnrb.get_env(
327
- {
328
- 'url' => 'http://test.com/foo',
329
- 'HTTP_COOKIE' => ''
330
- }
331
- )
332
-
333
- sut = Wovnrb::Interceptor.new(get_app, settings)
334
- status, res_headers, _body = sut.call(env)
335
-
336
- assert_equal(200, status)
337
- assert_nil(res_headers['location'])
338
- end
339
-
340
- def test_call__with_use_cookie_lang_false__should_not_redirect
341
- settings = {
342
- 'project_token' => '123456',
343
- 'url_pattern' => 'path',
344
- 'default_lang' => 'ja',
345
- 'supported_langs' => %w[ja en],
346
- 'use_cookie_lang' => false
347
- }
348
- env = Wovnrb.get_env(
349
- {
350
- 'url' => 'http://test.com/foo',
351
- 'HTTP_COOKIE' => 'wovn_selected_lang=en'
352
- }
353
- )
354
-
355
- sut = Wovnrb::Interceptor.new(get_app, settings)
356
- status, res_headers, _body = sut.call(env)
357
-
358
- assert_equal(200, status)
359
- assert_nil(res_headers['location'])
360
- end
361
-
362
- private
363
-
364
- def assert_call_affects_env(settings, env, mock_api:, affected:)
365
- app_mock = get_app
366
- sut = Wovnrb::Interceptor.new(app_mock, settings)
367
- unaffected_env = env
368
-
369
- mock_translation_api_response('', '') if mock_api
370
- sut.call(env.clone)
371
-
372
- assert_equal(unaffected_env != app_mock.env, affected)
373
- end
374
-
375
- def assert_switch_lang(original_lang, target_lang, body, expected_body, api_expected: true)
376
- subdomain = target_lang == original_lang ? '' : "#{target_lang}."
377
- interceptor = Wovnrb::Interceptor.new(get_app)
378
-
379
- store, headers = store_headers_factory(subdomain, original_lang)
380
- if api_expected
381
- dom = Wovnrb::Helpers::NokogumboHelper.parse_html(body)
382
- url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
383
- converter = Wovnrb::HtmlConverter.new(dom, store, headers, url_lang_switcher)
384
- apified_body, = converter.build_api_compatible_html
385
- mock_translation_api_response(apified_body, expected_body)
386
- end
387
-
388
- actual_bodies = interceptor.switch_lang(headers, [body])
389
-
390
- assert_same_elements([expected_body], actual_bodies)
391
- end
392
-
393
- def store_headers_factory(subdomain, original_lang)
394
- settings = {
395
- 'project_token' => '123456',
396
- 'custom_lang_aliases' => {},
397
- 'default_lang' => original_lang,
398
- 'url_pattern' => 'subdomain',
399
- 'url_pattern_reg' => '^(?<lang>[^.]+)\.'
400
- }
401
-
402
- store = Wovnrb::Store.instance
403
- store.update_settings(settings)
404
-
405
- headers = Wovnrb::Headers.new(
406
- Wovnrb.get_env('url' => "http://#{subdomain}page.com"),
407
- Wovnrb.get_settings(settings),
408
- Wovnrb::UrlLanguageSwitcher.new(store)
409
- )
410
-
411
- [store, headers]
412
- end
413
-
414
- def mock_translation_api_response(body, expected_body)
415
- Wovnrb::ApiTranslator.any_instance
416
- .expects(:translate)
417
- .once
418
- .with(body)
419
- .returns(expected_body)
420
- end
421
-
422
- def get_app(opts = {})
423
- RackMock.new(opts)
424
- end
425
-
426
- class RackMock
427
- attr_accessor :params, :env
428
-
429
- def initialize(opts = {})
430
- @params = {}
431
- if opts.key?(:params) && opts[:params].instance_of?(Hash)
432
- opts[:params].each do |key, val|
433
- @params[key] = val
434
- end
435
- end
436
- @request_headers = {}
437
- end
438
-
439
- def call(env)
440
- @env = env
441
- unless @params.empty?
442
- req = Rack::Request.new(@env)
443
- @params.each do |key, val|
444
- req.update_param(key, val)
445
- end
446
- end
447
- [200, { 'Content-Type' => 'text/html' }, ['']]
448
- end
449
-
450
- def [](key)
451
- @env[key]
452
- end
453
- end
454
- end
1
+ require 'test_helper'
2
+ require 'wovnrb'
3
+
4
+ class WovnrbTest < Minitest::Test
5
+ def setup
6
+ Wovnrb::Store.instance.reset
7
+ end
8
+
9
+ def test_initialize
10
+ i = Wovnrb::Interceptor.new(get_app)
11
+ refute_nil(i)
12
+ end
13
+
14
+ def test_switch_lang
15
+ body = '<html lang="ja"><body><h1>Mr. Belvedere Fan Club</h1><div><p>Hello</p></div></body></html>'
16
+
17
+ expected_body = [
18
+ '<html lang="ja"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">',
19
+ "<script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=&amp;backend=true&amp;currentLang=ja&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;version=#{Wovnrb::VERSION}\"> </script>",
20
+ '<link rel="alternate" hreflang="ja" href="http://ja.page.com/">',
21
+ '<link rel="alternate" hreflang="en" href="http://page.com/"></head>',
22
+ '<body><h1><!--wovn-src:Mr. Belvedere Fan Club-->ベルベデアさんファンクラブ</h1>',
23
+ '<div><p><!--wovn-src:Hello-->こんにちは</p></div>',
24
+ '</body></html>'
25
+ ].join
26
+
27
+ assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
28
+ end
29
+
30
+ def test_switch_lang_with_input_tags
31
+ body = [
32
+ '<html lang="ja">',
33
+ '<body>',
34
+ '<input type="hidden" value="test1">',
35
+ '<input type="hidden" value="test2">',
36
+ '<input type="hidden" value="">',
37
+ '<input value="test3">',
38
+ '</body></html>'
39
+ ].join
40
+
41
+ expected_body = [
42
+ '<html lang="ja"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">',
43
+ "<script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=&backend=true&currentLang=ja&defaultLang=en&urlPattern=path&langCodeAliases={}&version=#{Wovnrb::VERSION}\"> </script>",
44
+ '<link rel="alternate" hreflang="ja" href="http://ja.page.com/">',
45
+ '<link rel="alternate" hreflang="en" href="http://page.com/"></head>',
46
+ '<body>',
47
+ '<input type="hidden" value="test1">',
48
+ '<input type="hidden" value="test2">',
49
+ '<input type="hidden" value="">',
50
+ '<input value="test3">',
51
+ '<p><!--wovn-src:Hello-->こんにちは</p>',
52
+ '</body></html>'
53
+ ].join
54
+
55
+ assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
56
+ end
57
+
58
+ def test_switch_lang_of_html_fragment_with_japanese_translations
59
+ bodies = ['<span>Hello</span>'].join
60
+ expected_bodies = ['<span><!--wovn-src:Hello-->こんにちは</span>'].join
61
+
62
+ assert_switch_lang('en', 'ja', bodies, expected_bodies, api_expected: true)
63
+ end
64
+
65
+ def test_switch_lang_splitted_body
66
+ bodies = ['<html><body><h1>Mr. Belvedere Fan Club</h1>',
67
+ '<div><p>Hello</p></div>',
68
+ '</body></html>'].join
69
+ expected_bodies = ["<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=ja&amp;defaultLang=en&amp;urlPattern=subdomain&amp;langCodeAliases={}&amp;version=WOVN.rb_#{Wovnrb::VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"alternate\" hreflang=\"en\" href=\"http://page.com/\"></head><body><h1>Mr. Belvedere Fan Club</h1><div><p>Hello</p></div></body></html>"].join
70
+
71
+ assert_switch_lang('en', 'ja', bodies, expected_bodies, api_expected: true)
72
+ end
73
+
74
+ def test_switch_lang_of_html_fragment_in_splitted_body
75
+ body = ['<select name="test"><option value="1">1</option>',
76
+ '<option value="2">2</option></select>'].join
77
+ expected_body = ['<select name="test"><option value="1">1</option><option value="2">2</option></select>'].join
78
+
79
+ assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
80
+ end
81
+
82
+ def test_switch_lang_missing_values
83
+ body = "<html><body><h1>Mr. Belvedere Fan Club</h1>
84
+ <div><p>Hello</p></div>
85
+ </body></html>"
86
+ expected_body = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=&amp;backend=true&amp;currentLang=ja&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;version=#{Wovnrb::VERSION}\"> </script></head><body><h1>Mr. Belvedere Fan Club</h1>
87
+ <div><p>Hello</p></div>
88
+ </body></html>
89
+ "
90
+
91
+ assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
92
+ end
93
+
94
+ def test_switch_lang_on_fragment_with_translate_fragment_false
95
+ body = "<h1>Mr. Belvedere Fan Club</h1>
96
+ <div><p>Hello</p></div>"
97
+
98
+ Wovnrb::Store.instance.settings['translate_fragment'] = false
99
+ assert_switch_lang('en', 'ja', body, body, api_expected: false)
100
+ end
101
+
102
+ def test_switch_lang_on_fragment_with_translate_fragment_true
103
+ body = "<h1>Mr. Belvedere Fan Club</h1>
104
+ <div><p>Hello</p></div>"
105
+ expected_body = "<h1><!--wovn-src:Mr. Belvedere Fan Club-->ベルベデアさんファンクラブ</h1>
106
+ <div><p><!--wovn-src:Hello-->こんにちは</p></div>"
107
+
108
+ Wovnrb::Store.instance.settings['translate_fragment'] = true
109
+ assert_switch_lang('en', 'ja', body, expected_body, api_expected: true)
110
+ end
111
+
112
+ def test_switch_lang_ignores_amp
113
+ body = <<HTML
114
+ <html amp>
115
+ <head><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript></head>
116
+ <body>
117
+ <h1>Mr. Belvedere Fan Club</h1>
118
+ <div><p>Hello</p></div>
119
+ </body>
120
+ </html>
121
+ HTML
122
+
123
+ assert_switch_lang('en', 'ja', body, body, api_expected: false)
124
+ end
125
+
126
+ def test_switch_lang_ignores_amp_defined_with_symbol_attribute
127
+ body = <<HTML
128
+ <html ⚡>
129
+ <body>
130
+ <h1>Mr. Belvedere Fan Club</h1>
131
+ <div><p>Hello</p></div>
132
+ </body>
133
+ </html>
134
+ HTML
135
+
136
+ assert_switch_lang('en', 'ja', body, body, api_expected: false)
137
+ end
138
+
139
+ def test_call_without_path_ignored_should_change_environment
140
+ settings = {
141
+ 'project_token' => '123456',
142
+ 'url_pattern' => 'path',
143
+ 'default_lang' => 'ja',
144
+ 'supported_langs' => %w[ja en],
145
+ 'ignore_paths' => ['/en/ignored']
146
+ }
147
+ env = {
148
+ 'rack.input' => '',
149
+ 'rack.request.query_string' => '',
150
+ 'rack.request.query_hash' => {},
151
+ 'rack.request.form_input' => '',
152
+ 'rack.request.form_hash' => {},
153
+ 'HTTP_HOST' => 'test.com',
154
+ 'REQUEST_URI' => '/en/not_ignored',
155
+ 'PATH_INFO' => '/en/not_ignored'
156
+ }
157
+
158
+ assert_call_affects_env(settings, env, mock_api: true, affected: true)
159
+ end
160
+
161
+ def test_call_with_path_ignored_with_language_code_should_change_environment
162
+ settings = {
163
+ 'project_token' => '123456',
164
+ 'url_pattern' => 'path',
165
+ 'default_lang' => 'ja',
166
+ 'supported_langs' => %w[ja en],
167
+ 'ignore_paths' => ['/en/ignored']
168
+ }
169
+ env = {
170
+ 'rack.input' => '',
171
+ 'rack.request.query_string' => '',
172
+ 'rack.request.query_hash' => {},
173
+ 'rack.request.form_input' => '',
174
+ 'rack.request.form_hash' => {},
175
+ 'HTTP_HOST' => 'test.com',
176
+ 'REQUEST_URI' => '/ignored',
177
+ 'PATH_INFO' => '/ignored'
178
+ }
179
+
180
+ assert_call_affects_env(settings, env, mock_api: false, affected: true)
181
+ end
182
+
183
+ def test_call_with_path_ignored_without_language_code_should_change_environment
184
+ settings = {
185
+ 'project_token' => '123456',
186
+ 'url_pattern' => 'path',
187
+ 'default_lang' => 'ja',
188
+ 'supported_langs' => %w[ja en],
189
+ 'ignore_paths' => ['/ignored']
190
+ }
191
+ env = {
192
+ 'rack.input' => '',
193
+ 'rack.request.query_string' => '',
194
+ 'rack.request.query_hash' => {},
195
+ 'rack.request.form_input' => '',
196
+ 'rack.request.form_hash' => {},
197
+ 'HTTP_HOST' => 'test.com',
198
+ 'REQUEST_URI' => '/en/ignored',
199
+ 'PATH_INFO' => '/en/ignored'
200
+ }
201
+
202
+ assert_call_affects_env(settings, env, mock_api: false, affected: true)
203
+ end
204
+
205
+ def test_call_with_path_ignored_without_language_code_in_original_language_should_change_environment
206
+ settings = {
207
+ 'project_token' => '123456',
208
+ 'url_pattern' => 'path',
209
+ 'default_lang' => 'ja',
210
+ 'supported_langs' => %w[ja en],
211
+ 'ignore_paths' => ['/ignored']
212
+ }
213
+ env = {
214
+ 'rack.input' => '',
215
+ 'rack.request.query_string' => '',
216
+ 'rack.request.query_hash' => {},
217
+ 'rack.request.form_input' => '',
218
+ 'rack.request.form_hash' => {},
219
+ 'HTTP_HOST' => 'test.com',
220
+ 'REQUEST_URI' => '/ignored',
221
+ 'PATH_INFO' => '/ignored'
222
+ }
223
+
224
+ assert_call_affects_env(settings, env, mock_api: false, affected: true)
225
+ end
226
+
227
+ def test_call_with_path_ignored_should_not_change_environment
228
+ settings = {
229
+ 'project_token' => '123456',
230
+ 'url_pattern' => 'path',
231
+ 'default_lang' => 'ja',
232
+ 'supported_langs' => %w[ja en],
233
+ 'ignore_paths' => ['/en/ignored']
234
+ }
235
+ env = {
236
+ 'rack.input' => '',
237
+ 'rack.request.query_string' => '',
238
+ 'rack.request.query_hash' => {},
239
+ 'rack.request.form_input' => '',
240
+ 'rack.request.form_hash' => {},
241
+ 'rack.request.form_pairs' => [],
242
+ 'rack.request.cookie_hash' => {},
243
+ 'HTTP_HOST' => 'test.com',
244
+ 'REQUEST_URI' => '/en/ignored',
245
+ 'PATH_INFO' => '/en/ignored'
246
+ }
247
+
248
+ assert_call_affects_env(settings, env, mock_api: false, affected: false)
249
+ end
250
+
251
+ def test_call__with_use_cookie_lang_true__cookie_lang_is_target_lang__should_redirect
252
+ settings = {
253
+ 'project_token' => '123456',
254
+ 'url_pattern' => 'path',
255
+ 'default_lang' => 'ja',
256
+ 'supported_langs' => %w[ja en],
257
+ 'use_cookie_lang' => true
258
+ }
259
+ env = Wovnrb.get_env(
260
+ {
261
+ 'url' => 'http://test.com/foo',
262
+ 'HTTP_COOKIE' => 'wovn_selected_lang=en'
263
+ }
264
+ )
265
+
266
+ sut = Wovnrb::Interceptor.new(get_app, settings)
267
+ status, res_headers, _body = sut.call(env)
268
+
269
+ assert_equal(302, status)
270
+ assert_equal('http://test.com/en/foo', res_headers['location'])
271
+ end
272
+
273
+ def test_call__with_use_cookie_lang_true__request_method_is_post__should_not_redirect
274
+ settings = {
275
+ 'project_token' => '123456',
276
+ 'url_pattern' => 'path',
277
+ 'default_lang' => 'ja',
278
+ 'supported_langs' => %w[ja en],
279
+ 'use_cookie_lang' => true
280
+ }
281
+ env = Wovnrb.get_env(
282
+ {
283
+ 'url' => 'http://test.com/foo',
284
+ 'HTTP_COOKIE' => 'wovn_selected_lang=en',
285
+ 'REQUEST_METHOD' => 'POST'
286
+ }
287
+ )
288
+
289
+ sut = Wovnrb::Interceptor.new(get_app, settings)
290
+ status, res_headers, _body = sut.call(env)
291
+
292
+ assert_equal(200, status)
293
+ assert_nil(res_headers['location'])
294
+ end
295
+
296
+ def test_call__with_use_cookie_lang_true__cookie_lang_is_default_lang__should_not_redirect
297
+ settings = {
298
+ 'project_token' => '123456',
299
+ 'url_pattern' => 'path',
300
+ 'default_lang' => 'ja',
301
+ 'supported_langs' => %w[ja en],
302
+ 'use_cookie_lang' => true
303
+ }
304
+ env = Wovnrb.get_env(
305
+ {
306
+ 'url' => 'http://test.com/foo',
307
+ 'HTTP_COOKIE' => 'wovn_selected_lang=ja'
308
+ }
309
+ )
310
+
311
+ sut = Wovnrb::Interceptor.new(get_app, settings)
312
+ status, res_headers, _body = sut.call(env)
313
+
314
+ assert_equal(200, status)
315
+ assert_nil(res_headers['location'])
316
+ end
317
+
318
+ def test_call__with_use_cookie_lang_true__cookie_lang_is_different_target_lang__should_not_redirect
319
+ settings = {
320
+ 'project_token' => '123456',
321
+ 'url_pattern' => 'path',
322
+ 'default_lang' => 'ja',
323
+ 'supported_langs' => %w[ja en fr],
324
+ 'use_cookie_lang' => true
325
+ }
326
+ env = Wovnrb.get_env(
327
+ {
328
+ 'url' => 'http://test.com/en/foo',
329
+ 'HTTP_COOKIE' => 'wovn_selected_lang=fr'
330
+ }
331
+ )
332
+
333
+ mock_translation_api_response('', '')
334
+ sut = Wovnrb::Interceptor.new(get_app, settings)
335
+ status, res_headers, _body = sut.call(env)
336
+
337
+ assert_equal(200, status)
338
+ assert_nil(res_headers['location'])
339
+ end
340
+
341
+ def test_call__with_use_cookie_lang_true__cookie_lang_is_empty__should_not_redirect
342
+ settings = {
343
+ 'project_token' => '123456',
344
+ 'url_pattern' => 'path',
345
+ 'default_lang' => 'ja',
346
+ 'supported_langs' => %w[ja en],
347
+ 'use_cookie_lang' => true
348
+ }
349
+ env = Wovnrb.get_env(
350
+ {
351
+ 'url' => 'http://test.com/foo',
352
+ 'HTTP_COOKIE' => ''
353
+ }
354
+ )
355
+
356
+ sut = Wovnrb::Interceptor.new(get_app, settings)
357
+ status, res_headers, _body = sut.call(env)
358
+
359
+ assert_equal(200, status)
360
+ assert_nil(res_headers['location'])
361
+ end
362
+
363
+ def test_call__with_use_cookie_lang_false__should_not_redirect
364
+ settings = {
365
+ 'project_token' => '123456',
366
+ 'url_pattern' => 'path',
367
+ 'default_lang' => 'ja',
368
+ 'supported_langs' => %w[ja en],
369
+ 'use_cookie_lang' => false
370
+ }
371
+ env = Wovnrb.get_env(
372
+ {
373
+ 'url' => 'http://test.com/foo',
374
+ 'HTTP_COOKIE' => 'wovn_selected_lang=en'
375
+ }
376
+ )
377
+
378
+ sut = Wovnrb::Interceptor.new(get_app, settings)
379
+ status, res_headers, _body = sut.call(env)
380
+
381
+ assert_equal(200, status)
382
+ assert_nil(res_headers['location'])
383
+ end
384
+
385
+ private
386
+
387
+ def assert_call_affects_env(settings, env, mock_api:, affected:)
388
+ app_mock = get_app
389
+ sut = Wovnrb::Interceptor.new(app_mock, settings)
390
+ unaffected_env = env
391
+
392
+ mock_translation_api_response('', '') if mock_api
393
+ sut.call(env.clone)
394
+
395
+ assert_equal(unaffected_env != app_mock.env, affected)
396
+ end
397
+
398
+ def assert_switch_lang(original_lang, target_lang, body, expected_body, api_expected: true, expected_status_code: 200)
399
+ subdomain = target_lang == original_lang ? '' : "#{target_lang}."
400
+ interceptor = Wovnrb::Interceptor.new(get_app)
401
+
402
+ store, headers = store_headers_factory(subdomain, original_lang)
403
+ if api_expected
404
+ dom = Wovnrb::Helpers::NokogumboHelper.parse_html(body)
405
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
406
+ converter = Wovnrb::HtmlConverter.new(dom, store, headers, url_lang_switcher)
407
+ apified_body, = converter.build_api_compatible_html
408
+ mock_translation_api_response(apified_body, expected_body)
409
+ end
410
+
411
+ actual_bodies = interceptor.switch_lang(headers, [body], expected_status_code)
412
+
413
+ assert_same_elements([expected_body], actual_bodies)
414
+ end
415
+
416
+ def store_headers_factory(subdomain, original_lang)
417
+ settings = {
418
+ 'project_token' => '123456',
419
+ 'custom_lang_aliases' => {},
420
+ 'default_lang' => original_lang,
421
+ 'url_pattern' => 'subdomain',
422
+ 'url_pattern_reg' => '^(?<lang>[^.]+)\.'
423
+ }
424
+
425
+ store = Wovnrb::Store.instance
426
+ store.update_settings(settings)
427
+
428
+ headers = Wovnrb::Headers.new(
429
+ Wovnrb.get_env('url' => "http://#{subdomain}page.com"),
430
+ Wovnrb.get_settings(settings),
431
+ Wovnrb::UrlLanguageSwitcher.new(store)
432
+ )
433
+
434
+ [store, headers]
435
+ end
436
+
437
+ def mock_translation_api_response(body, expected_body)
438
+ Wovnrb::ApiTranslator.any_instance
439
+ .expects(:translate)
440
+ .once
441
+ .with(body)
442
+ .returns(expected_body)
443
+ end
444
+
445
+ def get_app(opts = {})
446
+ RackMock.new(opts)
447
+ end
448
+
449
+ class RackMock
450
+ attr_accessor :params, :env
451
+
452
+ def initialize(opts = {})
453
+ @params = {}
454
+ if opts.key?(:params) && opts[:params].instance_of?(Hash)
455
+ opts[:params].each do |key, val|
456
+ @params[key] = val
457
+ end
458
+ end
459
+ @request_headers = {}
460
+ end
461
+
462
+ def call(env)
463
+ @env = env
464
+ unless @params.empty?
465
+ req = Rack::Request.new(@env)
466
+ @params.each do |key, val|
467
+ req.update_param(key, val)
468
+ end
469
+ end
470
+ [200, { 'Content-Type' => 'text/html' }, ['']]
471
+ end
472
+
473
+ def [](key)
474
+ @env[key]
475
+ end
476
+ end
477
+ end