translate_status_service_spec.rb 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe TranslateStatusService do
  4. subject(:service) { described_class.new }
  5. let(:status) { Fabricate(:status, text: text, spoiler_text: spoiler_text, language: 'en', preloadable_poll: poll, media_attachments: media_attachments) }
  6. let(:text) { 'Hello' }
  7. let(:spoiler_text) { '' }
  8. let(:poll) { nil }
  9. let(:media_attachments) { [] }
  10. before do
  11. Fabricate(:custom_emoji, shortcode: 'highfive')
  12. end
  13. describe '#call' do
  14. before do
  15. translation_service = TranslationService.new
  16. allow(translation_service).to receive(:languages).and_return({ 'en' => ['es', 'es-MX'] })
  17. allow(translation_service).to receive(:translate) do |texts|
  18. texts.map do |text|
  19. TranslationService::Translation.new(
  20. text: text.gsub('Hello', 'Hola').gsub('higfive', 'cincoaltos'),
  21. detected_source_language: 'en',
  22. provider: 'Dummy'
  23. )
  24. end
  25. end
  26. allow(TranslationService).to receive_messages(configured?: true, configured: translation_service)
  27. end
  28. it 'returns translated status content and source language and provider and original status' do
  29. expect(service.call(status, 'es'))
  30. .to have_attributes(
  31. content: '<p>Hola</p>',
  32. detected_source_language: 'en',
  33. language: 'es',
  34. provider: 'Dummy',
  35. status: status
  36. )
  37. end
  38. describe 'status has content with custom emoji' do
  39. let(:text) { 'Hello & :highfive:' }
  40. it 'does not translate shortcode' do
  41. expect(service.call(status, 'es').content).to eq '<p>Hola &amp; :highfive:</p>'
  42. end
  43. end
  44. describe 'status has no spoiler_text' do
  45. it 'returns an empty string' do
  46. expect(service.call(status, 'es').spoiler_text).to eq ''
  47. end
  48. end
  49. describe 'status has spoiler_text' do
  50. let(:spoiler_text) { 'Hello & Hello!' }
  51. it 'translates the spoiler text' do
  52. expect(service.call(status, 'es').spoiler_text).to eq 'Hola & Hola!'
  53. end
  54. end
  55. describe 'status has spoiler_text with custom emoji' do
  56. let(:spoiler_text) { 'Hello :highfive:' }
  57. it 'does not translate shortcode' do
  58. expect(service.call(status, 'es').spoiler_text).to eq 'Hola :highfive:'
  59. end
  60. end
  61. describe 'status has spoiler_text with unmatched custom emoji' do
  62. let(:spoiler_text) { 'Hello :Hello:' }
  63. it 'translates the invalid shortcode' do
  64. expect(service.call(status, 'es').spoiler_text).to eq 'Hola :Hola:'
  65. end
  66. end
  67. describe 'status has poll' do
  68. let(:poll) { Fabricate(:poll, options: ['Hello 1', 'Hello 2']) }
  69. it 'translates the poll option title' do
  70. status_translation = service.call(status, 'es')
  71. expect(status_translation.poll_options.size).to eq 2
  72. expect(status_translation.poll_options.first.title).to eq 'Hola 1'
  73. end
  74. end
  75. describe 'status has media attachment' do
  76. let(:media_attachments) { [Fabricate(:media_attachment, description: 'Hello & :highfive:')] }
  77. it 'translates the media attachment description' do
  78. status_translation = service.call(status, 'es')
  79. media_attachment = status_translation.media_attachments.first
  80. expect(media_attachment.id).to eq media_attachments.first.id
  81. expect(media_attachment.description).to eq 'Hola & :highfive:'
  82. end
  83. end
  84. describe 'target language is regional' do
  85. it 'uses regional variant' do
  86. expect(service.call(status, 'es-MX').language).to eq 'es-MX'
  87. end
  88. it 'uses parent locale for unsupported regional variant' do
  89. expect(service.call(status, 'es-XX').language).to eq 'es'
  90. end
  91. end
  92. end
  93. describe '#source_texts' do
  94. before do
  95. service.instance_variable_set(:@status, status)
  96. end
  97. describe 'status only has content' do
  98. it 'returns formatted content' do
  99. expect(service.send(:source_texts)).to eq({ content: '<p>Hello</p>' })
  100. end
  101. end
  102. describe 'status content contains custom emoji' do
  103. let(:status) { Fabricate(:status, text: 'Hello :highfive:') }
  104. it 'returns formatted content' do
  105. source_texts = service.send(:source_texts)
  106. expect(source_texts[:content]).to eq '<p>Hello <span translate="no">:highfive:</span></p>'
  107. end
  108. end
  109. describe 'status content contains tags' do
  110. let(:status) { Fabricate(:status, text: 'Hello #hola') }
  111. it 'returns formatted content' do
  112. source_texts = service.send(:source_texts)
  113. expect(source_texts[:content]).to include '<p>Hello <a'
  114. expect(source_texts[:content]).to include '/tags/hola'
  115. end
  116. end
  117. describe 'status has spoiler text' do
  118. let(:status) { Fabricate(:status, spoiler_text: 'Hello :highfive:') }
  119. it 'returns formatted spoiler text' do
  120. source_texts = service.send(:source_texts)
  121. expect(source_texts[:spoiler_text]).to eq 'Hello <span translate="no">:highfive:</span>'
  122. end
  123. end
  124. describe 'status has poll' do
  125. let(:poll) { Fabricate(:poll, options: %w(Blue Green)) }
  126. context 'with source texts from the service' do
  127. let!(:source_texts) { service.send(:source_texts) }
  128. it 'returns formatted poll options' do
  129. expect(source_texts)
  130. .to have_attributes(
  131. size: 3,
  132. values: %w(<p>Hello</p> Blue Green),
  133. keys: contain_exactly(
  134. eq(:content),
  135. be_a(Poll::Option).and(have_attributes(id: '0', title: 'Blue')),
  136. be_a(Poll::Option).and(have_attributes(id: '1', title: 'Green'))
  137. )
  138. )
  139. end
  140. end
  141. end
  142. describe 'status has poll with custom emoji' do
  143. let(:poll) { Fabricate(:poll, options: ['Blue', 'Green :highfive:']) }
  144. it 'returns formatted poll options' do
  145. html = service.send(:source_texts).values.last
  146. expect(html).to eq 'Green <span translate="no">:highfive:</span>'
  147. end
  148. end
  149. describe 'status has media attachments' do
  150. let(:text) { '' }
  151. let(:media_attachments) { [Fabricate(:media_attachment, description: 'Hello :highfive:')] }
  152. it 'returns media attachments without custom emoji rendering' do
  153. source_texts = service.send(:source_texts)
  154. expect(source_texts.size).to eq 1
  155. key, text = source_texts.first
  156. expect(key).to eq media_attachments.first
  157. expect(text).to eq 'Hello :highfive:'
  158. end
  159. end
  160. end
  161. describe '#wrap_emoji_shortcodes' do
  162. before do
  163. service.instance_variable_set(:@status, status)
  164. end
  165. describe 'string contains custom emoji' do
  166. let(:text) { ':highfive:' }
  167. it 'renders the emoji' do
  168. html = service.send(:wrap_emoji_shortcodes, 'Hello :highfive:'.html_safe)
  169. expect(html).to eq 'Hello <span translate="no">:highfive:</span>'
  170. end
  171. end
  172. end
  173. describe '#unwrap_emoji_shortcodes' do
  174. describe 'string contains custom emoji' do
  175. it 'inserts the shortcode' do
  176. fragment = service.send(:unwrap_emoji_shortcodes, '<p>Hello <span translate="no">:highfive:</span>!</p>')
  177. expect(fragment.to_html).to eq '<p>Hello :highfive:!</p>'
  178. end
  179. it 'preserves other attributes than translate=no' do
  180. fragment = service.send(:unwrap_emoji_shortcodes, '<p>Hello <span translate="no" class="foo">:highfive:</span>!</p>')
  181. expect(fragment.to_html).to eq '<p>Hello <span class="foo">:highfive:</span>!</p>'
  182. end
  183. end
  184. end
  185. end