create_spec.rb 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'system/examples/core_workflow_examples'
  4. require 'system/examples/text_modules_examples'
  5. RSpec.describe 'Ticket Create', type: :system do
  6. context 'when calling without session' do
  7. describe 'redirect to' do
  8. it 'login screen after certain create was called', authenticated_as: false do
  9. visit '#ticket/create/id/1234'
  10. expect(page).to have_css('#login')
  11. end
  12. it 'login screen after generic create was called', authenticated_as: false do
  13. visit '#ticket/create'
  14. expect(page).to have_css('#login')
  15. end
  16. end
  17. end
  18. context 'when logged in as non admin' do
  19. let(:agent) { create(:agent) }
  20. it 'show manage templates text only', authenticated_as: :agent do
  21. visit 'ticket/create'
  22. expect(page).to have_no_css('div.js-createLink', visible: :all)
  23. expect(page).to have_no_css('div.js-createTextOnly', visible: :hidden)
  24. end
  25. end
  26. context 'when using the sidebar' do
  27. context 'when using a template' do
  28. before do
  29. visit 'ticket/create'
  30. use_template(create(:template, :dummy_data, customer: create(:customer, :with_org)))
  31. end
  32. it 'does show the edit link for the customer' do
  33. click '.tabsSidebar-tab[data-tab=customer]'
  34. click '#userAction'
  35. click_on 'Edit Customer'
  36. modal_ready
  37. end
  38. it 'does show the edit link for the organization' do
  39. click '.tabsSidebar-tab[data-tab=organization]'
  40. click '#userAction'
  41. click_on 'Edit Organization'
  42. modal_ready
  43. end
  44. end
  45. %w[idoit gitlab github].each do |service_name|
  46. it "#{service_name} tab is hidden" do
  47. visit 'ticket/create'
  48. expect(page).to have_no_css(".tabsSidebar-tab[data-tab=#{service_name}]")
  49. end
  50. context "when #{service_name} is enabled" do
  51. before do
  52. Setting.set("#{service_name}_integration", true)
  53. end
  54. context 'when agent' do
  55. it "#{service_name} tab is visible" do
  56. visit 'ticket/create'
  57. expect(page).to have_css(".tabsSidebar-tab[data-tab=#{service_name}]")
  58. end
  59. end
  60. context 'when customer', authenticated_as: :customer do
  61. let(:customer) { create(:customer) }
  62. it "#{service_name} tab is hidden" do
  63. visit 'customer_ticket_new'
  64. expect(page).to have_no_css(".tabsSidebar-tab[data-tab=#{service_name}]")
  65. end
  66. end
  67. end
  68. end
  69. end
  70. context 'when logged in as admin' do
  71. let(:admin) { create(:admin) }
  72. it 'show manage templates link', authenticated_as: :admin do
  73. visit 'ticket/create'
  74. expect(page).to have_no_css('div.js-createLink', visible: :hidden)
  75. expect(page).to have_no_css('div.js-createTextOnly', visible: :all)
  76. end
  77. end
  78. context 'when applying ticket templates' do
  79. let(:agent) { create(:agent, groups: [permitted_group]) }
  80. let(:permitted_group) { create(:group) }
  81. let(:unpermitted_group) { create(:group) }
  82. let!(:template_unpermitted_group) { create(:template, :dummy_data, group: unpermitted_group, owner: agent) }
  83. let!(:template_permitted_group) { create(:template, :dummy_data, group: permitted_group, owner: agent) }
  84. before { visit 'ticket/create' }
  85. # Regression test for issue #2424 - Unavailable ticket template attributes get applied
  86. it 'unavailable attributes do not get applied', authenticated_as: :agent do
  87. use_template(template_unpermitted_group)
  88. expect(all('[name="group_id"] option', visible: :all).map(&:value)).not_to eq unpermitted_group.id.to_s
  89. expect(find('[name="owner_id"]', visible: :all).value).to eq agent.id.to_s
  90. end
  91. it 'available attributes get applied', authenticated_as: :agent do
  92. use_template(template_permitted_group)
  93. expect(find('[name="group_id"]', visible: :all).value).to eq permitted_group.id.to_s
  94. expect(find('[name="owner_id"]', visible: :all).value).to eq agent.id.to_s
  95. end
  96. context 'with tag values' do
  97. let(:template) do
  98. create(:template,
  99. options: {
  100. 'ticket.tags': {
  101. value: template_value,
  102. operator: operator,
  103. }
  104. })
  105. end
  106. shared_examples 'merging with existing tags in a dirty form' do
  107. it 'merges with existing tags in a dirty form' do
  108. set_tokens_field_value('tags', %w[baz qux foo])
  109. use_template(template)
  110. check_tokens_field_value('tags', ['baz', 'qux', *template_value.split(', ')])
  111. end
  112. end
  113. shared_examples 'replacing tags in a clean form' do
  114. it 'replaces tags in a clean form' do
  115. use_template(template)
  116. check_tokens_field_value('tags', template_value.split(', '), visible: :all)
  117. end
  118. end
  119. shared_examples 'leaving tags empty in a clean form' do
  120. it 'does nothing in a clean form' do
  121. use_template(template)
  122. check_tokens_field_value('tags', '')
  123. end
  124. end
  125. context 'with add operator' do
  126. let(:operator) { 'add' }
  127. let(:template_value) { 'foo, bar' }
  128. it_behaves_like 'replacing tags in a clean form'
  129. it_behaves_like 'merging with existing tags in a dirty form'
  130. end
  131. context 'with remove operator' do
  132. let(:operator) { 'remove' }
  133. let(:template_value) { 'foo, bar' }
  134. it_behaves_like 'leaving tags empty in a clean form'
  135. it 'removes existing tags in a dirty form' do
  136. set_tokens_field_value('tags', %w[foo bar baz qux])
  137. use_template(template)
  138. check_tokens_field_value('tags', %w[baz qux])
  139. end
  140. end
  141. context 'without operator (legacy)' do
  142. let(:operator) { nil }
  143. let(:template_value) { 'foo, bar' }
  144. it_behaves_like 'replacing tags in a clean form'
  145. it_behaves_like 'merging with existing tags in a dirty form'
  146. end
  147. context 'with empty value' do
  148. let(:operator) { nil }
  149. let(:template_value) { nil }
  150. it_behaves_like 'leaving tags empty in a clean form'
  151. it 'leaves existing tags untouched in a dirty form' do
  152. set_tokens_field_value('tags', %w[baz qux])
  153. use_template(template)
  154. check_tokens_field_value('tags', %w[baz qux])
  155. end
  156. end
  157. end
  158. end
  159. context 'when using text modules' do
  160. include_examples 'text modules', path: 'ticket/create'
  161. end
  162. describe 'object manager attributes maxlength', authenticated_as: :authenticate, db_strategy: :reset do
  163. def authenticate
  164. create(:object_manager_attribute_text, :required_screen, name: 'maxtest', display: 'maxtest', data_option: {
  165. 'type' => 'text',
  166. 'maxlength' => 3,
  167. 'null' => true,
  168. 'translate' => false,
  169. 'default' => '',
  170. 'options' => {},
  171. 'relation' => '',
  172. })
  173. ObjectManager::Attribute.migration_execute
  174. true
  175. end
  176. it 'checks ticket create' do
  177. visit 'ticket/create'
  178. within(:active_content) do
  179. fill_in 'maxtest', with: 'hellu'
  180. expect(page.find_field('maxtest').value).to eq('hel')
  181. end
  182. end
  183. end
  184. describe 'object manager attributes default date', time_zone: 'Europe/London' do
  185. before :all do # rubocop:disable RSpec/BeforeAfterAll
  186. screens = {
  187. 'create_top' => {
  188. '-all-' => {
  189. 'null' => true
  190. }
  191. },
  192. }
  193. create(:object_manager_attribute_date, name: 'date_test', display: 'date_test', default: 24, screens: screens)
  194. create(:object_manager_attribute_datetime, name: 'datetime_test', display: 'datetime_test', default: 100, screens: screens)
  195. ObjectManager::Attribute.migration_execute # rubocop:disable Zammad/ExistsDbStrategy
  196. end
  197. after :all do # rubocop:disable RSpec/BeforeAfterAll
  198. ObjectManager::Attribute.where(name: %i[date_test datetime_test]).destroy_all
  199. end
  200. before do
  201. visit '/'
  202. template = create(:template, :dummy_data)
  203. travel 1.month
  204. browser_travel_to Time.current
  205. visit 'ticket/create'
  206. use_template template, without_taskbar: true
  207. end
  208. let(:field_date) { find 'input[name="{date}date_test"]', visible: :all }
  209. let(:field_time) { find 'input[name="{datetime}datetime_test"]', visible: :all }
  210. it 'prefills date' do
  211. expect(field_date.value).to eq 1.day.from_now.to_date.to_s
  212. end
  213. it 'prefills datetime' do
  214. expect(Time.zone.parse(field_time.value)).to eq 100.minutes.from_now.change(sec: 0, usec: 0)
  215. end
  216. it 'saves dates' do
  217. click '.js-submit'
  218. date = 1.day.from_now.to_date
  219. time = 100.minutes.from_now.change(sec: 0)
  220. expect(Ticket.last).to have_attributes date_test: date, datetime_test: time
  221. end
  222. it 'allows to save with different values' do
  223. date = 2.days.from_now.to_date
  224. time = 200.minutes.from_now.change(sec: 0)
  225. field_date.sibling('[data-item=date]').set date.strftime('%m/%d/%Y')
  226. field_time.sibling('[data-item=date]').set time.strftime('%m/%d/%Y')
  227. field_time.sibling('[data-item=time]').set time.strftime('%H:%M')
  228. click '.js-submit'
  229. expect(Ticket.last).to have_attributes date_test: date, datetime_test: time
  230. end
  231. it 'allows to save with cleared value' do
  232. field_date.sibling('[data-item=date]').click
  233. find('.datepicker .clear').click
  234. field_time.sibling('[data-item=date]').click
  235. find('.datepicker .clear').click
  236. click '.js-submit'
  237. expect(Ticket.last).to have_attributes date_test: nil, datetime_test: nil
  238. end
  239. end
  240. describe 'GitLab Integration', :integration, authenticated_as: :authenticate, required_envs: %w[GITLAB_ENDPOINT GITLAB_APITOKEN] do
  241. let(:customer) { create(:customer) }
  242. let(:agent) { create(:agent, groups: [Group.find_by(name: 'Users')]) }
  243. let!(:template) { create(:template, :dummy_data, group: Group.find_by(name: 'Users'), owner: agent, customer: customer) }
  244. def authenticate
  245. Setting.set('gitlab_integration', true)
  246. Setting.set('gitlab_config', {
  247. api_token: ENV['GITLAB_APITOKEN'],
  248. endpoint: ENV['GITLAB_ENDPOINT'],
  249. })
  250. true
  251. end
  252. it 'creates a ticket with links' do
  253. visit 'ticket/create'
  254. within(:active_content) do
  255. use_template(template)
  256. # switch to gitlab sidebar
  257. click('.tabsSidebar-tab[data-tab=gitlab]')
  258. click('.sidebar-header-headline.js-headline')
  259. # add issue
  260. click_on 'Link issue'
  261. fill_in 'link', with: ENV['GITLAB_ISSUE_LINK']
  262. click_on 'Submit'
  263. # verify issue
  264. content = find('.sidebar-git-issue-content')
  265. expect(content).to have_text('#1 Example issue')
  266. expect(content).to have_text('critical')
  267. expect(content).to have_text('special')
  268. expect(content).to have_text('important milestone')
  269. expect(content).to have_text('zammad-robot')
  270. # create Ticket
  271. click '.js-submit'
  272. # check stored data
  273. expect(Ticket.last.preferences[:gitlab][:issue_links][0]).to eq(ENV['GITLAB_ISSUE_LINK'])
  274. end
  275. end
  276. end
  277. describe 'GitHub Integration', :integration, authenticated_as: :authenticate, required_envs: %w[GITHUB_ENDPOINT GITHUB_APITOKEN] do
  278. let(:customer) { create(:customer) }
  279. let(:agent) { create(:agent, groups: [Group.find_by(name: 'Users')]) }
  280. let!(:template) { create(:template, :dummy_data, group: Group.find_by(name: 'Users'), owner: agent, customer: customer) }
  281. def authenticate
  282. Setting.set('github_integration', true)
  283. Setting.set('github_config', {
  284. api_token: ENV['GITHUB_APITOKEN'],
  285. endpoint: ENV['GITHUB_ENDPOINT'],
  286. })
  287. true
  288. end
  289. it 'creates a ticket with links' do
  290. visit 'ticket/create'
  291. within(:active_content) do
  292. use_template(template)
  293. # switch to github sidebar
  294. click('.tabsSidebar-tab[data-tab=github]')
  295. click('.sidebar-header-headline.js-headline')
  296. # add issue
  297. click_on 'Link issue'
  298. fill_in 'link', with: ENV['GITHUB_ISSUE_LINK']
  299. click_on 'Submit'
  300. # verify issue
  301. content = find('.sidebar-git-issue-content')
  302. expect(content).to have_text('#1575 GitHub integration')
  303. expect(content).to have_text('enhancement')
  304. expect(content).to have_text('integration')
  305. expect(content).to have_text('4.0')
  306. expect(content).to have_text('Thorsten')
  307. # create Ticket
  308. click '.js-submit'
  309. # check stored data
  310. expect(Ticket.last.preferences[:github][:issue_links][0]).to eq(ENV['GITHUB_ISSUE_LINK'])
  311. end
  312. end
  313. end
  314. describe 'Core Workflow' do
  315. include_examples 'core workflow' do
  316. let(:object_name) { 'Ticket' }
  317. let(:before_it) do
  318. lambda {
  319. ensure_websocket(check_if_pinged: false) do
  320. visit 'ticket/create'
  321. end
  322. }
  323. end
  324. end
  325. end
  326. # https://github.com/zammad/zammad/issues/2669
  327. context 'when canceling new ticket creation' do
  328. it 'closes the dialog' do
  329. visit 'ticket/create'
  330. task_key = find(:task_active)['data-key']
  331. expect { click('.js-cancel') }.to change { has_selector?(:task_with, task_key, wait: 0) }.to(false)
  332. end
  333. it 'asks for confirmation if the dialog was modified' do
  334. visit 'ticket/create'
  335. task_key = find(:task_active)['data-key']
  336. find('[name=title]').fill_in with: 'Title'
  337. click '.js-cancel'
  338. in_modal do
  339. click '.js-submit'
  340. end
  341. expect(page).to have_no_selector(:task_with, task_key)
  342. end
  343. it 'asks for confirmation if attachment was added' do
  344. visit 'ticket/create'
  345. within :active_content do
  346. page.find('input#fileUpload_1[data-initialized="true"]', visible: :all).set(Rails.root.join('test/data/mail/mail001.box'))
  347. await_empty_ajax_queue
  348. expect(page).to have_css('.attachments .attachment-delete', visible: :all)
  349. find('.js-cancel').click
  350. end
  351. in_modal do
  352. expect(page).to have_text 'Tab has changed'
  353. end
  354. end
  355. end
  356. context 'when uploading attachment' do
  357. it 'shows an error if server throws an error' do
  358. allow(Store).to receive(:create!) { raise 'Error' }
  359. visit 'ticket/create'
  360. within :active_content do
  361. page.find('input#fileUpload_1[data-initialized="true"]', visible: :all).set(Rails.root.join('test/data/mail/mail001.box'))
  362. await_empty_ajax_queue
  363. end
  364. in_modal do
  365. expect(page).to have_text 'Error'
  366. end
  367. end
  368. end
  369. context 'when closing taskbar tab for new ticket creation' do
  370. it 'close task bar entry after some changes in ticket create form' do
  371. visit 'ticket/create'
  372. within(:active_content) do
  373. find('[name=title]').fill_in with: 'Title'
  374. end
  375. wait.until { find(:task_active)['data-key'].present? }
  376. taskbar_tab_close(find(:task_active)['data-key'])
  377. end
  378. end
  379. describe 'customer selection to check the field search' do
  380. before do
  381. create(:customer, active: true)
  382. create(:customer, active: false)
  383. end
  384. it 'check for inactive customer in customer/organization selection' do
  385. visit 'ticket/create'
  386. within(:active_content) do
  387. find('[name=customer_id] ~ .user-select.token-input').fill_in with: '**'
  388. expect(page).to have_css('ul.recipientList > li.recipientList-entry', minimum: 2)
  389. expect(page).to have_css('ul.recipientList > li.recipientList-entry.is-inactive', count: 1)
  390. end
  391. end
  392. end
  393. context 'when agent and customer user login after another' do
  394. let(:agent) { create(:agent, password: 'test') }
  395. let(:customer) { create(:customer, password: 'test') }
  396. it 'customer user should not have agent object attributes', authenticated_as: false do
  397. # Create agent session and fetch object attributes.
  398. login(
  399. username: agent.login,
  400. password: 'test'
  401. )
  402. visit 'ticket/create'
  403. expect(page).to have_field('customer_id', type: 'hidden')
  404. # Remove local object attributes bound to the session.
  405. # There was an issue (#1856) where the old attribute values
  406. # persisted and were stored as the original attributes.
  407. logout
  408. # Create customer session and fetch object attributes.
  409. login(
  410. username: customer.login,
  411. password: 'test'
  412. )
  413. visit 'customer_ticket_new'
  414. expect(page).to have_no_field('customer_id', type: 'hidden')
  415. end
  416. end
  417. context 'when state options have a special translation', authenticated_as: :authenticate do
  418. let(:admin_de) { create(:admin, preferences: { locale: 'de-de' }) }
  419. context 'when translated state option has a single quote' do
  420. def authenticate
  421. open_tranlation = Translation.where(locale: 'de-de', source: 'open')
  422. open_tranlation.update(target: "off'en")
  423. admin_de
  424. end
  425. it 'shows the translated state options correctly' do
  426. visit 'ticket/create'
  427. expect(page).to have_select('state_id', with_options: ["off'en"])
  428. end
  429. end
  430. end
  431. describe 'It should be possible to show attributes which are configured shown false #3726', authenticated_as: :authenticate, db_strategy: :reset do
  432. let(:field_name) { SecureRandom.uuid }
  433. let(:field) do
  434. create(:object_manager_attribute_text, name: field_name, display: field_name, screens: {
  435. 'create_middle' => {
  436. 'ticket.agent' => {
  437. 'shown' => false,
  438. 'required' => false,
  439. }
  440. }
  441. })
  442. ObjectManager::Attribute.migration_execute
  443. end
  444. before do
  445. visit 'ticket/create'
  446. end
  447. context 'when field visible' do
  448. let(:workflow) do
  449. create(:core_workflow,
  450. object: 'Ticket',
  451. perform: { "ticket.#{field_name}" => { 'operator' => 'show', 'show' => 'true' } })
  452. end
  453. def authenticate
  454. field
  455. workflow
  456. true
  457. end
  458. it 'does show up the field' do
  459. expect(page).to have_css("div[data-attribute-name='#{field_name}']")
  460. end
  461. end
  462. context 'when field hidden' do
  463. def authenticate
  464. field
  465. true
  466. end
  467. it 'does not show the field' do
  468. expect(page).to have_css("div[data-attribute-name='#{field_name}'].is-hidden.is-removed", visible: :hidden)
  469. end
  470. end
  471. end
  472. describe 'Support workflow mechanism to do pending reminder state hide pending time use case #3790', authenticated_as: :authenticate do
  473. let(:template) { create(:template, :dummy_data) }
  474. def add_state
  475. Ticket::State.create_or_update(
  476. name: 'pending customer feedback',
  477. state_type: Ticket::StateType.find_by(name: 'pending reminder'),
  478. ignore_escalation: true,
  479. created_by_id: 1,
  480. updated_by_id: 1,
  481. )
  482. end
  483. def update_screens
  484. attribute = ObjectManager::Attribute.get(
  485. object: 'Ticket',
  486. name: 'state_id',
  487. )
  488. attribute.data_option[:filter] = Ticket::State.where(active: true).by_category_ids(:viewable)
  489. attribute.screens[:create_middle]['ticket.agent'][:filter] = Ticket::State.where(active: true).by_category_ids(:viewable_agent_new)
  490. attribute.screens[:create_middle]['ticket.customer'][:filter] = Ticket::State.where(active: true).by_category_ids(:viewable_customer_new)
  491. attribute.screens[:edit]['ticket.agent'][:filter] = Ticket::State.where(active: true).by_category_ids(:viewable_agent_edit)
  492. attribute.screens[:edit]['ticket.customer'][:filter] = Ticket::State.where(active: true).by_category_ids(:viewable_customer_edit)
  493. attribute.save!
  494. end
  495. def create_flow
  496. create(:core_workflow,
  497. object: 'Ticket',
  498. condition_selected: { 'ticket.state_id'=>{ 'operator' => 'is', 'value' => Ticket::State.find_by(name: 'pending customer feedback').id.to_s } },
  499. perform: { 'ticket.pending_time'=> { 'operator' => 'remove', 'remove' => 'true' } })
  500. end
  501. def authenticate
  502. add_state
  503. update_screens
  504. create_flow
  505. template
  506. true
  507. end
  508. before do
  509. visit 'ticket/create'
  510. use_template(template)
  511. end
  512. it 'does make it possible to create pending states where the pending time is optional and not visible' do
  513. select 'pending customer feedback', from: 'state_id'
  514. click '.js-submit'
  515. expect(current_url).to include('ticket/zoom')
  516. expect(Ticket.last.state_id).to eq(Ticket::State.find_by(name: 'pending customer feedback').id)
  517. expect(Ticket.last.pending_time).to be_nil
  518. end
  519. end
  520. context 'default priority', authenticated_as: :authenticate do
  521. let(:template) { create(:template, :dummy_data) }
  522. let(:ticket_priority) { create(:ticket_priority, default_create: true) }
  523. let(:another_priority) { Ticket::Priority.find(1) }
  524. let(:priority_field) { find('[name=priority_id]') }
  525. def authenticate
  526. template
  527. ticket_priority
  528. true
  529. end
  530. it 'shows default priority on load' do
  531. visit 'ticket/create'
  532. expect(priority_field.value).to eq ticket_priority.id.to_s
  533. end
  534. it 'does not reset to default priority on reload' do
  535. visit 'ticket/create'
  536. taskbar_timestamp = Taskbar.last.updated_at
  537. priority_field.select another_priority.name
  538. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  539. refresh
  540. expect(priority_field.reload.value).to eq another_priority.id.to_s
  541. end
  542. it 'saves default priority' do
  543. visit 'ticket/create'
  544. use_template template
  545. click '.js-submit'
  546. expect(Ticket.last).to have_attributes(priority: ticket_priority)
  547. end
  548. it 'saves different priority if overriden' do
  549. visit 'ticket/create'
  550. use_template template
  551. priority_field.select another_priority.name
  552. click '.js-submit'
  553. expect(Ticket.last).to have_attributes(priority: another_priority)
  554. end
  555. end
  556. describe 'When looking for customers, it is no longer possible to change into organizations #3815' do
  557. before do
  558. visit 'ticket/create'
  559. # modal reaper ;)
  560. sleep 3
  561. end
  562. context 'when less than 10 customers' do
  563. let(:organization) { Organization.first }
  564. it 'has no show more option' do
  565. find('[name=customer_id_completion]').fill_in with: 'zam'
  566. expect(page).to have_css("li.js-organization[data-organization-id='#{organization.id}']")
  567. page.find("li.js-organization[data-organization-id='#{organization.id}']").click
  568. expect(page).to have_css("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers.hidden", visible: :all)
  569. end
  570. end
  571. context 'when more than 10 customers', authenticated_as: :authenticate do
  572. def authenticate
  573. customers
  574. true
  575. end
  576. let(:organization) { create(:organization, name: 'Zammed') }
  577. let(:customers) do
  578. create_list(:customer, 50, organization: organization)
  579. end
  580. it 'does paginate through organization' do
  581. find('[name=customer_id_completion]').fill_in with: 'zam'
  582. expect(page).to have_css("li.js-organization[data-organization-id='#{organization.id}']")
  583. page.find("li.js-organization[data-organization-id='#{organization.id}']").click
  584. wait.until { page.all("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li", visible: :all).count == 12 } # 10 users + back + show more button
  585. expect(page).to have_css("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers[organization-member-limit='10']")
  586. scroll_into_view('li.js-showMoreMembers')
  587. page.find("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers").click
  588. wait.until { page.all("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li", visible: :all).count == 27 } # 25 users + back + show more button
  589. expect(page).to have_css("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers[organization-member-limit='25']")
  590. scroll_into_view('li.js-showMoreMembers')
  591. page.find("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers").click
  592. wait.until { page.all("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li", visible: :all).count == 52 } # 50 users + back + show more button
  593. scroll_into_view('li.js-showMoreMembers')
  594. expect(page).to have_css("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers.hidden", visible: :all)
  595. end
  596. end
  597. end
  598. describe 'Ticket create screen will loose attachments by time #3827' do
  599. before do
  600. visit 'ticket/create'
  601. end
  602. it 'does not loose attachments on rerender of the ui' do
  603. # upload two files
  604. page.find('input#fileUpload_1[data-initialized="true"]', visible: :all).set(Rails.root.join('test/data/mail/mail001.box'))
  605. await_empty_ajax_queue
  606. wait.until { page.all('div.attachment-delete.js-delete', visible: :all).count == 1 }
  607. expect(page).to have_text('mail001.box')
  608. page.find('input#fileUpload_1', visible: :all).set(Rails.root.join('test/data/mail/mail002.box'))
  609. await_empty_ajax_queue
  610. wait.until { page.all('div.attachment-delete.js-delete', visible: :all).count == 2 }
  611. expect(page).to have_text('mail002.box')
  612. # remove last file
  613. begin
  614. page.evaluate_script("$('div.attachment-delete.js-delete:last').trigger('click')") # not interactable
  615. rescue # Lint/SuppressedException
  616. # because its not interactable it also
  617. # returns this weird exception for the jquery
  618. # even tho it worked fine
  619. end
  620. await_empty_ajax_queue
  621. wait.until { page.all('div.attachment-delete.js-delete', visible: :all).count == 1 }
  622. expect(page).to have_text('mail001.box')
  623. expect(page).to have_no_text('mail002.box')
  624. # simulate rerender b
  625. page.evaluate_script("App.Event.trigger('ui:rerender')")
  626. expect(page).to have_text('mail001.box')
  627. expect(page).to have_no_text('mail002.box')
  628. end
  629. end
  630. describe 'Invalid group and owner list for tickets created via customer profile #3835' do
  631. let(:invalid_ticket) { create(:ticket) }
  632. before do
  633. visit "#ticket/create/id/#{invalid_ticket.id}/customer/#{User.find_by(firstname: 'Nicole').id}"
  634. end
  635. it 'does show an empty list of owners' do
  636. wait.until { page.all('select[name=owner_id] option').count == 1 }
  637. expect(page.all('select[name=owner_id] option').count).to eq(1)
  638. end
  639. end
  640. # https://github.com/zammad/zammad/issues/3825
  641. describe 'CC token field' do
  642. before do
  643. visit 'ticket/create'
  644. find('[data-type=email-out]').click
  645. end
  646. it 'can be cleared by cutting out text' do
  647. add_email 'asd@example.com'
  648. add_email 'def@example.com'
  649. find('.token', text: 'def@example.com').double_click
  650. send_keys([magic_key, 'x'])
  651. find('.token').click # trigger blur
  652. expect(find('[name="cc"]', visible: :all).value).to eq 'asd@example.com'
  653. end
  654. def add_email(input)
  655. field = find_field('CC')
  656. field.fill_in with: input
  657. field.execute_script "$(this).trigger('blur')" # trigger blur
  658. find '.token', text: input # wait for email to tokenize
  659. end
  660. end
  661. describe 'No signature on new ticket if email is default message type #3844', authenticated_as: :authenticate do
  662. def authenticate
  663. Setting.set('ui_ticket_create_default_type', 'email-out')
  664. Group.where.not(name: 'Users').each { |g| g.update(active: false) }
  665. true
  666. end
  667. before do
  668. visit 'ticket/create'
  669. end
  670. it 'does render the create screen with an initial core workflow state to set signatures and other defaults properly' do
  671. expect(page.find('.richtext-content')).to have_text('Support')
  672. end
  673. end
  674. describe 'Zammad 5 mail template double signature #3816', authenticated_as: :authenticate do
  675. let(:agent_template) { create(:agent) }
  676. let!(:template) do
  677. create(
  678. :template,
  679. :dummy_data,
  680. group: Group.first, owner: agent_template,
  681. body: 'Content dummy.<br><br><div data-signature="true" data-signature-id="1"> Test Other Agent<br><br>--<br> Super Support - Waterford Business Park<br> 5201 Blue Lagoon Drive - 8th Floor &amp; 9th Floor - Miami, 33126 USA<br> Email: hot@example.com - Web: <a href="http://www.example.com/" rel="nofollow noreferrer noopener" target="_blank">http://www.example.com/</a><br>--</div>'
  682. )
  683. end
  684. def authenticate
  685. Group.first.update(signature: Signature.first)
  686. true
  687. end
  688. before do
  689. visit 'ticket/create'
  690. find('[data-type=email-out]').click
  691. end
  692. it 'does not show double signature on template usage' do
  693. set_tree_select_value('group_id', Group.first.name)
  694. use_template(template)
  695. expect(page).to have_no_text('Test Other Agent')
  696. end
  697. end
  698. describe 'Tree select value cannot be set to "-" (empty) with Trigger/Scheduler/Core workflow #4024', authenticated_as: :authenticate, db_strategy: :reset do
  699. let(:field_name) { SecureRandom.uuid }
  700. let(:field) do
  701. create(:object_manager_attribute_tree_select, :required_screen, name: field_name, display: field_name)
  702. ObjectManager::Attribute.migration_execute
  703. end
  704. let(:workflow) do
  705. create(:core_workflow,
  706. object: 'Ticket',
  707. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '3 high').id.to_s } },
  708. perform: { "ticket.#{field_name}" => { 'operator' => 'select', 'select' => 'Incident' } })
  709. end
  710. let(:workflow2) do
  711. create(:core_workflow,
  712. object: 'Ticket',
  713. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '2 normal').id.to_s } },
  714. perform: { "ticket.#{field_name}" => { 'operator' => 'select', 'select' => '' } })
  715. end
  716. def authenticate
  717. field
  718. workflow
  719. workflow2
  720. true
  721. end
  722. before do
  723. visit 'ticket/create'
  724. end
  725. it 'does select the field value properly' do
  726. page.find('[name=priority_id]').select '3 high'
  727. wait.until { page.find("input[name='#{field_name}']", visible: :all).value == 'Incident' }
  728. page.find('[name=priority_id]').select '2 normal'
  729. wait.until { page.find("input[name='#{field_name}']", visible: :all).value == '' }
  730. end
  731. end
  732. describe 'Assign user to multiple organizations #1573' do
  733. let(:organization1) { create(:organization) }
  734. let(:organization2) { create(:organization) }
  735. let(:organization3) { create(:organization) }
  736. let(:organization4) { create(:organization) }
  737. let(:user1) { create(:agent, organization: organization1, organizations: [organization2, organization3]) }
  738. let(:user2) { create(:agent, organization: organization4) }
  739. let(:customer1) { create(:customer, organization: organization1, organizations: [organization2, organization3]) }
  740. let(:customer2) { create(:customer, organization: organization4) }
  741. context 'when agent', authenticated_as: :authenticate do
  742. def authenticate
  743. user1
  744. user2
  745. true
  746. end
  747. before do
  748. visit 'ticket/create'
  749. end
  750. it 'does not show the organization field for user 1' do
  751. find('[name=customer_id_completion]').fill_in with: user1.firstname
  752. find("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").click
  753. expect(page).to have_css("div[data-attribute-name='organization_id']")
  754. end
  755. it 'does show the organization field for user 2' do
  756. find('[name=customer_id_completion]').fill_in with: user2.firstname
  757. find("li.recipientList-entry.js-object[data-object-id='#{user2.id}']").click
  758. expect(page).to have_no_css("div[data-attribute-name='organization_id']")
  759. end
  760. it 'can create tickets for secondary organizations' do
  761. fill_in 'Title', with: 'test'
  762. find('.richtext-content').send_keys 'test'
  763. set_tree_select_value('group_id', Group.first.name)
  764. find('[name=customer_id_completion]').fill_in with: user1.firstname
  765. wait.until { page.all("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").present? }
  766. find("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").click
  767. find('div[data-attribute-name=organization_id] .js-input').fill_in with: user1.organizations[0].name, fill_options: { clear: :backspace }
  768. wait.until { page.all("div[data-attribute-name=organization_id] .js-option[data-value='#{user1.organizations[0].id}']").present? }
  769. page.find("div[data-attribute-name=organization_id] .js-option[data-value='#{user1.organizations[0].id}'] span").click
  770. click '.js-submit'
  771. wait.until { Ticket.last.organization_id == user1.organizations[0].id }
  772. end
  773. it 'restores saved organization selection correctly (#5347)' do
  774. find('[name=customer_id_completion]').fill_in with: user1.firstname
  775. wait.until { page.all("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").present? }
  776. find("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").click
  777. find('div[data-attribute-name=organization_id] .js-input').fill_in with: organization2.name, fill_options: { clear: :backspace }
  778. wait.until { page.all("div[data-attribute-name=organization_id] .js-option[data-value='#{organization2.id}']").present? }
  779. taskbar_timestamp = Taskbar.last.updated_at
  780. page.find("div[data-attribute-name=organization_id] .js-option[data-value='#{organization2.id}'] span").click
  781. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  782. refresh
  783. expect(find('div[data-attribute-name=organization_id] .js-input').value).to eq(organization2.name)
  784. end
  785. end
  786. context 'when customer' do
  787. before do
  788. visit 'customer_ticket_new'
  789. end
  790. it 'does not show the organization field for user 1', authenticated_as: :customer1 do
  791. expect(page).to have_css("div[data-attribute-name='organization_id']")
  792. end
  793. it 'does show the organization field for user 2', authenticated_as: :customer2 do
  794. expect(page).to have_no_css("div[data-attribute-name='organization_id']")
  795. end
  796. it 'can create tickets for secondary organizations', authenticated_as: :customer1 do
  797. fill_in 'Title', with: 'test'
  798. find('.richtext-content').send_keys 'test'
  799. set_tree_select_value('group_id', Group.first.name)
  800. find('div[data-attribute-name=organization_id] .js-input').fill_in with: customer1.organizations[0].name, fill_options: { clear: :backspace }
  801. wait.until { page.all("div[data-attribute-name=organization_id] .js-option[data-value='#{customer1.organizations[0].id}']").present? }
  802. page.find("div[data-attribute-name=organization_id] .js-option[data-value='#{customer1.organizations[0].id}'] span").click
  803. click '.js-submit'
  804. wait.until { Ticket.last.organization_id == customer1.organizations[0].id }
  805. end
  806. end
  807. end
  808. describe 'Wrong default values in ticket create when creating from user profile #4088' do
  809. let(:customer) { create(:customer) }
  810. before do
  811. visit "ticket/create/customer/#{customer.id}"
  812. end
  813. it 'does show the default state when creating a ticket from a user profile' do
  814. expect(page).to have_select('state_id', selected: 'open')
  815. end
  816. end
  817. describe 'Ticket templates do not save the owner attribute #4175' do
  818. let(:agent) { create(:agent, groups: [Group.first]) }
  819. let!(:template) { create(:template, :dummy_data, group: Group.first, owner: agent) }
  820. before do
  821. visit 'ticket/create'
  822. # Wait for the initial taskbar update to finish
  823. taskbar_timestamp = Taskbar.last.updated_at
  824. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  825. end
  826. it 'does set owners properly by templates and taskbars' do
  827. use_template(template)
  828. expect(page).to have_select('owner_id', selected: agent.fullname)
  829. wait.until { Taskbar.last.state['owner_id'].to_i == agent.id }
  830. refresh
  831. expect(page).to have_select('owner_id', selected: agent.fullname)
  832. end
  833. end
  834. describe 'Ticket templates resets article body #2434' do
  835. let!(:template1) { create(:template, :dummy_data, title: 'template 1', body: 'body 1') }
  836. let!(:template2) { create(:template, :dummy_data, title: 'template 2', body: 'body 2') }
  837. before do
  838. visit 'ticket/create'
  839. end
  840. it 'preserves text input from the user' do
  841. taskbar_timestamp = Taskbar.last.updated_at
  842. set_editor_field_value('body', 'foobar')
  843. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  844. use_template(template1)
  845. check_input_field_value('title', 'template 1')
  846. check_editor_field_value('body', 'foobar')
  847. end
  848. it 'allows easy switching between templates' do
  849. use_template(template1)
  850. check_input_field_value('title', 'template 1')
  851. check_editor_field_value('body', 'body 1')
  852. use_template(template2)
  853. check_input_field_value('title', 'template 2')
  854. check_editor_field_value('body', 'body 2')
  855. taskbar_timestamp = Taskbar.last.updated_at
  856. set_editor_field_value('body', 'foobar')
  857. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  858. # This time body value should be left as-is
  859. use_template(template1)
  860. check_input_field_value('title', 'template 1')
  861. check_editor_field_value('body', 'foobar')
  862. end
  863. end
  864. describe 'Ticket templates are missing pending till option #4318', time_zone: 'Europe/London' do
  865. shared_examples 'check datetime field' do
  866. shared_examples 'calculated datetime value' do
  867. it 'applies correct datetime value' do
  868. use_template(template, without_taskbar: true)
  869. check_date_field_value(field, date.strftime('%m/%d/%Y'))
  870. check_time_field_value(field, date.strftime('%H:%M'))
  871. end
  872. end
  873. context 'with static operator' do
  874. let(:operator) { 'static' }
  875. let(:date) { 3.days.from_now }
  876. let(:template_value) { date.to_datetime.to_s }
  877. it_behaves_like 'calculated datetime value'
  878. end
  879. context 'with relative operator' do
  880. let(:operator) { 'relative' }
  881. let(:template_value) { value.to_s }
  882. let(:date) do
  883. # Since front-end uses a JS-specific function to add a month value to the current date,
  884. # calculating the value here with Ruby code may lead to unexpected values.
  885. # Therefore, we use a reimplementation of the ECMAScript function instead.
  886. case range
  887. when 'month'
  888. frontend_relative_month(Time.current, value)
  889. when 'year'
  890. frontend_relative_month(Time.current, 0, year: value)
  891. else
  892. value.send(range).from_now
  893. end
  894. end
  895. %w[minute hour day week month year].each do |range|
  896. context "with #{range} range" do
  897. let(:range) { range }
  898. let(:value) do
  899. case range
  900. when 'minute' then [*(1..120)].sample
  901. when 'hour' then [*(1..48)].sample
  902. when 'day' then [*(1..31)].sample
  903. when 'week' then [*(1..53)].sample
  904. when 'month' then [*(1..12)].sample
  905. when 'year' then [*(1..20)].sample
  906. end
  907. end
  908. it_behaves_like 'calculated datetime value'
  909. end
  910. end
  911. end
  912. end
  913. shared_examples 'check date field' do
  914. let(:date) { 5.days.from_now }
  915. let(:template_value) { date.to_datetime.to_s }
  916. it 'applies correct date value' do
  917. use_template(template, without_taskbar: true)
  918. check_date_field_value(field, date.strftime('%m/%d/%Y'))
  919. end
  920. end
  921. describe 'pending till support' do
  922. let(:field) { 'pending_time' }
  923. let(:template) do
  924. create(:template,
  925. options: {
  926. 'ticket.state_id': {
  927. value: Ticket::State.find_by(name: 'pending reminder').id.to_s,
  928. },
  929. "ticket.#{field}": {
  930. value: template_value,
  931. operator: operator,
  932. range: (range if defined? range),
  933. }
  934. })
  935. end
  936. before do
  937. freeze_time
  938. template
  939. visit '/'
  940. browser_travel_to Time.current
  941. visit 'ticket/create'
  942. end
  943. include_examples 'check datetime field'
  944. end
  945. describe 'custom attribute support' do
  946. let(:template) do
  947. create(:template,
  948. options: {
  949. "ticket.#{field}": {
  950. value: template_value,
  951. operator: (operator if defined? operator),
  952. range: (range if defined? range),
  953. }
  954. })
  955. end
  956. before :all do # rubocop:disable RSpec/BeforeAfterAll
  957. screens = {
  958. create_middle: {
  959. 'ticket.agent' => {
  960. shown: true,
  961. },
  962. },
  963. }
  964. create(:object_manager_attribute_date, name: 'test_date', display: 'test_date', screens: screens)
  965. create(:object_manager_attribute_datetime, name: 'test_datetime', display: 'test_datetime', screens: screens)
  966. ObjectManager::Attribute.migration_execute # rubocop:disable Zammad/ExistsDbStrategy
  967. end
  968. after :all do # rubocop:disable RSpec/BeforeAfterAll
  969. ObjectManager::Attribute.where(name: %w[test_date test_datetime]).destroy_all
  970. end
  971. before do
  972. freeze_time
  973. template
  974. visit '/'
  975. browser_travel_to Time.current
  976. visit 'ticket/create'
  977. end
  978. context 'with date attribute' do
  979. let(:field) { 'test_date' }
  980. include_examples 'check date field'
  981. end
  982. context 'with datetime attribute' do
  983. let(:field) { 'test_datetime' }
  984. include_examples 'check datetime field'
  985. end
  986. end
  987. end
  988. describe 'Ticket templates are missing active flag #4381' do
  989. let!(:active_template) { create(:template, :dummy_data, active: true) }
  990. let!(:inactive_template) { create(:template, :dummy_data, active: false) }
  991. before do
  992. visit 'ticket/create'
  993. end
  994. it 'filters active templates only' do
  995. expect(find('#form-template select[name="id"]')).to have_css('option', text: active_template.name).and(have_no_selector('option', text: inactive_template.name))
  996. end
  997. end
  998. describe 'CC field cannot be customized in the new ticket templates #4421', authenticated_as: :agent do
  999. let(:group) { create(:group) }
  1000. let(:agent) { create(:agent, groups: [group]) }
  1001. let(:customer) { create(:customer) }
  1002. let(:cc_recipients) { Array.new(3) { Faker::Internet.unique.email }.join(', ') }
  1003. let!(:template) do
  1004. create(:template,
  1005. options: {
  1006. 'ticket.title': {
  1007. value: Faker::Name.unique.name_with_middle,
  1008. },
  1009. 'ticket.customer_id': {
  1010. value: customer.id,
  1011. value_completion: "#{customer.firstname} #{customer.lastname} <#{customer.email}>",
  1012. },
  1013. 'ticket.group_id': {
  1014. value: group.id,
  1015. },
  1016. 'ticket.formSenderType': {
  1017. value: form_sender_type,
  1018. },
  1019. 'article.cc': {
  1020. value: cc_recipients,
  1021. },
  1022. 'article.body': {
  1023. value: Faker::Hacker.say_something_smart,
  1024. },
  1025. })
  1026. end
  1027. before do
  1028. visit 'ticket/create'
  1029. end
  1030. context 'with email article type' do
  1031. let(:form_sender_type) { 'email-out' }
  1032. it 'applies configured cc value' do
  1033. use_template(template)
  1034. expect(page).to have_css('label', text: 'CC')
  1035. check_input_field_value('cc', cc_recipients, visible: :all)
  1036. click '.js-submit'
  1037. expect(Ticket::Article.last).to have_attributes(cc: cc_recipients)
  1038. end
  1039. end
  1040. context 'with phone article type' do
  1041. let(:form_sender_type) { 'phone-out' }
  1042. it 'ignores configured cc value' do
  1043. use_template(template)
  1044. expect(page).to have_no_css('label', text: 'CC')
  1045. click '.js-submit'
  1046. expect(Ticket::Article.last).not_to have_attributes(cc: cc_recipients)
  1047. end
  1048. end
  1049. end
  1050. describe 'Open ticket indicator coloring setting' do
  1051. let(:elem) { find('[data-tab="customer"]') }
  1052. let(:customer) { create(:customer) }
  1053. let(:group) { Group.first }
  1054. before do
  1055. Setting.set 'ui_sidebar_open_ticket_indicator_colored', state
  1056. customer.preferences[:tickets_open] = tickets_count
  1057. customer.save!
  1058. visit 'ticket/create'
  1059. field = find '[name=customer_id]', visible: :hidden
  1060. field.execute_script "this.value = #{customer.id}"
  1061. field.execute_script '$(this).trigger("change")'
  1062. end
  1063. context 'when enabled' do
  1064. let(:state) { true }
  1065. context 'with 1 ticket' do
  1066. let(:tickets_count) { 1 }
  1067. it 'highlights as warning' do
  1068. create(:ticket, customer: customer, group: group)
  1069. expect(elem)
  1070. .to have_no_selector('.tabsSidebar-tab-count--danger')
  1071. .and have_css('.tabsSidebar-tab-count--warning')
  1072. end
  1073. end
  1074. context 'with 2 tickets' do
  1075. let(:tickets_count) { 2 }
  1076. it 'highlights as danger' do
  1077. expect(elem)
  1078. .to have_css('.tabsSidebar-tab-count--danger')
  1079. .and have_no_selector('.tabsSidebar-tab-count--warning')
  1080. end
  1081. end
  1082. end
  1083. context 'when disabled' do
  1084. let(:state) { false }
  1085. context 'with 2 tickets' do
  1086. let(:tickets_count) { 2 }
  1087. it 'does not highlight' do
  1088. expect(elem)
  1089. .to have_no_selector('.tabsSidebar-tab-count--danger, .tabsSidebar-tab-count--warning')
  1090. end
  1091. end
  1092. end
  1093. end
  1094. describe 'Not possible to select multiple values in a multi-tree select when a workflow with a select action is executed #4465', authenticated_as: :authenticate, db_strategy: :reset do
  1095. let(:field_name) { SecureRandom.uuid }
  1096. let(:screens) do
  1097. {
  1098. 'create_middle' => {
  1099. 'ticket.agent' => {
  1100. 'shown' => true,
  1101. 'required' => false,
  1102. }
  1103. }
  1104. }
  1105. end
  1106. def authenticate
  1107. create(:object_manager_attribute_multi_tree_select, name: field_name, display: field_name, screens: screens)
  1108. ObjectManager::Attribute.migration_execute
  1109. create(:core_workflow,
  1110. object: 'Ticket',
  1111. perform: {
  1112. 'ticket.priority_id': {
  1113. operator: 'select',
  1114. select: [Ticket::Priority.find_by(name: '3 high').id.to_s]
  1115. },
  1116. })
  1117. true
  1118. end
  1119. def multi_tree_select_click(value)
  1120. page.evaluate_script("document.querySelector(\"div[data-attribute-name='#{field_name}'] .js-optionsList li[data-value='#{value}'] .searchableSelect-option-text\").click()")
  1121. await_empty_ajax_queue
  1122. end
  1123. before do
  1124. visit 'ticket/create'
  1125. end
  1126. it 'does not clear the values of the multi tree select' do
  1127. multi_tree_select_click('Incident')
  1128. multi_tree_select_click('Service request')
  1129. multi_tree_select_click('Change request')
  1130. select '1 low', from: 'priority_id'
  1131. select 'pending reminder', from: 'state_id'
  1132. expect(page).to have_css('span.token-label', text: 'Incident')
  1133. expect(page).to have_css('span.token-label', text: 'Service request')
  1134. expect(page).to have_css('span.token-label', text: 'Change request')
  1135. end
  1136. end
  1137. describe 'Support title and body in core workflow actions #4519', authenticated_as: :authenticate do
  1138. let(:workflow) do
  1139. create(:core_workflow,
  1140. object: 'Ticket',
  1141. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => [Ticket::Priority.find_by(name: '2 normal').id.to_s] } },
  1142. perform: { 'ticket.title' => { 'operator' => %w[fill_in set_readonly], 'fill_in' => 'title 123', 'set_readonly' => true }, 'ticket.body' => { 'operator' => %w[fill_in set_readonly], 'fill_in' => '<b>text 123</b>', 'set_readonly' => true } })
  1143. end
  1144. context 'when agent' do
  1145. def authenticate
  1146. workflow
  1147. true
  1148. end
  1149. before do
  1150. visit '#ticket/create'
  1151. end
  1152. it 'has core workflow support for title and text' do
  1153. expect(page).to have_css('div[data-attribute-name=title].is-readonly')
  1154. expect(page).to have_css('div[data-attribute-name=body].is-readonly')
  1155. expect(page.find_field('Title').value).to eq('title 123')
  1156. expect(page.find('div[data-name=body]')['innerHTML']).to eq('<b>text 123</b>')
  1157. # unset readonly (https://github.com/zammad/zammad/issues/4540)
  1158. select '1 low', from: 'priority_id'
  1159. expect(page).to have_no_css('div[data-attribute-name=title].is-readonly')
  1160. expect(page).to have_no_css('div[data-attribute-name=body].is-readonly')
  1161. # reset readonly
  1162. select '2 normal', from: 'priority_id'
  1163. expect(page).to have_css('div[data-attribute-name=title].is-readonly')
  1164. expect(page).to have_css('div[data-attribute-name=body].is-readonly')
  1165. end
  1166. end
  1167. context 'when customer' do
  1168. def authenticate
  1169. workflow
  1170. create(:customer)
  1171. end
  1172. before do
  1173. visit '#customer_ticket_new'
  1174. end
  1175. it 'has core workflow support for title and text' do
  1176. expect(page).to have_css('div[data-attribute-name=title].is-readonly')
  1177. expect(page).to have_css('div[data-attribute-name=body].is-readonly')
  1178. expect(page.find_field('Title').value).to eq('title 123')
  1179. expect(page.find('div[data-name=body]')['innerHTML']).to eq('<b>text 123</b>')
  1180. end
  1181. end
  1182. end
  1183. describe 'Date field value of a ticket template is not added into a new ticket #4864', authenticated_as: :authenticate, db_strategy: :reset do
  1184. let(:field_name) { SecureRandom.uuid }
  1185. let(:field) do
  1186. create(:object_manager_attribute_date, :required_screen, name: field_name, display: field_name)
  1187. ObjectManager::Attribute.migration_execute
  1188. end
  1189. let(:template) do
  1190. create(:template, :dummy_data).tap do |template|
  1191. template.update(options: template.options.merge("ticket.#{field_name}" => { 'operator' => 'relative', 'value' => '1', 'range' => 'day' }))
  1192. end
  1193. end
  1194. def authenticate
  1195. field
  1196. true
  1197. end
  1198. before do
  1199. visit 'ticket/create'
  1200. use_template(template)
  1201. end
  1202. it 'does create a date with a relative template value' do
  1203. click '.js-submit'
  1204. expect(Ticket.last).to have_attributes(field_name => 1.day.from_now.to_date)
  1205. end
  1206. end
  1207. describe 'Setting a group via CoreWorkflow in the ticket creation mask does not update text module filters and email signatures #4891', authenticated_as: :authenticate do
  1208. let(:group_1) { create(:group, signature: create(:signature, body: SecureRandom.uuid)) }
  1209. let(:group_2) { create(:group, signature: create(:signature, body: SecureRandom.uuid)) }
  1210. let(:workflow_1) do
  1211. create(:core_workflow,
  1212. object: 'Ticket',
  1213. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '3 high').id.to_s } },
  1214. perform: { 'ticket.group_id' => { 'operator' => 'select', 'select' => group_1.id.to_s } })
  1215. end
  1216. let(:workflow_2) do
  1217. create(:core_workflow,
  1218. object: 'Ticket',
  1219. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '1 low').id.to_s } },
  1220. perform: { 'ticket.group_id' => { 'operator' => 'select', 'select' => group_2.id.to_s } })
  1221. end
  1222. def authenticate
  1223. workflow_1 && workflow_2
  1224. group_1 && group_2
  1225. create(:agent, groups: Group.all)
  1226. end
  1227. it 'does change the signature when switching group via core workflow' do
  1228. visit 'ticket/create'
  1229. find('[data-type=email-out]').click
  1230. page.find('[name=priority_id]').select '3 high'
  1231. expect(page).to have_text(group_1.signature.body)
  1232. page.find('[name=priority_id]').select '1 low'
  1233. expect(page).to have_text(group_2.signature.body)
  1234. end
  1235. end
  1236. describe 'CoreWorkflow "fill in empty" fires on non-empty fields during ticket creation when logged in as customer #5004' do
  1237. let(:body_content) { SecureRandom.uuid }
  1238. let(:workflow) do
  1239. create(:core_workflow,
  1240. object: 'Ticket',
  1241. perform: { 'article.body' => { 'operator' => 'fill_in_empty', 'fill_in_empty' => body_content } })
  1242. end
  1243. def setup_workflows
  1244. workflow
  1245. end
  1246. context 'when agent', authenticated_as: :authenticate do
  1247. def authenticate
  1248. setup_workflows
  1249. true
  1250. end
  1251. before do
  1252. visit '#ticket/create'
  1253. end
  1254. it 'does fill the body' do
  1255. check_editor_field_value('body', body_content)
  1256. set_editor_field_value('body', 'new_content')
  1257. check_editor_field_value('body', 'new_content')
  1258. page.find('[name=priority_id]').select '3 high'
  1259. check_editor_field_value('body', 'new_content')
  1260. end
  1261. end
  1262. context 'when customer', authenticated_as: :authenticate do
  1263. def authenticate
  1264. setup_workflows
  1265. create(:customer)
  1266. end
  1267. before do
  1268. visit 'customer_ticket_new'
  1269. end
  1270. it 'does fill the body' do
  1271. check_editor_field_value('body', body_content)
  1272. set_editor_field_value('body', 'new_content')
  1273. check_editor_field_value('body', 'new_content')
  1274. page.find('[name=state_id]').select 'closed'
  1275. check_editor_field_value('body', 'new_content')
  1276. end
  1277. end
  1278. end
  1279. end