wovnrb 3.11.0 → 3.11.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)
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])
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