create_spec.rb 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  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. end
  774. context 'when customer' do
  775. before do
  776. visit 'customer_ticket_new'
  777. end
  778. it 'does not show the organization field for user 1', authenticated_as: :customer1 do
  779. expect(page).to have_css("div[data-attribute-name='organization_id']")
  780. end
  781. it 'does show the organization field for user 2', authenticated_as: :customer2 do
  782. expect(page).to have_no_css("div[data-attribute-name='organization_id']")
  783. end
  784. it 'can create tickets for secondary organizations', authenticated_as: :customer1 do
  785. fill_in 'Title', with: 'test'
  786. find('.richtext-content').send_keys 'test'
  787. set_tree_select_value('group_id', Group.first.name)
  788. find('div[data-attribute-name=organization_id] .js-input').fill_in with: customer1.organizations[0].name, fill_options: { clear: :backspace }
  789. wait.until { page.all("div[data-attribute-name=organization_id] .js-option[data-value='#{customer1.organizations[0].id}']").present? }
  790. page.find("div[data-attribute-name=organization_id] .js-option[data-value='#{customer1.organizations[0].id}'] span").click
  791. click '.js-submit'
  792. wait.until { Ticket.last.organization_id == customer1.organizations[0].id }
  793. end
  794. end
  795. end
  796. describe 'Wrong default values in ticket create when creating from user profile #4088' do
  797. let(:customer) { create(:customer) }
  798. before do
  799. visit "ticket/create/customer/#{customer.id}"
  800. end
  801. it 'does show the default state when creating a ticket from a user profile' do
  802. expect(page).to have_select('state_id', selected: 'open')
  803. end
  804. end
  805. describe 'Ticket templates do not save the owner attribute #4175' do
  806. let(:agent) { create(:agent, groups: [Group.first]) }
  807. let!(:template) { create(:template, :dummy_data, group: Group.first, owner: agent) }
  808. before do
  809. visit 'ticket/create'
  810. # Wait for the initial taskbar update to finish
  811. taskbar_timestamp = Taskbar.last.updated_at
  812. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  813. end
  814. it 'does set owners properly by templates and taskbars' do
  815. use_template(template)
  816. expect(page).to have_select('owner_id', selected: agent.fullname)
  817. wait.until { Taskbar.last.state['owner_id'].to_i == agent.id }
  818. refresh
  819. expect(page).to have_select('owner_id', selected: agent.fullname)
  820. end
  821. end
  822. describe 'Ticket templates resets article body #2434' do
  823. let!(:template1) { create(:template, :dummy_data, title: 'template 1', body: 'body 1') }
  824. let!(:template2) { create(:template, :dummy_data, title: 'template 2', body: 'body 2') }
  825. before do
  826. visit 'ticket/create'
  827. end
  828. it 'preserves text input from the user' do
  829. taskbar_timestamp = Taskbar.last.updated_at
  830. set_editor_field_value('body', 'foobar')
  831. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  832. use_template(template1)
  833. check_input_field_value('title', 'template 1')
  834. check_editor_field_value('body', 'foobar')
  835. end
  836. it 'allows easy switching between templates' do
  837. use_template(template1)
  838. check_input_field_value('title', 'template 1')
  839. check_editor_field_value('body', 'body 1')
  840. use_template(template2)
  841. check_input_field_value('title', 'template 2')
  842. check_editor_field_value('body', 'body 2')
  843. taskbar_timestamp = Taskbar.last.updated_at
  844. set_editor_field_value('body', 'foobar')
  845. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  846. # This time body value should be left as-is
  847. use_template(template1)
  848. check_input_field_value('title', 'template 1')
  849. check_editor_field_value('body', 'foobar')
  850. end
  851. end
  852. describe 'Ticket templates are missing pending till option #4318', time_zone: 'Europe/London' do
  853. shared_examples 'check datetime field' do
  854. shared_examples 'calculated datetime value' do
  855. it 'applies correct datetime value' do
  856. use_template(template, without_taskbar: true)
  857. check_date_field_value(field, date.strftime('%m/%d/%Y'))
  858. check_time_field_value(field, date.strftime('%H:%M'))
  859. end
  860. end
  861. context 'with static operator' do
  862. let(:operator) { 'static' }
  863. let(:date) { 3.days.from_now }
  864. let(:template_value) { date.to_datetime.to_s }
  865. it_behaves_like 'calculated datetime value'
  866. end
  867. context 'with relative operator' do
  868. let(:operator) { 'relative' }
  869. let(:template_value) { value.to_s }
  870. let(:date) do
  871. # Since front-end uses a JS-specific function to add a month value to the current date,
  872. # calculating the value here with Ruby code may lead to unexpected values.
  873. # Therefore, we use a reimplementation of the ECMAScript function instead.
  874. case range
  875. when 'month'
  876. frontend_relative_month(Time.current, value)
  877. when 'year'
  878. frontend_relative_month(Time.current, 0, year: value)
  879. else
  880. value.send(range).from_now
  881. end
  882. end
  883. %w[minute hour day week month year].each do |range|
  884. context "with #{range} range" do
  885. let(:range) { range }
  886. let(:value) do
  887. case range
  888. when 'minute' then [*(1..120)].sample
  889. when 'hour' then [*(1..48)].sample
  890. when 'day' then [*(1..31)].sample
  891. when 'week' then [*(1..53)].sample
  892. when 'month' then [*(1..12)].sample
  893. when 'year' then [*(1..20)].sample
  894. end
  895. end
  896. it_behaves_like 'calculated datetime value'
  897. end
  898. end
  899. end
  900. end
  901. shared_examples 'check date field' do
  902. let(:date) { 5.days.from_now }
  903. let(:template_value) { date.to_datetime.to_s }
  904. it 'applies correct date value' do
  905. use_template(template, without_taskbar: true)
  906. check_date_field_value(field, date.strftime('%m/%d/%Y'))
  907. end
  908. end
  909. describe 'pending till support' do
  910. let(:field) { 'pending_time' }
  911. let(:template) do
  912. create(:template,
  913. options: {
  914. 'ticket.state_id': {
  915. value: Ticket::State.find_by(name: 'pending reminder').id.to_s,
  916. },
  917. "ticket.#{field}": {
  918. value: template_value,
  919. operator: operator,
  920. range: (range if defined? range),
  921. }
  922. })
  923. end
  924. before do
  925. freeze_time
  926. template
  927. visit '/'
  928. browser_travel_to Time.current
  929. visit 'ticket/create'
  930. end
  931. include_examples 'check datetime field'
  932. end
  933. describe 'custom attribute support' do
  934. let(:template) do
  935. create(:template,
  936. options: {
  937. "ticket.#{field}": {
  938. value: template_value,
  939. operator: (operator if defined? operator),
  940. range: (range if defined? range),
  941. }
  942. })
  943. end
  944. before :all do # rubocop:disable RSpec/BeforeAfterAll
  945. screens = {
  946. create_middle: {
  947. 'ticket.agent' => {
  948. shown: true,
  949. },
  950. },
  951. }
  952. create(:object_manager_attribute_date, name: 'test_date', display: 'test_date', screens: screens)
  953. create(:object_manager_attribute_datetime, name: 'test_datetime', display: 'test_datetime', screens: screens)
  954. ObjectManager::Attribute.migration_execute # rubocop:disable Zammad/ExistsDbStrategy
  955. end
  956. after :all do # rubocop:disable RSpec/BeforeAfterAll
  957. ObjectManager::Attribute.where(name: %w[test_date test_datetime]).destroy_all
  958. end
  959. before do
  960. freeze_time
  961. template
  962. visit '/'
  963. browser_travel_to Time.current
  964. visit 'ticket/create'
  965. end
  966. context 'with date attribute' do
  967. let(:field) { 'test_date' }
  968. include_examples 'check date field'
  969. end
  970. context 'with datetime attribute' do
  971. let(:field) { 'test_datetime' }
  972. include_examples 'check datetime field'
  973. end
  974. end
  975. end
  976. describe 'Ticket templates are missing active flag #4381' do
  977. let!(:active_template) { create(:template, :dummy_data, active: true) }
  978. let!(:inactive_template) { create(:template, :dummy_data, active: false) }
  979. before do
  980. visit 'ticket/create'
  981. end
  982. it 'filters active templates only' do
  983. expect(find('#form-template select[name="id"]')).to have_css('option', text: active_template.name).and(have_no_selector('option', text: inactive_template.name))
  984. end
  985. end
  986. describe 'CC field cannot be customized in the new ticket templates #4421', authenticated_as: :agent do
  987. let(:group) { create(:group) }
  988. let(:agent) { create(:agent, groups: [group]) }
  989. let(:customer) { create(:customer) }
  990. let(:cc_recipients) { Array.new(3) { Faker::Internet.unique.email }.join(', ') }
  991. let!(:template) do
  992. create(:template,
  993. options: {
  994. 'ticket.title': {
  995. value: Faker::Name.unique.name_with_middle,
  996. },
  997. 'ticket.customer_id': {
  998. value: customer.id,
  999. value_completion: "#{customer.firstname} #{customer.lastname} <#{customer.email}>",
  1000. },
  1001. 'ticket.group_id': {
  1002. value: group.id,
  1003. },
  1004. 'ticket.formSenderType': {
  1005. value: form_sender_type,
  1006. },
  1007. 'article.cc': {
  1008. value: cc_recipients,
  1009. },
  1010. 'article.body': {
  1011. value: Faker::Hacker.say_something_smart,
  1012. },
  1013. })
  1014. end
  1015. before do
  1016. visit 'ticket/create'
  1017. end
  1018. context 'with email article type' do
  1019. let(:form_sender_type) { 'email-out' }
  1020. it 'applies configured cc value' do
  1021. use_template(template)
  1022. expect(page).to have_css('label', text: 'CC')
  1023. check_input_field_value('cc', cc_recipients, visible: :all)
  1024. click '.js-submit'
  1025. expect(Ticket::Article.last).to have_attributes(cc: cc_recipients)
  1026. end
  1027. end
  1028. context 'with phone article type' do
  1029. let(:form_sender_type) { 'phone-out' }
  1030. it 'ignores configured cc value' do
  1031. use_template(template)
  1032. expect(page).to have_no_css('label', text: 'CC')
  1033. click '.js-submit'
  1034. expect(Ticket::Article.last).not_to have_attributes(cc: cc_recipients)
  1035. end
  1036. end
  1037. end
  1038. describe 'Open ticket indicator coloring setting' do
  1039. let(:elem) { find('[data-tab="customer"]') }
  1040. let(:customer) { create(:customer) }
  1041. let(:group) { Group.first }
  1042. before do
  1043. Setting.set 'ui_sidebar_open_ticket_indicator_colored', state
  1044. customer.preferences[:tickets_open] = tickets_count
  1045. customer.save!
  1046. visit 'ticket/create'
  1047. field = find '[name=customer_id]', visible: :hidden
  1048. field.execute_script "this.value = #{customer.id}"
  1049. field.execute_script '$(this).trigger("change")'
  1050. end
  1051. context 'when enabled' do
  1052. let(:state) { true }
  1053. context 'with 1 ticket' do
  1054. let(:tickets_count) { 1 }
  1055. it 'highlights as warning' do
  1056. create(:ticket, customer: customer, group: group)
  1057. expect(elem)
  1058. .to have_no_selector('.tabsSidebar-tab-count--danger')
  1059. .and have_css('.tabsSidebar-tab-count--warning')
  1060. end
  1061. end
  1062. context 'with 2 tickets' do
  1063. let(:tickets_count) { 2 }
  1064. it 'highlights as danger' do
  1065. expect(elem)
  1066. .to have_css('.tabsSidebar-tab-count--danger')
  1067. .and have_no_selector('.tabsSidebar-tab-count--warning')
  1068. end
  1069. end
  1070. end
  1071. context 'when disabled' do
  1072. let(:state) { false }
  1073. context 'with 2 tickets' do
  1074. let(:tickets_count) { 2 }
  1075. it 'does not highlight' do
  1076. expect(elem)
  1077. .to have_no_selector('.tabsSidebar-tab-count--danger, .tabsSidebar-tab-count--warning')
  1078. end
  1079. end
  1080. end
  1081. end
  1082. 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
  1083. let(:field_name) { SecureRandom.uuid }
  1084. let(:screens) do
  1085. {
  1086. 'create_middle' => {
  1087. 'ticket.agent' => {
  1088. 'shown' => true,
  1089. 'required' => false,
  1090. }
  1091. }
  1092. }
  1093. end
  1094. def authenticate
  1095. create(:object_manager_attribute_multi_tree_select, name: field_name, display: field_name, screens: screens)
  1096. ObjectManager::Attribute.migration_execute
  1097. create(:core_workflow,
  1098. object: 'Ticket',
  1099. perform: {
  1100. 'ticket.priority_id': {
  1101. operator: 'select',
  1102. select: [Ticket::Priority.find_by(name: '3 high').id.to_s]
  1103. },
  1104. })
  1105. true
  1106. end
  1107. def multi_tree_select_click(value)
  1108. page.evaluate_script("document.querySelector(\"div[data-attribute-name='#{field_name}'] .js-optionsList li[data-value='#{value}'] .searchableSelect-option-text\").click()")
  1109. await_empty_ajax_queue
  1110. end
  1111. before do
  1112. visit 'ticket/create'
  1113. end
  1114. it 'does not clear the values of the multi tree select' do
  1115. multi_tree_select_click('Incident')
  1116. multi_tree_select_click('Service request')
  1117. multi_tree_select_click('Change request')
  1118. select '1 low', from: 'priority_id'
  1119. select 'pending reminder', from: 'state_id'
  1120. expect(page).to have_css('span.token-label', text: 'Incident')
  1121. expect(page).to have_css('span.token-label', text: 'Service request')
  1122. expect(page).to have_css('span.token-label', text: 'Change request')
  1123. end
  1124. end
  1125. describe 'Support title and body in core workflow actions #4519', authenticated_as: :authenticate do
  1126. let(:workflow) do
  1127. create(:core_workflow,
  1128. object: 'Ticket',
  1129. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => [Ticket::Priority.find_by(name: '2 normal').id.to_s] } },
  1130. 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 } })
  1131. end
  1132. context 'when agent' do
  1133. def authenticate
  1134. workflow
  1135. true
  1136. end
  1137. before do
  1138. visit '#ticket/create'
  1139. end
  1140. it 'has core workflow support for title and text' do
  1141. expect(page).to have_css('div[data-attribute-name=title].is-readonly')
  1142. expect(page).to have_css('div[data-attribute-name=body].is-readonly')
  1143. expect(page.find_field('Title').value).to eq('title 123')
  1144. expect(page.find('div[data-name=body]')['innerHTML']).to eq('<b>text 123</b>')
  1145. # unset readonly (https://github.com/zammad/zammad/issues/4540)
  1146. select '1 low', from: 'priority_id'
  1147. expect(page).to have_no_css('div[data-attribute-name=title].is-readonly')
  1148. expect(page).to have_no_css('div[data-attribute-name=body].is-readonly')
  1149. # reset readonly
  1150. select '2 normal', from: 'priority_id'
  1151. expect(page).to have_css('div[data-attribute-name=title].is-readonly')
  1152. expect(page).to have_css('div[data-attribute-name=body].is-readonly')
  1153. end
  1154. end
  1155. context 'when customer' do
  1156. def authenticate
  1157. workflow
  1158. create(:customer)
  1159. end
  1160. before do
  1161. visit '#customer_ticket_new'
  1162. end
  1163. it 'has core workflow support for title and text' do
  1164. expect(page).to have_css('div[data-attribute-name=title].is-readonly')
  1165. expect(page).to have_css('div[data-attribute-name=body].is-readonly')
  1166. expect(page.find_field('Title').value).to eq('title 123')
  1167. expect(page.find('div[data-name=body]')['innerHTML']).to eq('<b>text 123</b>')
  1168. end
  1169. end
  1170. end
  1171. describe 'Date field value of a ticket template is not added into a new ticket #4864', authenticated_as: :authenticate, db_strategy: :reset do
  1172. let(:field_name) { SecureRandom.uuid }
  1173. let(:field) do
  1174. create(:object_manager_attribute_date, :required_screen, name: field_name, display: field_name)
  1175. ObjectManager::Attribute.migration_execute
  1176. end
  1177. let(:template) do
  1178. create(:template, :dummy_data).tap do |template|
  1179. template.update(options: template.options.merge("ticket.#{field_name}" => { 'operator' => 'relative', 'value' => '1', 'range' => 'day' }))
  1180. end
  1181. end
  1182. def authenticate
  1183. field
  1184. true
  1185. end
  1186. before do
  1187. visit 'ticket/create'
  1188. use_template(template)
  1189. end
  1190. it 'does create a date with a relative template value' do
  1191. click '.js-submit'
  1192. expect(Ticket.last).to have_attributes(field_name => 1.day.from_now.to_date)
  1193. end
  1194. end
  1195. 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
  1196. let(:group_1) { create(:group, signature: create(:signature, body: SecureRandom.uuid)) }
  1197. let(:group_2) { create(:group, signature: create(:signature, body: SecureRandom.uuid)) }
  1198. let(:workflow_1) do
  1199. create(:core_workflow,
  1200. object: 'Ticket',
  1201. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '3 high').id.to_s } },
  1202. perform: { 'ticket.group_id' => { 'operator' => 'select', 'select' => group_1.id.to_s } })
  1203. end
  1204. let(:workflow_2) do
  1205. create(:core_workflow,
  1206. object: 'Ticket',
  1207. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '1 low').id.to_s } },
  1208. perform: { 'ticket.group_id' => { 'operator' => 'select', 'select' => group_2.id.to_s } })
  1209. end
  1210. def authenticate
  1211. workflow_1 && workflow_2
  1212. group_1 && group_2
  1213. create(:agent, groups: Group.all)
  1214. end
  1215. it 'does change the signature when switching group via core workflow' do
  1216. visit 'ticket/create'
  1217. find('[data-type=email-out]').click
  1218. page.find('[name=priority_id]').select '3 high'
  1219. expect(page).to have_text(group_1.signature.body)
  1220. page.find('[name=priority_id]').select '1 low'
  1221. expect(page).to have_text(group_2.signature.body)
  1222. end
  1223. end
  1224. describe 'CoreWorkflow "fill in empty" fires on non-empty fields during ticket creation when logged in as customer #5004' do
  1225. let(:body_content) { SecureRandom.uuid }
  1226. let(:workflow) do
  1227. create(:core_workflow,
  1228. object: 'Ticket',
  1229. perform: { 'article.body' => { 'operator' => 'fill_in_empty', 'fill_in_empty' => body_content } })
  1230. end
  1231. def setup_workflows
  1232. workflow
  1233. end
  1234. context 'when agent', authenticated_as: :authenticate do
  1235. def authenticate
  1236. setup_workflows
  1237. true
  1238. end
  1239. before do
  1240. visit '#ticket/create'
  1241. end
  1242. it 'does fill the body' do
  1243. check_editor_field_value('body', body_content)
  1244. set_editor_field_value('body', 'new_content')
  1245. check_editor_field_value('body', 'new_content')
  1246. page.find('[name=priority_id]').select '3 high'
  1247. check_editor_field_value('body', 'new_content')
  1248. end
  1249. end
  1250. context 'when customer', authenticated_as: :authenticate do
  1251. def authenticate
  1252. setup_workflows
  1253. create(:customer)
  1254. end
  1255. before do
  1256. visit 'customer_ticket_new'
  1257. end
  1258. it 'does fill the body' do
  1259. check_editor_field_value('body', body_content)
  1260. set_editor_field_value('body', 'new_content')
  1261. check_editor_field_value('body', 'new_content')
  1262. page.find('[name=state_id]').select 'closed'
  1263. check_editor_field_value('body', 'new_content')
  1264. end
  1265. end
  1266. end
  1267. end