update_spec.rb 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'system/examples/text_modules_examples'
  4. require 'system/examples/macros_examples'
  5. RSpec.describe 'Ticket Update', type: :system do
  6. let(:group) { Group.find_by(name: 'Users') }
  7. let(:ticket) { create(:ticket, group: group) }
  8. # Regression test for issue #2242 - mandatory fields can be empty (or "-") on ticket update
  9. context 'when updating a ticket without its required select attributes' do
  10. it 'frontend checks reject the update', db_strategy: :reset do
  11. # setup and migrate a required select attribute
  12. attribute = create_attribute(:object_manager_attribute_select, :required_screen,
  13. data_option: {
  14. options: {
  15. 'name 1': 'name 1',
  16. 'name 2': 'name 2',
  17. },
  18. default: '',
  19. null: false,
  20. relation: '',
  21. maxlength: 255,
  22. nulloption: true,
  23. })
  24. # create a new ticket and attempt to update its state without the required select attribute
  25. visit "#ticket/zoom/#{ticket.id}"
  26. within(:active_content) do
  27. expect(page).to have_css('.js-objectNumber', text: ticket.number)
  28. select('closed', from: 'state_id')
  29. click('.js-attributeBar .js-submit')
  30. expect(page).to have_no_css('.js-submitDropdown .js-submit[disabled]')
  31. end
  32. # the update should have failed and thus the ticket is still in the new state
  33. expect(ticket.reload.state.name).to eq('new')
  34. within(:active_content) do
  35. # update should work now
  36. find(".edit [name=#{attribute.name}]").select('name 2')
  37. click('.js-attributeBar .js-submit')
  38. expect(page).to have_no_css('.js-submitDropdown .js-submit[disabled]')
  39. end
  40. ticket.reload
  41. expect(ticket[attribute.name]).to eq('name 2')
  42. expect(ticket.state.name).to eq('closed')
  43. end
  44. end
  45. context 'when updating a ticket date attribute', db_strategy: :reset do
  46. let!(:date_attribute) do
  47. create_attribute(
  48. :object_manager_attribute_date,
  49. name: 'example_date',
  50. screens: {
  51. create: {
  52. 'ticket.agent' => {
  53. shown: true
  54. },
  55. },
  56. edit: {
  57. 'ticket.agent' => {
  58. shown: true
  59. }
  60. },
  61. view: {
  62. 'ticket.agent' => {
  63. shown: true
  64. },
  65. }
  66. },
  67. data_option: {
  68. 'future' => true,
  69. 'past' => false,
  70. 'diff' => 0,
  71. 'null' => true,
  72. }
  73. )
  74. end
  75. let(:ticket) { create(:ticket, group: group, "#{date_attribute.name}": '2018-02-28') }
  76. it 'set date attribute to empty' do
  77. visit "#ticket/zoom/#{ticket.id}"
  78. within(:active_content) do
  79. check_date_field_value(date_attribute.name, '02/28/2018')
  80. set_date_field_value(date_attribute.name, '')
  81. click('.js-attributeBar .js-submit')
  82. expect(page).to have_no_css('.js-submitDropdown .js-submit[disabled]')
  83. ticket.reload
  84. expect(ticket[date_attribute.name]).to be_nil
  85. end
  86. end
  87. end
  88. context 'when updating a ticket with macro' do
  89. context 'when required tree_select field is present' do
  90. it 'performs no validation (#2492)', db_strategy: :reset do
  91. # setup and migrate a required select attribute
  92. attribute = create_attribute(:object_manager_attribute_tree_select, :required_screen,
  93. data_option: {
  94. options: [
  95. {
  96. name: 'name 1',
  97. value: 'name 1',
  98. },
  99. {
  100. name: 'name 2',
  101. value: 'name 2',
  102. },
  103. ],
  104. default: '',
  105. null: false,
  106. relation: '',
  107. maxlength: 255,
  108. nulloption: true,
  109. })
  110. attribute_value = 'name 2'
  111. state = Ticket::State.by_category(:closed).first
  112. macro = create(:macro,
  113. perform: {
  114. 'ticket.state_id' => {
  115. value: state.id,
  116. },
  117. "ticket.#{attribute.name}" => {
  118. value: attribute_value,
  119. },
  120. },
  121. ux_flow_next_up: 'none',)
  122. # refresh browser to get macro accessible
  123. refresh
  124. # create a new ticket and attempt to update its state without the required select attribute
  125. visit "#ticket/zoom/#{ticket.id}"
  126. within(:active_content) do
  127. expect(page).to have_css('.js-objectNumber', text: ticket.number)
  128. expect(page).to have_field(attribute.name, with: '', visible: :hidden)
  129. expect(page).to have_select('state_id',
  130. selected: 'new',
  131. options: ['new', 'closed', 'open', 'pending close', 'pending reminder'])
  132. click('.js-openDropdownMacro')
  133. click(".js-dropdownActionMacro[data-id=\"#{macro.id}\"]")
  134. expect(page).to have_no_css('.js-submitDropdown .js-submit[disabled]')
  135. end
  136. expect(page).to have_field(attribute.name, with: attribute_value, visible: :hidden)
  137. expect(page).to have_select('state_id',
  138. selected: 'closed',
  139. options: ['closed', 'open', 'pending close', 'pending reminder'])
  140. # the update should not have failed and thus the ticket is in closed state
  141. ticket.reload
  142. expect(ticket[attribute.name]).to eq(attribute_value)
  143. expect(ticket.state.name).to eq(state.name)
  144. end
  145. end
  146. context 'when macro has article configured' do
  147. it 'creates an article with the configured attributes' do
  148. state = Ticket::State.find_by(name: 'closed')
  149. macro = create(:macro,
  150. perform: {
  151. 'ticket.state_id' => {
  152. value: state.id,
  153. },
  154. 'article.note' => {
  155. 'body' => 'test body',
  156. 'internal' => 'true',
  157. 'subject' => 'test sub'
  158. },
  159. },
  160. ux_flow_next_up: 'none',)
  161. # refresh browser to get macro accessible
  162. refresh
  163. # create a new ticket and attempt to update its state without the required select attribute
  164. visit "#ticket/zoom/#{ticket.id}"
  165. within(:active_content) do
  166. expect(page).to have_css('.js-objectNumber', text: ticket.number)
  167. expect(page).to have_select('state_id',
  168. selected: 'new',
  169. options: ['new', 'closed', 'open', 'pending close', 'pending reminder'])
  170. click('.js-openDropdownMacro')
  171. click(".js-dropdownActionMacro[data-id=\"#{macro.id}\"]")
  172. expect(page).to have_no_css('.js-submitDropdown .js-submit[disabled]')
  173. end
  174. expect(page).to have_css('.content.active .article-content', text: 'test body')
  175. expect(page).to have_select('state_id',
  176. selected: 'closed',
  177. options: ['closed', 'open', 'pending close', 'pending reminder'])
  178. # the update should not have failed and thus the ticket is in closed state
  179. ticket.reload
  180. expect(ticket.state.name).to eq(state.name)
  181. article = ticket.articles.last
  182. expect(article).to be_present
  183. expect(article.body).to eq('test body')
  184. expect(article.subject).to eq('test sub')
  185. expect(article.internal).to be(true)
  186. end
  187. end
  188. end
  189. context 'when merging tickets' do
  190. let!(:user) { create(:user) }
  191. let!(:origin_ticket) { create(:ticket, group: group) }
  192. let!(:target_ticket) { create(:ticket, group: group) }
  193. before do
  194. origin_ticket.merge_to(ticket_id: target_ticket.id, user_id: user.id)
  195. end
  196. # Issue #2469 - Add information "Ticket merged" to History
  197. it 'tickets history of both tickets should show the merge event' do
  198. visit "#ticket/zoom/#{origin_ticket.id}"
  199. within(:active_content) do
  200. expect(page).to have_css('.js-actions .dropdown-toggle')
  201. click '.js-actions .dropdown-toggle'
  202. click '.js-actions .dropdown-menu [data-type="ticket-history"]'
  203. in_modal do
  204. expect(page).to have_content "this ticket was merged into ticket ##{target_ticket.number}"
  205. expect(page).to have_link "##{target_ticket.number}", href: "#ticket/zoom/#{target_ticket.id}"
  206. end
  207. visit "#ticket/zoom/#{target_ticket.id}"
  208. expect(page).to have_css('.js-actions .dropdown-toggle')
  209. click '.js-actions .dropdown-toggle'
  210. click '.js-actions .dropdown-menu [data-type="ticket-history"]'
  211. in_modal do
  212. expect(page).to have_content("ticket ##{origin_ticket.number} was merged into this ticket")
  213. expect(page).to have_link "##{origin_ticket.number}", href: "#ticket/zoom/#{origin_ticket.id}"
  214. end
  215. end
  216. end
  217. # Issue #2960 - Ticket removal of merged / linked tickets doesn't remove references
  218. context 'when the merged origin ticket is deleted' do
  219. before do
  220. origin_ticket.destroy
  221. end
  222. it 'shows the target ticket history' do
  223. visit "#ticket/zoom/#{target_ticket.id}"
  224. within(:active_content) do
  225. expect(page).to have_css('.js-actions .dropdown-toggle')
  226. click '.js-actions .dropdown-toggle'
  227. click '.js-actions .dropdown-menu [data-type="ticket-history"]'
  228. end
  229. in_modal do
  230. expect(page).to have_text "##{origin_ticket.number} #{origin_ticket.title}"
  231. end
  232. end
  233. end
  234. # Issue #2960 - Ticket removal of merged / linked tickets doesn't remove references
  235. context 'when the merged target ticket is deleted' do
  236. before do
  237. target_ticket.destroy
  238. end
  239. it 'shows the origin history' do
  240. visit "#ticket/zoom/#{origin_ticket.id}"
  241. within(:active_content) do
  242. expect(page).to have_css('.js-actions .dropdown-toggle')
  243. click '.js-actions .dropdown-toggle'
  244. click '.js-actions .dropdown-menu [data-type="ticket-history"]'
  245. end
  246. in_modal do
  247. expect(page).to have_text "##{target_ticket.number} #{target_ticket.title}"
  248. end
  249. end
  250. end
  251. end
  252. context 'when closing taskbar tab for ticket' do
  253. it 'close task bar entry after some changes in ticket update form' do
  254. visit "#ticket/zoom/#{ticket.id}"
  255. within(:active_content) do
  256. find('.js-textarea').send_keys('some note')
  257. end
  258. taskbar_tab_close("Ticket-#{ticket.id}")
  259. end
  260. end
  261. context 'when using text modules' do
  262. include_examples 'text modules', path: "#ticket/zoom/#{Ticket.first.id}", ticket: Ticket.first
  263. context 'when owner is used in a text module and was updated in the ticket', authenticated_as: :authenticate do
  264. let(:user) { User.find_by(email: 'agent1@example.com') }
  265. let(:another_user) { create(:agent, groups: [Group.find_by(name: 'Users')]) }
  266. let(:ticket) { create(:ticket, group: group, owner: user) }
  267. let(:text_module) { create(:text_module, name: 'firstlast', keywords: 'firstlast', content: '#{ticket.owner.firstname} #{ticket.owner.lastname}') } # rubocop:disable Lint/InterpolationCheck
  268. def authenticate
  269. ticket && text_module && another_user
  270. true
  271. end
  272. def select_text_module
  273. find(:richtext).send_keys(':')
  274. find(:richtext).send_keys(':')
  275. find(:richtext).send_keys('firstlast')
  276. expect(page).to have_selector(:text_module, text_module.id)
  277. find(:richtext).send_keys(:enter)
  278. end
  279. it 'updates used data' do
  280. visit "#ticket/zoom/#{ticket.id}"
  281. expect(page).to have_field('owner_id', with: user.id)
  282. within(:active_content) do
  283. select_text_module
  284. expect(find(:richtext).text).to include("#{user.firstname} #{user.lastname}")
  285. select another_user.fullname, from: 'Owner'
  286. find('.js-submit').click
  287. expect(ticket.reload.owner_id).to eq(another_user.id)
  288. select_text_module
  289. expect(find(:richtext).text).to include("#{another_user.firstname} #{another_user.lastname}")
  290. end
  291. end
  292. end
  293. end
  294. context 'when using macros' do
  295. include_examples 'macros', path: "#ticket/zoom/#{Ticket.first.id}"
  296. end
  297. context 'when group will be changed' do
  298. let(:user) { User.find_by(email: 'agent1@example.com') }
  299. let(:ticket) { create(:ticket, group: group, owner: user) }
  300. it 'check that owner resets after group change' do
  301. visit "#ticket/zoom/#{ticket.id}"
  302. expect(page).to have_field('owner_id', with: user.id)
  303. set_tree_select_value('group_id', '') # empty selection
  304. expect(page).to have_field('owner_id', with: '')
  305. end
  306. end
  307. end