simultaneously_with_two_user_spec.rb 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. # Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe 'Ticket > Update > Simultaneously with two different user', performs_jobs: true, type: :system do
  4. let(:group) { Group.find_by(name: 'Users') }
  5. let(:ticket) { create(:ticket, group: group) }
  6. let(:agent) { User.find_by(login: 'agent1@example.com') }
  7. around { |example| perform_enqueued_jobs { example.run } }
  8. # rubocop:disable RSpec/InstanceVariable
  9. define :have_avatar do |expected|
  10. chain(:changed, :text)
  11. match do
  12. elem = find_element
  13. return false if elem.nil?
  14. return true if !@icon && !@no_icon
  15. return elem.has_no_css? '.icon' if @no_icon
  16. elem.has_css? ".icon-#{@icon}"
  17. end
  18. def find_element
  19. if expected.is_a? User
  20. actual.find "#{base_selector}#{select_by_user}"
  21. else
  22. actual.find base_selector, text: expected
  23. end
  24. rescue
  25. nil
  26. end
  27. match_when_negated do
  28. if expected.is_a? User
  29. return actual.has_no_css? "#{base_selector}#{select_by_user}"
  30. end
  31. actual.has_no_css? base_selector, text: expected
  32. end
  33. chain :changed! do
  34. @changed = true
  35. end
  36. chain :with_icon do |icon|
  37. @icon = icon
  38. end
  39. chain :with_no_icon! do
  40. @no_icon = true
  41. end
  42. def select_by_user
  43. "[data-id='#{expected.id}']"
  44. end
  45. def base_selector
  46. changed_class = @changed ? 'changed' : 'not-changed'
  47. ".js-attributeBar .js-avatar .avatar--#{changed_class}"
  48. end
  49. end
  50. # rubocop:enable RSpec/InstanceVariable
  51. def check_taskbar_tab(ticket_id, title: nil, modified: false)
  52. tab_data_key = "Ticket-#{ticket_id}"
  53. if title
  54. taskbar_tab = find(".tasks .task[data-key='#{tab_data_key}']")
  55. expect(taskbar_tab).to have_css('.nav-tab-name', text: title)
  56. end
  57. if modified
  58. expect(page).to have_css(".tasks .task[data-key='#{tab_data_key}'].is-modified")
  59. else
  60. expect(page).to have_no_css(".tasks .task[data-key='#{tab_data_key}'].is-modified")
  61. end
  62. end
  63. context 'when two different users are simultaneously in one ticket' do
  64. before do
  65. visit "#ticket/zoom/#{ticket.id}"
  66. using_session(:second_browser) do
  67. login(
  68. username: agent.login,
  69. password: 'test',
  70. )
  71. visit "#ticket/zoom/#{ticket.id}"
  72. end
  73. end
  74. it 'avatar from other user should be visible in ticket zoom' do
  75. perform_enqueued_jobs do
  76. expect(page).to have_avatar('AT')
  77. using_session(:second_browser) do
  78. expect(page).to have_avatar('TA')
  79. end
  80. end
  81. end
  82. it 'check changes from the first user and added changes from the second user' do
  83. perform_enqueued_jobs do
  84. within(:active_content) do
  85. find('.js-textarea').send_keys('some note')
  86. expect(page).to have_css('.js-reset')
  87. end
  88. expect(page).to have_avatar('AT')
  89. using_session(:second_browser) do
  90. expect(page).to have_avatar('TA').changed!
  91. within(:active_content) do
  92. find('.js-textarea').send_keys('some other note')
  93. expect(page).to have_css('.js-reset')
  94. end
  95. end
  96. expect(page).to have_avatar('AT').changed!
  97. using_session(:second_browser) do
  98. within(:active_content) do
  99. click '.js-attributeBar .js-submit'
  100. expect(page).to have_no_css('.js-reset')
  101. expect(page).to have_css('.article-content', text: 'some other note')
  102. end
  103. expect(page).to have_avatar('TA').changed!
  104. end
  105. expect(page).to have_avatar('AT')
  106. check_taskbar_tab(ticket.id, title: ticket.title, modified: true)
  107. within(:active_content) do
  108. expect(page).to have_css('.article-content', text: 'some other note')
  109. click '.js-attributeBar .js-submit'
  110. expect(page).to have_no_css('.js-reset')
  111. expect(page).to have_css('.article-content', text: 'some note')
  112. end
  113. using_session(:second_browser) do
  114. expect(page).to have_avatar('TA')
  115. expect(page).to have_css('.article-content', text: 'some note')
  116. check_taskbar_tab(ticket.id, title: ticket.title, modified: true)
  117. end
  118. # Reload browsers and check if state is correct.
  119. refresh
  120. using_session(:second_browser) do
  121. refresh
  122. expect(page).to have_avatar('TA')
  123. expect(page).to have_no_css('.js-reset')
  124. end
  125. expect(page).to have_avatar('AT')
  126. expect(page).to have_no_css('.js-reset')
  127. end
  128. end
  129. it 'check refresh for unsaved changes and reset after refresh' do
  130. perform_enqueued_jobs do
  131. using_session(:second_browser) do
  132. within(:active_content) do
  133. find('.js-textarea').send_keys('some other note')
  134. expect(page).to have_css('.js-reset')
  135. end
  136. expect(page).to have_avatar('TA')
  137. # We need to wait for the auto save feature.
  138. wait.until do
  139. Taskbar.find_by(key: "Ticket-#{ticket.id}", user_id: agent.id).state_changed?
  140. end
  141. refresh
  142. end
  143. expect(page).to have_avatar('AT').changed!
  144. using_session(:second_browser) do
  145. refresh
  146. within(:active_content) do
  147. click '.js-reset'
  148. expect(page).to have_css('.js-textarea', text: '')
  149. end
  150. end
  151. expect(page).to have_avatar('AT')
  152. end
  153. end
  154. it 'change title with second user' do
  155. perform_enqueued_jobs do
  156. find('.js-textarea').send_keys('some note')
  157. using_session(:second_browser) do
  158. find('.js-textarea').send_keys('some other note')
  159. find('.ticketZoom-header .js-objectTitle').set('TTTsome level 2 <b>subject</b> 123äöü')
  160. # Click in the body field, to trigger the title update.
  161. find('.js-textarea').send_keys('trigger title')
  162. expect(page).to have_css('.js-objectTitle', text: 'TTTsome level 2 <b>subject</b> 123äöü')
  163. check_taskbar_tab(ticket.id, title: 'TTTsome level 2 <b>subject</b> 123äöü')
  164. expect(page).to have_css('.js-textarea', text: 'some other note')
  165. end
  166. expect(page).to have_css('.js-objectTitle', text: 'TTTsome level 2 <b>subject</b> 123äöü')
  167. expect(page).to have_css('.js-textarea', text: 'some note')
  168. check_taskbar_tab(ticket.id, title: 'TTTsome level 2 <b>subject</b> 123äöü', modified: true)
  169. # Refresh and check that modified flag is gone
  170. refresh
  171. check_taskbar_tab(ticket.id, title: 'TTTsome level 2 <b>subject</b> 123äöü', modified: false)
  172. end
  173. end
  174. end
  175. context 'when working on multiple platforms', authenticated_as: :user do
  176. let(:ticket) { create(:ticket) }
  177. let(:user) { create(:agent, groups: [ticket.group]) }
  178. let(:another_user) { create(:agent, groups: [ticket.group]) }
  179. let(:key) { "Ticket-#{ticket.id}" }
  180. let(:path) { "ticket/zoom/#{ticket.id}" }
  181. let(:taskbar_mobile) { create(:taskbar, user: user, app: :mobile, key: key) }
  182. let(:taskbar_desktop) { create(:taskbar, user: user, app: :desktop, key: key) }
  183. let(:another_taskbar_mobile) { create(:taskbar, user: another_user, app: :mobile, key: key) }
  184. let(:another_taskbar_desktop) { create(:taskbar, user: another_user, app: :desktop, key: key) }
  185. context 'when looking on a ticket' do
  186. before do
  187. taskbar_desktop
  188. visit path
  189. end
  190. it 'does not show current user' do
  191. perform_enqueued_jobs do
  192. expect(page).not_to have_avatar(user)
  193. end
  194. end
  195. end
  196. context 'when another user is looking on desktop' do
  197. before do
  198. another_taskbar_desktop
  199. taskbar_desktop
  200. visit path
  201. end
  202. it 'shows another user' do
  203. perform_enqueued_jobs do
  204. expect(page).to have_avatar(another_user).with_no_icon!
  205. end
  206. end
  207. end
  208. context 'when another user is looking on mobile' do
  209. before do
  210. another_taskbar_mobile
  211. taskbar_desktop
  212. visit path
  213. end
  214. it 'shows another user' do
  215. perform_enqueued_jobs do
  216. expect(page).to have_avatar(another_user).with_icon(:mobile)
  217. end
  218. end
  219. end
  220. context 'when another user is looking on mobile and desktop' do
  221. before do
  222. another_taskbar_mobile
  223. another_taskbar_desktop
  224. taskbar_desktop
  225. visit path
  226. end
  227. it 'shows another user' do
  228. perform_enqueued_jobs do
  229. expect(page).to have_avatar(another_user).with_no_icon!
  230. end
  231. end
  232. end
  233. context 'when another user is editing on desktop' do
  234. before do
  235. another_taskbar_desktop.update!(state: { a: 1 })
  236. taskbar_desktop
  237. visit path
  238. end
  239. it 'shows another user' do
  240. perform_enqueued_jobs do
  241. expect(page).to have_avatar(another_user).with_icon(:pen).changed!
  242. end
  243. end
  244. end
  245. context 'when another user is editing on mobile' do
  246. before do
  247. another_taskbar_mobile.update!(state: { a: 1 })
  248. taskbar_desktop
  249. visit path
  250. end
  251. it 'shows another user' do
  252. perform_enqueued_jobs do
  253. expect(page).to have_avatar(another_user).with_icon(:pen).changed!
  254. end
  255. end
  256. end
  257. context 'when same user is looking on mobile too' do
  258. before do
  259. taskbar_mobile
  260. taskbar_desktop
  261. visit path
  262. end
  263. it 'shows same user' do
  264. perform_enqueued_jobs do
  265. expect(page).not_to have_avatar(user)
  266. end
  267. end
  268. end
  269. context 'when same user is editing' do
  270. before do
  271. taskbar_desktop.update!(state: { a: 1 })
  272. visit path
  273. end
  274. it 'do not show same user' do
  275. perform_enqueued_jobs do
  276. expect(page).not_to have_avatar(user)
  277. end
  278. end
  279. end
  280. context 'when same user is editing on mobile' do
  281. before do
  282. taskbar_mobile.update!(state: { a: 1 })
  283. taskbar_desktop
  284. visit path
  285. end
  286. it 'shows same user' do
  287. perform_enqueued_jobs do
  288. expect(page).to have_avatar(user).with_icon(:'mobile-edit').changed!
  289. end
  290. end
  291. end
  292. end
  293. end