renderer_spec.rb 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe NotificationFactory::Renderer do
  4. # rubocop:disable Lint/InterpolationCheck
  5. describe 'render' do
  6. before { @user = User.where(firstname: 'Nicole').first }
  7. it 'correctly renders a blank template' do
  8. renderer = build(:notification_factory_renderer)
  9. expect(renderer.render).to eq ''
  10. end
  11. context 'when rendering templates with ERB tags' do
  12. let(:template) { '<%% <%= "<%" %> %%>' }
  13. it 'ignores pre-existing ERB tags in an untrusted template' do
  14. renderer = build(:notification_factory_renderer, template: template)
  15. expect(renderer.render).to eq '<% <%= "<%" %> %%>'
  16. end
  17. it 'executes pre-existing ERB tags in a trusted template' do
  18. renderer = build(:notification_factory_renderer, template: template, trusted: true)
  19. expect(renderer.render).to eq '<% <% %%>'
  20. end
  21. end
  22. it 'correctly renders chained object references' do
  23. user = User.where(firstname: 'Nicole').first
  24. ticket = create(:ticket, customer: user)
  25. renderer = build(:notification_factory_renderer,
  26. objects: { ticket: ticket },
  27. template: '#{ticket.customer.firstname.downcase}')
  28. expect(renderer.render).to eq 'nicole'
  29. end
  30. it 'correctly renders multiple value calls' do
  31. ticket = create(:ticket, customer: @user)
  32. renderer = build(:notification_factory_renderer,
  33. objects: { ticket: ticket },
  34. template: '#{ticket.created_at.value.value.value.value.to_s.first}')
  35. expect(renderer.render).to eq '2'
  36. end
  37. it 'raises a StandardError when rendering a template with a broken syntax' do
  38. renderer = build(:notification_factory_renderer, template: 'test <% if %>', objects: {}, trusted: true)
  39. expect { renderer.render }.to raise_error(StandardError)
  40. end
  41. it 'raises a StandardError when rendering a template calling a non existant method' do
  42. renderer = build(:notification_factory_renderer, template: 'test <% Ticket.non_existant_method %>', objects: {}, trusted: true)
  43. expect { renderer.render }.to raise_error(StandardError)
  44. end
  45. it 'raises a StandardError when rendering a template referencing a non existant object' do
  46. renderer = build(:notification_factory_renderer, template: 'test <% NonExistantObject.first %>', objects: {}, trusted: true)
  47. expect { renderer.render }.to raise_error(StandardError)
  48. end
  49. context 'with different article variables' do
  50. let(:customer) { create(:customer, firstname: 'Nicole') }
  51. let(:ticket) { create(:ticket, customer: customer) }
  52. let(:objects) do
  53. last_article = nil
  54. last_internal_article = nil
  55. last_external_article = nil
  56. all_articles = ticket.articles
  57. if article.nil?
  58. last_article = all_articles.last
  59. last_internal_article = all_articles.reverse.find(&:internal?)
  60. last_external_article = all_articles.reverse.find { |a| !a.internal? }
  61. else
  62. last_article = article
  63. last_internal_article = article.internal? ? article : all_articles.reverse.find(&:internal?)
  64. last_external_article = article.internal? ? all_articles.reverse.find { |a| !a.internal? } : article
  65. end
  66. {
  67. ticket: ticket,
  68. article: last_article,
  69. last_article: last_article,
  70. last_internal_article: last_internal_article,
  71. last_external_article: last_external_article,
  72. created_article: article,
  73. created_internal_article: article&.internal? ? article : nil,
  74. created_external_article: article&.internal? ? nil : article,
  75. }
  76. end
  77. let(:renderer) do
  78. build(:notification_factory_renderer,
  79. objects: objects,
  80. template: template)
  81. end
  82. let(:body) { 'test' }
  83. let(:article) { create(:ticket_article, ticket: ticket, body: body) }
  84. context 'with ticket.tags as template' do
  85. let(:template) { '#{ticket.tags}' }
  86. before do
  87. ticket.tag_add('Tag1', customer.id)
  88. end
  89. it 'correctly renders ticket tags references' do
  90. expect(renderer.render).to eq 'Tag1'
  91. end
  92. end
  93. %w[article last_article last_internal_article last_external_article
  94. created_article created_internal_article created_external_article].each do |tag|
  95. context "with #{tag}.body as template" do
  96. let(:template) { "\#{#{tag}.body}" }
  97. let(:article) do
  98. create(
  99. :ticket_article,
  100. ticket: ticket,
  101. body: body,
  102. internal: tag.match?('internal')
  103. )
  104. end
  105. it "renders an #{tag} body with quote" do
  106. expect(renderer.render).to eq "&gt; #{body}<br>"
  107. end
  108. end
  109. end
  110. end
  111. context 'when handling ObjectManager::Attribute usage', db_strategy: :reset do
  112. before do
  113. create_object_manager_attribute
  114. ObjectManager::Attribute.migration_execute
  115. end
  116. let(:renderer) do
  117. build(:notification_factory_renderer,
  118. objects: { ticket: ticket },
  119. template: template)
  120. end
  121. shared_examples 'correctly rendering the attributes' do
  122. it 'correctly renders the attributes' do
  123. expect(renderer.render).to eq expected_render
  124. end
  125. end
  126. context 'with a simple select attribute' do
  127. let(:create_object_manager_attribute) do
  128. create(:object_manager_attribute_select, name: 'select')
  129. end
  130. let(:ticket) { create(:ticket, customer: @user, select: 'key_1') }
  131. let(:template) { '#{ticket.select} _SEPERATOR_ #{ticket.select.value}' }
  132. let(:expected_render) { 'key_1 _SEPERATOR_ value_1' }
  133. it_behaves_like 'correctly rendering the attributes'
  134. end
  135. context 'with select attribute on chained user object' do
  136. let(:create_object_manager_attribute) do
  137. create(:object_manager_attribute_select,
  138. object_lookup_id: ObjectLookup.by_name('User'),
  139. name: 'select')
  140. end
  141. let(:user) do
  142. user = User.where(firstname: 'Nicole').first
  143. user.select = 'key_2'
  144. user.save
  145. user
  146. end
  147. let(:ticket) { create(:ticket, customer: user) }
  148. let(:template) { '#{ticket.customer.select} _SEPERATOR_ #{ticket.customer.select.value}' }
  149. let(:expected_render) { 'key_2 _SEPERATOR_ value_2' }
  150. it_behaves_like 'correctly rendering the attributes'
  151. end
  152. context 'with select attribute on chained group object' do
  153. let(:create_object_manager_attribute) do
  154. create(:object_manager_attribute_select,
  155. object_lookup_id: ObjectLookup.by_name('Group'),
  156. name: 'select')
  157. end
  158. let(:template) { '#{ticket.group.select} _SEPERATOR_ #{ticket.group.select.value}' }
  159. let(:expected_render) { 'key_3 _SEPERATOR_ value_3' }
  160. let(:ticket) { create(:ticket, customer: @user) }
  161. before do
  162. group = ticket.group
  163. group.select = 'key_3'
  164. group.save
  165. end
  166. it_behaves_like 'correctly rendering the attributes'
  167. end
  168. context 'with select attribute on chained organization object' do
  169. let(:create_object_manager_attribute) do
  170. create(:object_manager_attribute_select,
  171. object_lookup_id: ObjectLookup.by_name('Organization'),
  172. name: 'select')
  173. end
  174. let(:user) do
  175. @user.organization.select = 'key_2'
  176. @user.organization.save
  177. @user
  178. end
  179. let(:ticket) { create(:ticket, customer: user) }
  180. let(:template) { '#{ticket.customer.organization.select} _SEPERATOR_ #{ticket.customer.organization.select.value}' }
  181. let(:expected_render) { 'key_2 _SEPERATOR_ value_2' }
  182. it_behaves_like 'correctly rendering the attributes'
  183. end
  184. context 'with multiselect', mariadb: true do
  185. context 'with a simple multiselect attribute' do
  186. let(:create_object_manager_attribute) do
  187. create(:object_manager_attribute_multiselect, name: 'multiselect')
  188. end
  189. let(:ticket) { create(:ticket, customer: @user, multiselect: ['key_1']) }
  190. let(:template) { '#{ticket.multiselect} _SEPERATOR_ #{ticket.multiselect.value}' }
  191. let(:expected_render) { 'key_1 _SEPERATOR_ value_1' }
  192. it_behaves_like 'correctly rendering the attributes'
  193. end
  194. context 'with single multiselect attribute on chained user object' do
  195. let(:create_object_manager_attribute) do
  196. create(:object_manager_attribute_multiselect,
  197. object_lookup_id: ObjectLookup.by_name('User'),
  198. name: 'multiselect')
  199. end
  200. let(:user) do
  201. user = User.where(firstname: 'Nicole').first
  202. user.multiselect = ['key_2']
  203. user.save
  204. user
  205. end
  206. let(:ticket) { create(:ticket, customer: user) }
  207. let(:template) { '#{ticket.customer.multiselect} _SEPERATOR_ #{ticket.customer.multiselect.value}' }
  208. let(:expected_render) { 'key_2 _SEPERATOR_ value_2' }
  209. it_behaves_like 'correctly rendering the attributes'
  210. end
  211. context 'with single multiselect attribute on chained group object' do
  212. let(:create_object_manager_attribute) do
  213. create(:object_manager_attribute_multiselect,
  214. object_lookup_id: ObjectLookup.by_name('Group'),
  215. name: 'multiselect')
  216. end
  217. let(:template) { '#{ticket.group.multiselect} _SEPERATOR_ #{ticket.group.multiselect.value}' }
  218. let(:expected_render) { 'key_3 _SEPERATOR_ value_3' }
  219. let(:ticket) { create(:ticket, customer: @user) }
  220. before do
  221. group = ticket.group
  222. group.multiselect = ['key_3']
  223. group.save
  224. end
  225. it_behaves_like 'correctly rendering the attributes'
  226. end
  227. context 'with single multiselect attribute on chained organization object' do
  228. let(:create_object_manager_attribute) do
  229. create(:object_manager_attribute_multiselect,
  230. object_lookup_id: ObjectLookup.by_name('Organization'),
  231. name: 'multiselect')
  232. end
  233. let(:user) do
  234. @user.organization.multiselect = ['key_2']
  235. @user.organization.save
  236. @user
  237. end
  238. let(:ticket) { create(:ticket, customer: user) }
  239. let(:template) { '#{ticket.customer.organization.multiselect} _SEPERATOR_ #{ticket.customer.organization.multiselect.value}' }
  240. let(:expected_render) { 'key_2 _SEPERATOR_ value_2' }
  241. it_behaves_like 'correctly rendering the attributes'
  242. end
  243. context 'with a multiple multiselect attribute' do
  244. let(:create_object_manager_attribute) do
  245. create(:object_manager_attribute_multiselect, name: 'multiselect')
  246. end
  247. let(:ticket) { create(:ticket, customer: @user, multiselect: %w[key_1 key_2]) }
  248. let(:template) { '#{ticket.multiselect} _SEPERATOR_ #{ticket.multiselect.value}' }
  249. let(:expected_render) { 'key_1, key_2 _SEPERATOR_ value_1, value_2' }
  250. it_behaves_like 'correctly rendering the attributes'
  251. end
  252. context 'with multiple multiselect attribute on chained user object' do
  253. let(:create_object_manager_attribute) do
  254. create(:object_manager_attribute_multiselect,
  255. object_lookup_id: ObjectLookup.by_name('User'),
  256. name: 'multiselect')
  257. end
  258. let(:user) do
  259. user = User.where(firstname: 'Nicole').first
  260. user.multiselect = %w[key_2 key_3]
  261. user.save
  262. user
  263. end
  264. let(:ticket) { create(:ticket, customer: user) }
  265. let(:template) { '#{ticket.customer.multiselect} _SEPERATOR_ #{ticket.customer.multiselect.value}' }
  266. let(:expected_render) { 'key_2, key_3 _SEPERATOR_ value_2, value_3' }
  267. it_behaves_like 'correctly rendering the attributes'
  268. end
  269. context 'with multiple multiselect attribute on chained group object' do
  270. let(:create_object_manager_attribute) do
  271. create(:object_manager_attribute_multiselect,
  272. object_lookup_id: ObjectLookup.by_name('Group'),
  273. name: 'multiselect')
  274. end
  275. let(:template) { '#{ticket.group.multiselect} _SEPERATOR_ #{ticket.group.multiselect.value}' }
  276. let(:expected_render) { 'key_3, key_1 _SEPERATOR_ value_3, value_1' }
  277. let(:ticket) { create(:ticket, customer: @user) }
  278. before do
  279. group = ticket.group
  280. group.multiselect = %w[key_3 key_1]
  281. group.save
  282. end
  283. it_behaves_like 'correctly rendering the attributes'
  284. end
  285. context 'with multiple multiselect attribute on chained organization object' do
  286. let(:create_object_manager_attribute) do
  287. create(:object_manager_attribute_multiselect,
  288. object_lookup_id: ObjectLookup.by_name('Organization'),
  289. name: 'multiselect')
  290. end
  291. let(:user) do
  292. @user.organization.multiselect = %w[key_2 key_1]
  293. @user.organization.save
  294. @user
  295. end
  296. let(:ticket) { create(:ticket, customer: user) }
  297. let(:template) { '#{ticket.customer.organization.multiselect} _SEPERATOR_ #{ticket.customer.organization.multiselect.value}' }
  298. let(:expected_render) { 'key_2, key_1 _SEPERATOR_ value_2, value_1' }
  299. it_behaves_like 'correctly rendering the attributes'
  300. end
  301. end
  302. context 'with a tree select attribute' do
  303. let(:create_object_manager_attribute) do
  304. create(:object_manager_attribute_tree_select, name: 'tree_select')
  305. end
  306. let(:ticket) { create(:ticket, customer: @user, tree_select: 'Incident::Hardware::Laptop') }
  307. let(:template) { '#{ticket.tree_select} _SEPERATOR_ #{ticket.tree_select.value}' }
  308. let(:expected_render) { 'Incident::Hardware::Laptop _SEPERATOR_ Incident::Hardware::Laptop' }
  309. it_behaves_like 'correctly rendering the attributes'
  310. end
  311. end
  312. end
  313. # rubocop:enable Lint/InterpolationCheck
  314. end