view_spec.rb 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe 'Ticket views', authenticated_as: :authenticate, type: :system do
  4. def authenticate
  5. true
  6. end
  7. context 'when calling without session' do
  8. describe 'redirect to' do
  9. it 'login screen after certain overview was called', authenticated_as: false do
  10. visit '#ticket/view/all_open'
  11. expect(page).to have_css('#login')
  12. end
  13. it 'login screen after not overview was called', authenticated_as: false do
  14. visit '#ticket/view'
  15. expect(page).to have_css('#login')
  16. end
  17. end
  18. end
  19. context 'macros' do
  20. let(:group1) { create(:group) }
  21. let(:group2) { create(:group) }
  22. let(:macro_without_group) { create(:macro) }
  23. let(:macro_note) { create(:macro, perform: { 'article.note'=>{ 'body' => 'macro body', 'internal' => 'true', 'subject' => 'macro note' } }) }
  24. let(:macro_group1) { create(:macro, groups: [group1]) }
  25. let(:macro_group2) { create(:macro, groups: [group2]) }
  26. let(:ticket1) { create(:ticket, group: group1) }
  27. let(:ticket2) { create(:ticket, group: group2) }
  28. describe 'group-dependent macros' do
  29. let(:agent) { create(:agent, groups: Group.all) }
  30. def authenticate
  31. ticket1 && ticket2
  32. macro_without_group && macro_group1 && macro_group2
  33. agent
  34. end
  35. it 'shows only non-group macro when ticket does not match any group macros' do
  36. visit '#ticket/view/all_open'
  37. within(:active_content) do
  38. display_macro_batches Ticket.first
  39. expect(page).to have_selector(:macro_batch, macro_without_group.id)
  40. .and(have_no_selector(:macro_batch, macro_group1.id))
  41. .and(have_no_selector(:macro_batch, macro_group2.id))
  42. end
  43. end
  44. it 'shows non-group and matching group macros for matching ticket' do
  45. visit '#ticket/view/all_open'
  46. within(:active_content) do
  47. display_macro_batches ticket1
  48. expect(page).to have_selector(:macro_batch, macro_without_group.id)
  49. .and(have_selector(:macro_batch, macro_group1.id))
  50. .and(have_no_selector(:macro_batch, macro_group2.id))
  51. end
  52. end
  53. end
  54. describe 'macro article creation' do
  55. def authenticate
  56. macro_note
  57. true
  58. end
  59. it 'can use macro to create article' do
  60. visit '#ticket/view/all_open'
  61. within(:active_content) do
  62. display_macro_batches Ticket.first
  63. move_mouse_to find(:macro_batch, macro_note.id)
  64. release_mouse
  65. expect do
  66. wait.until { Ticket.first.articles.last.subject == 'macro note' }
  67. end.not_to raise_error
  68. end
  69. end
  70. end
  71. context 'when saving is blocked by one of selected tickets' do
  72. let(:ticket) { Ticket.first }
  73. let(:core_workflow_action) { { 'ticket.priority_id': { operator: 'remove_option', remove_option: '3' } } }
  74. let(:core_workflow) { create(:core_workflow, :active_and_screen, :perform_action) }
  75. let(:macro_perform) do
  76. {
  77. 'ticket.priority_id': { pre_condition: 'specific', value: 3.to_s }
  78. }
  79. end
  80. let(:macro_priority) { create(:macro, perform: macro_perform) }
  81. def authenticate
  82. core_workflow && macro_priority && ticket1
  83. true
  84. end
  85. it 'shows modal with blocking ticket title' do
  86. visit '#ticket/view/all_open'
  87. within(:active_content) do
  88. display_macro_batches ticket
  89. move_mouse_to find(:macro_batch, macro_priority.id)
  90. release_mouse
  91. in_modal do
  92. expect(page).to have_text(ticket.title)
  93. end
  94. end
  95. end
  96. end
  97. describe 'when agent cannot change some of the tickets' do
  98. let(:agent) { create(:agent) }
  99. def authenticate
  100. macro_without_group
  101. agent
  102. .tap { |user| user.user_groups.create! group: ticket1.group, access: 'full' }
  103. .tap { |user| user.user_groups.create! group: ticket2.group, access: 'overview' }
  104. end
  105. before do
  106. visit '#ticket/view/all_open'
  107. end
  108. it 'show macros if agent cannot change selected tickets' do
  109. display_macro_batches ticket1
  110. within(:active_content) do
  111. expect(page).to have_no_text(%r{No macros available}i)
  112. .and(have_selector(:macro_batch, macro_without_group.id))
  113. end
  114. end
  115. it 'show no macros if agent cannot change selected tickets' do
  116. display_macro_batches ticket2
  117. within(:active_content) do
  118. expect(page).to have_text(%r{No macros available}i)
  119. .and(have_text(%r{no change permission}i))
  120. .and(have_no_selector(:macro_batch, macro_without_group.id))
  121. end
  122. end
  123. end
  124. describe 'when user is agent-customer' do
  125. let(:agent_customer) { create(:agent_and_customer) }
  126. def authenticate
  127. ticket1.update!(customer: agent_customer)
  128. ticket2
  129. macro_without_group && macro_group1 && macro_group2
  130. agent_customer
  131. .tap { |user| user.groups << ticket2.group }
  132. end
  133. before do
  134. visit '#ticket/view/all_open'
  135. end
  136. it 'show no macros if the ticket is customer-like' do
  137. display_macro_batches ticket1
  138. within :active_content do
  139. expect(page).to have_text(%r{No macros available}i)
  140. .and(have_text(%r{no change permission}i))
  141. .and(have_no_selector(:macro_batch, macro_without_group.id))
  142. .and(have_no_selector(:macro_batch, macro_group1.id))
  143. .and(have_no_selector(:macro_batch, macro_group2.id))
  144. end
  145. end
  146. it 'show macros if tickets are only agent-like' do
  147. display_macro_batches ticket2
  148. within :active_content do
  149. expect(page).to have_no_text(%r{No macros available}i)
  150. .and(have_selector(:macro_batch, macro_without_group.id))
  151. .and(have_no_selector(:macro_batch, macro_group1.id))
  152. .and(have_selector(:macro_batch, macro_group2.id))
  153. end
  154. end
  155. end
  156. describe 'when user is customer' do
  157. let(:customer) { create(:customer) }
  158. def authenticate
  159. ticket1.update!(customer: customer)
  160. customer
  161. end
  162. before do
  163. visit '#ticket/view/my_tickets'
  164. end
  165. it 'shows no overlay' do
  166. display_macro_batches ticket1
  167. within :active_content do
  168. expect(page).to have_no_selector('.batch-overlay-backdrop')
  169. end
  170. end
  171. end
  172. context 'with macro batch overlay' do
  173. shared_examples "adding 'small' class to macro element" do
  174. it 'adds a "small" class to the macro element' do
  175. within(:active_content) do
  176. display_macro_batches Ticket.first
  177. expect(page).to have_css('.batch-overlay-macro-entry.small')
  178. end
  179. end
  180. end
  181. shared_examples "not adding 'small' class to macro element" do
  182. it 'does not add a "small" class to the macro element' do
  183. within(:active_content) do
  184. display_macro_batches Ticket.first
  185. expect(page).to have_no_selector('.batch-overlay-macro-entry.small')
  186. end
  187. end
  188. end
  189. shared_examples 'showing all macros' do
  190. it 'shows all macros' do
  191. within(:active_content) do
  192. display_macro_batches Ticket.first
  193. expect(page).to have_css('.batch-overlay-macro-entry', count: all)
  194. end
  195. end
  196. end
  197. shared_examples 'showing some macros' do |count|
  198. it 'shows all macros' do
  199. within(:active_content) do
  200. display_macro_batches Ticket.first
  201. expect(page).to have_css('.batch-overlay-macro-entry', count: count)
  202. end
  203. end
  204. end
  205. def authenticate
  206. Macro.destroy_all && create_list(:macro, all)
  207. true
  208. end
  209. before do
  210. visit '#ticket/view/all_open'
  211. end
  212. context 'with few macros' do
  213. let(:all) { 15 }
  214. context 'when on large screen', screen_size: :desktop do
  215. it_behaves_like 'showing all macros'
  216. it_behaves_like "not adding 'small' class to macro element"
  217. end
  218. context 'when on small screen', screen_size: :tablet do
  219. it_behaves_like 'showing all macros'
  220. it_behaves_like "not adding 'small' class to macro element"
  221. end
  222. end
  223. context 'with many macros' do
  224. let(:all) { 50 }
  225. context 'when on large screen', screen_size: :desktop do
  226. it_behaves_like 'showing some macros', 32
  227. end
  228. context 'when on small screen', screen_size: :tablet do
  229. it_behaves_like 'showing some macros', 24
  230. it_behaves_like "adding 'small' class to macro element"
  231. end
  232. end
  233. end
  234. end
  235. context 'when performing a Bulk action' do
  236. context 'when creating a Note', authenticated_as: :user do
  237. let(:group) { create(:group) }
  238. let(:user) { create(:admin, groups: [group]) }
  239. let(:ticket1) { create(:ticket, state_name: 'open', owner: user, group: group) }
  240. let(:ticket2) { create(:ticket, state_name: 'open', owner: user, group: group) }
  241. let(:note) { Faker::Lorem.sentence }
  242. it 'adds note to all selected tickets' do
  243. ticket1 && ticket2
  244. visit 'ticket/view/my_assigned'
  245. within :active_content do
  246. all('.js-checkbox-field', count: 2).each(&:click)
  247. click '.js-confirm'
  248. find('.js-confirm-step textarea').fill_in with: note
  249. click '.js-submit'
  250. end
  251. expect do
  252. wait.until { [ ticket1.articles.last&.body, ticket2.articles.last&.body ] == [note, note] }
  253. end.not_to raise_error
  254. end
  255. end
  256. # https://github.com/zammad/zammad/issues/3568
  257. # We need a manual ticket creation to test the correct behaviour of the bulk functionality, because of some
  258. # leftovers after the creation in the the javascript assets store.
  259. context 'when performed a manual Ticket creation', authenticated_as: :agent do
  260. let(:customer) { create(:customer) }
  261. let(:group) { Group.find_by(name: 'Users') }
  262. let(:agent) { create(:agent, groups: [group]) }
  263. let!(:template) { create(:template, :dummy_data, group: group, owner: agent, customer: customer) }
  264. before do
  265. visit 'ticket/create'
  266. within(:active_content) do
  267. use_template(template)
  268. click('.js-submit')
  269. find('.ticket-article-item')
  270. end
  271. end
  272. it 'check that no duplicated article was created after usage of bulk action' do
  273. click('.menu-item[href="#ticket/view"]')
  274. created_ticket_id = Ticket.last.id
  275. within(:active_content) do
  276. click("tr[data-id='#{created_ticket_id}'] .js-checkbox-field")
  277. find('select[name="priority_id"] option[value="1"]').select_option
  278. click('.js-confirm')
  279. click('.js-submit')
  280. await_empty_ajax_queue
  281. # Check if still only one article exists on the ticket.
  282. click("tr[data-id='#{created_ticket_id}'] a")
  283. expect(page).to have_css('.ticket-article-item', count: 1)
  284. end
  285. end
  286. end
  287. context 'when saving is blocked by one of selected tickets', authenticated_as: :pre_authentication do
  288. let(:core_workflow) { create(:core_workflow, :active_and_screen, :perform_action) }
  289. let(:ticket1) { create(:ticket, group: Group.first) }
  290. def pre_authentication
  291. core_workflow && ticket1
  292. true
  293. end
  294. it 'shows modal with blocking ticket title' do
  295. visit 'ticket/view/all_open'
  296. within(:active_content) do
  297. find("tr[data-id='#{ticket1.id}']").check('bulk', allow_label_click: true)
  298. select '3 high', from: 'priority_id'
  299. click '.js-confirm'
  300. click '.js-submit'
  301. in_modal do
  302. expect(page).to have_text(ticket1.title)
  303. end
  304. end
  305. end
  306. end
  307. end
  308. context 'Setting "ui_table_group_by_show_count"', authenticated_as: :authenticate, db_strategy: :reset do
  309. let(:custom_attribute) { create(:object_manager_attribute_select, name: 'grouptest') }
  310. let(:tickets) do
  311. [
  312. create(:ticket, group: Group.find_by(name: 'Users')),
  313. create(:ticket, group: Group.find_by(name: 'Users'), grouptest: 'key_1'),
  314. create(:ticket, group: Group.find_by(name: 'Users'), grouptest: 'key_2'),
  315. create(:ticket, group: Group.find_by(name: 'Users'), grouptest: 'key_1')
  316. ]
  317. end
  318. def authenticate
  319. custom_attribute
  320. ObjectManager::Attribute.migration_execute
  321. tickets
  322. Overview.find_by(name: 'Open Tickets').update(group_by: custom_attribute.name)
  323. Setting.set('ui_table_group_by_show_count', true)
  324. true
  325. end
  326. it 'shows correct ticket counts' do
  327. visit 'ticket/view/all_open'
  328. within(:active_content) do
  329. expect(page).to have_css('.js-tableBody td b', text: '(1)')
  330. .and(have_css('.js-tableBody td b', text: 'value_1 (2)'))
  331. .and(have_css('.js-tableBody td b', text: 'value_2 (1)'))
  332. end
  333. end
  334. end
  335. context 'Customer', authenticated_as: :authenticate do
  336. let(:customer) { create(:customer, :with_org) }
  337. let(:ticket) { create(:ticket, customer: customer) }
  338. def authenticate
  339. ticket
  340. customer
  341. end
  342. it 'shows ticket in my tickets' do
  343. visit 'ticket/view/my_tickets'
  344. expect(page).to have_text(ticket.title)
  345. end
  346. it 'shows ticket in my organization tickets' do
  347. visit 'ticket/view/my_tickets'
  348. click_on 'My Organization Tickets'
  349. expect(page).to have_text(ticket.title)
  350. end
  351. end
  352. describe 'Grouping by custom attribute', authenticated_as: :authenticate, db_strategy: :reset do
  353. def authenticate
  354. custom_attribute
  355. ObjectManager::Attribute.migration_execute
  356. tickets
  357. Overview.find_by(link: 'all_unassigned').update(group_by: custom_attribute.name)
  358. true
  359. end
  360. context 'when sorted by custom object date' do
  361. let(:custom_attribute) { create(:object_manager_attribute_date, name: 'cdate') }
  362. let(:tickets) do
  363. [
  364. create(:ticket, group: Group.find_by(name: 'Users'), cdate: '2021-08-18'),
  365. create(:ticket, group: Group.find_by(name: 'Users'), cdate: '2019-01-19'),
  366. create(:ticket, group: Group.find_by(name: 'Users'), cdate: '2018-01-17'),
  367. create(:ticket, group: Group.find_by(name: 'Users'), cdate: '2018-08-19')
  368. ]
  369. end
  370. it 'does show the values grouped and sorted by date key value (yyy-mm-dd) instead of display value' do
  371. visit 'ticket/view/all_unassigned'
  372. headers = all('.js-tableBody td[colspan="6"]').map(&:text)
  373. expect(headers).to eq ['01/17/2018', '08/19/2018', '01/19/2019', '08/18/2021', '-']
  374. end
  375. end
  376. context 'when sorted by custom object select', authenticated_as: :authenticate, db_strategy: :reset do
  377. let(:custom_attribute) do
  378. create(:object_manager_attribute_select,
  379. name: 'cselect',
  380. data_option_options: {
  381. 'a' => 'Zzz a',
  382. 'b' => 'Yyy b',
  383. 'c' => 'Xxx c',
  384. })
  385. end
  386. let(:tickets) do
  387. [
  388. create(:ticket, group: Group.find_by(name: 'Users'), cselect: 'a'),
  389. create(:ticket, group: Group.find_by(name: 'Users'), cselect: 'b'),
  390. create(:ticket, group: Group.find_by(name: 'Users'), cselect: 'c')
  391. ]
  392. end
  393. it 'does show the values grouped and sorted by display value instead of key value' do
  394. visit 'ticket/view/all_unassigned'
  395. headers = all('.js-tableBody td[colspan="6"]').map(&:text)
  396. expect(headers).to eq ['-', 'Xxx c', 'Yyy b', 'Zzz a']
  397. end
  398. end
  399. end
  400. context 'Overview is not refreshing #5260', authenticated_as: :agent, sessions_jobs: true do
  401. let(:agent) { create(:agent, groups: Group.all) }
  402. let(:ticket) { Ticket.first }
  403. let(:new_title_1) { SecureRandom.uuid }
  404. let(:new_title_2) { SecureRandom.uuid }
  405. let(:new_title_3) { SecureRandom.uuid }
  406. before do
  407. visit '#ticket/view/all_open'
  408. ensure_websocket
  409. end
  410. it 'does refresh the ticket after the title has changed' do
  411. expect(page).to have_text(ticket.title)
  412. ticket.update(title: new_title_1)
  413. expect(page).to have_text(ticket.title)
  414. ticket.update(title: new_title_2)
  415. expect(page).to have_text(ticket.title)
  416. ticket.update(title: new_title_3)
  417. expect(page).to have_text(ticket.title)
  418. end
  419. end
  420. end