ticket_create_spec.rb 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'system/apps/mobile/examples/core_workflow_examples'
  4. RSpec.describe 'Mobile > Ticket > Create', app: :mobile, authenticated_as: :user, type: :system do
  5. let(:group) { Group.find_by(name: 'Users') }
  6. let(:user) { create(:agent, groups: [group]) }
  7. let!(:customer) { create(:customer) }
  8. def next_step
  9. find_button('Continue').click
  10. end
  11. def check_is_step(step)
  12. expect(find("button[order=\"#{step}\"]").disabled?).to be(true)
  13. end
  14. def go_to_step(step)
  15. find("button[order=\"#{step}\"]").click
  16. end
  17. def submit_form
  18. find_button('Create').click
  19. wait_for_gql('apps/mobile/pages/ticket/graphql/mutations/create.graphql')
  20. end
  21. def check_is_focused(element)
  22. wait.until do
  23. page.driver.browser.switch_to.active_element == element.native
  24. end
  25. end
  26. before do
  27. visit '/'
  28. find_link('Create new ticket').click
  29. wait_for_form_to_settle('ticket-create')
  30. end
  31. shared_examples 'creating a ticket' do |article_type:, direction: nil, redirect: nil|
  32. it 'can complete all steps' do
  33. expect(find_button('Create', disabled: true).disabled?).to be(true)
  34. within_form(form_updater_gql_number: 1) do
  35. # Step 1.
  36. find_input('Title').type(Faker::Name.unique.name_with_middle)
  37. next_step
  38. # Step 2.
  39. case article_type
  40. when 'email'
  41. find_radio('articleSenderType').select_choice('Send Email')
  42. when 'phone'
  43. if direction == 'out'
  44. find_radio('articleSenderType').select_choice('Outbound Call')
  45. end
  46. end
  47. find_select('Group').select_option('Users') if article_type == 'web'
  48. next_step
  49. if article_type != 'web'
  50. # Step 3.
  51. find_autocomplete('Customer').search_for_option(customer.email, label: customer.fullname)
  52. find_autocomplete('CC') if article_type == 'email'
  53. next_step
  54. end
  55. # Step 4.
  56. find_editor('Text').type(Faker::Hacker.say_something_smart)
  57. end
  58. submit_form
  59. find('[role=alert]', text: 'Ticket has been created successfully.')
  60. expect(page).to have_current_path(redirect || "/mobile/tickets/#{Ticket.last.id}")
  61. expect(Ticket.last.create_article_type_id).to eq(Ticket::Article::Type.find_by(name: article_type).id)
  62. end
  63. end
  64. context 'with different article types' do
  65. it_behaves_like 'creating a ticket', article_type: 'phone'
  66. it_behaves_like 'creating a ticket', article_type: 'phone', direction: 'out'
  67. it_behaves_like 'creating a ticket', article_type: 'email'
  68. context 'when dont have a "read" permission, but have "create" permission' do
  69. it_behaves_like 'creating a ticket', article_type: 'email', redirect: '/mobile/' do
  70. before do
  71. user.group_names_access_map = {
  72. group.name => ['create']
  73. }
  74. end
  75. end
  76. end
  77. context 'when a customer', authenticated_as: :customer do
  78. it_behaves_like 'creating a ticket', article_type: 'web'
  79. end
  80. end
  81. context 'with signatures' do
  82. let(:signature1) { create(:signature, body: '<strong>custom signature</strong>') }
  83. let(:group1) { create(:group, signature: signature1) }
  84. let(:group2) { Group.find_by(name: 'Users') }
  85. let(:group3) { create(:group) }
  86. let(:user) { create(:agent, groups: [group1, group2, group3]) }
  87. it 'adds signature' do
  88. within_form(form_updater_gql_number: 1) do
  89. find_input('Title').type(Faker::Name.unique.name_with_middle)
  90. next_step
  91. find_radio('articleSenderType').select_choice('Send Email')
  92. next_step
  93. next_step
  94. # only label is rendered as text
  95. expect(find_editor('Text')).to have_text_value('', exact: true)
  96. go_to_step(3)
  97. find_select('Group').select_option('Users')
  98. go_to_step(4)
  99. expect(find_editor('Text')).to have_text_value(user.fullname) # default signature is added
  100. end
  101. end
  102. it 'changes signature, when group is changed' do
  103. within_form(form_updater_gql_number: 1) do
  104. find_input('Title').type(Faker::Name.unique.name_with_middle)
  105. next_step
  106. find_radio('articleSenderType').select_choice('Send Email')
  107. next_step
  108. find_select('Group').select_option('Users')
  109. next_step
  110. expect(find_editor('Text')).to have_text_value(user.fullname)
  111. go_to_step(3)
  112. find_select('Group').select_option(group1.name)
  113. next_step
  114. expect(find_editor('Text')).to have_text_value('custom signature')
  115. end
  116. end
  117. it 'removes signature, when another group without signature is selected' do
  118. within_form(form_updater_gql_number: 1) do
  119. find_input('Title').type(Faker::Name.unique.name_with_middle)
  120. next_step
  121. find_radio('articleSenderType').select_choice('Send Email')
  122. next_step
  123. find_select('Group').select_option('Users')
  124. next_step
  125. expect(find_editor('Text')).to have_text_value(user.fullname)
  126. go_to_step(3)
  127. find_select('Group').select_option(group3.name)
  128. next_step
  129. expect(find_editor('Text')).to have_text_value('', exact: true)
  130. end
  131. end
  132. it 'removes signature when type is not email' do
  133. within_form(form_updater_gql_number: 1) do
  134. find_input('Title').type(Faker::Name.unique.name_with_middle)
  135. next_step
  136. find_radio('articleSenderType').select_choice('Send Email')
  137. next_step
  138. find_select('Group').select_option('Users')
  139. next_step
  140. expect(find_editor('Text')).to have_text_value(user.fullname)
  141. go_to_step(2)
  142. find_radio('articleSenderType').select_choice('Outbound Call')
  143. go_to_step(4)
  144. # only label is rendered as text
  145. expect(find_editor('Text')).to have_text_value('', exact: true)
  146. end
  147. end
  148. it 'removes signature when group is deselected' do
  149. within_form(form_updater_gql_number: 1) do
  150. find_input('Title').type(Faker::Name.unique.name_with_middle)
  151. next_step
  152. find_radio('articleSenderType').select_choice('Send Email')
  153. next_step
  154. find_select('Group').select_option('Users')
  155. next_step
  156. expect(find_editor('Text')).to have_text_value(user.fullname)
  157. go_to_step(3)
  158. find_select('Group').clear_selection
  159. go_to_step(4)
  160. # only label is rendered as text
  161. expect(find_editor('Text')).to have_text_value('', exact: true)
  162. end
  163. end
  164. end
  165. # TODO: Frontend tests!?
  166. context 'with entered form fields' do
  167. it 'remembers the data when switching between steps' do
  168. within_form(form_updater_gql_number: 1) do
  169. # Step 1.
  170. title = Faker::Name.unique.name_with_middle
  171. find_input('Title').type(title)
  172. next_step
  173. # Step 2.
  174. type = 'Outbound Call'
  175. find_radio('articleSenderType').select_choice(type)
  176. next_step
  177. # Step 3.
  178. find_autocomplete('Customer').search_for_option(customer.email, label: customer.fullname)
  179. next_step
  180. # Step 4.
  181. body = Faker::Hacker.say_something_smart
  182. find_editor('Text').type(body)
  183. # Step 1.
  184. go_to_step(1)
  185. expect(find_input('Title')).to have_value(title)
  186. # Step 3.
  187. go_to_step(3)
  188. expect(find_autocomplete('Customer')).to have_selected_option(customer.fullname)
  189. # Step 2.
  190. go_to_step(2)
  191. expect(find_radio('articleSenderType')).to have_selected_choice(type)
  192. # Step 4.
  193. go_to_step(4)
  194. expect(find_editor('Text')).to have_text_value(body)
  195. end
  196. end
  197. it 'shows a confirmation dialog when leaving the screen' do
  198. within_form(form_updater_gql_number: 1) do
  199. find_input('Title').type(Faker::Name.unique.name_with_middle)
  200. end
  201. find_button('Go home').click
  202. within '[role=alert]' do
  203. expect(page).to have_text('Are you sure? You have unsaved changes that will get lost.')
  204. end
  205. end
  206. end
  207. context 'with accessibility support' do
  208. it 'focuses first visible field when switching between steps' do
  209. wait_for_form_autofocus('ticket-create')
  210. # Step 1.
  211. check_is_focused find_input('Title').input_element
  212. next_step
  213. # Step 2.
  214. check_is_focused find_radio('articleSenderType').find('label', text: 'Received Call').find('input')
  215. next_step
  216. # Step 3.
  217. check_is_focused find_autocomplete('Customer').input_element
  218. next_step
  219. # Step 4.
  220. check_is_focused find_editor('Text').input_element
  221. # Step 1.
  222. go_to_step(1)
  223. check_is_focused find_input('Title').input_element
  224. # Step 3.
  225. go_to_step(3)
  226. check_is_focused find_autocomplete('Customer').input_element
  227. # Step 2.
  228. go_to_step(2)
  229. check_is_focused find_radio('articleSenderType').find('label', text: 'Received Call').find('input')
  230. # Step 4.
  231. go_to_step(4)
  232. check_is_focused find_editor('Text').input_element
  233. end
  234. it 'advances to the next step on submit' do
  235. find_input('Title').input_element.send_keys :enter
  236. check_is_step(2)
  237. find_radio('articleSenderType').find('label', text: 'Received Call').find('input').send_keys :enter
  238. check_is_step(3)
  239. end
  240. context 'with many object attributes', authenticated_as: :authenticate, db_strategy: :reset do
  241. let(:screens) do
  242. {
  243. create_middle: {
  244. '-all-' => {
  245. shown: true,
  246. required: false,
  247. },
  248. },
  249. }
  250. end
  251. def authenticate
  252. create(:object_manager_attribute_select, screens: screens)
  253. create(:object_manager_attribute_text, screens: screens)
  254. create(:object_manager_attribute_tree_select, screens: screens)
  255. create(:object_manager_attribute_select, screens: screens)
  256. ObjectManager::Attribute.migration_execute
  257. true
  258. end
  259. it 'can interact with the fields at the bottom of the form without any obstructions' do
  260. # Step 3.
  261. next_step
  262. next_step
  263. # Tags is the last field in the form.
  264. # In case the field is obscured, the following action would fail.
  265. find_autocomplete('Tags').search_for_option('tag 1')
  266. end
  267. end
  268. end
  269. context 'when using ticket create as customer' do
  270. let(:group1) { Group.find_by(name: 'Users') }
  271. let(:user) { create(:customer, :with_org, groups: [group1]) }
  272. shared_examples 'can complete all steps as customer' do
  273. it 'can complete all steps' do
  274. within_form(form_updater_gql_number: 1) do
  275. find_input('Title').type(Faker::Name.unique.name_with_middle)
  276. next_step
  277. find_select('Group').select_option('Users')
  278. if organizations
  279. find_select('Organization').select_option(organizations.last.name)
  280. else
  281. expect(page).to have_no_select('Organization')
  282. end
  283. next_step
  284. find_editor('Text').type(Faker::Hacker.say_something_smart)
  285. end
  286. submit_form
  287. find('[role=alert]', text: 'Ticket has been created successfully.')
  288. expect(page).to have_current_path("/mobile/tickets/#{Ticket.last.id}")
  289. end
  290. end
  291. context 'with secondary organizations' do
  292. include_examples 'can complete all steps as customer' do
  293. let(:user) { create(:customer, :with_org, organizations: organizations, groups: [group1]) }
  294. let(:organizations) { create_list(:organization, 3) }
  295. end
  296. end
  297. context 'without secondary organizations' do
  298. include_examples 'can complete all steps as customer' do
  299. let(:organizations) { nil }
  300. end
  301. end
  302. end
  303. context 'when using suggestions' do
  304. let(:text_option) { create(:text_module, name: 'test', content: "Hello, \#{ticket.customer.firstname}!") }
  305. it 'text suggestion parses correctly' do
  306. within_form(form_updater_gql_number: 1) do
  307. find_input('Title').type(Faker::Name.unique.name_with_middle)
  308. next_step
  309. next_step
  310. find_autocomplete('Customer').search_for_option(customer.email, label: customer.fullname)
  311. next_step
  312. editor = find_editor('Text')
  313. # only label is rendered as text
  314. expect(editor).to have_text_value('', exact: true)
  315. editor.type('::test')
  316. find('[role="option"]', text: text_option.name).click
  317. expect(editor).to have_text_value("Hello, #{customer.firstname}!")
  318. end
  319. end
  320. end
  321. describe 'Core Workflow' do
  322. include_examples 'mobile app: core workflow' do
  323. let(:object_name) { 'Ticket' }
  324. let(:form_updater_gql_number) { 2 }
  325. let(:before_it) do
  326. lambda {
  327. visit '/tickets/create'
  328. wait_for_form_to_settle('ticket-create')
  329. within_form(form_updater_gql_number: 1) do
  330. find_input('Title').type(Faker::Name.unique.name_with_middle)
  331. end
  332. next_step
  333. next_step
  334. }
  335. end
  336. end
  337. end
  338. end