create_spec.rb 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. # Copyright (C) 2012-2022 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 applying ticket templates' do
  7. let(:agent) { create(:agent, groups: [permitted_group]) }
  8. let(:permitted_group) { create(:group) }
  9. let(:unpermitted_group) { create(:group) }
  10. let!(:template) { create(:template, :dummy_data, group: unpermitted_group, owner: agent) }
  11. # Regression test for issue #2424 - Unavailable ticket template attributes get applied
  12. it 'unavailable attributes do not get applied', authenticated_as: :agent do
  13. visit 'ticket/create'
  14. use_template(template)
  15. expect(page).to have_no_select('group_id')
  16. end
  17. end
  18. context 'when using text modules' do
  19. include_examples 'text modules', path: 'ticket/create'
  20. end
  21. context 'S/MIME', authenticated_as: :authenticate do
  22. def authenticate
  23. Setting.set('smime_integration', true)
  24. Setting.set('smime_config', smime_config) if defined?(smime_config)
  25. current_user
  26. end
  27. context 'no certificate present' do
  28. let!(:template) { create(:template, :dummy_data) }
  29. let(:current_user) { true }
  30. it 'has no security selections' do
  31. visit 'ticket/create'
  32. within(:active_content) do
  33. use_template(template)
  34. expect(page).to have_no_css('div.js-securityEncrypt.btn--active')
  35. expect(page).to have_no_css('div.js-securitySign.btn--active')
  36. click '.js-submit'
  37. expect(page).to have_css('.ticket-article-item', count: 1)
  38. open_article_meta
  39. expect(page).to have_no_css('span', text: 'Signed')
  40. expect(page).to have_no_css('span', text: 'Encrypted')
  41. security_result = Ticket::Article.last.preferences['security']
  42. expect(security_result['encryption']['success']).to be_nil
  43. expect(security_result['sign']['success']).to be_nil
  44. end
  45. end
  46. end
  47. context 'private key configured' do
  48. let(:current_user) { agent }
  49. let!(:template) { create(:template, :dummy_data, group: group, owner: agent, customer: customer) }
  50. let(:system_email_address) { 'smime1@example.com' }
  51. let(:email_address) { create(:email_address, email: system_email_address) }
  52. let(:group) { create(:group, email_address: email_address) }
  53. let(:agent_groups) { [group] }
  54. let(:agent) { create(:agent, groups: agent_groups) }
  55. before do
  56. create(:smime_certificate, :with_private, fixture: system_email_address)
  57. end
  58. context 'recipient certificate present' do
  59. let(:recipient_email_address) { 'smime2@example.com' }
  60. let(:customer) { create(:customer, email: recipient_email_address) }
  61. before do
  62. create(:smime_certificate, fixture: recipient_email_address)
  63. end
  64. it 'plain' do
  65. visit 'ticket/create'
  66. within(:active_content) do
  67. use_template(template)
  68. # wait till S/MIME check AJAX call is ready
  69. expect(page).to have_css('div.js-securityEncrypt.btn--active')
  70. expect(page).to have_css('div.js-securitySign.btn--active')
  71. # deactivate encryption and signing
  72. click '.js-securityEncrypt'
  73. click '.js-securitySign'
  74. click '.js-submit'
  75. expect(page).to have_css('.ticket-article-item', count: 1)
  76. open_article_meta
  77. expect(page).to have_no_css('span', text: 'Signed')
  78. expect(page).to have_no_css('span', text: 'Encrypted')
  79. security_result = Ticket::Article.last.preferences['security']
  80. expect(security_result['encryption']['success']).to be_nil
  81. expect(security_result['sign']['success']).to be_nil
  82. end
  83. end
  84. it 'signed' do
  85. visit 'ticket/create'
  86. within(:active_content) do
  87. use_template(template)
  88. # wait till S/MIME check AJAX call is ready
  89. expect(page).to have_css('div.js-securityEncrypt.btn--active')
  90. expect(page).to have_css('div.js-securitySign.btn--active')
  91. # deactivate encryption
  92. click '.js-securityEncrypt'
  93. click '.js-submit'
  94. expect(page).to have_css('.ticket-article-item', count: 1)
  95. open_article_meta
  96. expect(page).to have_css('span', text: 'Signed')
  97. expect(page).to have_no_css('span', text: 'Encrypted')
  98. security_result = Ticket::Article.last.preferences['security']
  99. expect(security_result['encryption']['success']).to be_nil
  100. expect(security_result['sign']['success']).to be true
  101. end
  102. end
  103. it 'encrypted' do
  104. visit 'ticket/create'
  105. within(:active_content) do
  106. use_template(template)
  107. # wait till S/MIME check AJAX call is ready
  108. expect(page).to have_css('div.js-securityEncrypt.btn--active')
  109. expect(page).to have_css('div.js-securitySign.btn--active')
  110. # deactivate signing
  111. click '.js-securitySign'
  112. click '.js-submit'
  113. expect(page).to have_css('.ticket-article-item', count: 1)
  114. open_article_meta
  115. expect(page).to have_no_css('span', text: 'Signed')
  116. expect(page).to have_css('span', text: 'Encrypted')
  117. security_result = Ticket::Article.last.preferences['security']
  118. expect(security_result['encryption']['success']).to be true
  119. expect(security_result['sign']['success']).to be_nil
  120. end
  121. end
  122. it 'signed and encrypted' do
  123. visit 'ticket/create'
  124. within(:active_content) do
  125. use_template(template)
  126. # wait till S/MIME check AJAX call is ready
  127. expect(page).to have_css('div.js-securityEncrypt.btn--active')
  128. expect(page).to have_css('div.js-securitySign.btn--active')
  129. click '.js-submit'
  130. expect(page).to have_css('.ticket-article-item', count: 1)
  131. open_article_meta
  132. expect(page).to have_css('span', text: 'Signed')
  133. expect(page).to have_css('span', text: 'Encrypted')
  134. security_result = Ticket::Article.last.preferences['security']
  135. expect(security_result['encryption']['success']).to be true
  136. expect(security_result['sign']['success']).to be true
  137. end
  138. end
  139. context 'Group default behavior' do
  140. let(:smime_config) { {} }
  141. shared_examples 'security defaults example' do |sign:, encrypt:|
  142. it "security defaults sign: #{sign}, encrypt: #{encrypt}" do
  143. within(:active_content) do
  144. if sign
  145. expect(page).to have_css('.js-securitySign.btn--active')
  146. else
  147. expect(page).to have_no_css('.js-securitySign.btn--active')
  148. end
  149. if encrypt
  150. expect(page).to have_css('.js-securityEncrypt.btn--active')
  151. else
  152. expect(page).to have_no_css('.js-securityEncrypt.btn--active')
  153. end
  154. end
  155. end
  156. end
  157. shared_examples 'security defaults' do |sign:, encrypt:|
  158. before do
  159. visit 'ticket/create'
  160. within(:active_content) do
  161. use_template(template)
  162. end
  163. end
  164. include_examples 'security defaults example', sign: sign, encrypt: encrypt
  165. end
  166. shared_examples 'security defaults group change' do |sign:, encrypt:|
  167. before do
  168. visit 'ticket/create'
  169. within(:active_content) do
  170. use_template(template)
  171. select new_group.name, from: 'group_id'
  172. end
  173. end
  174. include_examples 'security defaults example', sign: sign, encrypt: encrypt
  175. end
  176. context 'not configured' do
  177. it_behaves_like 'security defaults', sign: true, encrypt: true
  178. end
  179. context 'configuration present' do
  180. let(:smime_config) do
  181. {
  182. 'group_id' => group_defaults
  183. }
  184. end
  185. let(:group_defaults) do
  186. {
  187. 'default_encryption' => {
  188. group.id.to_s => default_encryption,
  189. },
  190. 'default_sign' => {
  191. group.id.to_s => default_sign,
  192. }
  193. }
  194. end
  195. let(:default_sign) { true }
  196. let(:default_encryption) { true }
  197. shared_examples 'sign and encrypt variations' do |check_examples_name|
  198. it_behaves_like check_examples_name, sign: true, encrypt: true
  199. context 'no value' do
  200. let(:group_defaults) { {} }
  201. it_behaves_like check_examples_name, sign: true, encrypt: true
  202. end
  203. context 'signing disabled' do
  204. let(:default_sign) { false }
  205. it_behaves_like check_examples_name, sign: false, encrypt: true
  206. end
  207. context 'encryption disabled' do
  208. let(:default_encryption) { false }
  209. it_behaves_like check_examples_name, sign: true, encrypt: false
  210. end
  211. end
  212. context 'same Group' do
  213. it_behaves_like 'sign and encrypt variations', 'security defaults'
  214. end
  215. context 'Group change' do
  216. let(:new_group) { create(:group, email_address: email_address) }
  217. let(:agent_groups) { [group, new_group] }
  218. let(:group_defaults) do
  219. {
  220. 'default_encryption' => {
  221. new_group.id.to_s => default_encryption,
  222. },
  223. 'default_sign' => {
  224. new_group.id.to_s => default_sign,
  225. }
  226. }
  227. end
  228. it_behaves_like 'sign and encrypt variations', 'security defaults group change'
  229. end
  230. end
  231. end
  232. end
  233. end
  234. end
  235. describe 'object manager attributes maxlength', authenticated_as: :authenticate, db_strategy: :reset do
  236. def authenticate
  237. create :object_manager_attribute_text, name: 'maxtest', display: 'maxtest', screens: attributes_for(:required_screen), data_option: {
  238. 'type' => 'text',
  239. 'maxlength' => 3,
  240. 'null' => true,
  241. 'translate' => false,
  242. 'default' => '',
  243. 'options' => {},
  244. 'relation' => '',
  245. }
  246. ObjectManager::Attribute.migration_execute
  247. true
  248. end
  249. it 'checks ticket create' do
  250. visit 'ticket/create'
  251. within(:active_content) do
  252. fill_in 'maxtest', with: 'hellu'
  253. expect(page.find_field('maxtest').value).to eq('hel')
  254. end
  255. end
  256. end
  257. describe 'object manager attributes default date', time_zone: 'Europe/London' do
  258. before :all do # rubocop:disable RSpec/BeforeAfterAll
  259. screens = {
  260. 'create_top' => {
  261. '-all-' => {
  262. 'null' => true
  263. }
  264. },
  265. }
  266. create(:object_manager_attribute_date, name: 'date_test', display: 'date_test', default: 24, screens: screens)
  267. create(:object_manager_attribute_datetime, name: 'datetime_test', display: 'datetime_test', default: 100, screens: screens)
  268. ObjectManager::Attribute.migration_execute # rubocop:disable Zammad/ExistsDbStrategy
  269. end
  270. after :all do # rubocop:disable RSpec/BeforeAfterAll
  271. ObjectManager::Attribute.where(name: %i[object_manager_attribute_date object_manager_attribute_datetime]).destroy_all
  272. end
  273. around do |example|
  274. Time.use_zone('Europe/London') { example.run }
  275. end
  276. before do
  277. template = create(:template, :dummy_data)
  278. travel 1.month
  279. browser_travel_to Time.current
  280. visit 'ticket/create'
  281. use_template template
  282. end
  283. let(:field_date) { find 'input[name="{date}date_test"]', visible: :all }
  284. let(:field_time) { find 'input[name="{datetime}datetime_test"]', visible: :all }
  285. it 'prefills date' do
  286. expect(field_date.value).to eq 1.day.from_now.to_date.to_s
  287. end
  288. it 'prefills datetime' do
  289. expect(Time.zone.parse(field_time.value)).to eq 100.minutes.from_now.change(sec: 0, usec: 0)
  290. end
  291. it 'saves dates' do
  292. click '.js-submit'
  293. date = 1.day.from_now.to_date
  294. time = 100.minutes.from_now.change(sec: 0)
  295. expect(Ticket.last).to have_attributes date_test: date, datetime_test: time
  296. end
  297. it 'allows to save with different values' do
  298. date = 2.days.from_now.to_date
  299. time = 200.minutes.from_now.change(sec: 0)
  300. field_date.sibling('[data-item=date]').set date.strftime('%m/%d/%Y')
  301. field_time.sibling('[data-item=date]').set time.strftime('%m/%d/%Y')
  302. field_time.sibling('[data-item=time]').set time.strftime('%H:%M')
  303. click '.js-submit'
  304. expect(Ticket.last).to have_attributes date_test: date, datetime_test: time
  305. end
  306. it 'allows to save with cleared value' do
  307. field_date.sibling('[data-item=date]').click
  308. find('.datepicker .clear').click
  309. field_time.sibling('[data-item=date]').click
  310. find('.datepicker .clear').click
  311. click '.js-submit'
  312. expect(Ticket.last).to have_attributes date_test: nil, datetime_test: nil
  313. end
  314. end
  315. describe 'GitLab Integration', :integration, authenticated_as: :authenticate, required_envs: %w[GITLAB_ENDPOINT GITLAB_APITOKEN] do
  316. let(:customer) { create(:customer) }
  317. let(:agent) { create(:agent, groups: [Group.find_by(name: 'Users')]) }
  318. let!(:template) { create(:template, :dummy_data, group: Group.find_by(name: 'Users'), owner: agent, customer: customer) }
  319. def authenticate
  320. Setting.set('gitlab_integration', true)
  321. Setting.set('gitlab_config', {
  322. api_token: ENV['GITLAB_APITOKEN'],
  323. endpoint: ENV['GITLAB_ENDPOINT'],
  324. })
  325. true
  326. end
  327. it 'creates a ticket with links' do
  328. visit 'ticket/create'
  329. within(:active_content) do
  330. use_template(template)
  331. # switch to gitlab sidebar
  332. click('.tabsSidebar-tab[data-tab=gitlab]')
  333. click('.sidebar-header-headline.js-headline')
  334. # add issue
  335. click_on 'Link issue'
  336. fill_in 'link', with: ENV['GITLAB_ISSUE_LINK']
  337. click_on 'Submit'
  338. # verify issue
  339. content = find('.sidebar-git-issue-content')
  340. expect(content).to have_text('#1 Example issue')
  341. expect(content).to have_text('critical')
  342. expect(content).to have_text('special')
  343. expect(content).to have_text('important milestone')
  344. expect(content).to have_text('zammad-robot')
  345. # create Ticket
  346. click '.js-submit'
  347. # check stored data
  348. expect(Ticket.last.preferences[:gitlab][:issue_links][0]).to eq(ENV['GITLAB_ISSUE_LINK'])
  349. end
  350. end
  351. end
  352. describe 'GitHub Integration', :integration, authenticated_as: :authenticate, required_envs: %w[GITHUB_ENDPOINT GITHUB_APITOKEN] do
  353. let(:customer) { create(:customer) }
  354. let(:agent) { create(:agent, groups: [Group.find_by(name: 'Users')]) }
  355. let!(:template) { create(:template, :dummy_data, group: Group.find_by(name: 'Users'), owner: agent, customer: customer) }
  356. def authenticate
  357. Setting.set('github_integration', true)
  358. Setting.set('github_config', {
  359. api_token: ENV['GITHUB_APITOKEN'],
  360. endpoint: ENV['GITHUB_ENDPOINT'],
  361. })
  362. true
  363. end
  364. it 'creates a ticket with links' do
  365. visit 'ticket/create'
  366. within(:active_content) do
  367. use_template(template)
  368. # switch to github sidebar
  369. click('.tabsSidebar-tab[data-tab=github]')
  370. click('.sidebar-header-headline.js-headline')
  371. # add issue
  372. click_on 'Link issue'
  373. fill_in 'link', with: ENV['GITHUB_ISSUE_LINK']
  374. click_on 'Submit'
  375. # verify issue
  376. content = find('.sidebar-git-issue-content')
  377. expect(content).to have_text('#1575 GitHub integration')
  378. expect(content).to have_text('feature backlog')
  379. expect(content).to have_text('integration')
  380. expect(content).to have_text('4.0')
  381. expect(content).to have_text('Thorsten')
  382. # create Ticket
  383. click '.js-submit'
  384. # check stored data
  385. expect(Ticket.last.preferences[:github][:issue_links][0]).to eq(ENV['GITHUB_ISSUE_LINK'])
  386. end
  387. end
  388. end
  389. describe 'Core Workflow' do
  390. include_examples 'core workflow' do
  391. let(:object_name) { 'Ticket' }
  392. let(:before_it) do
  393. lambda {
  394. ensure_websocket(check_if_pinged: false) do
  395. visit 'ticket/create'
  396. end
  397. }
  398. end
  399. end
  400. end
  401. # https://github.com/zammad/zammad/issues/2669
  402. context 'when canceling new ticket creation' do
  403. it 'closes the dialog' do
  404. visit 'ticket/create'
  405. task_key = find(:task_active)['data-key']
  406. expect { click('.js-cancel') }.to change { has_selector?(:task_with, task_key, wait: 0) }.to(false)
  407. end
  408. it 'asks for confirmation if the dialog was modified' do
  409. visit 'ticket/create'
  410. task_key = find(:task_active)['data-key']
  411. find('[name=title]').fill_in with: 'Title'
  412. click '.js-cancel'
  413. in_modal do
  414. click '.js-submit'
  415. end
  416. expect(page).to have_no_selector(:task_with, task_key)
  417. end
  418. it 'asks for confirmation if attachment was added' do
  419. visit 'ticket/create'
  420. within :active_content do
  421. page.find('input#fileUpload_1', visible: :all).set(Rails.root.join('test/data/mail/mail001.box'))
  422. await_empty_ajax_queue
  423. find('.js-cancel').click
  424. end
  425. in_modal do
  426. expect(page).to have_text 'Tab has changed'
  427. end
  428. end
  429. end
  430. context 'when uploading attachment' do
  431. it 'shows an error if server throws an error' do
  432. allow(Store).to receive(:create!) { raise 'Error' }
  433. visit 'ticket/create'
  434. within :active_content do
  435. page.find('input#fileUpload_1', visible: :all).set(Rails.root.join('test/data/mail/mail001.box'))
  436. end
  437. in_modal do
  438. expect(page).to have_text 'Error'
  439. end
  440. end
  441. end
  442. context 'when closing taskbar tab for new ticket creation' do
  443. it 'close task bar entry after some changes in ticket create form' do
  444. visit 'ticket/create'
  445. within(:active_content) do
  446. find('[name=title]').fill_in with: 'Title'
  447. end
  448. taskbar_tab_close(find(:task_active)['data-key'])
  449. end
  450. end
  451. describe 'customer selection to check the field search' do
  452. before do
  453. create(:customer, active: true)
  454. create(:customer, active: false)
  455. end
  456. it 'check for inactive customer in customer/organization selection' do
  457. visit 'ticket/create'
  458. within(:active_content) do
  459. find('[name=customer_id] ~ .user-select.token-input').fill_in with: '**'
  460. expect(page).to have_css('ul.recipientList > li.recipientList-entry', minimum: 2)
  461. expect(page).to have_css('ul.recipientList > li.recipientList-entry.is-inactive', count: 1)
  462. end
  463. end
  464. end
  465. context 'when agent and customer user login after another' do
  466. let(:agent) { create(:agent, password: 'test') }
  467. let(:customer) { create(:customer, password: 'test') }
  468. it 'customer user should not have agent object attributes', authenticated_as: :agent do
  469. # Log out again, so that we can execute the next login.
  470. logout
  471. # Re-create agent session and fetch object attributes.
  472. login(
  473. username: agent.login,
  474. password: 'test'
  475. )
  476. visit 'ticket/create'
  477. # Re-remove local object attributes bound to the session
  478. # there was an issue (#1856) where the old attribute values
  479. # persisted and were stored as the original attributes.
  480. logout
  481. # Create customer session and fetch object attributes.
  482. login(
  483. username: customer.login,
  484. password: 'test'
  485. )
  486. visit 'customer_ticket_new'
  487. expect(page).to have_no_css('.newTicket input[name="customer_id"]')
  488. end
  489. end
  490. context 'when state options have a special translation', authenticated_as: :authenticate do
  491. let(:admin_de) { create(:admin, preferences: { locale: 'de-de' }) }
  492. context 'when translated state option has a single quote' do
  493. def authenticate
  494. open_tranlation = Translation.where(locale: 'de-de', source: 'open')
  495. open_tranlation.update(target: "off'en")
  496. admin_de
  497. end
  498. it 'shows the translated state options correctly' do
  499. visit 'ticket/create'
  500. expect(page).to have_select('state_id', with_options: ["off'en"])
  501. end
  502. end
  503. end
  504. describe 'It should be possible to show attributes which are configured shown false #3726', authenticated_as: :authenticate, db_strategy: :reset do
  505. let(:field_name) { SecureRandom.uuid }
  506. let(:field) do
  507. create :object_manager_attribute_text, name: field_name, display: field_name, screens: {
  508. 'create_middle' => {
  509. 'ticket.agent' => {
  510. 'shown' => false,
  511. 'required' => false,
  512. }
  513. }
  514. }
  515. ObjectManager::Attribute.migration_execute
  516. end
  517. before do
  518. visit 'ticket/create'
  519. end
  520. context 'when field visible' do
  521. let(:workflow) do
  522. create(:core_workflow,
  523. object: 'Ticket',
  524. perform: { "ticket.#{field_name}" => { 'operator' => 'show', 'show' => 'true' } })
  525. end
  526. def authenticate
  527. field
  528. workflow
  529. true
  530. end
  531. it 'does show up the field' do
  532. expect(page).to have_css("div[data-attribute-name='#{field_name}']")
  533. end
  534. end
  535. context 'when field hidden' do
  536. def authenticate
  537. field
  538. true
  539. end
  540. it 'does not show the field' do
  541. expect(page).to have_css("div[data-attribute-name='#{field_name}'].is-hidden.is-removed", visible: :hidden)
  542. end
  543. end
  544. end
  545. describe 'Support workflow mechanism to do pending reminder state hide pending time use case #3790', authenticated_as: :authenticate do
  546. let(:template) { create(:template, :dummy_data) }
  547. def add_state
  548. Ticket::State.create_or_update(
  549. name: 'pending customer feedback',
  550. state_type: Ticket::StateType.find_by(name: 'pending reminder'),
  551. ignore_escalation: true,
  552. created_by_id: 1,
  553. updated_by_id: 1,
  554. )
  555. end
  556. def update_screens
  557. attribute = ObjectManager::Attribute.get(
  558. object: 'Ticket',
  559. name: 'state_id',
  560. )
  561. attribute.data_option[:filter] = Ticket::State.by_category(:viewable).pluck(:id)
  562. attribute.screens[:create_middle]['ticket.agent'][:filter] = Ticket::State.by_category(:viewable_agent_new).pluck(:id)
  563. attribute.screens[:create_middle]['ticket.customer'][:filter] = Ticket::State.by_category(:viewable_customer_new).pluck(:id)
  564. attribute.screens[:edit]['ticket.agent'][:filter] = Ticket::State.by_category(:viewable_agent_edit).pluck(:id)
  565. attribute.screens[:edit]['ticket.customer'][:filter] = Ticket::State.by_category(:viewable_customer_edit).pluck(:id)
  566. attribute.save!
  567. end
  568. def create_flow
  569. create(:core_workflow,
  570. object: 'Ticket',
  571. condition_selected: { 'ticket.state_id'=>{ 'operator' => 'is', 'value' => Ticket::State.find_by(name: 'pending customer feedback').id.to_s } },
  572. perform: { 'ticket.pending_time'=> { 'operator' => 'remove', 'remove' => 'true' } })
  573. end
  574. def authenticate
  575. add_state
  576. update_screens
  577. create_flow
  578. template
  579. true
  580. end
  581. before do
  582. visit 'ticket/create'
  583. use_template(template)
  584. end
  585. it 'does make it possible to create pending states where the pending time is optional and not visible' do
  586. select 'pending customer feedback', from: 'state_id'
  587. click '.js-submit'
  588. expect(current_url).to include('ticket/zoom')
  589. expect(Ticket.last.state_id).to eq(Ticket::State.find_by(name: 'pending customer feedback').id)
  590. expect(Ticket.last.pending_time).to be_nil
  591. end
  592. end
  593. context 'default priority', authenticated_as: :authenticate do
  594. let(:template) { create(:template, :dummy_data) }
  595. let(:ticket_priority) { create(:ticket_priority, default_create: true) }
  596. let(:another_priority) { Ticket::Priority.find(1) }
  597. let(:priority_field) { find('[name=priority_id]') }
  598. def authenticate
  599. template
  600. ticket_priority
  601. true
  602. end
  603. it 'shows default priority on load' do
  604. visit 'ticket/create'
  605. expect(priority_field.value).to eq ticket_priority.id.to_s
  606. end
  607. it 'does not reset to default priority on reload' do
  608. visit 'ticket/create'
  609. taskbar_timestamp = Taskbar.last.updated_at
  610. priority_field.select another_priority.name
  611. wait.until { Taskbar.last.updated_at != taskbar_timestamp }
  612. refresh
  613. expect(priority_field.reload.value).to eq another_priority.id.to_s
  614. end
  615. it 'saves default priority' do
  616. visit 'ticket/create'
  617. use_template template
  618. click '.js-submit'
  619. expect(Ticket.last).to have_attributes(priority: ticket_priority)
  620. end
  621. it 'saves different priority if overriden' do
  622. visit 'ticket/create'
  623. use_template template
  624. priority_field.select another_priority.name
  625. click '.js-submit'
  626. expect(Ticket.last).to have_attributes(priority: another_priority)
  627. end
  628. end
  629. describe 'When looking for customers, it is no longer possible to change into organizations #3815' do
  630. before do
  631. visit 'ticket/create'
  632. # modal reaper ;)
  633. sleep 3
  634. end
  635. context 'when less than 10 customers' do
  636. let(:organization) { Organization.first }
  637. it 'has no show more option' do
  638. find('[name=customer_id_completion]').fill_in with: 'zam'
  639. expect(page).to have_selector("li.js-organization[data-organization-id='#{organization.id}']")
  640. page.find("li.js-organization[data-organization-id='#{organization.id}']").click
  641. expect(page).to have_selector("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers.hidden", visible: :all)
  642. end
  643. end
  644. context 'when more than 10 customers', authenticated_as: :authenticate do
  645. def authenticate
  646. customers
  647. true
  648. end
  649. let(:organization) { create(:organization, name: 'Zammed') }
  650. let(:customers) do
  651. create_list(:customer, 50, organization: organization)
  652. end
  653. it 'does paginate through organization' do
  654. find('[name=customer_id_completion]').fill_in with: 'zam'
  655. expect(page).to have_selector("li.js-organization[data-organization-id='#{organization.id}']")
  656. page.find("li.js-organization[data-organization-id='#{organization.id}']").click
  657. wait.until { page.all("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li", visible: :all).count == 12 } # 10 users + back + show more button
  658. expect(page).to have_selector("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers[organization-member-limit='10']")
  659. scroll_into_view('li.js-showMoreMembers')
  660. page.find("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers").click
  661. wait.until { page.all("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li", visible: :all).count == 27 } # 25 users + back + show more button
  662. expect(page).to have_selector("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers[organization-member-limit='25']")
  663. scroll_into_view('li.js-showMoreMembers')
  664. page.find("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers").click
  665. wait.until { page.all("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li", visible: :all).count == 52 } # 50 users + back + show more button
  666. scroll_into_view('li.js-showMoreMembers')
  667. expect(page).to have_selector("ul.recipientList-organizationMembers[organization-id='#{organization.id}'] li.js-showMoreMembers.hidden", visible: :all)
  668. end
  669. end
  670. end
  671. describe 'Ticket create screen will loose attachments by time #3827' do
  672. before do
  673. visit 'ticket/create'
  674. end
  675. it 'does not loose attachments on rerender of the ui' do
  676. # upload two files
  677. await_empty_ajax_queue
  678. page.find('input#fileUpload_1', visible: :all).set(Rails.root.join('test/data/mail/mail001.box'))
  679. await_empty_ajax_queue
  680. wait.until { page.all('div.attachment-delete.js-delete', visible: :all).count == 1 }
  681. expect(page).to have_text('mail001.box')
  682. page.find('input#fileUpload_1', visible: :all).set(Rails.root.join('test/data/mail/mail002.box'))
  683. await_empty_ajax_queue
  684. wait.until { page.all('div.attachment-delete.js-delete', visible: :all).count == 2 }
  685. expect(page).to have_text('mail002.box')
  686. # remove last file
  687. begin
  688. page.evaluate_script("$('div.attachment-delete.js-delete:last').trigger('click')") # not interactable
  689. rescue # Lint/SuppressedException
  690. # because its not interactable it also
  691. # returns this weird exception for the jquery
  692. # even tho it worked fine
  693. end
  694. await_empty_ajax_queue
  695. wait.until { page.all('div.attachment-delete.js-delete', visible: :all).count == 1 }
  696. expect(page).to have_text('mail001.box')
  697. expect(page).to have_no_text('mail002.box')
  698. # simulate rerender b
  699. page.evaluate_script("App.Event.trigger('ui:rerender')")
  700. expect(page).to have_text('mail001.box')
  701. expect(page).to have_no_text('mail002.box')
  702. end
  703. end
  704. describe 'Invalid group and owner list for tickets created via customer profile #3835' do
  705. let(:invalid_ticket) { create(:ticket) }
  706. before do
  707. visit "#ticket/create/id/#{invalid_ticket.id}/customer/#{User.find_by(firstname: 'Nicole').id}"
  708. end
  709. it 'does show an empty list of owners' do
  710. wait.until { page.all('select[name=owner_id] option').count == 1 }
  711. expect(page.all('select[name=owner_id] option').count).to eq(1)
  712. end
  713. end
  714. # https://github.com/zammad/zammad/issues/3825
  715. describe 'CC token field' do
  716. before do
  717. visit 'ticket/create'
  718. find('[data-type=email-out]').click
  719. end
  720. it 'can be cleared by cutting out text' do
  721. add_email 'asd@example.com'
  722. add_email 'def@example.com'
  723. find('.token', text: 'def@example.com').double_click
  724. send_keys([magic_key, 'x'])
  725. find('.token').click # trigger blur
  726. expect(find('[name="cc"]', visible: :all).value).to eq 'asd@example.com'
  727. end
  728. def add_email(input)
  729. fill_in 'CC', with: input
  730. send_keys(:enter) # trigger blur
  731. find '.token', text: input # wait for email to tokenize
  732. end
  733. end
  734. describe 'No signature on new ticket if email is default message type #3844', authenticated_as: :authenticate do
  735. def authenticate
  736. Setting.set('ui_ticket_create_default_type', 'email-out')
  737. Group.where.not(name: 'Users').each { |g| g.update(active: false) }
  738. true
  739. end
  740. before do
  741. visit 'ticket/create'
  742. end
  743. it 'does render the create screen with an initial core workflow state to set signatures and other defaults properly' do
  744. expect(page.find('.richtext-content')).to have_text('Support')
  745. end
  746. end
  747. describe 'Zammad 5 mail template double signature #3816', authenticated_as: :authenticate do
  748. let(:agent_template) { create(:agent) }
  749. let!(:template) do
  750. create(
  751. :template,
  752. :dummy_data,
  753. group: Group.first, owner: agent_template,
  754. 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>'
  755. )
  756. end
  757. def authenticate
  758. Group.first.update(signature: Signature.first)
  759. true
  760. end
  761. before do
  762. visit 'ticket/create'
  763. find('[data-type=email-out]').click
  764. end
  765. it 'does not show double signature on template usage' do
  766. select Group.first.name, from: 'group_id'
  767. use_template(template)
  768. expect(page).to have_no_text('Test Other Agent')
  769. end
  770. end
  771. describe 'Tree select value cannot be set to "-" (empty) with Trigger/Scheduler/Core workflow #4024', authenticated_as: :authenticate, db_strategy: :reset do
  772. let(:field_name) { SecureRandom.uuid }
  773. let(:field) do
  774. create :object_manager_attribute_tree_select, name: field_name, display: field_name, screens: attributes_for(:required_screen)
  775. ObjectManager::Attribute.migration_execute
  776. end
  777. let(:workflow) do
  778. create(:core_workflow,
  779. object: 'Ticket',
  780. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '3 high').id.to_s } },
  781. perform: { "ticket.#{field_name}" => { 'operator' => 'select', 'select' => 'Incident' } })
  782. end
  783. let(:workflow2) do
  784. create(:core_workflow,
  785. object: 'Ticket',
  786. condition_selected: { 'ticket.priority_id'=>{ 'operator' => 'is', 'value' => Ticket::Priority.find_by(name: '2 normal').id.to_s } },
  787. perform: { "ticket.#{field_name}" => { 'operator' => 'select', 'select' => '' } })
  788. end
  789. def authenticate
  790. field
  791. workflow
  792. workflow2
  793. true
  794. end
  795. before do
  796. visit 'ticket/create'
  797. end
  798. it 'does select the field value properly' do
  799. page.find('[name=priority_id]').select '3 high'
  800. wait.until { page.find("input[name='#{field_name}']", visible: :all).value == 'Incident' }
  801. page.find('[name=priority_id]').select '2 normal'
  802. wait.until { page.find("input[name='#{field_name}']", visible: :all).value == '' }
  803. end
  804. end
  805. describe 'Assign user to multiple organizations #1573' do
  806. let(:organization1) { create(:organization) }
  807. let(:organization2) { create(:organization) }
  808. let(:organization3) { create(:organization) }
  809. let(:organization4) { create(:organization) }
  810. let(:user1) { create(:agent, organization: organization1, organizations: [organization2, organization3]) }
  811. let(:user2) { create(:agent, organization: organization4) }
  812. let(:customer1) { create(:customer, organization: organization1, organizations: [organization2, organization3]) }
  813. let(:customer2) { create(:customer, organization: organization4) }
  814. context 'when agent', authenticated_as: :authenticate do
  815. def authenticate
  816. user1
  817. user2
  818. true
  819. end
  820. before do
  821. visit 'ticket/create'
  822. end
  823. it 'does not show the organization field for user 1' do
  824. find('[name=customer_id_completion]').fill_in with: user1.firstname
  825. find("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").click
  826. expect(page).to have_css("div[data-attribute-name='organization_id']")
  827. end
  828. it 'does show the organization field for user 2' do
  829. find('[name=customer_id_completion]').fill_in with: user2.firstname
  830. find("li.recipientList-entry.js-object[data-object-id='#{user2.id}']").click
  831. expect(page).to have_no_css("div[data-attribute-name='organization_id']")
  832. end
  833. it 'can create tickets for secondary organizations' do
  834. fill_in 'Title', with: 'test'
  835. find('.richtext-content').send_keys 'test'
  836. select Group.first.name, from: 'group_id'
  837. find('[name=customer_id_completion]').fill_in with: user1.firstname
  838. wait.until { page.all("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").present? }
  839. find("li.recipientList-entry.js-object[data-object-id='#{user1.id}']").click
  840. find('div[data-attribute-name=organization_id] .js-input').fill_in with: user1.organizations[0].name, fill_options: { clear: :backspace }
  841. wait.until { page.all("div[data-attribute-name=organization_id] .js-option[data-value='#{user1.organizations[0].id}']").present? }
  842. page.find("div[data-attribute-name=organization_id] .js-option[data-value='#{user1.organizations[0].id}'] span").click
  843. click '.js-submit'
  844. wait.until { Ticket.last.organization_id == user1.organizations[0].id }
  845. end
  846. end
  847. context 'when customer' do
  848. before do
  849. visit 'customer_ticket_new'
  850. end
  851. it 'does not show the organization field for user 1', authenticated_as: :customer1 do
  852. expect(page).to have_css("div[data-attribute-name='organization_id']")
  853. end
  854. it 'does show the organization field for user 2', authenticated_as: :customer2 do
  855. expect(page).to have_no_css("div[data-attribute-name='organization_id']")
  856. end
  857. it 'can create tickets for secondary organizations', authenticated_as: :customer1 do
  858. fill_in 'Title', with: 'test'
  859. find('.richtext-content').send_keys 'test'
  860. select Group.first.name, from: 'group_id'
  861. find('div[data-attribute-name=organization_id] .js-input').fill_in with: customer1.organizations[0].name, fill_options: { clear: :backspace }
  862. wait.until { page.all("div[data-attribute-name=organization_id] .js-option[data-value='#{customer1.organizations[0].id}']").present? }
  863. page.find("div[data-attribute-name=organization_id] .js-option[data-value='#{customer1.organizations[0].id}'] span").click
  864. click '.js-submit'
  865. wait.until { Ticket.last.organization_id == customer1.organizations[0].id }
  866. end
  867. end
  868. end
  869. describe 'Wrong default values in ticket create when creating from user profile #4088' do
  870. let(:customer) { create(:customer) }
  871. before do
  872. visit "ticket/create/customer/#{customer.id}"
  873. end
  874. it 'does show the default state when creating a ticket from a user profile' do
  875. expect(page).to have_select('state_id', selected: 'open')
  876. end
  877. end
  878. describe 'Ticket templates do not save the owner attribute #4175' do
  879. let(:ticket) { create(:ticket, group: Group.first) }
  880. let(:agent) { create(:agent, groups: [Group.first]) }
  881. let!(:template) { create(:template, :dummy_data, group: Group.first, owner: agent) }
  882. before do
  883. visit 'ticket/create'
  884. end
  885. it 'does set owners properly by templates and taskbars' do
  886. use_template(template)
  887. expect(page).to have_select('owner_id', selected: agent.fullname)
  888. wait.until { Taskbar.last.state['owner_id'].to_i == agent.id }
  889. refresh
  890. expect(page).to have_select('owner_id', selected: agent.fullname)
  891. end
  892. end
  893. end