# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ require 'rails_helper' RSpec.describe 'Ticket > Update > Simultaneously with two different user', type: :system do let(:group) { Group.find_by(name: 'Users') } let(:ticket) { create(:ticket, group: group) } let(:agent) { User.find_by(login: 'agent1@example.com') } # rubocop:disable RSpec/InstanceVariable define :have_avatar do |expected| chain(:changed, :text) match do elem = find_element return false if elem.nil? return true if !@icon && !@no_icon return elem.has_no_css? '.icon' if @no_icon elem.has_css? ".icon-#{@icon}" end def find_element if expected.is_a? User actual.find "#{base_selector}#{select_by_user}" else actual.find base_selector, text: expected end rescue nil end match_when_negated do if expected.is_a? User return actual.has_no_css? "#{base_selector}#{select_by_user}" end actual.has_no_css? base_selector, text: expected end chain :changed! do @changed = true end chain :with_icon do |icon| @icon = icon end chain :with_no_icon! do @no_icon = true end def select_by_user "[data-id='#{expected.id}']" end def base_selector changed_class = @changed ? 'changed' : 'not-changed' ".js-attributeBar .js-avatar .avatar--#{changed_class}" end end # rubocop:enable RSpec/InstanceVariable def check_taskbar_tab(ticket_id, title: nil, modified: false) tab_data_key = "Ticket-#{ticket_id}" if title taskbar_tab = find(".tasks .task[data-key='#{tab_data_key}']") expect(taskbar_tab).to have_css('.nav-tab-name', text: title) end if modified expect(page).to have_css(".tasks .task[data-key='#{tab_data_key}'].is-modified") else expect(page).to have_no_css(".tasks .task[data-key='#{tab_data_key}'].is-modified") end end context 'when two different users are simultaneously in one ticket' do before do visit "#ticket/zoom/#{ticket.id}" using_session(:second_browser) do login( username: agent.login, password: 'test', ) visit "#ticket/zoom/#{ticket.id}" end end it 'avatar from other user should be visible in ticket zoom' do expect(page).to have_avatar('AT') using_session(:second_browser) do expect(page).to have_avatar('TA') end end it 'check changes from the first user and added changes from the second user' do within(:active_content) do find('.js-textarea').send_keys('some note') expect(page).to have_css('.js-reset') end expect(page).to have_avatar('AT') using_session(:second_browser) do expect(page).to have_avatar('TA').changed! within(:active_content) do find('.js-textarea').send_keys('some other note') expect(page).to have_css('.js-reset') end end expect(page).to have_avatar('AT').changed! using_session(:second_browser) do within(:active_content) do click '.js-attributeBar .js-submit' expect(page).to have_no_css('.js-reset') expect(page).to have_css('.article-content', text: 'some other note') end expect(page).to have_avatar('TA').changed! end expect(page).to have_avatar('AT') check_taskbar_tab(ticket.id, title: ticket.title, modified: true) within(:active_content) do expect(page).to have_css('.article-content', text: 'some other note') click '.js-attributeBar .js-submit' expect(page).to have_no_css('.js-reset') expect(page).to have_css('.article-content', text: 'some note') end using_session(:second_browser) do expect(page).to have_avatar('TA') expect(page).to have_css('.article-content', text: 'some note') check_taskbar_tab(ticket.id, title: ticket.title, modified: true) end # Reload browsers and check if state is correct. refresh using_session(:second_browser) do refresh expect(page).to have_avatar('TA') expect(page).to have_no_css('.js-reset') end expect(page).to have_avatar('AT') expect(page).to have_no_css('.js-reset') end it 'check refresh for unsaved changes and reset after refresh' do using_session(:second_browser) do within(:active_content) do find('.js-textarea').send_keys('some other note') expect(page).to have_css('.js-reset') end expect(page).to have_avatar('TA') # We need to wait for the auto save feature. wait.until do Taskbar.find_by(key: "Ticket-#{ticket.id}", user_id: agent.id).state_changed? end refresh end expect(page).to have_avatar('AT').changed! using_session(:second_browser) do refresh within(:active_content) do click '.js-reset' expect(page).to have_css('.js-textarea', text: '') end end expect(page).to have_avatar('AT') end it 'change title with second user' do find('.js-textarea').send_keys('some note') using_session(:second_browser) do find('.js-textarea').send_keys('some other note') find('.ticketZoom-header .js-objectTitle').set('TTTsome level 2 subject 123äöü') # Click in the body field, to trigger the title update. find('.js-textarea').send_keys('trigger title') expect(page).to have_css('.js-objectTitle', text: 'TTTsome level 2 subject 123äöü') check_taskbar_tab(ticket.id, title: 'TTTsome level 2 subject 123äöü') expect(page).to have_css('.js-textarea', text: 'some other note') end expect(page).to have_css('.js-objectTitle', text: 'TTTsome level 2 subject 123äöü') expect(page).to have_css('.js-textarea', text: 'some note') check_taskbar_tab(ticket.id, title: 'TTTsome level 2 subject 123äöü', modified: true) # Refresh and check that modified flag is gone refresh check_taskbar_tab(ticket.id, title: 'TTTsome level 2 subject 123äöü', modified: false) end end context 'when working on multiple platforms', authenticated_as: :user do let(:ticket) { create(:ticket) } let(:user) { create(:agent, groups: [ticket.group]) } let(:another_user) { create(:agent, groups: [ticket.group]) } let(:key) { "Ticket-#{ticket.id}" } let(:path) { "ticket/zoom/#{ticket.id}" } let(:taskbar_mobile) { create(:taskbar, user: user, app: :mobile, key: key) } let(:taskbar_desktop) { create(:taskbar, user: user, app: :desktop, key: key) } let(:another_taskbar_mobile) { create(:taskbar, user: another_user, app: :mobile, key: key) } let(:another_taskbar_desktop) { create(:taskbar, user: another_user, app: :desktop, key: key) } context 'when looking on a ticket' do before do taskbar_desktop visit path end it 'does not show current user' do expect(page).not_to have_avatar(user) end end context 'when another user is looking on desktop' do before do another_taskbar_desktop taskbar_desktop visit path end it 'shows another user' do expect(page).to have_avatar(another_user).with_no_icon! end end context 'when another user is looking on mobile' do before do another_taskbar_mobile taskbar_desktop visit path end it 'shows another user' do expect(page).to have_avatar(another_user).with_icon(:mobile) end end context 'when another user is looking on mobile and desktop' do before do another_taskbar_mobile another_taskbar_desktop taskbar_desktop visit path end it 'shows another user' do expect(page).to have_avatar(another_user).with_no_icon! end end context 'when another user is editing on desktop' do before do another_taskbar_desktop.update!(state: { a: 1 }) taskbar_desktop visit path end it 'shows another user' do expect(page).to have_avatar(another_user).with_icon(:pen).changed! end end context 'when another user is editing on mobile' do before do another_taskbar_mobile.update!(state: { a: 1 }) taskbar_desktop visit path end it 'shows another user' do expect(page).to have_avatar(another_user).with_icon(:pen).changed! end end context 'when same user is looking on mobile too' do before do taskbar_mobile taskbar_desktop visit path end it 'shows same user' do expect(page).not_to have_avatar(user) end end context 'when same user is editing' do before do taskbar_desktop.update!(state: { a: 1 }) visit path end it 'do not show same user' do expect(page).not_to have_avatar(user) end end context 'when same user is editing on mobile' do before do taskbar_mobile.update!(state: { a: 1 }) taskbar_desktop visit path end it 'shows same user' do expect(page).to have_avatar(user).with_icon(:'mobile-edit').changed! end end end end