diff --git a/src/components/RightSidebar/Participants/Participant.spec.js b/src/components/RightSidebar/Participants/Participant.spec.js index bd2689f1621..bfbb4f5b078 100644 --- a/src/components/RightSidebar/Participants/Participant.spec.js +++ b/src/components/RightSidebar/Participants/Participant.spec.js @@ -3,6 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ import { createLocalVue, shallowMount } from '@vue/test-utils' +import flushPromises from 'flush-promises' import { cloneDeep } from 'lodash' import Vuex from 'vuex' @@ -17,6 +18,7 @@ import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js' import NcInputField from '@nextcloud/vue/dist/Components/NcInputField.js' +import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js' import NcTextArea from '@nextcloud/vue/dist/Components/NcTextArea.js' import Participant from './Participant.vue' @@ -32,34 +34,11 @@ describe('Participant.vue', () => { let store let localVue let testStoreConfig - let tooltipMock - - /** - * @param {object} wrapper Wrapper where the tooltip is mounted in - * @param {HTMLElement} htmlEl Tooltip to find - */ - async function getLastTooltipValue(wrapper, htmlEl) { - tooltipMock.mockClear() - await wrapper.vm.forceEnableTooltips() - - const filteredCalls = tooltipMock.mock.calls.filter((call) => { - // only keep calls on wanted node - return call[0] === htmlEl - }) - - if (filteredCalls.length) { - return filteredCalls.at(-1)[1].value - } - - return null - } beforeEach(() => { localVue = createLocalVue() localVue.use(Vuex) - tooltipMock = jest.fn() - participant = { displayName: 'Alice', inCall: PARTICIPANT.CALL_FLAG.DISCONNECTED, @@ -113,11 +92,9 @@ describe('Participant.vue', () => { NcCheckboxRadioSwitch, NcDialog, NcInputField, + NcListItem, NcTextArea, }, - directives: { - tooltip: tooltipMock, - }, mixins: [{ // force tooltip display for testing methods: { @@ -201,103 +178,106 @@ describe('Participant.vue', () => { }) describe('user name', () => { - /** - * @param {object} wrapper Wrapper where the tooltip is mounted in - */ - async function getUserTooltip(wrapper) { - const tooltipEl = wrapper.find('.participant-row__user-name').element - return getLastTooltipValue(wrapper, tooltipEl) - } - beforeEach(() => { participant.statusIcon = '' participant.statusMessage = '' }) - test('renders plain user name for regular user', async () => { + /** + * Check which text is currently rendered as a name + * @param {object} participant participant object + * @param {RegExp} regexp regex pattern which expected to be rendered + */ + function checkUserNameRendered(participant, regexp) { const wrapper = mountParticipant(participant) - expect(wrapper.text()).toBe('Alice') - expect(await getUserTooltip(wrapper)).toBe('Alice') + expect(wrapper.find('.participant__user').exists()).toBeTruthy() + expect(wrapper.find('.participant__user').text()).toMatch(regexp) + } + + test('renders plain user name for regular user', async () => { + checkUserNameRendered(participant, /^Alice$/) }) test('renders guest suffix for guests', async () => { participant.participantType = PARTICIPANT.TYPE.GUEST - const wrapper = mountParticipant(participant) - expect(wrapper.text()).toStrictEqual(expect.stringMatching(/^Alice\s+\(guest\)$/)) - expect(await getUserTooltip(wrapper)).toBe('Alice (guest)') + checkUserNameRendered(participant, /^Alice\s+\(guest\)$/) }) test('renders moderator suffix for moderators', async () => { participant.participantType = PARTICIPANT.TYPE.MODERATOR - const wrapper = mountParticipant(participant) - expect(wrapper.text()).toStrictEqual(expect.stringMatching(/^Alice\s+\(moderator\)$/)) - expect(await getUserTooltip(wrapper)).toBe('Alice (moderator)') + checkUserNameRendered(participant, /^Alice\s+\(moderator\)$/) }) test('renders guest moderator suffix for guest moderators', async () => { participant.participantType = PARTICIPANT.TYPE.GUEST_MODERATOR - const wrapper = mountParticipant(participant) - expect(wrapper.text()).toStrictEqual(expect.stringMatching(/^Alice\s+\(moderator\)\s+\(guest\)$/)) - expect(await getUserTooltip(wrapper)).toBe('Alice (moderator) (guest)') + checkUserNameRendered(participant, /^Alice\s+\(moderator\)\s+\(guest\)$/) }) test('renders bot suffix for bots', async () => { participant.actorType = ATTENDEE.ACTOR_TYPE.USERS participant.actorId = ATTENDEE.BRIDGE_BOT_ID - const wrapper = mountParticipant(participant) - expect(wrapper.text()).toStrictEqual(expect.stringMatching(/^Alice\s+\(bot\)$/)) - expect(await getUserTooltip(wrapper)).toBe('Alice (bot)') + checkUserNameRendered(participant, /^Alice\s+\(bot\)$/) }) }) describe('user status', () => { /** - * @param {object} wrapper Wrapper where the tooltip is mounted in + * Check which status is currently rendered + * @param {object} participant participant object + * @param {string|null} status status which expected to be rendered */ - async function getStatusTooltip(wrapper) { - const tooltipEl = wrapper.find('.participant-row__status>span').element - return getLastTooltipValue(wrapper, tooltipEl) + async function checkUserSubnameRendered(participant, status) { + const wrapper = mountParticipant(participant) + await flushPromises() + if (status) { + expect(wrapper.find('.participant__status').exists()).toBeTruthy() + expect(wrapper.find('.participant__status').text()).toBe(status) + } else { + expect(wrapper.find('.participant__status').exists()).toBeFalsy() + } } test('renders user status', async () => { - const wrapper = mountParticipant(participant) - expect(wrapper.find('.participant-row__status').text()).toBe('🌧️ rainy') - expect(await getStatusTooltip(wrapper)).toBe('🌧️ rainy') + await checkUserSubnameRendered(participant, '🌧️ rainy') }) - test('does not render user status when not set', () => { + test('does not render user status when not set', async () => { participant.statusIcon = '' participant.statusMessage = '' - const wrapper = mountParticipant(participant) - expect(wrapper.find('.participant-row__status').exists()).toBe(false) + await checkUserSubnameRendered(participant, null) }) test('renders dnd status', async () => { participant.statusMessage = '' participant.status = 'dnd' - const wrapper = mountParticipant(participant) - expect(wrapper.find('.participant-row__status').text()).toBe('🌧️ Do not disturb') - expect(await getStatusTooltip(wrapper)).toBe('🌧️ Do not disturb') + await checkUserSubnameRendered(participant, '🌧️ Do not disturb') }) test('renders away status', async () => { participant.statusMessage = '' participant.status = 'away' - const wrapper = mountParticipant(participant) - expect(wrapper.find('.participant-row__status').text()).toBe('🌧️ Away') - expect(await getStatusTooltip(wrapper)).toBe('🌧️ Away') + await checkUserSubnameRendered(participant, '🌧️ Away') }) }) describe('call icons', () => { let getParticipantRaisedHandMock + const components = [VideoIcon, Phone, Microphone, HandBackLeft] /** - * @param {object} wrapper Wrapper where the tooltip is mounted in + * Check which icons are currently rendered + * @param {object} participant participant object + * @param {object} icon icon which expected to be rendered */ - async function getCallIconTooltip(wrapper) { - const tooltipEl = wrapper.find('.participant-row__callstate-icon').element - return getLastTooltipValue(wrapper, tooltipEl) + function checkStateIconsRendered(participant, icon) { + const wrapper = mountParticipant(participant) + if (icon) { + expect(wrapper.findComponent(icon).exists()).toBeTruthy() + } else { + components.forEach(component => { + expect(wrapper.findComponent(component).exists()).toBeFalsy() + }) + } } beforeEach(() => { @@ -307,86 +287,43 @@ describe('Participant.vue', () => { testStoreConfig.modules.callViewStore.getters.getParticipantRaisedHand = () => getParticipantRaisedHandMock store = new Vuex.Store(testStoreConfig) }) - test('does not renders call icon when disconnected', () => { + + test('does not renders call icon and hand raised icon when disconnected', () => { participant.inCall = PARTICIPANT.CALL_FLAG.DISCONNECTED - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(VideoIcon).exists()).toBe(false) - expect(wrapper.findComponent(Phone).exists()).toBe(false) - expect(wrapper.findComponent(Microphone).exists()).toBe(false) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(false) + getParticipantRaisedHandMock = jest.fn().mockReturnValue({ state: true }) + + checkStateIconsRendered(participant, null) + expect(getParticipantRaisedHandMock).not.toHaveBeenCalled() }) test('renders video call icon', async () => { participant.inCall = PARTICIPANT.CALL_FLAG.WITH_VIDEO - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(VideoIcon).exists()).toBe(true) - expect(wrapper.findComponent(Phone).exists()).toBe(false) - expect(wrapper.findComponent(Microphone).exists()).toBe(false) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(false) - - expect(await getCallIconTooltip(wrapper)).toBe('Joined with video') + checkStateIconsRendered(participant, VideoIcon) }) test('renders audio call icon', async () => { participant.inCall = PARTICIPANT.CALL_FLAG.WITH_AUDIO - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(VideoIcon).exists()).toBe(false) - expect(wrapper.findComponent(Phone).exists()).toBe(false) - expect(wrapper.findComponent(Microphone).exists()).toBe(true) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(false) - - expect(await getCallIconTooltip(wrapper)).toBe('Joined with audio') + checkStateIconsRendered(participant, Microphone) }) test('renders phone call icon', async () => { participant.inCall = PARTICIPANT.CALL_FLAG.WITH_PHONE - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(VideoIcon).exists()).toBe(false) - expect(wrapper.findComponent(Phone).exists()).toBe(true) - expect(wrapper.findComponent(Microphone).exists()).toBe(false) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(false) - - expect(await getCallIconTooltip(wrapper)).toBe('Joined via phone') + checkStateIconsRendered(participant, Phone) }) test('renders hand raised icon', async () => { participant.inCall = PARTICIPANT.CALL_FLAG.WITH_VIDEO getParticipantRaisedHandMock = jest.fn().mockReturnValue({ state: true }) - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(VideoIcon).exists()).toBe(false) - expect(wrapper.findComponent(Phone).exists()).toBe(false) - expect(wrapper.findComponent(Microphone).exists()).toBe(false) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(true) - + checkStateIconsRendered(participant, HandBackLeft) expect(getParticipantRaisedHandMock).toHaveBeenCalledWith(['session-id-alice']) - - expect(await getCallIconTooltip(wrapper)).toBe('Raised their hand') }) test('renders video call icon when joined with multiple', async () => { participant.inCall = PARTICIPANT.CALL_FLAG.WITH_VIDEO | PARTICIPANT.CALL_FLAG.WITH_PHONE - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(VideoIcon).exists()).toBe(true) - expect(wrapper.findComponent(Phone).exists()).toBe(false) - expect(wrapper.findComponent(Microphone).exists()).toBe(false) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(false) - - expect(await getCallIconTooltip(wrapper)).toBe('Joined with video') + checkStateIconsRendered(participant, VideoIcon) }) - test('does not render hand raised icon when disconnected', () => { - participant.inCall = PARTICIPANT.CALL_FLAG.DISCONNECTED - getParticipantRaisedHandMock = jest.fn().mockReturnValue({ state: true }) - - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(false) - - expect(getParticipantRaisedHandMock).not.toHaveBeenCalled() - }) - test('does not render hand raised icon when searched', () => { participant.inCall = PARTICIPANT.CALL_FLAG.WITH_VIDEO participant.label = 'searched result' getParticipantRaisedHandMock = jest.fn().mockReturnValue({ state: true }) - const wrapper = mountParticipant(participant) - expect(wrapper.findComponent(HandBackLeft).exists()).toBe(false) - + checkStateIconsRendered(participant, null) expect(getParticipantRaisedHandMock).not.toHaveBeenCalled() }) }) @@ -868,7 +805,7 @@ describe('Participant.vue', () => { const wrapper = mountParticipant(participant) wrapper.vm.$on('click-participant', eventHandler) - await wrapper.find('li').trigger('click') + wrapper.find('a').trigger('click') expect(eventHandler).toHaveBeenCalledWith(participant) }) @@ -880,7 +817,7 @@ describe('Participant.vue', () => { const wrapper = mountParticipant(participant) wrapper.vm.$on('click-participant', eventHandler) - await wrapper.find('li').trigger('click') + wrapper.find('a').trigger('click') expect(eventHandler).not.toHaveBeenCalledWith(participant) }) diff --git a/src/components/RightSidebar/Participants/Participant.vue b/src/components/RightSidebar/Participants/Participant.vue index 6161b46c321..f35dff92450 100644 --- a/src/components/RightSidebar/Participants/Participant.vue +++ b/src/components/RightSidebar/Participants/Participant.vue @@ -4,154 +4,128 @@ -->