action_spec.rb 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'models/core_workflow/base'
  4. RSpec.describe 'CoreWorkflow > Action', mariadb: true, type: :model do
  5. include_context 'with core workflow base'
  6. describe '.perform - Stop after match' do
  7. let(:stop_after_match) { false }
  8. before do
  9. create(:core_workflow,
  10. object: 'Ticket',
  11. perform: {
  12. 'ticket.priority_id': {
  13. operator: 'hide',
  14. hide: 'true'
  15. },
  16. })
  17. create(:core_workflow,
  18. object: 'Ticket',
  19. perform: {
  20. 'ticket.priority_id': {
  21. operator: 'show',
  22. show: 'true'
  23. },
  24. },
  25. stop_after_match: stop_after_match)
  26. create(:core_workflow,
  27. object: 'Ticket',
  28. perform: {
  29. 'ticket.priority_id': {
  30. operator: 'hide',
  31. hide: 'true'
  32. },
  33. })
  34. end
  35. it 'does not stop' do
  36. expect(result[:visibility]['priority_id']).to eq('hide')
  37. end
  38. describe 'with stop_after_match' do
  39. let(:stop_after_match) { true }
  40. it 'does stop' do
  41. expect(result[:visibility]['priority_id']).to eq('show')
  42. end
  43. end
  44. end
  45. describe '.perform - Condition - Custom module' do
  46. let(:modules) { ['CoreWorkflow::Custom::Testa', 'CoreWorkflow::Custom::Testb', 'CoreWorkflow::Custom::Testc'] }
  47. let(:custom_class_false) do
  48. Class.new(CoreWorkflow::Custom::Backend) do
  49. def selected_attribute_match?
  50. false
  51. end
  52. end
  53. end
  54. let(:custom_class_true) do
  55. Class.new(CoreWorkflow::Custom::Backend) do
  56. def selected_attribute_match?
  57. true
  58. end
  59. end
  60. end
  61. let!(:workflow) do
  62. create(:core_workflow,
  63. object: 'Ticket',
  64. condition_selected: {
  65. 'custom.module': {
  66. operator: operator,
  67. value: modules,
  68. },
  69. })
  70. end
  71. describe 'with "match all modules" false' do
  72. let(:operator) { 'match all modules' }
  73. before do
  74. stub_const 'CoreWorkflow::Custom::Testa', custom_class_false
  75. stub_const 'CoreWorkflow::Custom::Testb', custom_class_false
  76. stub_const 'CoreWorkflow::Custom::Testc', custom_class_false
  77. end
  78. it 'does not match' do
  79. expect(result[:matched_workflows]).not_to include(workflow.id)
  80. end
  81. end
  82. describe 'with "match all modules" true' do
  83. let(:operator) { 'match all modules' }
  84. before do
  85. stub_const 'CoreWorkflow::Custom::Testa', custom_class_true
  86. stub_const 'CoreWorkflow::Custom::Testb', custom_class_true
  87. stub_const 'CoreWorkflow::Custom::Testc', custom_class_true
  88. end
  89. it 'does match' do
  90. expect(result[:matched_workflows]).to include(workflow.id)
  91. end
  92. end
  93. describe 'with "match all modules" blank' do
  94. let(:modules) { [] }
  95. let(:operator) { 'match all modules' }
  96. it 'does match' do
  97. expect(result[:matched_workflows]).to include(workflow.id)
  98. end
  99. end
  100. describe 'with "match one module" true' do
  101. let(:operator) { 'match one module' }
  102. before do
  103. stub_const 'CoreWorkflow::Custom::Testa', custom_class_false
  104. stub_const 'CoreWorkflow::Custom::Testb', custom_class_false
  105. stub_const 'CoreWorkflow::Custom::Testc', custom_class_true
  106. end
  107. it 'does match' do
  108. expect(result[:matched_workflows]).to include(workflow.id)
  109. end
  110. end
  111. describe 'with "match one module" false' do
  112. let(:operator) { 'match one module' }
  113. before do
  114. stub_const 'CoreWorkflow::Custom::Testa', custom_class_false
  115. stub_const 'CoreWorkflow::Custom::Testb', custom_class_false
  116. stub_const 'CoreWorkflow::Custom::Testc', custom_class_false
  117. end
  118. it 'does not match' do
  119. expect(result[:matched_workflows]).not_to include(workflow.id)
  120. end
  121. end
  122. describe 'with "match one module" blank' do
  123. let(:modules) { [] }
  124. let(:operator) { 'match one module' }
  125. it 'does match' do
  126. expect(result[:matched_workflows]).to include(workflow.id)
  127. end
  128. end
  129. describe 'with "match no modules" true' do
  130. let(:operator) { 'match no modules' }
  131. before do
  132. stub_const 'CoreWorkflow::Custom::Testa', custom_class_false
  133. stub_const 'CoreWorkflow::Custom::Testb', custom_class_false
  134. stub_const 'CoreWorkflow::Custom::Testc', custom_class_false
  135. end
  136. it 'does match' do
  137. expect(result[:matched_workflows]).to include(workflow.id)
  138. end
  139. end
  140. describe 'with "match no modules" false' do
  141. let(:operator) { 'match no modules' }
  142. before do
  143. stub_const 'CoreWorkflow::Custom::Testa', custom_class_true
  144. stub_const 'CoreWorkflow::Custom::Testb', custom_class_true
  145. stub_const 'CoreWorkflow::Custom::Testc', custom_class_true
  146. end
  147. it 'does not match' do
  148. expect(result[:matched_workflows]).not_to include(workflow.id)
  149. end
  150. end
  151. describe 'with "match no modules" blank' do
  152. let(:modules) { [] }
  153. let(:operator) { 'match no modules' }
  154. it 'does match' do
  155. expect(result[:matched_workflows]).to include(workflow.id)
  156. end
  157. end
  158. end
  159. describe '.perform - Select' do
  160. let!(:workflow1) do
  161. create(:core_workflow,
  162. object: 'Ticket',
  163. perform: {
  164. 'ticket.group_id': {
  165. operator: 'select',
  166. select: [ticket.group.id.to_s]
  167. },
  168. })
  169. end
  170. let!(:workflow2) do
  171. create(:core_workflow,
  172. object: 'Ticket',
  173. condition_selected: {
  174. 'ticket.group_id': {
  175. operator: 'is',
  176. value: ticket.group.id.to_s
  177. },
  178. },
  179. perform: {
  180. 'ticket.owner_id': {
  181. operator: 'select',
  182. select: [action_user.id.to_s]
  183. },
  184. })
  185. end
  186. it 'does match workflows' do
  187. expect(result[:matched_workflows]).to include(workflow1.id, workflow2.id)
  188. end
  189. it 'does select group' do
  190. expect(result[:select]['group_id']).to eq(ticket.group.id.to_s)
  191. end
  192. it 'does select owner (recursion)' do
  193. expect(result[:select]['owner_id']).to eq(action_user.id.to_s)
  194. end
  195. it 'does rerun 2 times (group select + owner select)' do
  196. expect(result[:rerun_count]).to eq(2)
  197. end
  198. end
  199. describe '.perform - Auto Select' do
  200. let!(:workflow1) do
  201. create(:core_workflow,
  202. object: 'Ticket',
  203. perform: {
  204. 'ticket.group_id': {
  205. operator: 'auto_select',
  206. auto_select: true
  207. },
  208. })
  209. end
  210. let!(:workflow2) do
  211. create(:core_workflow,
  212. object: 'Ticket',
  213. condition_selected: {
  214. 'ticket.group_id': {
  215. operator: 'is',
  216. value: ticket.group.id.to_s
  217. },
  218. },
  219. perform: {
  220. 'ticket.owner_id': {
  221. operator: 'auto_select',
  222. auto_select: true
  223. },
  224. })
  225. end
  226. it 'does match workflows' do
  227. expect(result[:matched_workflows]).to include(workflow1.id, workflow2.id)
  228. end
  229. it 'does select group' do
  230. expect(result[:select]['group_id']).to eq(ticket.group.id.to_s)
  231. end
  232. it 'does select owner (recursion)' do
  233. expect(result[:select]['owner_id']).to eq(action_user.id.to_s)
  234. end
  235. it 'does rerun 2 times (group select + owner select)' do
  236. expect(result[:rerun_count]).to eq(2)
  237. end
  238. describe 'with owner' do
  239. let(:payload) do
  240. base_payload.merge('params' => {
  241. 'group_id' => ticket.group.id.to_s,
  242. 'owner_id' => action_user.id.to_s,
  243. })
  244. end
  245. it 'does not select owner' do
  246. expect(result[:select]['owner_id']).to be_nil
  247. end
  248. it 'does rerun 0 times' do
  249. expect(result[:rerun_count]).to eq(0)
  250. end
  251. end
  252. end
  253. describe '.perform - Fill in' do
  254. let!(:workflow1) do
  255. create(:core_workflow,
  256. object: 'Ticket',
  257. perform: {
  258. 'ticket.group_id': {
  259. operator: 'select',
  260. select: [ticket.group.id.to_s]
  261. },
  262. })
  263. end
  264. let!(:workflow2) do
  265. create(:core_workflow,
  266. object: 'Ticket',
  267. condition_selected: {
  268. 'ticket.group_id': {
  269. operator: 'is',
  270. value: ticket.group.id.to_s
  271. },
  272. },
  273. perform: {
  274. 'ticket.title': {
  275. operator: 'fill_in',
  276. fill_in: 'hello'
  277. },
  278. })
  279. end
  280. it 'does match workflows' do
  281. expect(result[:matched_workflows]).to include(workflow1.id, workflow2.id)
  282. end
  283. it 'does select group' do
  284. expect(result[:select]['group_id']).to eq(ticket.group.id.to_s)
  285. end
  286. it 'does fill in title' do
  287. expect(result[:fill_in]['title']).to eq('hello')
  288. end
  289. it 'does rerun 1 time (group select + title fill in)' do
  290. expect(result[:rerun_count]).to eq(1)
  291. end
  292. end
  293. describe '.perform - Fill in empty' do
  294. let!(:workflow1) do
  295. create(:core_workflow,
  296. object: 'Ticket',
  297. perform: {
  298. 'ticket.group_id': {
  299. operator: 'select',
  300. select: [ticket.group.id.to_s]
  301. },
  302. })
  303. end
  304. let!(:workflow2) do
  305. create(:core_workflow,
  306. object: 'Ticket',
  307. condition_selected: {
  308. 'ticket.group_id': {
  309. operator: 'is',
  310. value: ticket.group.id.to_s
  311. },
  312. },
  313. perform: {
  314. 'ticket.title': {
  315. operator: 'fill_in_empty',
  316. fill_in_empty: 'hello'
  317. },
  318. })
  319. end
  320. it 'does match workflows' do
  321. expect(result[:matched_workflows]).to include(workflow1.id, workflow2.id)
  322. end
  323. it 'does select group' do
  324. expect(result[:select]['group_id']).to eq(ticket.group.id.to_s)
  325. end
  326. it 'does fill in title' do
  327. expect(result[:fill_in]['title']).to eq('hello')
  328. end
  329. it 'does rerun 1 time (group select + title fill in)' do
  330. expect(result[:rerun_count]).to eq(1)
  331. end
  332. describe 'with title' do
  333. let(:payload) do
  334. base_payload.merge('params' => {
  335. 'title' => 'ha!',
  336. })
  337. end
  338. it 'does not fill in title' do
  339. expect(result[:fill_in]['title']).to be_nil
  340. end
  341. it 'does rerun 1 times (group select)' do
  342. expect(result[:rerun_count]).to eq(1)
  343. end
  344. end
  345. end
  346. describe '.perform - Rerun attributes default cache bug' do
  347. before do
  348. create(:core_workflow,
  349. object: 'Ticket',
  350. perform: {
  351. 'ticket.group_id': {
  352. operator: 'select',
  353. select: [ticket.group.id.to_s]
  354. },
  355. })
  356. create(:core_workflow,
  357. object: 'Ticket',
  358. condition_selected: {
  359. 'ticket.group_id': {
  360. operator: 'is_set',
  361. },
  362. },
  363. perform: {
  364. 'ticket.owner_id': {
  365. operator: 'select',
  366. select: [action_user.id.to_s]
  367. },
  368. })
  369. create(:core_workflow,
  370. object: 'Ticket',
  371. condition_selected: {
  372. 'ticket.owner_id': {
  373. operator: 'not_set',
  374. },
  375. },
  376. perform: {
  377. 'ticket.priority_id': {
  378. operator: 'hide',
  379. hide: 'true'
  380. },
  381. })
  382. end
  383. it 'does not hide priority id' do
  384. expect(result[:visibility]['priority_id']).to eq('show')
  385. end
  386. end
  387. describe '.perform - Clean up params after restrict values removed selected value by set_fixed_to' do
  388. let(:payload) do
  389. base_payload.merge('params' => {
  390. 'owner_id' => action_user.id,
  391. })
  392. end
  393. before do
  394. create(:core_workflow,
  395. object: 'Ticket',
  396. perform: {
  397. 'ticket.group_id': {
  398. operator: 'select',
  399. select: [ticket.group.id.to_s]
  400. },
  401. })
  402. create(:core_workflow,
  403. object: 'Ticket',
  404. condition_selected: {
  405. 'ticket.group_id': {
  406. operator: 'is_set',
  407. },
  408. },
  409. perform: {
  410. 'ticket.owner_id': {
  411. operator: 'set_fixed_to',
  412. set_fixed_to: ['']
  413. },
  414. })
  415. create(:core_workflow,
  416. object: 'Ticket',
  417. condition_selected: {
  418. 'ticket.owner_id': {
  419. operator: 'is_set',
  420. },
  421. },
  422. perform: {
  423. 'ticket.priority_id': {
  424. operator: 'hide',
  425. hide: 'true'
  426. },
  427. })
  428. end
  429. it 'does not allow owner_id' do
  430. expect(result[:restrict_values]['owner_id']).not_to include(action_user.id)
  431. end
  432. it 'does not hide priority id' do
  433. expect(result[:visibility]['priority_id']).to eq('show')
  434. end
  435. end
  436. describe '.perform - Clean up params after restrict values removed selected value by remove_option' do
  437. let(:payload) do
  438. base_payload.merge('params' => {
  439. 'owner_id' => action_user.id,
  440. })
  441. end
  442. before do
  443. create(:core_workflow,
  444. object: 'Ticket',
  445. perform: {
  446. 'ticket.group_id': {
  447. operator: 'select',
  448. select: [ticket.group.id.to_s]
  449. },
  450. })
  451. create(:core_workflow,
  452. object: 'Ticket',
  453. condition_selected: {
  454. 'ticket.group_id': {
  455. operator: 'is_set',
  456. },
  457. },
  458. perform: {
  459. 'ticket.owner_id': {
  460. operator: 'remove_option',
  461. remove_option: [action_user.id]
  462. },
  463. })
  464. create(:core_workflow,
  465. object: 'Ticket',
  466. condition_selected: {
  467. 'ticket.owner_id': {
  468. operator: 'is_set',
  469. },
  470. },
  471. perform: {
  472. 'ticket.priority_id': {
  473. operator: 'hide',
  474. hide: 'true'
  475. },
  476. })
  477. end
  478. it 'does not allow owner_id' do
  479. expect(result[:restrict_values]['owner_id']).not_to include(action_user.id)
  480. end
  481. it 'does not hide priority id' do
  482. expect(result[:visibility]['priority_id']).to eq('show')
  483. end
  484. end
  485. describe '.perform - Clean up params after restrict values removed selected value by default attributes' do
  486. let(:payload) do
  487. base_payload.merge('params' => {
  488. 'owner_id' => action_user.id,
  489. })
  490. end
  491. before do
  492. create(:core_workflow,
  493. object: 'Ticket',
  494. condition_selected: {
  495. 'ticket.owner_id': {
  496. operator: 'is_set',
  497. },
  498. },
  499. perform: {
  500. 'ticket.priority_id': {
  501. operator: 'hide',
  502. hide: 'true'
  503. },
  504. })
  505. end
  506. it 'does not allow owner_id' do
  507. expect(result[:restrict_values]['owner_id']).not_to include(action_user.id)
  508. end
  509. it 'does not hide priority id' do
  510. expect(result[:visibility]['priority_id']).to eq('show')
  511. end
  512. end
  513. describe '.perform - Default - auto selection based on only_shown_if_selectable' do
  514. it 'does auto select group' do
  515. expect(result[:select]['group_id']).not_to be_nil
  516. end
  517. it 'does auto hide group' do
  518. expect(result[:visibility]['group_id']).to eq('hide')
  519. end
  520. end
  521. describe '.perform - One field and two perform actions' do
  522. before do
  523. create(:core_workflow,
  524. object: 'Ticket',
  525. perform: {
  526. 'ticket.owner_id': {
  527. operator: %w[select set_optional],
  528. select: [action_user.id.to_s],
  529. set_optional: 'true',
  530. },
  531. })
  532. end
  533. it 'does auto select owner' do
  534. expect(result[:select]['owner_id']).to eq(action_user.id.to_s)
  535. end
  536. it 'does set owner optional' do
  537. expect(result[:mandatory]['owner_id']).to be(false)
  538. end
  539. end
  540. describe '.perform - Hide mobile based on user login' do
  541. let(:base_payload) do
  542. {
  543. 'event' => 'core_workflow',
  544. 'request_id' => 'default',
  545. 'class_name' => 'User',
  546. 'screen' => 'create',
  547. 'params' => {
  548. 'login' => 'nicole.special@zammad.org',
  549. },
  550. }
  551. end
  552. before do
  553. create(:core_workflow,
  554. object: 'User',
  555. condition_selected: { 'user.login'=>{ 'operator' => 'is', 'value' => 'nicole.special@zammad.org' } },
  556. perform: { 'user.mobile'=>{ 'operator' => 'hide', 'hide' => 'true' } },)
  557. end
  558. it 'does hide mobile for user' do
  559. expect(result[:visibility]['mobile']).to eq('hide')
  560. end
  561. end
  562. describe '.perform - Readonly' do
  563. let!(:workflow1) do
  564. create(:core_workflow,
  565. object: 'Ticket',
  566. perform: {
  567. 'ticket.group_id': {
  568. operator: 'set_readonly',
  569. set_readonly: 'true'
  570. },
  571. })
  572. end
  573. it 'does match workflow' do
  574. expect(result[:matched_workflows]).to include(workflow1.id)
  575. end
  576. it 'does set group readonly' do
  577. expect(result[:readonly]['group_id']).to be(true)
  578. end
  579. context 'when readonly unset' do
  580. let!(:workflow2) do
  581. create(:core_workflow,
  582. object: 'Ticket',
  583. perform: {
  584. 'ticket.group_id': {
  585. operator: 'unset_readonly',
  586. unset_readonly: 'true'
  587. },
  588. })
  589. end
  590. it 'does match workflows' do
  591. expect(result[:matched_workflows]).to include(workflow1.id, workflow2.id)
  592. end
  593. it 'does set group readonly' do
  594. expect(result[:readonly]['group_id']).to be(false)
  595. end
  596. end
  597. end
  598. end