create_spec.rb 56 KB

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