overviews_expert_conditions_spec.rb 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. # Copyright (C) 2012-2023 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. visit path
  255. within ".table-#{object_name} .js-tableBody" do
  256. find("tr[data-id='#{object.id}'] td.table-draggable").click
  257. end
  258. modal_ready
  259. end
  260. context 'with expert conditions' do
  261. let(:condition) do
  262. {
  263. 'operator' => 'OR',
  264. 'conditions' => [
  265. {
  266. 'name' => 'ticket.state_id',
  267. 'operator' => 'is',
  268. 'value' => %w[1],
  269. },
  270. {
  271. 'operator' => 'NOT',
  272. 'conditions' => [
  273. {
  274. 'name' => 'ticket.priority_id',
  275. 'operator' => 'is',
  276. 'value' => %w[1],
  277. },
  278. ],
  279. },
  280. ],
  281. }
  282. end
  283. it 'renders in expert mode' do
  284. scroll_into_view('.ticket_selector')
  285. within '.ticket_selector' do
  286. check_expert_mode(true)
  287. check_subclause_selector(1, 'Match any (OR)')
  288. check_condition(2, 'State', 'is', value: ['new'])
  289. check_subclause_selector(3, 'Match none (NOT)')
  290. check_condition(4, 'Priority', 'is', value: ['1 low'])
  291. end
  292. end
  293. it 'shows a confirmation dialog when turning off the expert mode' do
  294. scroll_into_view('.ticket_selector')
  295. within '.ticket_selector' do
  296. toggle_expert_mode(false)
  297. end
  298. # We cannot use `in_modal` here, since the alert is shown in an additional, smaller dialog.
  299. within '.modal.modal--small' do # rubocop:disable Zammad/EnforceInModal
  300. expect(find('.modal-dialog')).to have_text('Are you sure?')
  301. end
  302. end
  303. it 'downgrades the selector with some data loss' do
  304. scroll_into_view('.ticket_selector')
  305. within '.ticket_selector' do
  306. toggle_expert_mode(false)
  307. end
  308. # We cannot use `in_modal` here, since the alert is shown in an additional, smaller dialog.
  309. within '.modal.modal--small' do # rubocop:disable Zammad/EnforceInModal
  310. click '.js-submit'
  311. end
  312. within '.ticket_selector' do
  313. check_expert_mode(false)
  314. check_condition(1, 'State', 'is', value: ['new'])
  315. end
  316. click '.js-submit'
  317. await_empty_ajax_queue
  318. param_condition = {
  319. 'ticket.state_id' => {
  320. 'operator' => 'is',
  321. 'value' => %w[1],
  322. },
  323. }
  324. expect(object.reload.condition).to eq(param_condition)
  325. end
  326. context 'when using ticket tags' do
  327. let(:condition) do
  328. {
  329. 'operator' => 'OR',
  330. 'conditions' => [
  331. {
  332. 'name' => 'ticket.tags',
  333. 'operator' => 'contains one',
  334. 'value' => %w[tag1 tag2].join(', '),
  335. },
  336. {
  337. 'name' => 'ticket.tags',
  338. 'operator' => 'contains one not',
  339. 'value' => %w[tag3 tag4].join(', '),
  340. },
  341. ],
  342. }
  343. end
  344. it 'edits condition with ticket tags attribute without errors (#4507)' do
  345. scroll_into_view('.ticket_selector')
  346. within '.ticket_selector' do
  347. check_expert_mode(true)
  348. check_subclause_selector(1, 'Match any (OR)')
  349. check_condition(2, 'Tags', 'contains one', value_token_input: %w[tag1 tag2])
  350. check_condition(3, 'Tags', 'contains one not', value_token_input: %w[tag3 tag4])
  351. set_condition(2, 'Tags', 'contains all', value_token_input: %w[tag5 tag6])
  352. set_condition(3, 'Tags', 'contains all not', value_token_input: %w[tag7])
  353. end
  354. click '.js-submit'
  355. await_empty_ajax_queue
  356. param_condition = {
  357. 'operator' => 'OR',
  358. 'conditions' => [
  359. {
  360. 'name' => 'ticket.tags',
  361. 'operator' => 'contains all',
  362. 'value' => %w[tag5 tag6].join(', '),
  363. },
  364. {
  365. 'name' => 'ticket.tags',
  366. 'operator' => 'contains all not',
  367. 'value' => %w[tag7].join(', '),
  368. },
  369. ],
  370. }
  371. expect(object.reload.condition).to eq(param_condition)
  372. end
  373. end
  374. context 'with pre-conditions' do
  375. let(:condition) do
  376. {
  377. 'operator' => 'OR',
  378. 'conditions' => [
  379. {
  380. 'name' => 'ticket.organization_id',
  381. 'operator' => 'is',
  382. 'pre_condition' => 'current_user.organization_id',
  383. 'value' => [],
  384. },
  385. {
  386. 'name' => 'ticket.owner_id',
  387. 'operator' => 'is',
  388. 'pre_condition' => 'not_set',
  389. 'value' => [],
  390. },
  391. ],
  392. }
  393. end
  394. it 'saves changes made to pre-condition options (#4532)' do
  395. scroll_into_view('.ticket_selector')
  396. within '.ticket_selector' do
  397. check_expert_mode(true)
  398. check_subclause_selector(1, 'Match any (OR)')
  399. check_condition(2, 'Organization', 'is', pre_condition: 'current user organization')
  400. check_condition(3, 'Owner', 'is', pre_condition: 'not set (not defined)')
  401. set_condition(3, nil, nil, pre_condition: 'current user')
  402. end
  403. click '.js-submit'
  404. await_empty_ajax_queue
  405. param_condition = {
  406. 'operator' => 'OR',
  407. 'conditions' => [
  408. {
  409. 'name' => 'ticket.organization_id',
  410. 'operator' => 'is',
  411. 'pre_condition' => 'current_user.organization_id',
  412. 'value' => [],
  413. },
  414. {
  415. 'name' => 'ticket.owner_id',
  416. 'operator' => 'is',
  417. 'pre_condition' => 'current_user.id',
  418. 'value' => [],
  419. },
  420. ],
  421. }
  422. expect(object.reload.condition).to eq(param_condition)
  423. within ".table-#{object_name} .js-tableBody" do
  424. find("tr[data-id='#{object.id}'] td.table-draggable").click
  425. end
  426. modal_ready
  427. scroll_into_view('.ticket_selector')
  428. within '.ticket_selector' do
  429. check_condition(3, 'Owner', 'is', pre_condition: 'current user')
  430. set_condition(2, nil, nil, pre_condition: 'not set (not defined)')
  431. end
  432. click '.js-submit'
  433. await_empty_ajax_queue
  434. param_condition = {
  435. 'operator' => 'OR',
  436. 'conditions' => [
  437. {
  438. 'name' => 'ticket.organization_id',
  439. 'operator' => 'is',
  440. 'pre_condition' => 'not_set',
  441. 'value' => [],
  442. },
  443. {
  444. 'name' => 'ticket.owner_id',
  445. 'operator' => 'is',
  446. 'pre_condition' => 'current_user.id',
  447. 'value' => [],
  448. },
  449. ],
  450. }
  451. expect(object.reload.condition).to eq(param_condition)
  452. end
  453. end
  454. end
  455. context 'without expert conditions' do
  456. let(:condition) do
  457. {
  458. 'ticket.state_id' => {
  459. 'operator' => 'is',
  460. 'value' => %w[1],
  461. },
  462. 'ticket.priority_id' => {
  463. 'operator' => 'is not',
  464. 'value' => %w[1],
  465. },
  466. }
  467. end
  468. it 'renders with the expert mode turned off' do
  469. scroll_into_view('.ticket_selector')
  470. within '.ticket_selector' do
  471. check_expert_mode(false)
  472. check_condition(1, 'State', 'is', value: ['new'])
  473. check_condition(2, 'Priority', 'is not', value: ['1 low'])
  474. end
  475. end
  476. it 'supports toggling expert mode with seamless selector migration and downgrade' do
  477. scroll_into_view('.ticket_selector')
  478. within '.ticket_selector' do
  479. toggle_expert_mode(true)
  480. check_subclause_selector(1, 'Match all (AND)')
  481. check_condition(2, 'State', 'is', value: ['new'])
  482. check_condition(3, 'Priority', 'is not', value: ['1 low'])
  483. toggle_expert_mode(false)
  484. check_condition(1, 'State', 'is', value: ['new'])
  485. check_condition(2, 'Priority', 'is not', value: ['1 low'])
  486. toggle_expert_mode(true)
  487. end
  488. click '.js-submit'
  489. await_empty_ajax_queue
  490. param_condition = {
  491. 'operator' => 'AND',
  492. 'conditions' => [
  493. {
  494. 'name' => 'ticket.state_id',
  495. 'operator' => 'is',
  496. 'value' => %w[1],
  497. },
  498. {
  499. 'name' => 'ticket.priority_id',
  500. 'operator' => 'is not',
  501. 'value' => %w[1],
  502. },
  503. ],
  504. }
  505. expect(object.reload.condition).to eq(param_condition)
  506. end
  507. end
  508. end
  509. end
  510. context 'with expert conditions turned off' do
  511. before do
  512. Setting.set('ticket_allow_expert_conditions', false)
  513. end
  514. context 'with new objects' do
  515. before do
  516. visit path
  517. click '.content.active a[data-type="new"]'
  518. modal_ready
  519. end
  520. it 'renders default selector without expert mode switch' do
  521. scroll_into_view('.ticket_selector')
  522. within '.ticket_selector' do
  523. check_condition(1, 'State', 'is')
  524. expect(self).to have_no_selector('.js-switch')
  525. end
  526. end
  527. end
  528. context 'with existing objects' do
  529. let(:object_name) { described_class.name.downcase }
  530. let(:object) { create(object_name.to_sym, condition: condition) }
  531. before do
  532. visit path
  533. within ".table-#{object_name} .js-tableBody" do
  534. find("tr[data-id='#{object.id}'] td.table-draggable").click
  535. end
  536. modal_ready
  537. end
  538. context 'with expert conditions' do
  539. let(:condition) do
  540. {
  541. 'operator' => 'AND',
  542. 'conditions' => [
  543. {
  544. 'name' => 'ticket.title',
  545. 'operator' => 'contains',
  546. 'value' => 'w',
  547. },
  548. {
  549. 'name' => 'ticket.title',
  550. 'operator' => 'contains',
  551. 'value' => 'e',
  552. },
  553. {
  554. 'name' => 'ticket.title',
  555. 'operator' => 'contains',
  556. 'value' => 'l',
  557. },
  558. ],
  559. }
  560. end
  561. it 'shows an alert that a data loss may occur upon save' do
  562. within '.ticket_selector' do
  563. check_condition(1, 'Title', 'contains', value_input: 'l')
  564. expect(self).to have_selector('.js-alert')
  565. end
  566. end
  567. end
  568. context 'without expert conditions' do
  569. let(:condition) do
  570. {
  571. 'operator' => 'AND',
  572. 'conditions' => [
  573. {
  574. 'name' => 'ticket.title',
  575. 'operator' => 'contains',
  576. 'value' => 'welcome',
  577. },
  578. ],
  579. }
  580. end
  581. it 'does not show an alert' do
  582. within '.ticket_selector' do
  583. check_condition(1, 'Title', 'contains', value_input: 'welcome')
  584. expect(self).to have_no_selector('.js-alert')
  585. end
  586. end
  587. end
  588. end
  589. end
  590. def check_subclause_selector(row_number, value)
  591. subclause_selector = find(".js-filterElement:nth-child(#{row_number}) .js-subclauseSelector select")
  592. selected_option = subclause_selector.find("option[value='#{subclause_selector.value}']")
  593. expect(selected_option).to have_text(value)
  594. end
  595. def set_subclause_selector(row_number, value)
  596. subclause_selector = find(".js-filterElement:nth-child(#{row_number}) .js-subclauseSelector select")
  597. option = subclause_selector.find('option', text: value)
  598. option.select_option
  599. end
  600. def check_attribute_selector(row_number, value)
  601. attribute_selector = find(".js-filterElement:nth-child(#{row_number}) .js-attributeSelector select")
  602. selected_option = attribute_selector.find("option[value='#{attribute_selector.value}']")
  603. expect(selected_option).to have_text(value)
  604. end
  605. def set_attribute_selector(row_number, value)
  606. attribute_selector = find(".js-filterElement:nth-child(#{row_number}) .js-attributeSelector select")
  607. option = attribute_selector.find('option', text: value)
  608. option.select_option
  609. end
  610. def check_operator_selector(row_number, value)
  611. operator_selector = find(".js-filterElement:nth-child(#{row_number}) .js-operator select")
  612. selected_option = operator_selector.find("option[value='#{operator_selector.value}']")
  613. expect(selected_option).to have_text(value)
  614. end
  615. def set_operator_selector(row_number, value)
  616. operator_selector = find(".js-filterElement:nth-child(#{row_number}) .js-operator select")
  617. option = operator_selector.find("option[value='#{value}']")
  618. option.select_option
  619. end
  620. def check_pre_condition_selector(row_number, value)
  621. precondition_selector = find(".js-filterElement:nth-child(#{row_number}) .js-preCondition select")
  622. selected_option = precondition_selector.find("option[value='#{precondition_selector.value}']")
  623. expect(selected_option).to have_text(value)
  624. end
  625. def set_precondition_selector(row_number, value)
  626. precondition_selector = find(".js-filterElement:nth-child(#{row_number}) .js-preCondition select")
  627. option = precondition_selector.find('option', text: value)
  628. option.select_option
  629. end
  630. def check_customer_fullname(row_number, customer_fullname)
  631. token_label = find(".js-filterElement:nth-child(#{row_number}) .js-value .token-label")
  632. expect(token_label).to have_text(customer_fullname)
  633. end
  634. def check_value_input(row_number, value)
  635. input = find(".js-filterElement:nth-child(#{row_number}) .js-value input")
  636. expect(input.value).to eq(value)
  637. end
  638. def check_value_token_input(row_number, value)
  639. input = find(".js-filterElement:nth-child(#{row_number}) .js-value input.form-control", visible: :all)
  640. expect(input.value).to eq(value.join(', '))
  641. end
  642. def check_value_selector(row_number, value)
  643. value_selector = find(".js-filterElement:nth-child(#{row_number}) .js-value select")
  644. value_selector.value.each_with_index do |v, index|
  645. selected_option = value_selector.find("option[value='#{v}']")
  646. expect(selected_option).to have_text(value[index])
  647. end
  648. end
  649. def set_value_input(row_number, value)
  650. value_input = find(".js-filterElement:nth-child(#{row_number}) .js-value input")
  651. value_input.fill_in with: value.join
  652. end
  653. def set_value_token_input(row_number, value)
  654. value_token_input = find(".js-filterElement:nth-child(#{row_number}) .js-value .token-input")
  655. value_token_input.fill_in with: value.join(', ')
  656. send_keys :tab
  657. end
  658. def set_value_selector(row_number, value)
  659. value_selector = find(".js-filterElement:nth-child(#{row_number}) .js-value select")
  660. value.each do |v|
  661. option = value_selector.find('option', text: v)
  662. option.select_option
  663. end
  664. end
  665. def check_condition(row_number, attribute, operator, pre_condition: nil, value: nil, value_input: nil, value_token_input: nil, customer_fullname: nil)
  666. check_attribute_selector(row_number, attribute)
  667. check_operator_selector(row_number, operator)
  668. if !pre_condition.nil?
  669. check_pre_condition_selector(row_number, pre_condition)
  670. end
  671. if !customer_fullname.nil?
  672. check_customer_fullname(row_number, customer_fullname)
  673. end
  674. if !value_input.nil?
  675. check_value_input(row_number, value_input)
  676. elsif !value_token_input.nil?
  677. check_value_token_input(row_number, value_token_input)
  678. end
  679. return if value.nil?
  680. check_value_selector(row_number, value)
  681. end
  682. def set_condition(row_number, attribute, operator, pre_condition: nil, value: nil, value_input: nil, value_token_input: nil)
  683. set_attribute_selector(row_number, attribute) if attribute.present?
  684. set_operator_selector(row_number, operator) if operator.present?
  685. if !pre_condition.nil?
  686. set_precondition_selector(row_number, pre_condition)
  687. end
  688. if !value_input.nil?
  689. set_value_input(row_number, value_input)
  690. elsif !value_token_input.nil?
  691. set_value_token_input(row_number, value_token_input)
  692. end
  693. return if value.nil?
  694. set_value_selector(row_number, value)
  695. end
  696. def check_expert_conditions(param_condition)
  697. param_value = JSON.parse(find('.js-expertConditions input', visible: :all).value)
  698. expect(param_value).to eq(param_condition)
  699. end
  700. def toggle_expert_mode(value)
  701. switch = find('.js-switch')
  702. if switch.find('input', visible: :all).checked?
  703. switch.click if !value
  704. elsif value
  705. switch.click
  706. end
  707. end
  708. def check_expert_mode(value)
  709. checkbox = find('.js-switch input', visible: :all)
  710. if value
  711. expect(checkbox).to be_checked
  712. else
  713. expect(checkbox).not_to be_checked
  714. end
  715. end
  716. def insert_subclause_after(row_number, value)
  717. find(".js-filterElement:nth-child(#{row_number}) .js-subclause").click
  718. set_subclause_selector(row_number + 1, value)
  719. end
  720. def insert_condition_after(row_number, attribute, operator, pre_condition: nil, value: nil)
  721. find(".js-filterElement:nth-child(#{row_number}) .js-add").click
  722. set_condition(row_number + 1, attribute, operator, pre_condition: pre_condition, value: value)
  723. end
  724. end