overviews_expert_conditions_spec.rb 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe 'Expert conditions in Manage > Overviews', type: :system do
  4. let(:described_class) { Overview }
  5. let(:path) { '/#manage/overviews' }
  6. context 'with expert conditions turned on' do
  7. before do
  8. Setting.set('ticket_allow_expert_conditions', true)
  9. end
  10. context 'with new objects' do
  11. before do
  12. visit path
  13. click '.content.active a[data-type="new"]'
  14. modal_ready
  15. end
  16. it 'renders default selector with expert mode turned off by default' do
  17. scroll_into_view('.ticket_selector')
  18. within '.ticket_selector' do
  19. check_condition(1, 'State', 'is')
  20. check_expert_mode(false)
  21. end
  22. end
  23. it 'renders default subclause and state condition' do
  24. scroll_into_view('.ticket_selector')
  25. within '.ticket_selector' do
  26. toggle_expert_mode(true)
  27. check_subclause_selector(1, 'Match all (AND)')
  28. check_condition(2, 'State', 'is')
  29. end
  30. end
  31. it 'supports toggling expert mode with seamless selector migration and downgrade' do
  32. scroll_into_view('.ticket_selector')
  33. within '.ticket_selector' do
  34. set_condition(1, 'State', 'is', value: %w[new])
  35. toggle_expert_mode(true)
  36. check_subclause_selector(1, 'Match all (AND)')
  37. check_condition(2, 'State', 'is', value: %w[new])
  38. set_condition(2, 'State', 'is', value: %w[new open])
  39. toggle_expert_mode(false)
  40. check_condition(1, 'State', 'is', value: %w[new open])
  41. end
  42. end
  43. it 'supports complex conditions with subclauses' do
  44. object_name = Faker::Name.unique.name
  45. fill_in 'Name', with: object_name
  46. # Select target roles, if the field is present, since this field is required.
  47. if has_css?('div[data-attribute-name="role_ids"]')
  48. find('div[data-attribute-name="role_ids"] div.js-pool div[data-value="1"]').click
  49. end
  50. scroll_into_view('.ticket_selector')
  51. within '.ticket_selector' do
  52. toggle_expert_mode(true)
  53. set_condition(2, 'State', 'is', value: %w[new open])
  54. insert_subclause_after(1, 'Match any (OR)')
  55. insert_condition_after(2, 'Priority', 'is not', value: ['2 normal', '3 high'])
  56. end
  57. click '.js-submit'
  58. await_empty_ajax_queue
  59. param_condition = {
  60. 'operator' => 'AND',
  61. 'conditions' => [
  62. {
  63. 'operator' => 'OR',
  64. 'conditions' => [
  65. {
  66. 'name' => 'ticket.priority_id',
  67. 'operator' => 'is not',
  68. 'value' => %w[2 3],
  69. },
  70. ],
  71. },
  72. {
  73. 'name' => 'ticket.state_id',
  74. 'operator' => 'is',
  75. 'value' => %w[1 2],
  76. },
  77. ],
  78. }
  79. expect(described_class.find_by(name: object_name).condition).to eq(param_condition)
  80. end
  81. it 'saves condition with ticket tags attribute without errors (#4507)' do
  82. object_name = Faker::Name.unique.name
  83. fill_in 'Name', with: object_name
  84. # Select target roles, if the field is present, since this field is required.
  85. if has_css?('div[data-attribute-name="role_ids"]')
  86. find('div[data-attribute-name="role_ids"] div.js-pool div[data-value="1"]').click
  87. end
  88. scroll_into_view('.ticket_selector')
  89. within '.ticket_selector' do
  90. toggle_expert_mode(true)
  91. set_condition(2, 'Tags', 'contains all', value_token_input: %w[tag1 tag2])
  92. end
  93. click '.js-submit'
  94. await_empty_ajax_queue
  95. param_condition = {
  96. 'operator' => 'AND',
  97. 'conditions' => [
  98. {
  99. 'name' => 'ticket.tags',
  100. 'operator' => 'contains all',
  101. 'value' => %w[tag1 tag2].join(', '),
  102. },
  103. ],
  104. }
  105. expect(described_class.find_by(name: object_name).condition).to eq(param_condition)
  106. end
  107. context 'with drag and drop support' do
  108. it 'supports moving complete subclauses around' do
  109. scroll_into_view('.ticket_selector')
  110. within '.ticket_selector' do
  111. toggle_expert_mode(true)
  112. set_condition(2, 'State', 'is', value: %w[new])
  113. insert_subclause_after(2, 'Match any (OR)')
  114. insert_condition_after(3, 'Priority', 'is not', value: ['3 high'])
  115. subclause_draggable = find('.js-filterElement:nth-child(3) .draggable')
  116. state_condition = find('.js-filterElement:nth-child(2)')
  117. subclause_draggable.drag_to state_condition
  118. await_empty_ajax_queue
  119. check_subclause_selector(2, 'Match any (OR)')
  120. check_condition(3, 'Priority', 'is not', value: ['3 high'])
  121. check_condition(4, 'State', 'is', value: %w[new])
  122. param_condition = {
  123. 'operator' => 'AND',
  124. 'conditions' => [
  125. {
  126. 'operator' => 'OR',
  127. 'conditions' => [
  128. {
  129. 'name' => 'ticket.priority_id',
  130. 'operator' => 'is not',
  131. 'value' => ['3'],
  132. },
  133. ],
  134. },
  135. {
  136. 'name' => 'ticket.state_id',
  137. 'operator' => 'is',
  138. 'value' => ['1'],
  139. },
  140. ],
  141. }
  142. check_expert_conditions(param_condition)
  143. end
  144. end
  145. it 'supports keeping nested levels' do
  146. scroll_into_view('.ticket_selector')
  147. within '.ticket_selector' do
  148. toggle_expert_mode(true)
  149. set_condition(2, 'State', 'is', value: %w[new])
  150. insert_subclause_after(1, 'Match any (OR)')
  151. insert_condition_after(2, 'Priority', 'is not', value: ['3 high'])
  152. state_condition_draggable = find('.js-filterElement:nth-child(4) .draggable')
  153. priority_condition = find('.js-filterElement:nth-child(3)')
  154. priority_height = priority_condition.native.size.height.to_i
  155. # Drag the state condition right above the priority, but drop it to the same subclause.
  156. # Move the cursor vertically for the whole height of the priority element.
  157. # Also, slightly move the cursor to the right, but more than the width of a single level constant (27px).
  158. # Finally, drop the condition in order to assign it to the second level.
  159. page.driver.browser.action
  160. .move_to(state_condition_draggable.native)
  161. .click_and_hold
  162. .move_by(30, -priority_height)
  163. .release
  164. .perform
  165. await_empty_ajax_queue
  166. check_subclause_selector(2, 'Match any (OR)')
  167. check_condition(3, 'State', 'is', value: %w[new])
  168. check_condition(4, 'Priority', 'is not', value: ['3 high'])
  169. param_condition = {
  170. 'operator' => 'AND',
  171. 'conditions' => [
  172. {
  173. 'operator' => 'OR',
  174. 'conditions' => [
  175. {
  176. 'name' => 'ticket.state_id',
  177. 'operator' => 'is',
  178. 'value' => ['1'],
  179. },
  180. {
  181. 'name' => 'ticket.priority_id',
  182. 'operator' => 'is not',
  183. 'value' => ['3'],
  184. },
  185. ],
  186. },
  187. ],
  188. }
  189. check_expert_conditions(param_condition)
  190. end
  191. end
  192. it 'supports changing nested levels' do
  193. scroll_into_view('.ticket_selector')
  194. within '.ticket_selector' do
  195. toggle_expert_mode(true)
  196. set_condition(2, 'State', 'is', value: %w[new])
  197. insert_subclause_after(1, 'Match any (OR)')
  198. insert_condition_after(2, 'Priority', 'is not', value: ['3 high'])
  199. state_condition_draggable = find('.js-filterElement:nth-child(4) .draggable')
  200. priority_condition = find('.js-filterElement:nth-child(3)')
  201. priority_height = priority_condition.native.size.height.to_i
  202. # Drag the state condition above the priority, but drop it on the same level as the subclause to break it.
  203. # Move the cursor vertically for the whole height of the priority element.
  204. # Also, do not move the cursor horizontally, so it stays flush with the element above.
  205. # Finally, drop the condition in order to assign it to the first level.
  206. page.driver.browser.action
  207. .move_to(state_condition_draggable.native)
  208. .click_and_hold
  209. .move_by(0, -priority_height)
  210. .release
  211. .perform
  212. await_empty_ajax_queue
  213. check_subclause_selector(2, 'Match any (OR)')
  214. check_condition(3, 'State', 'is', value: %w[new])
  215. check_condition(4, 'Priority', 'is not', value: ['3 high'])
  216. param_condition = {
  217. 'operator' => 'AND',
  218. 'conditions' => [
  219. {
  220. 'operator' => 'OR',
  221. 'conditions' => [],
  222. },
  223. {
  224. 'name' => 'ticket.state_id',
  225. 'operator' => 'is',
  226. 'value' => ['1'],
  227. },
  228. {
  229. 'name' => 'ticket.priority_id',
  230. 'operator' => 'is not',
  231. 'value' => ['3'],
  232. },
  233. ],
  234. }
  235. check_expert_conditions(param_condition)
  236. end
  237. end
  238. end
  239. it 'does not allow duplicate attributes when the expert mode is switched off (#4414)' do
  240. scroll_into_view('.ticket_selector')
  241. within '.ticket_selector' do
  242. check_expert_mode(false)
  243. # Check if the State attribute is disabled in the new dropdown.
  244. find('.js-filterElement:nth-child(1) .js-add').click
  245. attribute_selector = find('.js-filterElement:nth-child(2) .js-attributeSelector select')
  246. expect(attribute_selector.find('option', text: 'State').disabled?).to be(true)
  247. end
  248. end
  249. end
  250. context 'with existing objects' do
  251. let(:object_name) { described_class.name.downcase }
  252. let(:object) { create(object_name.to_sym, condition: condition) }
  253. before do
  254. object
  255. visit path
  256. within ".table-#{object_name} .js-tableBody" do
  257. find("tr[data-id='#{object.id}'] td.table-draggable").click
  258. end
  259. modal_ready
  260. end
  261. context 'with expert conditions' do
  262. let(:condition) do
  263. {
  264. 'operator' => 'OR',
  265. 'conditions' => [
  266. {
  267. 'name' => 'ticket.state_id',
  268. 'operator' => 'is',
  269. 'value' => %w[1],
  270. },
  271. {
  272. 'operator' => 'NOT',
  273. 'conditions' => [
  274. {
  275. 'name' => 'ticket.priority_id',
  276. 'operator' => 'is',
  277. 'value' => %w[1],
  278. },
  279. ],
  280. },
  281. ],
  282. }
  283. end
  284. it 'renders in expert mode' do
  285. scroll_into_view('.ticket_selector')
  286. within '.ticket_selector' do
  287. check_expert_mode(true)
  288. check_subclause_selector(1, 'Match any (OR)')
  289. check_condition(2, 'State', 'is', value: ['new'])
  290. check_subclause_selector(3, 'Match none (NOT)')
  291. check_condition(4, 'Priority', 'is', value: ['1 low'])
  292. end
  293. end
  294. it 'shows a confirmation dialog when turning off the expert mode' do
  295. scroll_into_view('.ticket_selector')
  296. within '.ticket_selector' do
  297. toggle_expert_mode(false)
  298. end
  299. # We cannot use `in_modal` here, since the alert is shown in an additional, smaller dialog.
  300. within '.modal.modal--small' do # rubocop:disable Zammad/EnforceInModal
  301. expect(find('.modal-dialog')).to have_text('Are you sure?')
  302. end
  303. end
  304. it 'downgrades the selector with some data loss' do
  305. scroll_into_view('.ticket_selector')
  306. within '.ticket_selector' do
  307. toggle_expert_mode(false)
  308. end
  309. # We cannot use `in_modal` here, since the alert is shown in an additional, smaller dialog.
  310. within '.modal.modal--small' do # rubocop:disable Zammad/EnforceInModal
  311. click '.js-submit'
  312. end
  313. within '.ticket_selector' do
  314. check_expert_mode(false)
  315. check_condition(1, 'State', 'is', value: ['new'])
  316. end
  317. click '.js-submit'
  318. await_empty_ajax_queue
  319. param_condition = {
  320. 'ticket.state_id' => {
  321. 'operator' => 'is',
  322. 'value' => %w[1],
  323. },
  324. }
  325. expect(object.reload.condition).to eq(param_condition)
  326. end
  327. context 'when using ticket tags' do
  328. let(:condition) do
  329. {
  330. 'operator' => 'OR',
  331. 'conditions' => [
  332. {
  333. 'name' => 'ticket.tags',
  334. 'operator' => 'contains one',
  335. 'value' => %w[tag1 tag2].join(', '),
  336. },
  337. {
  338. 'name' => 'ticket.tags',
  339. 'operator' => 'contains one not',
  340. 'value' => %w[tag3 tag4].join(', '),
  341. },
  342. ],
  343. }
  344. end
  345. it 'edits condition with ticket tags attribute without errors (#4507)' do
  346. scroll_into_view('.ticket_selector')
  347. within '.ticket_selector' do
  348. check_expert_mode(true)
  349. check_subclause_selector(1, 'Match any (OR)')
  350. check_condition(2, 'Tags', 'contains one', value_token_input: %w[tag1 tag2])
  351. check_condition(3, 'Tags', 'contains one not', value_token_input: %w[tag3 tag4])
  352. set_condition(2, 'Tags', 'contains all', value_token_input: %w[tag5 tag6])
  353. set_condition(3, 'Tags', 'contains all not', value_token_input: %w[tag7])
  354. end
  355. click '.js-submit'
  356. await_empty_ajax_queue
  357. param_condition = {
  358. 'operator' => 'OR',
  359. 'conditions' => [
  360. {
  361. 'name' => 'ticket.tags',
  362. 'operator' => 'contains all',
  363. 'value' => %w[tag5 tag6].join(', '),
  364. },
  365. {
  366. 'name' => 'ticket.tags',
  367. 'operator' => 'contains all not',
  368. 'value' => %w[tag7].join(', '),
  369. },
  370. ],
  371. }
  372. expect(object.reload.condition).to eq(param_condition)
  373. end
  374. end
  375. context 'with pre-conditions' do
  376. let(:condition) do
  377. {
  378. 'operator' => 'OR',
  379. 'conditions' => [
  380. {
  381. 'name' => 'ticket.organization_id',
  382. 'operator' => 'is',
  383. 'pre_condition' => 'current_user.organization_id',
  384. 'value' => [],
  385. },
  386. {
  387. 'name' => 'ticket.owner_id',
  388. 'operator' => 'is',
  389. 'pre_condition' => 'not_set',
  390. 'value' => [],
  391. },
  392. ],
  393. }
  394. end
  395. it 'saves changes made to pre-condition options (#4532)' do
  396. scroll_into_view('.ticket_selector')
  397. within '.ticket_selector' do
  398. check_expert_mode(true)
  399. check_subclause_selector(1, 'Match any (OR)')
  400. check_condition(2, 'Organization', 'is', pre_condition: 'current user organization')
  401. check_condition(3, 'Owner', 'is', pre_condition: 'not set (not defined)')
  402. set_condition(3, nil, nil, pre_condition: 'current user')
  403. end
  404. click '.js-submit'
  405. await_empty_ajax_queue
  406. param_condition = {
  407. 'operator' => 'OR',
  408. 'conditions' => [
  409. {
  410. 'name' => 'ticket.organization_id',
  411. 'operator' => 'is',
  412. 'pre_condition' => 'current_user.organization_id',
  413. 'value' => [],
  414. },
  415. {
  416. 'name' => 'ticket.owner_id',
  417. 'operator' => 'is',
  418. 'pre_condition' => 'current_user.id',
  419. 'value' => [],
  420. },
  421. ],
  422. }
  423. expect(object.reload.condition).to eq(param_condition)
  424. within ".table-#{object_name} .js-tableBody" do
  425. find("tr[data-id='#{object.id}'] td.table-draggable").click
  426. end
  427. modal_ready
  428. scroll_into_view('.ticket_selector')
  429. within '.ticket_selector' do
  430. check_condition(3, 'Owner', 'is', pre_condition: 'current user')
  431. set_condition(2, nil, nil, pre_condition: 'not set (not defined)')
  432. end
  433. click '.js-submit'
  434. await_empty_ajax_queue
  435. param_condition = {
  436. 'operator' => 'OR',
  437. 'conditions' => [
  438. {
  439. 'name' => 'ticket.organization_id',
  440. 'operator' => 'is',
  441. 'pre_condition' => 'not_set',
  442. 'value' => [],
  443. },
  444. {
  445. 'name' => 'ticket.owner_id',
  446. 'operator' => 'is',
  447. 'pre_condition' => 'current_user.id',
  448. 'value' => [],
  449. },
  450. ],
  451. }
  452. expect(object.reload.condition).to eq(param_condition)
  453. end
  454. end
  455. end
  456. context 'without expert conditions' do
  457. let(:condition) do
  458. {
  459. 'ticket.state_id' => {
  460. 'operator' => 'is',
  461. 'value' => %w[1],
  462. },
  463. 'ticket.priority_id' => {
  464. 'operator' => 'is not',
  465. 'value' => %w[1],
  466. },
  467. }
  468. end
  469. it 'renders with the expert mode turned off' do
  470. scroll_into_view('.ticket_selector')
  471. within '.ticket_selector' do
  472. check_expert_mode(false)
  473. check_condition(1, 'State', 'is', value: ['new'])
  474. check_condition(2, 'Priority', 'is not', value: ['1 low'])
  475. end
  476. end
  477. it 'supports toggling expert mode with seamless selector migration and downgrade' do
  478. scroll_into_view('.ticket_selector')
  479. within '.ticket_selector' do
  480. toggle_expert_mode(true)
  481. check_subclause_selector(1, 'Match all (AND)')
  482. check_condition(2, 'State', 'is', value: ['new'])
  483. check_condition(3, 'Priority', 'is not', value: ['1 low'])
  484. toggle_expert_mode(false)
  485. check_condition(1, 'State', 'is', value: ['new'])
  486. check_condition(2, 'Priority', 'is not', value: ['1 low'])
  487. toggle_expert_mode(true)
  488. end
  489. click '.js-submit'
  490. await_empty_ajax_queue
  491. param_condition = {
  492. 'operator' => 'AND',
  493. 'conditions' => [
  494. {
  495. 'name' => 'ticket.state_id',
  496. 'operator' => 'is',
  497. 'value' => %w[1],
  498. },
  499. {
  500. 'name' => 'ticket.priority_id',
  501. 'operator' => 'is not',
  502. 'value' => %w[1],
  503. },
  504. ],
  505. }
  506. expect(object.reload.condition).to eq(param_condition)
  507. end
  508. end
  509. end
  510. end
  511. context 'with expert conditions turned off' do
  512. before do
  513. Setting.set('ticket_allow_expert_conditions', false)
  514. end
  515. context 'with new objects' do
  516. before do
  517. visit path
  518. click '.content.active a[data-type="new"]'
  519. modal_ready
  520. end
  521. it 'renders default selector without expert mode switch' do
  522. scroll_into_view('.ticket_selector')
  523. within '.ticket_selector' do
  524. check_condition(1, 'State', 'is')
  525. expect(self).to have_no_selector('.js-switch')
  526. end
  527. end
  528. end
  529. context 'with existing objects' do
  530. let(:object_name) { described_class.name.downcase }
  531. let(:object) { create(object_name.to_sym, condition: condition) }
  532. before do
  533. object
  534. visit path
  535. within ".table-#{object_name} .js-tableBody" do
  536. find("tr[data-id='#{object.id}'] td.table-draggable").click
  537. end
  538. modal_ready
  539. end
  540. context 'with expert conditions' do
  541. let(:condition) do
  542. {
  543. 'operator' => 'AND',
  544. 'conditions' => [
  545. {
  546. 'name' => 'ticket.title',
  547. 'operator' => 'contains',
  548. 'value' => 'w',
  549. },
  550. {
  551. 'name' => 'ticket.title',
  552. 'operator' => 'contains',
  553. 'value' => 'e',
  554. },
  555. {
  556. 'name' => 'ticket.title',
  557. 'operator' => 'contains',
  558. 'value' => 'l',
  559. },
  560. ],
  561. }
  562. end
  563. it 'shows an alert that a data loss may occur upon save' do
  564. within '.ticket_selector' do
  565. check_condition(1, 'Title', 'contains', value_input: 'l')
  566. expect(self).to have_css('.js-alert')
  567. end
  568. end
  569. end
  570. context 'without expert conditions' do
  571. let(:condition) do
  572. {
  573. 'operator' => 'AND',
  574. 'conditions' => [
  575. {
  576. 'name' => 'ticket.title',
  577. 'operator' => 'contains',
  578. 'value' => 'welcome',
  579. },
  580. ],
  581. }
  582. end
  583. it 'does not show an alert' do
  584. within '.ticket_selector' do
  585. check_condition(1, 'Title', 'contains', value_input: 'welcome')
  586. expect(self).to have_no_selector('.js-alert')
  587. end
  588. end
  589. end
  590. end
  591. end
  592. def check_subclause_selector(row_number, value)
  593. subclause_selector = find(".js-filterElement:nth-child(#{row_number}) .js-subclauseSelector select")
  594. selected_option = subclause_selector.find("option[value='#{subclause_selector.value}']")
  595. expect(selected_option).to have_text(value)
  596. end
  597. def set_subclause_selector(row_number, value)
  598. subclause_selector = find(".js-filterElement:nth-child(#{row_number}) .js-subclauseSelector select")
  599. option = subclause_selector.find('option', text: value)
  600. option.select_option
  601. end
  602. def check_attribute_selector(row_number, value)
  603. attribute_selector = find(".js-filterElement:nth-child(#{row_number}) .js-attributeSelector select")
  604. selected_option = attribute_selector.find("option[value='#{attribute_selector.value}']")
  605. expect(selected_option).to have_text(value)
  606. end
  607. def set_attribute_selector(row_number, value)
  608. attribute_selector = find(".js-filterElement:nth-child(#{row_number}) .js-attributeSelector select")
  609. option = attribute_selector.find('option', text: value)
  610. option.select_option
  611. end
  612. def check_operator_selector(row_number, value)
  613. operator_selector = find(".js-filterElement:nth-child(#{row_number}) .js-operator select")
  614. selected_option = operator_selector.find("option[value='#{operator_selector.value}']")
  615. expect(selected_option).to have_text(value)
  616. end
  617. def set_operator_selector(row_number, value)
  618. operator_selector = find(".js-filterElement:nth-child(#{row_number}) .js-operator select")
  619. option = operator_selector.find("option[value='#{value}']")
  620. option.select_option
  621. end
  622. def check_pre_condition_selector(row_number, value)
  623. precondition_selector = find(".js-filterElement:nth-child(#{row_number}) .js-preCondition select")
  624. selected_option = precondition_selector.find("option[value='#{precondition_selector.value}']")
  625. expect(selected_option).to have_text(value)
  626. end
  627. def set_precondition_selector(row_number, value)
  628. precondition_selector = find(".js-filterElement:nth-child(#{row_number}) .js-preCondition select")
  629. option = precondition_selector.find('option', text: value)
  630. option.select_option
  631. end
  632. def check_customer_fullname(row_number, customer_fullname)
  633. token_label = find(".js-filterElement:nth-child(#{row_number}) .js-value .token-label")
  634. expect(token_label).to have_text(customer_fullname)
  635. end
  636. def check_value_input(row_number, value)
  637. input = find(".js-filterElement:nth-child(#{row_number}) .js-value input")
  638. expect(input.value).to eq(value)
  639. end
  640. def check_value_token_input(row_number, value)
  641. input = find(".js-filterElement:nth-child(#{row_number}) .js-value input.form-control", visible: :all)
  642. expect(input.value).to eq(value.join(', '))
  643. end
  644. def check_value_selector(row_number, value)
  645. value_selector = find(".js-filterElement:nth-child(#{row_number}) .js-value select")
  646. value_selector.value.each_with_index do |v, index|
  647. selected_option = value_selector.find("option[value='#{v}']")
  648. expect(selected_option).to have_text(value[index])
  649. end
  650. end
  651. def set_value_input(row_number, value)
  652. value_input = find(".js-filterElement:nth-child(#{row_number}) .js-value input")
  653. value_input.fill_in with: value.join
  654. end
  655. def set_value_token_input(row_number, value)
  656. value_token_input = find(".js-filterElement:nth-child(#{row_number}) .js-value .token-input")
  657. value_token_input.fill_in with: value.join(', ')
  658. send_keys :tab
  659. end
  660. def set_value_selector(row_number, value)
  661. value_selector = find(".js-filterElement:nth-child(#{row_number}) .js-value select")
  662. value.each do |v|
  663. option = value_selector.find('option', text: v)
  664. option.select_option
  665. end
  666. end
  667. def check_condition(row_number, attribute, operator, pre_condition: nil, value: nil, value_input: nil, value_token_input: nil, customer_fullname: nil)
  668. check_attribute_selector(row_number, attribute)
  669. check_operator_selector(row_number, operator)
  670. if !pre_condition.nil?
  671. check_pre_condition_selector(row_number, pre_condition)
  672. end
  673. if !customer_fullname.nil?
  674. check_customer_fullname(row_number, customer_fullname)
  675. end
  676. if !value_input.nil?
  677. check_value_input(row_number, value_input)
  678. elsif !value_token_input.nil?
  679. check_value_token_input(row_number, value_token_input)
  680. end
  681. return if value.nil?
  682. check_value_selector(row_number, value)
  683. end
  684. def set_condition(row_number, attribute, operator, pre_condition: nil, value: nil, value_input: nil, value_token_input: nil)
  685. set_attribute_selector(row_number, attribute) if attribute.present?
  686. set_operator_selector(row_number, operator) if operator.present?
  687. if !pre_condition.nil?
  688. set_precondition_selector(row_number, pre_condition)
  689. end
  690. if !value_input.nil?
  691. set_value_input(row_number, value_input)
  692. elsif !value_token_input.nil?
  693. set_value_token_input(row_number, value_token_input)
  694. end
  695. return if value.nil?
  696. set_value_selector(row_number, value)
  697. end
  698. def check_expert_conditions(param_condition)
  699. param_value = JSON.parse(find('.js-expertConditions input', visible: :all).value)
  700. expect(param_value).to eq(param_condition)
  701. end
  702. def toggle_expert_mode(value)
  703. switch = find('.js-switch')
  704. if switch.find('input', visible: :all).checked?
  705. switch.click if !value
  706. elsif value
  707. switch.click
  708. end
  709. end
  710. def check_expert_mode(value)
  711. checkbox = find('.js-switch input', visible: :all)
  712. if value
  713. expect(checkbox).to be_checked
  714. else
  715. expect(checkbox).not_to be_checked
  716. end
  717. end
  718. def insert_subclause_after(row_number, value)
  719. find(".js-filterElement:nth-child(#{row_number}) .js-subclause").click
  720. set_subclause_selector(row_number + 1, value)
  721. end
  722. def insert_condition_after(row_number, attribute, operator, pre_condition: nil, value: nil)
  723. find(".js-filterElement:nth-child(#{row_number}) .js-add").click
  724. set_condition(row_number + 1, attribute, operator, pre_condition: pre_condition, value: value)
  725. end
  726. end