diff --git a/tests/specs/jaas/dial/sipjibri.spec.ts b/tests/specs/jaas/dial/sipjibri.spec.ts deleted file mode 100644 index a3aeaf2321..0000000000 --- a/tests/specs/jaas/dial/sipjibri.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import type { Participant } from '../../../helpers/Participant'; -import { setTestProperties } from '../../../helpers/TestProperties'; -import { config as testsConfig } from '../../../helpers/TestsConfig'; -import WebhookProxy from '../../../helpers/WebhookProxy'; -import { joinJaasMuc, generateJaasToken as t } from '../../../helpers/jaas'; - -import { waitForMedia } from './util'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true, -}); - - -describe('SIP jibri invite', () => { - let p1: Participant, webhooksProxy: WebhookProxy; - const customerId = testsConfig.jaas.customerId || ''; - const dialOutUrl = process.env.SIP_JIBRI_DIAL_OUT_URL || ''; - - it('setup', async () => { - const room = ctx.roomName; - - if (true) { - // This is temporary until we figure out how to fix it and configure it properly. - ctx.skipSuiteTests = 'This test is disabled as the code doesn\'t work anymore.'; - - return; - } - - if (!dialOutUrl) { - ctx.skipSuiteTests = 'SIP_JIBRI_DIAL_OUT_URL is not set.'; - - return; - } - - p1 = await joinJaasMuc({ name: 'p1', iFrameApi: true, token: t({ room, moderator: true }) }); - webhooksProxy = ctx.webhooksProxy; - - expect(await p1.isInMuc()).toBe(true); - expect(Boolean(await p1.execute(() => config.inviteServiceUrl))).toBe(true); - }); - - it('sip jibri', async () => { - await p1.switchToMainFrame(); - await p1.getIframeAPI().inviteSIP(dialOutUrl); - await p1.switchToIFrame(); - await p1.waitForParticipants(1); - await waitForMedia(p1); - - const startedEvent: { - customerId: string; - data: { - participantFullJid: string; - participantId: string; - participantJid: string; - sipAddress: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('SIP_CALL_OUT_STARTED'); - - expect('SIP_CALL_OUT_STARTED').toBe(startedEvent.eventType); - expect(startedEvent.data.sipAddress).toBe(`sip:${process.env.SIP_JIBRI_DIAL_OUT_URL}`); - expect(startedEvent.customerId).toBe(customerId); - - const endpointId = await p1.execute(() => APP?.conference?.listMembers()[0].getId()); - - await p1.getFilmstrip().kickParticipant(endpointId); - - const endedEvent: { - customerId: string; - data: { - direction: string; - participantFullJid: string; - participantId: string; - participantJid: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('SIP_CALL_OUT_ENDED'); - - expect('SIP_CALL_OUT_ENDED').toBe(endedEvent.eventType); - expect(endedEvent.customerId).toBe(customerId); - expect(endedEvent.data.participantFullJid).toBe(startedEvent.data.participantFullJid); - expect(endedEvent.data.participantId).toBe(startedEvent.data.participantId); - expect(endedEvent.data.participantJid).toBe(startedEvent.data.participantJid); - }); -}); diff --git a/tests/specs/jaas/passcodeInvalid.spec.ts b/tests/specs/jaas/passcodeInvalid.spec.ts deleted file mode 100644 index 1ecda4057f..0000000000 --- a/tests/specs/jaas/passcodeInvalid.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { joinJaasMuc, generateJaasToken as t } from '../../helpers/jaas'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true -}); - -// This test is separate from passcode.spec.ts, because it needs to use a different room name, and webhooksProxy is only -// setup for the default room name. -describe('Setting invalid passcode through settings provisioning', () => { - it('With an invalid passcode', async () => { - ctx.webhooksProxy.defaultMeetingSettings = { - passcode: 'passcode-must-be-digits-only' - }; - - const p = await joinJaasMuc({ token: t({ room: ctx.roomName }) }, { roomName: ctx.roomName }); - - // The settings provisioning contains an invalid passcode, the expected result is that the room is not - // configured to require a passcode. - await p.waitToJoinMUC(); - expect(await p.isInMuc()).toBe(true); - expect(await p.getPasswordDialog().isOpen()).toBe(false); - }); -}); diff --git a/tests/specs/jaas/presence.spec.ts b/tests/specs/jaas/presence.spec.ts deleted file mode 100644 index a4914b8cc3..0000000000 --- a/tests/specs/jaas/presence.spec.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { expect } from '@wdio/globals'; - -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import WebhookProxy from '../../helpers/WebhookProxy'; -import { joinJaasMuc, generateJaasToken as t } from '../../helpers/jaas'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true, - usesBrowsers: [ 'p1', 'p2' ] -}); - -/** - * Tests the basic webhooks fired for participants joining, leaving, and creating/destroying a conference: - * PARTICIPANT_JOINED, PARTICIPANT_LEFT, ROOM_CREATED, ROOM_DESTROYED, ROLE_CHANGED, USAGE. - */ -describe('Create/destroy/join/leave webhooks', () => { - let conferenceJid: string = ''; - let p1: Participant, p2: Participant; - let p1EpId: string, p2EpId: string; - let webhooksProxy: WebhookProxy; - let room: string; - - async function checkParticipantJoinedHook(p: Participant) { - const event: { - data: { - conference: string; - isBreakout: boolean; - moderator: boolean; - name: string; - participantId: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('PARTICIPANT_JOINED'); - - expect(event.eventType).toBe('PARTICIPANT_JOINED'); - expect(event.data.conference).toBe(conferenceJid); - expect(event.data.isBreakout).toBe(false); - expect(event.data.moderator).toBe(p.getToken()?.options?.moderator); - expect(event.data.name).toBe(await p.getLocalDisplayName()); - expect(event.data.participantId).toBe(await p.getEndpointId()); - expect(event.data.name).toBe(p.name); - } - async function checkParticipantLeftHook(p: Participant, reason: string) { - - const event: { - customerId: string; - data: { - conference: string; - disconnectReason: string; - group: string; - id: string; - isBreakout: boolean; - name: string; - participantId: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('PARTICIPANT_LEFT'); - - expect(event.eventType).toBe('PARTICIPANT_LEFT'); - expect(event.data.conference).toBe(conferenceJid); - expect(event.data.disconnectReason).toBe(reason); - expect(event.data.isBreakout).toBe(false); - expect(event.data.participantId).toBe(await p.getEndpointId()); - expect(event.data.name).toBe(p.name); - - const jwtPayload = p.getToken()?.payload; - - expect(event.data.id).toBe(jwtPayload?.context?.user?.id); - expect(event.data.group).toBe(jwtPayload?.context?.group); - expect(event.customerId).toBe(testsConfig.jaas.customerId); - } - - it('setup', async () => { - room = ctx.roomName; - conferenceJid = `${room}@conference.${testsConfig.jaas.tenant}.${new URL(process.env.BASE_URL || '').hostname}`; - webhooksProxy = ctx.webhooksProxy; - p1 = await joinJaasMuc({ name: 'p1', iFrameApi: true, token: t({ room, moderator: true }) }); - p1EpId = await p1.getEndpointId(); - expect(await p1.isModerator()).toBe(true); - await checkParticipantJoinedHook(p1); - await p1.switchToMainFrame(); - p2 = await joinJaasMuc({ name: 'p2', token: t({ room }) }); - p2EpId = await p2.getEndpointId(); - expect(await p2.isModerator()).toBe(false); - await checkParticipantJoinedHook(p2); - }); - - it('USAGE webhook', async () => { - const event: { - data: [ - { participantId: string; } - ]; - eventType: string; - } = await webhooksProxy.waitForEvent('USAGE'); - - expect(event.eventType).toBe('USAGE'); - - expect(event.data.some(d => d.participantId === p1EpId)); - expect(event.data.some(d => d.participantId === p2EpId)); - }); - - it('ROOM_CREATED webhook', async () => { - const event: { - data: { - conference: string; - isBreakout: boolean; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('ROOM_CREATED'); - - expect(event.eventType).toBe('ROOM_CREATED'); - expect(event.data.conference).toBe(conferenceJid); - expect(event.data.isBreakout).toBe(false); - }); - - it('ROLE_CHANGED webhook', async () => { - await p1.getIframeAPI().executeCommand('grantModerator', p2EpId); - - const event: { - data: { - grantedBy: { - participantId: string; - }; - grantedTo: { - participantId: string; - }; - role: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('ROLE_CHANGED'); - - expect(event.eventType).toBe('ROLE_CHANGED'); - expect(event.data.role).toBe('moderator'); - expect(event.data.grantedBy.participantId).toBe(p1EpId); - expect(event.data.grantedTo.participantId).toBe(p2EpId); - }); - - it('kick participant', async () => { - webhooksProxy.clearCache(); - await p1.getIframeAPI().executeCommand('kickParticipant', p2EpId); - await checkParticipantLeftHook(p2, 'kicked'); - }); - - it('join after kick', async () => { - webhooksProxy.clearCache(); - - // join again - p2 = await joinJaasMuc({ name: 'p2', token: t({ room }) }); - p2EpId = await p2.getEndpointId(); - - await checkParticipantJoinedHook(p2); - }); - - it('hangup', async () => { - await p2.hangup(); - await checkParticipantLeftHook(p2, 'left'); - }); - - it('dispose conference', async () => { - await p1.getIframeAPI().executeCommand('hangup'); - await checkParticipantLeftHook(p1, 'left'); - - const event: { - data: { - conference: string; - isBreakout: boolean; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('ROOM_DESTROYED'); - - expect(event.eventType).toBe('ROOM_DESTROYED'); - expect(event.data.conference).toBe(conferenceJid); - expect(event.data.isBreakout).toBe(false); - }); -}); diff --git a/tests/specs/jaas/recording.spec.ts b/tests/specs/jaas/recording.spec.ts deleted file mode 100644 index a301e2b5f1..0000000000 --- a/tests/specs/jaas/recording.spec.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import WebhookProxy from '../../helpers/WebhookProxy'; -import { joinJaasMuc, generateJaasToken as t } from '../../helpers/jaas'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true -}); - -/** - * Tests the recording and live-streaming functionality of JaaS (including relevant webhooks) exercising the iFrame API - * commands and functions. - * TODO: read flags from config. - * TODO: also assert "this meeting is being recorder" notificaitons are show/played? - */ -describe('Recording and live-streaming', () => { - const tenant = testsConfig.jaas.tenant; - const customerId = tenant?.replace('vpaas-magic-cookie-', ''); - // TODO: read from config - let recordingDisabled: boolean; - // TODO: read from config - let liveStreamingDisabled: boolean; - let p: Participant; - let webhooksProxy: WebhookProxy; - - it('setup', async () => { - webhooksProxy = ctx.webhooksProxy; - p = await joinJaasMuc({ iFrameApi: true, token: t({ moderator: true }) }, { roomName: ctx.roomName }); - - // TODO: what should we do in this case? Add a config for this? - if (await p.execute(() => config.disableIframeAPI)) { - ctx.skipSuiteTests = 'The environment has the iFrame API disabled.'; - - return; - } - - // TODO: only read if config says so - recordingDisabled = Boolean(!await p.execute(() => config.recordingService?.enabled)); - liveStreamingDisabled = Boolean(!await p.execute(() => config.liveStreaming?.enabled)) - || !process.env.YTUBE_TEST_STREAM_KEY; - - await p.switchToMainFrame(); - }); - - /** - * Starts recording and asserts that the expected iFrame and JaaS events are received. - * @param command whether to use the "command" or the "function" iFrame API. - */ - async function startRecording(command: boolean) { - await p.getIframeAPI().addEventListener('recordingStatusChanged'); - await p.getIframeAPI().addEventListener('recordingLinkAvailable'); - - if (command) { - await p.getIframeAPI().executeCommand('startRecording', { - mode: 'file' - }); - } else { - await p.getIframeAPI().startRecording({ - mode: 'file' - }); - } - - const jaasEvent: { - customerId: string; - eventType: string; - } = await webhooksProxy.waitForEvent('RECORDING_STARTED'); - - expect('RECORDING_STARTED').toBe(jaasEvent.eventType); - expect(jaasEvent.customerId).toBe(customerId); - - webhooksProxy.clearCache(); - - const iFrameEvent = await p.driver.waitUntil(() => - p.getIframeAPI().getEventResult('recordingStatusChanged'), { - timeout: 5000, - timeoutMsg: 'recordingStatusChanged event not received' - }); - - expect(iFrameEvent.mode).toBe('file'); - expect(iFrameEvent.on).toBe(true); - - const linkEvent = await p.driver.waitUntil(() => - p.getIframeAPI().getEventResult('recordingLinkAvailable'), { - timeout: 5000, - timeoutMsg: 'recordingLinkAvailable event not received' - }); - - expect(linkEvent.link.startsWith('https://')).toBe(true); - expect(linkEvent.link.includes(tenant)).toBe(true); - expect(linkEvent.ttl > 0).toBe(true); - } - - /** - * Stops recording and asserts that the expected iFrame and JaaS events are received. - * @param command whether to use the "command" or the "function" iFrame API. - */ - async function stopRecording(command: boolean) { - if (command) { - await p.getIframeAPI().executeCommand('stopRecording', 'file'); - } else { - await p.getIframeAPI().stopRecording('file'); - } - - const jaasEndedEvent: { - customerId: string; - eventType: string; - } = await webhooksProxy.waitForEvent('RECORDING_ENDED'); - - expect('RECORDING_ENDED').toBe(jaasEndedEvent.eventType); - expect(jaasEndedEvent.customerId).toBe(customerId); - - const jaasUploadedEvent: { - customerId: string; - data: { - initiatorId: string; - participants: Array; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('RECORDING_UPLOADED'); - - const jwtPayload = p.getToken()?.payload; - - expect(jaasUploadedEvent.data.initiatorId).toBe(jwtPayload?.context?.user?.id); - expect(jaasUploadedEvent.data.participants.some( - // @ts-ignore - e => e.id === jwtPayload?.context?.user?.id)).toBe(true); - - webhooksProxy.clearCache(); - - const iFrameEvent = (await p.getIframeAPI().getEventResult('recordingStatusChanged')); - - expect(iFrameEvent.mode).toBe('file'); - expect(iFrameEvent.on).toBe(false); - - await p.getIframeAPI().clearEventResults('recordingStatusChanged'); - } - - it('start/stop recording using the iFrame command', async () => { - if (recordingDisabled) { - return; - } - - await startRecording(true); - await stopRecording(true); - - // to avoid rate limits - await p.driver.pause(30000); - }); - - it('start/stop recording using the iFrame function', async () => { - if (recordingDisabled) { - return; - } - - await startRecording(false); - await stopRecording(false); - - // to avoid rate limits - await p.driver.pause(30000); - }); - - it('start/stop live-streaming using the iFrame command', async () => { - if (liveStreamingDisabled) { - return; - } - - await p.getIframeAPI().addEventListener('recordingStatusChanged'); - - await p.getIframeAPI().executeCommand('startRecording', { - youtubeBroadcastID: process.env.YTUBE_TEST_BROADCAST_ID, - mode: 'stream', - youtubeStreamKey: process.env.YTUBE_TEST_STREAM_KEY - }); - - const jaasEvent: { - customerId: string; - eventType: string; - } = await webhooksProxy.waitForEvent('LIVE_STREAM_STARTED'); - - expect('LIVE_STREAM_STARTED').toBe(jaasEvent.eventType); - expect(jaasEvent.customerId).toBe(customerId); - - const iFrameEvent = (await p.getIframeAPI().getEventResult('recordingStatusChanged')); - - expect(iFrameEvent.mode).toBe('stream'); - expect(iFrameEvent.on).toBe(true); - - if (process.env.YTUBE_TEST_BROADCAST_ID) { - const liveStreamUrl = await p.getIframeAPI().getLivestreamUrl(); - - expect(liveStreamUrl.livestreamUrl).toBeDefined(); - } - - await p.getIframeAPI().executeCommand('stopRecording', 'stream'); - - const jaasEndedEvent: { - customerId: string; - eventType: string; - } = await webhooksProxy.waitForEvent('LIVE_STREAM_ENDED'); - - expect(jaasEndedEvent.eventType).toBe('LIVE_STREAM_ENDED'); - expect(jaasEndedEvent.customerId).toBe(customerId); - - const iFrameEndedEvent = (await p.getIframeAPI().getEventResult('recordingStatusChanged')); - - expect(iFrameEndedEvent.mode).toBe('stream'); - expect(iFrameEndedEvent.on).toBe(false); - }); -}); - diff --git a/tests/specs/jaas/transcriptions.spec.ts b/tests/specs/jaas/transcriptions.spec.ts deleted file mode 100644 index 424779fdba..0000000000 --- a/tests/specs/jaas/transcriptions.spec.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { expect } from '@wdio/globals'; - -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import type WebhookProxy from '../../helpers/WebhookProxy'; -import { joinJaasMuc, generateJaasToken as t } from '../../helpers/jaas'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true, - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Transcription', () => { - let p1: Participant, p2: Participant; - let webhooksProxy: WebhookProxy; - - it('setup', async () => { - const room = ctx.roomName; - - webhooksProxy = ctx.webhooksProxy; - - p1 = await joinJaasMuc({ - name: 'p1', - token: t({ room, moderator: true }), - iFrameApi: true }); - - if (await p1.execute(() => config.disableIframeAPI || !config.transcription?.enabled)) { - // skip the test if iframeAPI or transcriptions are disabled - ctx.skipSuiteTests = 'The environment has the iFrame API or transcriptions disabled.'; - - return; - } - - p2 = await joinJaasMuc({ - name: 'p2', - token: t({ room }), - iFrameApi: true }, { - configOverwrite: { - startWithAudioMuted: true - } - }); - - await Promise.all([ - p1.switchToMainFrame(), - p2.switchToMainFrame(), - ]); - - expect(await p1.getIframeAPI().getEventResult('isModerator')).toBe(true); - expect(await p1.getIframeAPI().getEventResult('videoConferenceJoined')).toBeDefined(); - }); - - it('toggle subtitles', async () => { - await p1.getIframeAPI().addEventListener('transcriptionChunkReceived'); - await p2.getIframeAPI().addEventListener('transcriptionChunkReceived'); - await p1.getIframeAPI().executeCommand('toggleSubtitles'); - - await checkReceivingChunks(p1, p2, webhooksProxy); - - await p1.getIframeAPI().clearEventResults('transcribingStatusChanged'); - await p1.getIframeAPI().addEventListener('transcribingStatusChanged'); - - await p1.getIframeAPI().executeCommand('toggleSubtitles'); - - await p1.driver.waitUntil(() => p1.getIframeAPI() - .getEventResult('transcribingStatusChanged'), { - timeout: 15000, - timeoutMsg: 'transcribingStatusChanged event not received by p1' - }); - }); - - it('set subtitles on and off', async () => { - // we need to clear results or the last one will be used, from the previous time subtitles were on - await p1.getIframeAPI().clearEventResults('transcriptionChunkReceived'); - await p2.getIframeAPI().clearEventResults('transcriptionChunkReceived'); - - await p1.getIframeAPI().executeCommand('setSubtitles', true, true); - - await checkReceivingChunks(p1, p2, webhooksProxy); - - await p1.getIframeAPI().clearEventResults('transcribingStatusChanged'); - - await p1.getIframeAPI().executeCommand('setSubtitles', false); - - await p1.driver.waitUntil(() => p1.getIframeAPI() - .getEventResult('transcribingStatusChanged'), { - timeout: 15000, - timeoutMsg: 'transcribingStatusChanged event not received by p1' - }); - }); - - it('start/stop transcriptions via recording', async () => { - // we need to clear results or the last one will be used, from the previous time subtitles were on - await p1.getIframeAPI().clearEventResults('transcribingStatusChanged'); - await p1.getIframeAPI().clearEventResults('transcriptionChunkReceived'); - await p2.getIframeAPI().clearEventResults('transcriptionChunkReceived'); - - await p2.getIframeAPI().addEventListener('transcribingStatusChanged'); - - await p1.getIframeAPI().executeCommand('startRecording', { transcription: true }); - - let allTranscriptionStatusChanged: Promise[] = []; - - allTranscriptionStatusChanged.push(await p1.driver.waitUntil(() => p1.getIframeAPI() - .getEventResult('transcribingStatusChanged'), { - timeout: 10000, - timeoutMsg: 'transcribingStatusChanged event not received on p1' - })); - allTranscriptionStatusChanged.push(await p2.driver.waitUntil(() => p2.getIframeAPI() - .getEventResult('transcribingStatusChanged'), { - timeout: 10000, - timeoutMsg: 'transcribingStatusChanged event not received on p2' - })); - - let result = await Promise.allSettled(allTranscriptionStatusChanged); - - expect(result.length).toBe(2); - - result.forEach(e => { - // @ts-ignore - expect(e.value.on).toBe(true); - }); - - await checkReceivingChunks(p1, p2, webhooksProxy); - - await p1.getIframeAPI().clearEventResults('transcribingStatusChanged'); - await p2.getIframeAPI().clearEventResults('transcribingStatusChanged'); - - await p1.getIframeAPI().executeCommand('stopRecording', 'file', true); - - allTranscriptionStatusChanged = []; - - allTranscriptionStatusChanged.push(await p1.driver.waitUntil(() => p1.getIframeAPI() - .getEventResult('transcribingStatusChanged'), { - timeout: 10000, - timeoutMsg: 'transcribingStatusChanged event not received on p1' - })); - allTranscriptionStatusChanged.push(await p2.driver.waitUntil(() => p2.getIframeAPI() - .getEventResult('transcribingStatusChanged'), { - timeout: 10000, - timeoutMsg: 'transcribingStatusChanged event not received on p2' - })); - - result = await Promise.allSettled(allTranscriptionStatusChanged); - - expect(result.length).toBe(2); - - result.forEach(e => { - // @ts-ignore - expect(e.value.on).toBe(false); - }); - - await p1.getIframeAPI().executeCommand('hangup'); - await p2.getIframeAPI().executeCommand('hangup'); - - // sometimes events are not immediately received, - // let's wait for destroy event before waiting for those that depends on it - await webhooksProxy.waitForEvent('ROOM_DESTROYED'); - - const event: { - data: { - preAuthenticatedLink: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('TRANSCRIPTION_UPLOADED'); - - expect('TRANSCRIPTION_UPLOADED').toBe(event.eventType); - expect(event.data.preAuthenticatedLink).toBeDefined(); - }); -}); - -async function checkReceivingChunks(p1: Participant, p2: Participant, webhooksProxy: WebhookProxy) { - const allTranscripts: Promise[] = []; - - allTranscripts.push(await p1.driver.waitUntil(() => p1.getIframeAPI() - .getEventResult('transcriptionChunkReceived'), { - timeout: 60000, - timeoutMsg: 'transcriptionChunkReceived event not received on p1 side' - })); - - allTranscripts.push(await p2.driver.waitUntil(() => p2.getIframeAPI() - .getEventResult('transcriptionChunkReceived'), { - timeout: 60000, - timeoutMsg: 'transcriptionChunkReceived event not received on p2 side' - })); - - // TRANSCRIPTION_CHUNK_RECEIVED webhook - allTranscripts.push((async () => { - const event: { - data: { - final: string; - language: string; - messageID: string; - participant: { - id: string; - name: string; - }; - stable: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('TRANSCRIPTION_CHUNK_RECEIVED'); - - expect('TRANSCRIPTION_CHUNK_RECEIVED').toBe(event.eventType); - - event.data.stable = event.data.final; - - return event; - })()); - - const result = await Promise.allSettled(allTranscripts); - - expect(result.length).toBeGreaterThan(0); - - // @ts-ignore - const firstEntryData = result[0].value.data; - const stable = firstEntryData.stable || firstEntryData.final; - const language = firstEntryData.language; - const messageID = firstEntryData.messageID; - const p1Id = await p1.getEndpointId(); - - result.map(r => { - // @ts-ignore - const v = r.value; - - expect(v).toBeDefined(); - - return v.data; - }).forEach(tr => { - const checkTranscripts = stable.includes(tr.stable || tr.final) || (tr.stable || tr.final).includes(stable); - - if (!checkTranscripts) { - console.log('received events', JSON.stringify(result)); - } - - expect(checkTranscripts).toBe(true); - expect(tr.language).toBe(language); - expect(tr.messageID).toBe(messageID); - expect(tr.participant.id).toBe(p1Id); - expect(tr.participant.name).toBe(p1.name); - }); -} diff --git a/tests/specs/jaas/visitors/participantsSoftLimit.spec.ts b/tests/specs/jaas/visitors/participantsSoftLimit.spec.ts deleted file mode 100644 index 775643177e..0000000000 --- a/tests/specs/jaas/visitors/participantsSoftLimit.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { setTestProperties } from '../../../helpers/TestProperties'; -import { joinJaasMuc, generateJaasToken as t } from '../../../helpers/jaas'; - -setTestProperties(__filename, { - useJaas: true, - useWebhookProxy: true, - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Visitors triggered by reaching participantsSoftLimit', () => { - it('test participantsSoftLimit', async () => { - ctx.webhooksProxy.defaultMeetingSettings = { - participantsSoftLimit: 2, - visitorsEnabled: true - }; - - /// XXX the "name" of the participant MUST match one of the "capabilities" defined in wdio. It's not a "participant", it's an instance configuration! - const m = await joinJaasMuc({ - token: t({ room: ctx.roomName, displayName: 'Mo de Rator', moderator: true }) - }); - - expect(await m.isInMuc()).toBe(true); - expect(await m.isModerator()).toBe(true); - expect(await m.isVisitor()).toBe(false); - console.log('Moderator joined'); - - // Joining with a participant token before participantSoftLimit has been reached - const p = await joinJaasMuc({ - name: 'p2', - token: t({ room: ctx.roomName, displayName: 'Parti Cipant' }) - }); - - expect(await p.isInMuc()).toBe(true); - expect(await p.isModerator()).toBe(false); - expect(await p.isVisitor()).toBe(false); - console.log('Participant joined'); - - // Joining with a participant token after participantSoftLimit has been reached - const v = await joinJaasMuc({ - name: 'p3', - token: t({ room: ctx.roomName, displayName: 'Visi Tor' }) - }); - - expect(await v.isInMuc()).toBe(true); - expect(await v.isModerator()).toBe(false); - expect(await v.isVisitor()).toBe(true); - console.log('Visitor joined'); - }); -}); diff --git a/tests/specs/jaas/visitors/videoWithSingleSender.spec.ts b/tests/specs/jaas/visitors/videoWithSingleSender.spec.ts deleted file mode 100644 index c50ff7e369..0000000000 --- a/tests/specs/jaas/visitors/videoWithSingleSender.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { setTestProperties } from '../../../helpers/TestProperties'; -import { joinJaasMuc, generateJaasToken as t } from '../../../helpers/jaas'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true, - usesBrowsers: [ 'p1', 'p2', 'p3', 'p4' ] -}); - -/** - * This is a case which fails if jitsi-videobridge doesn't properly forward PLIs from visitors. - */ -describe('Visitor receiving video from a single remote participant', () => { - it('joining the meeting', async () => { - ctx.webhooksProxy.defaultMeetingSettings = { - visitorsEnabled: true, - visitorsLive: true, - }; - - // Force a connection via JVB. - const configOverwrite = { - p2p: { - enabled: false - } - }; - const sender = await joinJaasMuc({ - token: t({ room: ctx.roomName, displayName: 'Sender', moderator: true }) - }, { - configOverwrite - }); - const senderEndpointId = await sender.getEndpointId(); - - const testVisitor = async function(instanceId: 'p1' | 'p2' | 'p3' | 'p4') { - const visitor = await joinJaasMuc({ - name: instanceId, - token: t({ room: ctx.roomName, displayName: 'Visitor', visitor: true }) - }, { - configOverwrite - }); - - await visitor.waitForIceConnected(); - - const iceConnected = performance.now(); - - await visitor.driver.waitUntil( - () => visitor.isRemoteVideoReceivedAndDisplayed(senderEndpointId), { - timeout: 10_000, - timeoutMsg: `Visitor (${instanceId}) is not receiving video from the sender` - }); - - const duration = performance.now() - iceConnected; - - console.log(`Video displayed after ${duration} ms after ICE connected (${instanceId})`); - }; - - await testVisitor('p2'); - await testVisitor('p3'); - await testVisitor('p4'); - }); -}); diff --git a/tests/specs/jaas/visitors/visitorTokens.spec.ts b/tests/specs/jaas/visitors/visitorTokens.spec.ts deleted file mode 100644 index db549d5fb5..0000000000 --- a/tests/specs/jaas/visitors/visitorTokens.spec.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { Participant } from '../../../helpers/Participant'; -import { setTestProperties } from '../../../helpers/TestProperties'; -import { config as testsConfig } from '../../../helpers/TestsConfig'; -import WebhookProxy from '../../../helpers/WebhookProxy'; -import { joinJaasMuc, generateJaasToken as t } from '../../../helpers/jaas'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true, - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Visitors triggered by visitor tokens', () => { - let webhooksProxy: WebhookProxy; - let room: string; - - async function verifyJoinedWebhook(participant: Participant) { - const context = participant.getToken()?.payload.context; - const event: { - customerId: string; - data: { - avatar: string; - email: string; - group: string; - id: string; - name: string; - participantJid: string; - role: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('PARTICIPANT_JOINED'); - - expect('PARTICIPANT_JOINED').toBe(event.eventType); - expect(event.data.avatar).toBe(context.user.avatar); - expect(event.data.email).toBe(context.user.email); - expect(event.data.id).toBe(context.user.id); - expect(event.data.group).toBe(context.group); - expect(event.data.name).toBe(context.user.name); - if (context.user.visitor) { - expect(event.data.participantJid.indexOf('meet.jitsi') != -1).toBe(true); - expect(event.data.role).toBe('visitor'); - } - expect(event.customerId).toBe(testsConfig.jaas.customerId); - } - - async function verifyLeftWebhook(participant: Participant) { - const context = participant.getToken()?.payload.context; - const eventLeft: { - customerId: string; - data: { - avatar: string; - email: string; - group: string; - id: string; - name: string; - participantJid: string; - role: string; - }; - eventType: string; - } = await webhooksProxy.waitForEvent('PARTICIPANT_LEFT'); - - expect('PARTICIPANT_LEFT').toBe(eventLeft.eventType); - expect(eventLeft.data.avatar).toBe(context.user.avatar); - expect(eventLeft.data.email).toBe(context.user.email); - expect(eventLeft.data.id).toBe(context.user.id); - expect(eventLeft.data.group).toBe(context.group); - expect(eventLeft.data.name).toBe(context.user.name); - if (context.user.visitor) { - expect(eventLeft.data.participantJid.indexOf('meet.jitsi') != -1).toBe(true); - expect(eventLeft.data.role).toBe('visitor'); - } - expect(eventLeft.customerId).toBe(testsConfig.jaas.customerId); - } - - it('setup', async () => { - webhooksProxy = ctx.webhooksProxy; - webhooksProxy.defaultMeetingSettings = { - visitorsEnabled: true - }; - room = ctx.roomName; - }); - - it('test visitor tokens', async () => { - - webhooksProxy.clearCache(); - const moderatorToken = t({ room, displayName: 'Mo de Rator', moderator: true }); - const moderator = await joinJaasMuc({ name: 'p1', token: moderatorToken }); - - expect(await moderator.isInMuc()).toBe(true); - expect(await moderator.isModerator()).toBe(true); - expect(await moderator.isVisitor()).toBe(false); - await verifyJoinedWebhook(moderator); - - webhooksProxy.clearCache(); - // Joining with a participant token before any visitors - const participantToken = t({ room, displayName: 'Parti Cipant' }); - const participant = await joinJaasMuc({ name: 'p2', token: participantToken }); - - expect(await participant.isInMuc()).toBe(true); - expect(await participant.isModerator()).toBe(false); - expect(await participant.isVisitor()).toBe(false); - await verifyJoinedWebhook(participant); - - webhooksProxy.clearCache(); - // Joining with a visitor token - const visitorToken = t({ room, displayName: 'Visi Tor', visitor: true }); - const visitor = await joinJaasMuc({ name: 'p3', token: visitorToken }); - - expect(await visitor.isInMuc()).toBe(true); - expect(await visitor.isModerator()).toBe(false); - expect(await visitor.isVisitor()).toBe(true); - await verifyJoinedWebhook(visitor); - - webhooksProxy.clearCache(); - await participant.hangup(); - await verifyLeftWebhook(participant); - - webhooksProxy.clearCache(); - // Joining with a participant token after visitors -> visitor - const participantToken2 = t({ room, displayName: 'Visi Tor 2' }); - const visitor2 = await joinJaasMuc({ name: 'p2', token: participantToken2 }); - - expect(await visitor2.isInMuc()).toBe(true); - expect(await visitor2.isModerator()).toBe(false); - expect(await visitor2.isVisitor()).toBe(true); - await verifyJoinedWebhook(visitor2); - - webhooksProxy.clearCache(); - await visitor.hangup(); - await verifyLeftWebhook(visitor); - - webhooksProxy.clearCache(); - await visitor2.hangup(); - await verifyLeftWebhook(visitor2); - - webhooksProxy.clearCache(); - await moderator.hangup(); - await verifyLeftWebhook(moderator); - }); -}); diff --git a/tests/specs/jaas/visitors/visitorsLive.spec.ts b/tests/specs/jaas/visitors/visitorsLive.spec.ts deleted file mode 100644 index a867894a50..0000000000 --- a/tests/specs/jaas/visitors/visitorsLive.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { expect } from '@wdio/globals'; - -import { Participant } from '../../../helpers/Participant'; -import { setTestProperties } from '../../../helpers/TestProperties'; -import { joinJaasMuc, generateJaasToken as t } from '../../../helpers/jaas'; - -setTestProperties(__filename, { - requireWebhookProxy: true, - useJaas: true, - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Visitors live', () => { - let visitor: Participant, moderator: Participant; - - it('setup', async () => { - ctx.webhooksProxy.defaultMeetingSettings = { - visitorsEnabled: true, - visitorsLive: false - }; - - moderator = await joinJaasMuc({ - name: 'p1', - token: t({ room: ctx.roomName, displayName: 'Mo de Rator', moderator: true }) - }); - - // TODO: Remove this in favor of configurable test expectations - await moderator.driver.waitUntil(() => moderator.execute(() => APP.conference._room.isVisitorsSupported()), { - timeout: 2000 - }).catch(e => { - ctx.skipSuiteTests = `Because isVisitorsSupported() returned an error: ${e}.`; - }); - - visitor = await joinJaasMuc({ - name: 'p2', - token: t({ room: ctx.roomName, displayName: 'Visi Tor', visitor: true }) - }, { - skipWaitToJoin: true - }); - }); - - - it('go live', async () => { - - const vVisitors = visitor.getVisitors(); - const mVisitors = moderator.getVisitors(); - - await visitor.driver.waitUntil(async () => vVisitors.isVisitorsQueueUIShown(), { - timeout: 5000, - timeoutMsg: 'Missing visitors queue UI' - }); - - await moderator.driver.waitUntil(async () => await mVisitors.getWaitingVisitorsInQueue() - === 'Viewers waiting in queue: 1', { - timeout: 15000, - timeoutMsg: 'Missing visitors queue count in UI' - }); - - await mVisitors.goLive(); - - await visitor.waitToJoinMUC(); - await visitor.waitForReceiveMedia(15000, 'Visitor is not receiving media'); - await visitor.waitForRemoteStreams(1); - - await visitor.driver.waitUntil(() => vVisitors.hasVisitorsDialog(), { - timeout: 5000, - timeoutMsg: 'Missing visitors dialog' - }); - - expect((await mVisitors.getVisitorsCount()).trim()).toBe('1'); - expect((await mVisitors.getVisitorsHeaderFromParticipantsPane()).trim()).toBe('Viewers 1'); - }); -}); diff --git a/tests/specs/media/activeSpeaker.spec.ts b/tests/specs/media/activeSpeaker.spec.ts deleted file mode 100644 index 8a59fe2cb2..0000000000 --- a/tests/specs/media/activeSpeaker.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureThreeParticipants } from '../../helpers/participants'; -import { muteAudioAndCheck } from '../helpers/mute'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Active speaker', () => { - it('testActiveSpeaker', async () => { - await ensureThreeParticipants(); - - const { p1, p2, p3 } = ctx; - - await muteAudioAndCheck(p1, p2); - await muteAudioAndCheck(p2, p1); - await muteAudioAndCheck(p3, p1); - - // participant1 becomes active speaker - check from participant2's perspective - await testActiveSpeaker(p1, p2, p3); - - // participant3 becomes active speaker - check from participant2's perspective - await testActiveSpeaker(p3, p2, p1); - - // participant2 becomes active speaker - check from participant1's perspective - await testActiveSpeaker(p2, p1, p3); - - // check the displayed speakers, there should be only one speaker - await assertOneDominantSpeaker(p1); - await assertOneDominantSpeaker(p2); - await assertOneDominantSpeaker(p3); - }); -}); - -/** - * Tries to make given participant an active speaker by unmuting it. - * Verifies from {@code participant2}'s perspective that the active speaker - * has been displayed on the large video area. Mutes him back. - * - * @param {Participant} activeSpeaker - Participant instance of the participant who will be tested as an - * active speaker. - * @param {Participant} otherParticipant1 - Participant of the participant who will be observing and verifying - * active speaker change. - * @param {Participant} otherParticipant2 - Used only to print some debugging info. - */ -async function testActiveSpeaker( - activeSpeaker: Participant, otherParticipant1: Participant, otherParticipant2: Participant) { - await activeSpeaker.log(`Start testActiveSpeaker for participant: ${activeSpeaker.name}`); - - const speakerEndpoint = await activeSpeaker.getEndpointId(); - - // just a debug print to go in logs - await activeSpeaker.log('Unmuting in testActiveSpeaker'); - - // Unmute - await activeSpeaker.getToolbar().clickAudioUnmuteButton(); - - // just a debug print to go in logs - await otherParticipant1.log(`Participant unmuted in testActiveSpeaker ${speakerEndpoint}`); - await otherParticipant2.log(`Participant unmuted in testActiveSpeaker ${speakerEndpoint}`); - - await activeSpeaker.getFilmstrip().assertAudioMuteIconIsDisplayed(activeSpeaker, true); - - // Verify that the user is now an active speaker from otherParticipant1's perspective - const otherParticipant1Driver = otherParticipant1.driver; - - await otherParticipant1Driver.waitUntil( - async () => await otherParticipant1.getLargeVideo().getResource() === speakerEndpoint, - { - timeout: 30_000, // 30 seconds - timeoutMsg: 'Active speaker not displayed on large video.' - }); - - // just a debug print to go in logs - await activeSpeaker.log('Muting in testActiveSpeaker'); - - // Mute back again - await activeSpeaker.getToolbar().clickAudioMuteButton(); - - // just a debug print to go in logs - await otherParticipant1.log(`Participant muted in testActiveSpeaker ${speakerEndpoint}`); - await otherParticipant2.log(`Participant muted in testActiveSpeaker ${speakerEndpoint}`); - - await otherParticipant1.getFilmstrip().assertAudioMuteIconIsDisplayed(activeSpeaker); -} - -/** - * Asserts that the number of small videos with the dominant speaker - * indicator displayed equals 1. - * - * @param {Participant} participant - The participant to check. - */ -async function assertOneDominantSpeaker(participant: Participant) { - expect(await participant.driver.$$( - '//span[not(contains(@class, "tile-view"))]//span[contains(@class,"dominant-speaker")]').length).toBe(1); -} diff --git a/tests/specs/media/audioOnly.spec.ts b/tests/specs/media/audioOnly.spec.ts deleted file mode 100644 index caa58e83ed..0000000000 --- a/tests/specs/media/audioOnly.spec.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Audio-only mode', () => { - it('joining the meeting', () => ensureTwoParticipants()); - - /** - * Enables audio only mode for p1 and verifies that the other participant sees participant1 as video muted. - */ - it('set and check', () => setAudioOnlyAndCheck(true)); - - /** - * Verifies that participant1 sees avatars for itself and other participants. - */ - it('avatars check', async () => { - const { p1 } = ctx; - - await p1.driver.$('//div[@id="dominantSpeaker"]').waitForDisplayed(); - - // Makes sure that the avatar is displayed in the local thumbnail and that the video is not displayed. - await p1.assertThumbnailShowsAvatar(p1); - }); - - /** - * Disables audio only mode and verifies that both participants see p1 as not video muted. - */ - it('disable and check', () => setAudioOnlyAndCheck(false)); - - /** - * Mutes video on participant1, toggles audio-only twice and then verifies if both participants see participant1 - * as video muted. - */ - it('mute video, set twice and check muted', async () => { - const { p1 } = ctx; - - // Mute video on participant1. - await p1.getToolbar().clickVideoMuteButton(); - - await verifyVideoMute(true); - - // Enable audio-only mode. - await setAudioOnlyAndCheck(true); - - // Disable audio-only mode. - await p1.getVideoQualityDialog().setVideoQuality(false); - - // p1 should stay muted since it was muted before audio-only was enabled. - await verifyVideoMute(true); - }); - - it('unmute video and check not muted', async () => { - // Unmute video on participant1. - await ctx.p1.getToolbar().clickVideoUnmuteButton(); - - await verifyVideoMute(false); - }); -}); - -/** - * Toggles the audio only state of a p1 participant and verifies participant sees the audio only label and that - * p2 participant sees a video mute state for the former. - * @param enable - */ -async function setAudioOnlyAndCheck(enable: boolean) { - const { p1 } = ctx; - - await p1.getVideoQualityDialog().setVideoQuality(enable); - - await verifyVideoMute(enable); - - await p1.driver.$('//div[@id="videoResolutionLabel"][contains(@class, "audio-only")]') - .waitForDisplayed({ reverse: !enable }); -} - -/** - * Verifies that p1 and p2 see p1 as video muted or not. - * @param muted - */ -async function verifyVideoMute(muted: boolean) { - const { p1, p2 } = ctx; - - // Verify the observer sees the testee in the desired muted state. - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1, !muted); - - // Verify the testee sees itself in the desired muted state. - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1, !muted); -} diff --git a/tests/specs/media/audioVideoModeration.spec.ts b/tests/specs/media/audioVideoModeration.spec.ts deleted file mode 100644 index 85aae63263..0000000000 --- a/tests/specs/media/audioVideoModeration.spec.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { expectations } from '../../helpers/expectations'; -import { - ensureOneParticipant, - ensureThreeParticipants, ensureTwoParticipants, - hangupAllParticipants -} from '../../helpers/participants'; -import { unmuteAudioAndCheck, unmuteVideoAndCheck } from '../helpers/mute'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Audio/video moderation', () => { - - it('setup', async () => { - await ensureThreeParticipants(); - - const { p1, p2, p3 } = ctx; - - // if all 3 participants are moderators, skip this test - if (!await p1.isModerator() - || (await p1.isModerator() && await p2.isModerator() && await p3.isModerator())) { - ctx.skipSuiteTests = `Unsupported moderator configuration: p1=${await p1.isModerator()},\ - p2=${await p2.isModerator()}, p3=${await p3.isModerator()}`; - } - }); - - it('check audio enable/disable', async () => { - const { p1, p3 } = ctx; - const p1ParticipantsPane = p1.getParticipantsPane(); - - await p1ParticipantsPane.clickContextMenuButton(); - await p1ParticipantsPane.getAVModerationMenu().clickStartAudioModeration(); - - await p1ParticipantsPane.close(); - - // Here we want to try unmuting and check that we are still muted. - await tryToAudioUnmuteAndCheck(p3, p1); - - await p1ParticipantsPane.clickContextMenuButton(); - await p1ParticipantsPane.getAVModerationMenu().clickStopAudioModeration(); - - await p1ParticipantsPane.close(); - - await unmuteAudioAndCheck(p3, p1); - }); - - it('check video enable/disable', async () => { - const { p1, p3 } = ctx; - const p1ParticipantsPane = p1.getParticipantsPane(); - - await p1ParticipantsPane.clickContextMenuButton(); - await p1ParticipantsPane.getAVModerationMenu().clickStartVideoModeration(); - - await p1ParticipantsPane.close(); - - // Here we want to try unmuting and check that we are still muted. - await tryToVideoUnmuteAndCheck(p3, p1); - - await p1ParticipantsPane.clickContextMenuButton(); - await p1ParticipantsPane.getAVModerationMenu().clickStopVideoModeration(); - - await p1ParticipantsPane.close(); - - await unmuteVideoAndCheck(p3, p1); - }); - - it('unmute by moderator', async () => { - const { p1, p2, p3 } = ctx; - - await unmuteByModerator(p1, p3, true, true); - - // moderation is stopped at this point, make sure participants 1 & 2 are also unmuted, - // participant3 was unmuted by unmuteByModerator - await unmuteAudioAndCheck(p2, p1); - await unmuteVideoAndCheck(p2, p1); - - // make sure p1 is not muted after turning on and then off the AV moderation - await p1.getFilmstrip().assertAudioMuteIconIsDisplayed(p1, true); - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p2, true); - }); - - it('hangup and change moderator', async () => { - // The test below is only correct when the environment is configured to automatically elect a new moderator - // when the moderator leaves. For environments where this is not the case, the test is skipped. - if (!expectations.autoModerator) { - return; - } - - await Promise.all([ ctx.p2.hangup(), ctx.p3.hangup() ]); - - await ensureThreeParticipants(); - const { p1, p2, p3 } = ctx; - - await p2.getToolbar().clickAudioMuteButton(); - await p3.getToolbar().clickAudioMuteButton(); - - const p1ParticipantsPane = p1.getParticipantsPane(); - - await p1ParticipantsPane.clickContextMenuButton(); - await p1ParticipantsPane.getAVModerationMenu().clickStartAudioModeration(); - await p1ParticipantsPane.getAVModerationMenu().clickStartVideoModeration(); - - await p2.getToolbar().clickRaiseHandButton(); - await p3.getToolbar().clickRaiseHandButton(); - - await p1.hangup(); - - // we don't use ensureThreeParticipants to avoid all meeting join checks - // all participants are muted and checks for media will fail - await ensureOneParticipant(); - - // After p1 re-joins either p2 or p3 is promoted to moderator. They should still be muted. - const isP2Moderator = await p2.isModerator(); - const moderator = isP2Moderator ? p2 : p3; - const nonModerator = isP2Moderator ? p3 : p2; - const moderatorParticipantsPane = moderator.getParticipantsPane(); - const nonModeratorParticipantsPane = nonModerator.getParticipantsPane(); - - await moderatorParticipantsPane.assertVideoMuteIconIsDisplayed(moderator); - await nonModeratorParticipantsPane.assertVideoMuteIconIsDisplayed(nonModerator); - - await moderatorParticipantsPane.allowVideo(nonModerator); - await moderatorParticipantsPane.askToUnmute(nonModerator, false); - - await nonModerator.getNotifications().waitForAskToUnmuteNotification(); - - await unmuteAudioAndCheck(nonModerator, p1); - await unmuteVideoAndCheck(nonModerator, p1); - - await moderatorParticipantsPane.clickContextMenuButton(); - await moderatorParticipantsPane.getAVModerationMenu().clickStopAudioModeration(); - await moderatorParticipantsPane.getAVModerationMenu().clickStopVideoModeration(); - }); - it('grant moderator', async () => { - await hangupAllParticipants(); - - await ensureThreeParticipants(); - - const { p1, p2, p3 } = ctx; - - const p1ParticipantsPane = p1.getParticipantsPane(); - - await p1ParticipantsPane.clickContextMenuButton(); - await p1ParticipantsPane.getAVModerationMenu().clickStartAudioModeration(); - await p1ParticipantsPane.getAVModerationMenu().clickStartVideoModeration(); - - await p1.getFilmstrip().grantModerator(p3); - - await p3.driver.waitUntil( - () => p3.isModerator(), { - timeout: 5000, - timeoutMsg: `${p3.name} is not moderator` - }); - - await unmuteByModerator(p3, p2, false, true); - }); - it('ask to unmute', async () => { - await hangupAllParticipants(); - - await ensureTwoParticipants(); - - const { p1, p2 } = ctx; - - // mute p2 - await p2.getToolbar().clickAudioMuteButton(); - - // ask p2 to unmute - await p1.getParticipantsPane().askToUnmute(p2, true); - - await p2.getNotifications().waitForAskToUnmuteNotification(); - - await p1.getParticipantsPane().close(); - }); - it('remove from whitelist', async () => { - const { p1, p2 } = ctx; - - await unmuteByModerator(p1, p2, true, false); - - // p1 mute audio on p2 and check - await p1.getFilmstrip().muteAudio(p2); - await p1.getFilmstrip().assertAudioMuteIconIsDisplayed(p2); - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p2); - - // we try to unmute and test it that it was still muted - await tryToAudioUnmuteAndCheck(p2, p1); - - // stop video and check - await p1.getFilmstrip().muteVideo(p2); - - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2); - - await tryToVideoUnmuteAndCheck(p2, p1); - }); - it('join moderated', async () => { - await hangupAllParticipants(); - - await ensureOneParticipant(); - - const p1ParticipantsPane = ctx.p1.getParticipantsPane(); - - await p1ParticipantsPane.clickContextMenuButton(); - await p1ParticipantsPane.getAVModerationMenu().clickStartAudioModeration(); - await p1ParticipantsPane.getAVModerationMenu().clickStartVideoModeration(); - await p1ParticipantsPane.close(); - - // join with second participant and check - await ensureTwoParticipants({ - skipInMeetingChecks: true - }); - const { p1, p2 } = ctx; - - await p2.getNotifications().closeYouAreMutedNotification(); - await tryToAudioUnmuteAndCheck(p2, p1); - await tryToVideoUnmuteAndCheck(p2, p1); - - // asked to unmute and check - await unmuteByModerator(p1, p2, false, false); - - // mute and check - await p1.getFilmstrip().muteAudio(p2); - await p1.getFilmstrip().assertAudioMuteIconIsDisplayed(p2); - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p2); - - await tryToAudioUnmuteAndCheck(p2, p1); - }); -}); - -/** - * Checks a user can unmute after being asked by moderator. - * @param moderator - The participant that is moderator. - * @param participant - The participant being asked to unmute. - * @param turnOnModeration - if we want to turn on moderation before testing (when it is currently off). - * @param stopModeration - true if moderation to be stopped when done. - */ -async function unmuteByModerator( - moderator: Participant, - participant: Participant, - turnOnModeration: boolean, - stopModeration: boolean) { - const moderatorParticipantsPane = moderator.getParticipantsPane(); - - if (turnOnModeration) { - await moderatorParticipantsPane.clickContextMenuButton(); - await moderatorParticipantsPane.getAVModerationMenu().clickStartAudioModeration(); - await moderatorParticipantsPane.getAVModerationMenu().clickStartVideoModeration(); - - await moderatorParticipantsPane.close(); - } - - // raise hand to speak - await participant.getToolbar().clickRaiseHandButton(); - await moderator.getNotifications().waitForRaisedHandNotification(); - - // ask participant to unmute - await moderatorParticipantsPane.allowVideo(participant); - await moderatorParticipantsPane.askToUnmute(participant, false); - await participant.getNotifications().waitForAskToUnmuteNotification(); - - await unmuteAudioAndCheck(participant, moderator); - await unmuteVideoAndCheck(participant, moderator); - - if (stopModeration) { - await moderatorParticipantsPane.clickContextMenuButton(); - await moderatorParticipantsPane.getAVModerationMenu().clickStopAudioModeration(); - await moderatorParticipantsPane.getAVModerationMenu().clickStopVideoModeration(); - - await moderatorParticipantsPane.close(); - } -} - -/** - * In case of moderation, tries to audio unmute but stays muted. - * Checks locally and remotely that this is still the case. - * @param participant - * @param observer - */ -async function tryToAudioUnmuteAndCheck(participant: Participant, observer: Participant) { - // try to audio unmute and check - await participant.getToolbar().clickAudioUnmuteButton(); - - // Check local audio muted icon state - await participant.getFilmstrip().assertAudioMuteIconIsDisplayed(participant); - await observer.getFilmstrip().assertAudioMuteIconIsDisplayed(participant); -} - -/** - * In case of moderation, tries to video unmute but stays muted. - * Checks locally and remotely that this is still the case. - * @param participant - * @param observer - */ -async function tryToVideoUnmuteAndCheck(participant: Participant, observer: Participant) { - // try to video unmute and check - await participant.getToolbar().clickVideoUnmuteButton(); - - // Check local audio muted icon state - await participant.getParticipantsPane().assertVideoMuteIconIsDisplayed(participant); - await observer.getParticipantsPane().assertVideoMuteIconIsDisplayed(participant); -} diff --git a/tests/specs/media/codecSelection.spec.ts b/tests/specs/media/codecSelection.spec.ts deleted file mode 100644 index 0b890abdce..0000000000 --- a/tests/specs/media/codecSelection.spec.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { VIDEO_CODEC } from '../../../react/features/video-quality/constants'; -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { - ensureOneParticipant, - ensureThreeParticipants, - ensureTwoParticipants, - hangupAllParticipants -} from '../../helpers/participants'; -const { VP8, VP9, AV1 } = VIDEO_CODEC; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Codec selection', () => { - it('asymmetric codecs', async () => { - await ensureOneParticipant({ - configOverwrite: { - videoQuality: { - codecPreferenceOrder: [ 'VP9', 'VP8', 'AV1' ] - } - } - }); - - await ensureTwoParticipants({ - configOverwrite: { - videoQuality: { - codecPreferenceOrder: [ 'VP8', 'VP9', 'AV1' ] - } - } - }); - const { p1, p2 } = ctx; - - // Check if media is playing on both endpoints. - expect(await p1.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true); - expect(await p2.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true); - - // Check if p1 is sending VP9 and p2 is sending VP8 as per their codec preferences. - // Except on Firefox because it doesn't support VP9 encode. - const p1ExpectedCodec = p1.driver.isFirefox ? VP8 : VP9; - - await Promise.all([ - waitForCodec(p1, p1ExpectedCodec), - waitForCodec(p2, VP8) - ]); - }); - - it('asymmetric codecs with AV1', async () => { - await ensureThreeParticipants({ - configOverwrite: { - videoQuality: { - codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8' ] - } - } - }); - const { p1, p2, p3 } = ctx; - - // Check if media is playing on p3. - expect(await p3.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true); - - const majorVersion = parseInt(p1.driver.capabilities.browserVersion || '0', 10); - - // Check if p1 is encoding in VP9, p2 in VP8 and p3 in AV1 as per their codec preferences. - // Except on Firefox because it doesn't support VP9 encode. - const p1ExpectedCodec = p1.driver.isFirefox ? VP8 : VP9; - const p3ExpectedCodec = (p1.driver.isFirefox && majorVersion < 136) ? VP9 : AV1; - - await Promise.all([ - waitForCodec(p1, p1ExpectedCodec), - waitForCodec(p2, VP8), - waitForCodec(p3, p3ExpectedCodec) - ]); - }); - - it('codec switch over', async () => { - await hangupAllParticipants(); - - await ensureTwoParticipants({ - configOverwrite: { - videoQuality: { - codecPreferenceOrder: [ 'VP9', 'VP8', 'AV1' ] - } - } - }); - const { p1, p2 } = ctx; - - // Disable this test on Firefox because it doesn't support VP9 encode. - if (p1.driver.isFirefox) { - return; - } - - // Check if p1 and p2 are encoding in VP9 which is the default codec. - await Promise.all([ - waitForCodec(p1, VP9), - waitForCodec(p2, VP9) - ]); - - await ensureThreeParticipants({ - configOverwrite: { - videoQuality: { - codecPreferenceOrder: [ 'VP8' ] - } - } - }); - const { p3 } = ctx; - - await Promise.all([ - waitForCodec(p1, VP8), - waitForCodec(p2, VP8), - waitForCodec(p3, VP8) - ]); - - await p3.hangup(); - - // Check of p1 and p2 have switched to VP9. - await Promise.all([ - waitForCodec(p1, VP9), - waitForCodec(p2, VP9) - ]); - }); -}); - -async function waitForCodec(p: Participant, codec: string) { - await p.driver.waitUntil( - () => p.execute(c => JitsiMeetJS.app.testing.getLocalCameraEncoding() === c, codec), - { - timeout: 10000, - timeoutMsg: `${p.name} failed to use VP8` - } - ); -} diff --git a/tests/specs/media/desktopSharing.spec.ts b/tests/specs/media/desktopSharing.spec.ts deleted file mode 100644 index a879882071..0000000000 --- a/tests/specs/media/desktopSharing.spec.ts +++ /dev/null @@ -1,386 +0,0 @@ -import { SET_AUDIO_ONLY } from '../../../react/features/base/audio-only/actionTypes'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { - checkForScreensharingTile, - ensureFourParticipants, - ensureOneParticipant, - ensureThreeParticipants, - ensureTwoParticipants, - hangupAllParticipants -} from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3', 'p4' ] -}); - -describe('Desktop sharing', () => { - it('start', async () => { - await ensureTwoParticipants({ - configOverwrite: { - p2p: { - backToP2PDelay: 3, - enabled: true - } - } - }); - const { p1, p2 } = ctx; - - await p1.waitForP2PIceConnected(); - await p2.getToolbar().clickDesktopSharingButton(); - - // Check if a remote screen share tile is created on p1. - await checkForScreensharingTile(p2, p1); - - // Check if a local screen share tile is created on p2. - await checkForScreensharingTile(p2, p2); - - expect(await p2.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true); - }); - - it('stop', async () => { - const { p1, p2 } = ctx; - - await p2.getToolbar().clickStopDesktopSharingButton(); - - // Check if the local screen share thumbnail disappears on p2. - await checkForScreensharingTile(p2, p2, true); - - // Check if the remote screen share thumbnail disappears on p1. - await checkForScreensharingTile(p1, p2, true); - }); - - /** - * Ensures screen share is still visible when the call switches from p2p to jvb connection. - */ - it('p2p to jvb switch', async () => { - await ctx.p2.getToolbar().clickDesktopSharingButton(); - - await ensureThreeParticipants({ - configOverwrite: { - p2p: { - enabled: true - } - } - }); - const { p1, p2, p3 } = ctx; - const p2EndpointId = await p2.getEndpointId(); - - // Check if a remote screen share tile is created on all participants. - await checkForScreensharingTile(p2, p1); - await checkForScreensharingTile(p2, p2); - await checkForScreensharingTile(p2, p3); - - await p1.getFilmstrip().assertNoGapsInFilmstrip(); - await p3.getFilmstrip().assertNoGapsInFilmstrip(); - await p3.waitForParticipantOnLargeVideo(`${p2EndpointId}-v1`); - }); - - /** - * Ensure screen share is still visible when the call switches from jvb to p2p and back. - */ - it('p2p to jvb switch and back', async () => { - const { p1, p2, p3 } = ctx; - - await p3.hangup(); - - // Wait for p1 and p2 to switch back to p2p. - await p1.waitForP2PIceConnected(); - await p2.waitForP2PIceConnected(); - - // Check if a remote screen share tile is created on p1 and p2 after switching back to p2p. - await checkForScreensharingTile(p2, p1); - await checkForScreensharingTile(p2, p2); - - // The video should be playing. - await p1.waitForParticipantOnLargeVideo(`${await p2.getEndpointId()}-v1`); - - // Start desktop share on p1. - await p1.getToolbar().clickDesktopSharingButton(); - - // Check if a new tile for p1's screen share is created on both p1 and p2. - await checkForScreensharingTile(p1, p1); - await checkForScreensharingTile(p1, p2); - - await ensureThreeParticipants({ - configOverwrite: { - p2p: { - backToP2PDelay: 3, - enabled: true - } - } - }); - - await checkForScreensharingTile(p1, p3); - await checkForScreensharingTile(p2, p3); - }); - - /** - * Ensure that screen share is still visible in jvb connection when share is toggled while the users are - * in p2p mode, i.e., share is restarted when user is in p2p mode and then the call switches over to jvb mode. - */ - it('stop screen sharing and back', async () => { - const { p1, p2, p3 } = ctx; - - // Stop share on both p1 and p2. - await p1.getToolbar().clickStopDesktopSharingButton(); - await p2.getToolbar().clickStopDesktopSharingButton(); - - await p3.hangup(); - - // Wait for p1 and p2 to switch back to p2p. - await p1.waitForP2PIceConnected(); - await p2.waitForP2PIceConnected(); - - // Start share on both p1 and p2. - await p1.getToolbar().clickDesktopSharingButton(); - await p2.getToolbar().clickDesktopSharingButton(); - - // Check if p1 and p2 can see each other's shares in p2p. - await checkForScreensharingTile(p1, p2); - await checkForScreensharingTile(p2, p1); - - // Add p3 back to the conference and check if p1 and p2's shares are visible on p3. - await ensureThreeParticipants({ - configOverwrite: { - p2p: { - backToP2PDelay: 3, - enabled: true - } - } - }); - - await checkForScreensharingTile(p1, p3); - await checkForScreensharingTile(p2, p3); - - // Add another particpant to verify multiple screenshares are visible without gaps in filmstrip. - await ensureFourParticipants({ - configOverwrite: { - filmstrip: { - stageFilmstripParticipants: 2 - }, - startWithAudioMuted: true - } - }); - - const { p4 } = ctx; - - await checkForScreensharingTile(p1, p4); - await checkForScreensharingTile(p2, p4); - await p3.getFilmstrip().assertNoGapsInFilmstrip(); - await p4.getFilmstrip().assertNoGapsInFilmstrip(); - }); - - /** - * Ensures screen share is visible when a muted screen share track is added to the conference, i.e., - * users starts and stops the share before anyone else joins the call. - * The call switches to jvb and then back to p2p. - */ - it('screen sharing toggle before others join', async () => { - await hangupAllParticipants(); - - await ensureOneParticipant({ - configOverwrite: { - p2p: { - backToP2PDelay: 3, - enabled: true - } - } - }); - const { p1 } = ctx; - - // p1 starts share when alone in the call. - await p1.getToolbar().clickDesktopSharingButton(); - await checkForScreensharingTile(p1, p1); - - // p1 stops share. - await p1.getToolbar().clickStopDesktopSharingButton(); - - // Call switches to jvb. - await ensureThreeParticipants({ - configOverwrite: { - p2p: { - backToP2PDelay: 3, - enabled: true - } - } - }); - const { p2, p3 } = ctx; - const p1EndpointId = await p1.getEndpointId(); - const p1ScreenShareTileId = `${p1EndpointId}-v1`; - const p2EndpointId = await p2.getEndpointId(); - const p2ScreenShareTileId = `${p2EndpointId}-v1`; - - // p1 starts share again when call switches to jvb. - await p1.getToolbar().clickDesktopSharingButton(); - - // Check p2 and p3 are able to see p1's share. - await checkForScreensharingTile(p1, p2); - await checkForScreensharingTile(p1, p3); - - await p2.waitForParticipantOnLargeVideo(p1ScreenShareTileId); - await p3.waitForParticipantOnLargeVideo(p1ScreenShareTileId); - - // p3 leaves the call. - await p3.hangup(); - - // Wait for p1 and p2 to switch back to p2p. - await p1.waitForP2PIceConnected(); - await p2.waitForP2PIceConnected(); - - // Make sure p2 see's p1's share after the call switches back to p2p. - await checkForScreensharingTile(p1, p2); - await p2.waitForParticipantOnLargeVideo(p1ScreenShareTileId); - - // p2 starts share when in p2p. - await p2.getToolbar().clickDesktopSharingButton(); - - // Makes sure p2's share is visible on p1. - await checkForScreensharingTile(p2, p1); - await p1.waitForParticipantOnLargeVideo(p2ScreenShareTileId); - }); - - /** - * A case where a non-dominant speaker is sharing screen for a participant in low bandwidth mode - * where only a screen share can be received. A bug fixed in jvb 0c5dd91b where the video was not received. - */ - it('audio only and non dominant screen share', async () => { - await hangupAllParticipants(); - - await ensureOneParticipant(); - const { p1 } = ctx; - - // a workaround to directly set audio only mode without going through the rest of the settings in the UI - await p1.execute(type => { - APP?.store?.dispatch({ - type, - audioOnly: true - }); - APP?.conference?.onToggleAudioOnly(); - }, SET_AUDIO_ONLY); - await p1.getToolbar().clickAudioMuteButton(); - - await ensureThreeParticipants({ - skipInMeetingChecks: true - }); - const { p2, p3 } = ctx; - - await p3.getToolbar().clickAudioMuteButton(); - await p3.getToolbar().clickDesktopSharingButton(); - - await checkForScreensharingTile(p3, p1); - await checkForScreensharingTile(p3, p2); - - // the video should be playing - await p1.driver.waitUntil(() => p1.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived()), { - timeout: 5_000, - timeoutMsg: 'expected remote screen share to be on large' - }); - }); - - /** - * A case where first participant is muted (a&v) and enters low bandwidth mode, - * the second one is audio muted only and the one sharing (the third) is dominant speaker. - * A problem fixed in jitsi-meet 3657c19e and d6ab0a72. - */ - it('audio only and dominant screen share', async () => { - await hangupAllParticipants(); - - await ensureOneParticipant({ - configOverwrite: { - startWithAudioMuted: true, - startWithVideoMuted: true - } - }); - const { p1 } = ctx; - - // a workaround to directly set audio only mode without going through the rest of the settings in the UI - await p1.execute(type => { - APP?.store?.dispatch({ - type, - audioOnly: true - }); - APP?.conference?.onToggleAudioOnly(); - }, SET_AUDIO_ONLY); - - await ensureTwoParticipants({ - configOverwrite: { - startWithAudioMuted: true - }, - skipInMeetingChecks: true - }); - await ensureThreeParticipants({ - skipInMeetingChecks: true - }); - const { p2, p3 } = ctx; - - await p3.getToolbar().clickDesktopSharingButton(); - - await checkForScreensharingTile(p3, p1); - await checkForScreensharingTile(p3, p2); - - // The desktop sharing participant should be on large - expect(await p1.getLargeVideo().getResource()).toBe(`${await p3.getEndpointId()}-v1`); - - // the video should be playing - await p1.driver.waitUntil(() => p1.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived()), { - timeout: 5_000, - timeoutMsg: 'expected remote screen share to be on large' - }); - }); - - /** - * Test screensharing with lastN. We add p4 with lastN=2 and verify that it receives the expected streams. - */ - it('with lastN', async () => { - await hangupAllParticipants(); - - await ensureThreeParticipants(); - const { p1, p2, p3 } = ctx; - - await p3.getToolbar().clickDesktopSharingButton(); - - await p1.getToolbar().clickAudioMuteButton(); - await p3.getToolbar().clickAudioMuteButton(); - - await ensureFourParticipants({ - configOverwrite: { - channelLastN: 2, - startWithAudioMuted: true - } - }); - const { p4 } = ctx; - - // We now have p1, p2, p3, p4. - // p3 is screensharing. - // p1, p3, p4 are audio muted, so p2 should eventually become dominant speaker. - // Participants should display p3 on-stage because it is screensharing. - await checkForScreensharingTile(p3, p1); - await checkForScreensharingTile(p3, p2); - await checkForScreensharingTile(p3, p4); - - // And the video should be playing - expect(await p4.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true); - - // Check that there are no gaps in the filmstrip when participant joins during screensharing - await p1.getFilmstrip().assertNoGapsInFilmstrip(); - await p2.getFilmstrip().assertNoGapsInFilmstrip(); - await p4.getFilmstrip().assertNoGapsInFilmstrip(); - - const p1EndpointId = await p1.getEndpointId(); - const p2EndpointId = await p2.getEndpointId(); - - // p4 has lastN=2 and has selected p3. With p2 being dominant speaker p4 should eventually - // see video for [p3, p2] and p1 as ninja. - await p4.waitForNinjaIcon(p1EndpointId); - await p4.waitForRemoteVideo(p2EndpointId); - - // Let's switch and check, muting participant 2 and unmuting 1 will leave participant 1 as dominant - await p1.getToolbar().clickAudioUnmuteButton(); - await p2.getToolbar().clickAudioMuteButton(); - - // Participant4 should eventually see video for [p3, p1] and p2 as a ninja. - await p4.waitForNinjaIcon(p2EndpointId); - await p4.waitForRemoteVideo(p1EndpointId); - }); -}); - diff --git a/tests/specs/media/lastN.spec.ts b/tests/specs/media/lastN.spec.ts deleted file mode 100644 index c06c291d4d..0000000000 --- a/tests/specs/media/lastN.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureFourParticipants, ensureThreeParticipants, ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3', 'p4' ] -}); - -describe('LastN', () => { - it('joining the meeting', async () => { - await ensureTwoParticipants({ - configOverwrite: { - startWithAudioMuted: true, - startWithVideoMuted: true, - channelLastN: 1 - }, - skipInMeetingChecks: true - }); - - await ensureThreeParticipants({ - configOverwrite: { - channelLastN: 1 - }, - skipInMeetingChecks: true, - }); - }); - - it('checks', async () => { - const { p3 } = ctx; - const p3Toolbar = p3.getToolbar(); - - await p3.waitForSendMedia(); - - await ctx.p1.waitForRemoteVideo(await p3.getEndpointId()); - - // Mute audio on participant3. - await p3Toolbar.clickAudioMuteButton(); - - await ensureFourParticipants({ - configOverwrite: { - channelLastN: 1 - }, - skipInMeetingChecks: true - }); - - const { p1, p2, p4 } = ctx; - - await p4.waitForSendReceiveData(); - - // Mute audio on p4 and unmute p3. - await p4.getToolbar().clickAudioMuteButton(); - await p3Toolbar.clickAudioUnmuteButton(); - - const p4EndpointId = await p4.getEndpointId(); - const p3EndpointId = await p3.getEndpointId(); - - // Check if p1 starts receiving video from p3 and p4 shows up as ninja. - await p1.waitForNinjaIcon(p4EndpointId); - await p1.waitForRemoteVideo(p3EndpointId); - - // At this point, mute video of p3 and others should be receiving p4's video. - // Mute p1's video - await p3Toolbar.clickVideoMuteButton(); - await p3.getParticipantsPane().assertVideoMuteIconIsDisplayed(p3); - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p3); - await p1.waitForRemoteVideo(p4EndpointId); - - // Unmute p3's video and others should switch to receiving p3's video. - await p3Toolbar.clickVideoUnmuteButton(); - await p1.waitForRemoteVideo(p3EndpointId); - await p1.waitForNinjaIcon(p4EndpointId); - - // Mute p3's audio and unmute p2's audio. Other endpoints should continue to receive video from p3 - // even though p2 is the dominant speaker. - await p3Toolbar.clickAudioMuteButton(); - await p2.getToolbar().clickAudioUnmuteButton(); - await p1.waitForRemoteVideo(p3EndpointId); - }); -}); diff --git a/tests/specs/media/mute.spec.ts b/tests/specs/media/mute.spec.ts deleted file mode 100644 index 8d2cb626e2..0000000000 --- a/tests/specs/media/mute.spec.ts +++ /dev/null @@ -1,145 +0,0 @@ -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { - checkForScreensharingTile, - ensureOneParticipant, - ensureTwoParticipants, - joinSecondParticipant, -} from '../../helpers/participants'; -import { - muteAudioAndCheck, - unmuteAudioAndCheck, - unmuteVideoAndCheck -} from '../helpers/mute'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Mute', () => { - it('joining the meeting', () => ensureTwoParticipants()); - - it('mute p1 and check', () => toggleMuteAndCheck(ctx.p1, ctx.p2, true)); - - it('unmute p1 and check', () => toggleMuteAndCheck(ctx.p1, ctx.p2, false)); - - it('mute p2 and check', () => toggleMuteAndCheck(ctx.p2, ctx.p1, true)); - - it('unmute p2 and check', () => toggleMuteAndCheck(ctx.p2, ctx.p1, false)); - - it('p1 mutes p2 and check', async () => { - const { p1, p2 } = ctx; - - if (!await p1.isModerator()) { - return; - } - - await p1.getFilmstrip().muteAudio(p2); - - // and now check whether second participant is muted - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p2); - }); - - it('p2 unmute after p1 mute and check', async () => { - const { p1, p2 } = ctx; - - await unmuteAudioAndCheck(p2, p1); - }); - - it('p1 mutes before p2 joins', async () => { - await ctx.p2.hangup(); - - const { p1 } = ctx; - - await p1.getToolbar().clickAudioMuteButton(); - - await ensureTwoParticipants(); - - const { p2 } = ctx; - - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p1); - - await toggleMuteAndCheck(p1, p2, false); - }); - - it('mute before join and screen share after in p2p', () => muteP1BeforeP2JoinsAndScreenshare(true)); - - it('mute before join and screen share after with jvb', () => muteP1BeforeP2JoinsAndScreenshare(false)); -}); - -/** - * Toggles the mute state of a specific Meet conference participant and - * verifies that a specific other Meet conference participants sees a - * specific mute state for the former. - * @param testee The participant whose mute state is to be toggled. - * @param observer The participant to verify the mute state of {@code testee}. - * @param muted the mute state of {@code testee} expected to be observed by {@code observer}. - */ -async function toggleMuteAndCheck( - testee: Participant, - observer: Participant, - muted: boolean) { - if (muted) { - await muteAudioAndCheck(testee, observer); - } else { - await unmuteAudioAndCheck(testee, observer); - } -} - -/** - * Video mutes participant1 before participant2 joins and checks if participant1 can share or unmute video - * and that media is being received on participant2 in both the cases. - * - * @param p2p whether to enable p2p or not. - */ -async function muteP1BeforeP2JoinsAndScreenshare(p2p: boolean) { - await Promise.all([ ctx.p1?.hangup(), ctx.p2?.hangup() ]); - - await ensureOneParticipant({ - configOverwrite: { - p2p: { - enabled: p2p - } - } - }); - - const { p1 } = ctx; - - await p1.getToolbar().clickVideoMuteButton(); - - await joinSecondParticipant({ - configOverwrite: { - p2p: { - enabled: p2p - } - } - }); - - const { p2 } = ctx; - - if (p2p) { - await p2.waitForP2PIceConnected(); - } else { - await p2.waitForIceConnected(); - } - - await p2.waitForSendMedia(); - - // Check if p1 appears video muted on p2. - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - - // Start desktop share. - await p1.getToolbar().clickDesktopSharingButton(); - - await checkForScreensharingTile(p1, p2); - - // we need to pass the id of the fake participant we use for the screensharing - await p2.waitForRemoteVideo(`${await p1.getEndpointId()}-v1`); - - // Stop desktop share and unmute video and check for video again. - await p1.getToolbar().clickStopDesktopSharingButton(); - - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - await unmuteVideoAndCheck(p1, p2); - await p2.waitForRemoteVideo(await p1.getEndpointId()); -} diff --git a/tests/specs/media/pinning.spec.ts b/tests/specs/media/pinning.spec.ts deleted file mode 100644 index 3d88d68fac..0000000000 --- a/tests/specs/media/pinning.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Pinning', () => { - it('joining the meeting', () => ensureTwoParticipants()); - - it('p1 click on local', () => ctx.p1.getFilmstrip().pinParticipant(ctx.p1)); - - it('p1 click on remote', async () => { - await closeToolbarMenu(); - - const { p1, p2 } = ctx; - - await p1.getFilmstrip().pinParticipant(p2); - }); - - it('p1 unpin remote', () => ctx.p1.getFilmstrip().unpinParticipant(ctx.p2)); - - it('p2 pin remote', () => ctx.p2.getFilmstrip().pinParticipant(ctx.p1)); - - it('p2 unpin remote', () => ctx.p2.getFilmstrip().unpinParticipant(ctx.p1)); - - it('p2 click on local', () => ctx.p2.getFilmstrip().pinParticipant(ctx.p2)); - - it('p2 click on remote', async () => { - await closeToolbarMenu(); - - const { p1, p2 } = ctx; - - await p2.getFilmstrip().pinParticipant(p1); - }); -}); - -/** - * Closes the overflow menu on both participants. - */ -async function closeToolbarMenu() { - await ctx.p1.getToolbar().closeOverflowMenu(); - await ctx.p2.getToolbar().closeOverflowMenu(); -} diff --git a/tests/specs/media/startMuted.spec.ts b/tests/specs/media/startMuted.spec.ts deleted file mode 100644 index b9bf5a8523..0000000000 --- a/tests/specs/media/startMuted.spec.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { - checkForScreensharingTile, - ensureOneParticipant, - ensureTwoParticipants, - hangupAllParticipants, - joinSecondParticipant, - joinThirdParticipant -} from '../../helpers/participants'; -import { unmuteVideoAndCheck } from '../helpers/mute'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Start muted', () => { - it('checkboxes test', async () => { - const options = { - configOverwrite: { - p2p: { - enabled: true - }, - testing: { - testMode: true, - debugAudioLevels: true - } - } }; - - await ensureOneParticipant(options); - - const { p1 } = ctx; - const p1EndpointId = await p1.getEndpointId(); - - await p1.getToolbar().clickSettingsButton(); - - const settingsDialog = p1.getSettingsDialog(); - - await settingsDialog.waitForDisplay(); - - await settingsDialog.setStartAudioMuted(true); - await settingsDialog.setStartVideoMuted(true); - await settingsDialog.submit(); - - // Check that p1 doesn't get muted. - await p1.getFilmstrip().assertAudioMuteIconIsDisplayed(p1, true); - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1, true); - - await joinSecondParticipant(options); - - // Enable screenshare on p1. - p1.getToolbar().clickDesktopSharingButton(); - await checkForScreensharingTile(p1, p1); - - const { p2 } = ctx; - const p2EndpointId = await p2.getEndpointId(); - - await p2.waitForIceConnected(); - await p2.waitForReceiveMedia(); - - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p2); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2); - await p1.waitForAudioMuted(p2, true); - await p1.waitForRemoteVideo(p2EndpointId, true); - - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p1, true); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1, true); - await p2.waitForAudioMuted(p1, false); - await p2.waitForRemoteVideo(p1EndpointId, false); - - // Check if a remote screenshare tile is created on p2. - await checkForScreensharingTile(p1, p2); - - // Enable video on p2 and check if p2 appears unmuted on p1. - await Promise.all([ - p2.getToolbar().clickAudioUnmuteButton(), p2.getToolbar().clickVideoUnmuteButton() - ]); - - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p2, true); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2, true); - - await p1.waitForAudioMuted(p2, false); - await p1.waitForRemoteVideo(p2EndpointId, false); - - // Add a third participant and check p3 is able to receive audio and video from p2. - await joinThirdParticipant(options); - - const { p3 } = ctx; - - await p3.waitForIceConnected(); - await p3.waitForReceiveMedia(); - - await p3.getFilmstrip().assertAudioMuteIconIsDisplayed(p2, true); - await p3.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2, true); - await checkForScreensharingTile(p1, p3); - }); - - it('config options test', async () => { - await hangupAllParticipants(); - - const options = { - configOverwrite: { - testing: { - testMode: true, - debugAudioLevels: true - }, - startAudioMuted: 2, - startVideoMuted: 2 - } - }; - - await ensureOneParticipant(options); - await joinSecondParticipant(options); - - const { p2 } = ctx; - - await p2.waitForIceConnected(); - await p2.waitForReceiveMedia(); - - await joinThirdParticipant(options); - - const { p3 } = ctx; - - await p3.waitForIceConnected(); - await p3.waitForReceiveMedia(); - - const { p1 } = ctx; - - const p2ID = await p2.getEndpointId(); - - await p1.log(`Start configOptionsTest, second participant: ${p2ID}`); - - // Participant 3 should be muted, 1 and 2 unmuted. - await p3.getFilmstrip().assertAudioMuteIconIsDisplayed(p3); - await p3.getParticipantsPane().assertVideoMuteIconIsDisplayed(p3); - - await Promise.all([ - p1.waitForAudioMuted(p3, true), - p2.waitForAudioMuted(p3, true) - ]); - - await p3.getFilmstrip().assertAudioMuteIconIsDisplayed(p1, true); - await p3.getFilmstrip().assertAudioMuteIconIsDisplayed(p2, true); - await p3.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1, true); - await p3.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2, true); - - // Unmute and see if the audio works - // we need 1 and 2 to be muted so we have a dominant speaker event for correct audio levels calculations - await p1.getToolbar().clickAudioMuteButton(); - await p2.getToolbar().clickAudioMuteButton(); - await p3.getToolbar().clickAudioUnmuteButton(); - await p1.log('configOptionsTest, unmuted third participant'); - await p1.waitForAudioMuted(p3, false /* unmuted */); - }); - - it('startWithVideoMuted=true can unmute', async () => { - // Maybe disable if there is FF or Safari participant. - - await hangupAllParticipants(); - - // Explicitly enable P2P due to a regression with unmute not updating - // large video while in P2P. - const options = { - configOverwrite: { - p2p: { - enabled: true - }, - startWithVideoMuted: true - } - }; - - await ensureTwoParticipants(options); - - const { p1, p2 } = ctx; - - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - - await Promise.all([ - p1.getLargeVideo().waitForSwitchTo(await p2.getEndpointId()), - p2.getLargeVideo().waitForSwitchTo(await p1.getEndpointId()) - ]); - - await unmuteVideoAndCheck(p2, p1); - await p1.getLargeVideo().assertPlaying(); - }); - - it('startWithAudioMuted=true can unmute', async () => { - await hangupAllParticipants(); - - const options = { - configOverwrite: { - startWithAudioMuted: true, - testing: { - testMode: true, - debugAudioLevels: true - } - } - }; - - await ensureTwoParticipants(options); - - const { p1, p2 } = ctx; - - await Promise.all([ p1.waitForAudioMuted(p2, true), p2.waitForAudioMuted(p1, true) ]); - await p1.getToolbar().clickAudioUnmuteButton(); - await Promise.all([ p1.waitForAudioMuted(p2, true), p2.waitForAudioMuted(p1, false) ]); - }); - - it('startWithAudioVideoMuted=true can unmute', async () => { - await hangupAllParticipants(); - - const options = { - configOverwrite: { - startWithAudioMuted: true, - startWithVideoMuted: true, - p2p: { - enabled: true - } - } - }; - - await ensureOneParticipant(options); - await joinSecondParticipant({ - configOverwrite: { - testing: { - testMode: true, - debugAudioLevels: true - }, - p2p: { - enabled: true - } - } - }); - - const { p1, p2 } = ctx; - - await p2.waitForIceConnected(); - await p2.waitForSendMedia(); - - await p2.waitForAudioMuted(p1, true); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - - // Unmute p1's both audio and video and check on p2. - await p1.getToolbar().clickAudioUnmuteButton(); - await p2.waitForAudioMuted(p1, false); - - await unmuteVideoAndCheck(p1, p2); - await p2.getLargeVideo().assertPlaying(); - }); - - - it('test p2p JVB switch and switch back', async () => { - const { p1, p2 } = ctx; - - // Mute p2's video just before p3 joins. - await p2.getToolbar().clickVideoMuteButton(); - - await joinThirdParticipant({ - configOverwrite: { - p2p: { - enabled: true - } - } - }); - - const { p3 } = ctx; - - // Unmute p2 and check if its video is being received by p1 and p3. - await unmuteVideoAndCheck(p2, p3); - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2, true); - - // Mute p2's video just before p3 leaves. - await p2.getToolbar().clickVideoMuteButton(); - - await p3.hangup(); - - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2); - - await p2.getToolbar().clickVideoUnmuteButton(); - - // Check if p2's video is playing on p1. - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2, true); - await p1.getLargeVideo().assertPlaying(); - }); -}); diff --git a/tests/specs/media/stopVideo.spec.ts b/tests/specs/media/stopVideo.spec.ts deleted file mode 100644 index 25764c98bd..0000000000 --- a/tests/specs/media/stopVideo.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureTwoParticipants } from '../../helpers/participants'; -import { muteVideoAndCheck, unmuteVideoAndCheck } from '../helpers/mute'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Stop video', () => { - it('joining the meeting', () => ensureTwoParticipants()); - - it('stop video and check', () => muteVideoAndCheck(ctx.p1, ctx.p2)); - - it('start video and check', () => unmuteVideoAndCheck(ctx.p1, ctx.p2)); - - it('start video and check stream', async () => { - await muteVideoAndCheck(ctx.p1, ctx.p2); - - // now participant2 should be on large video - const largeVideoId = await ctx.p1.getLargeVideo().getId(); - - await unmuteVideoAndCheck(ctx.p1, ctx.p2); - - // check if video stream from second participant is still on large video - expect(largeVideoId).toBe(await ctx.p1.getLargeVideo().getId()); - }); - - it('stop video on participant and check', () => muteVideoAndCheck(ctx.p2, ctx.p1)); - - it('start video on participant and check', () => unmuteVideoAndCheck(ctx.p2, ctx.p1)); - - it('stop video on before second joins', async () => { - await ctx.p2.hangup(); - - const { p1 } = ctx; - - await p1.getToolbar().clickVideoMuteButton(); - - await ensureTwoParticipants(); - - const { p2 } = ctx; - - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - - await unmuteVideoAndCheck(p1, p2); - }); -}); diff --git a/tests/specs/misc/avatars.spec.ts b/tests/specs/misc/avatars.spec.ts deleted file mode 100644 index 490d820041..0000000000 --- a/tests/specs/misc/avatars.spec.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureThreeParticipants, ensureTwoParticipants } from '../../helpers/participants'; -import { unmuteVideoAndCheck } from '../helpers/mute'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -const EMAIL = 'support@jitsi.org'; -const HASH = '38f014e4b7dde0f64f8157d26a8c812e'; - -describe('Avatar', () => { - it('setup the meeting', () => - ensureTwoParticipants({ - skipDisplayName: true - }) - ); - - it('change and check', async () => { - const { p1, p2 } = ctx; - - // check default avatar for p1 on p2 - await p2.assertDefaultAvatarExist(p1); - - await p1.getToolbar().clickProfileButton(); - - const settings = p1.getSettingsDialog(); - - await settings.waitForDisplay(); - await settings.setEmail(EMAIL); - await settings.submit(); - - // check if the local avatar in the toolbar menu has changed - await p1.driver.waitUntil( - async () => (await p1.getToolbar().getProfileImage())?.includes(HASH), { - timeout: 3000, // give more time for the initial download of the image - timeoutMsg: 'Avatar has not changed for p1' - }); - - // check if the avatar in the local thumbnail has changed - expect(await p1.getLocalVideoAvatar()).toContain(HASH); - - const p1EndpointId = await p1.getEndpointId(); - - await p2.driver.waitUntil( - async () => (await p2.getFilmstrip().getAvatar(p1EndpointId))?.includes(HASH), { - timeout: 5000, - timeoutMsg: 'Avatar has not changed for p1 on p2' - }); - - // check if the avatar in the large video has changed - expect(await p2.getLargeVideo().getAvatar()).toContain(HASH); - - // we check whether the default avatar of participant2 is displayed on both sides - await p1.assertDefaultAvatarExist(p2); - await p2.assertDefaultAvatarExist(p2); - - // the problem on FF where we can send keys to the input field, - // and the m from the text can mute the call, check whether we are muted - await p2.getFilmstrip().assertAudioMuteIconIsDisplayed(p1, true); - }); - - it('when video muted', async () => { - const { p1 } = ctx; - - await ctx.p2.hangup(); - - // Mute p1's video - await p1.getToolbar().clickVideoMuteButton(); - - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - - await p1.driver.waitUntil( - async () => (await p1.getLargeVideo().getAvatar())?.includes(HASH), { - timeout: 2000, - timeoutMsg: 'Avatar on large video did not change' - }); - - const p1LargeSrc = await p1.getLargeVideo().getAvatar(); - const p1ThumbSrc = await p1.getLocalVideoAvatar(); - - // Check if avatar on large video is the same as on local thumbnail - expect(p1ThumbSrc).toBe(p1LargeSrc); - - // Join p2 - await ensureTwoParticipants({ - skipDisplayName: true - }); - const { p2 } = ctx; - - // Verify that p1 is muted from the perspective of p2 - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - - await p2.getFilmstrip().pinParticipant(p1); - - // Check if p1's avatar is on large video now - await p2.driver.waitUntil( - async () => await p2.getLargeVideo().getAvatar() === p1LargeSrc, { - timeout: 2000, - timeoutMsg: 'Avatar on large video did not change' - }); - - // p1 pins p2's video - await p1.getFilmstrip().pinParticipant(p2); - - // Check if avatar is displayed on p1's local video thumbnail - await p1.assertThumbnailShowsAvatar(p1, false, false, true); - - // Unmute - now local avatar should be hidden and local video displayed - await unmuteVideoAndCheck(p1, p2); - - await p1.asserLocalThumbnailShowsVideo(); - - // Now both p1 and p2 have video muted - await p1.getToolbar().clickVideoMuteButton(); - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p1); - - await p2.getToolbar().clickVideoMuteButton(); - await p2.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2); - await p1.getParticipantsPane().assertVideoMuteIconIsDisplayed(p2); - - // Start the third participant - await ensureThreeParticipants({ - skipInMeetingChecks: true - }); - - const { p3 } = ctx; - - // When the first participant is FF because of their audio mic feed it will never become dominant speaker - // and no audio track will be received by the third participant and video is muted, - // that's why we need to do a different check that expects any track just from p2 - if (p1.driver.isFirefox) { - await Promise.all([ p2.waitForRemoteStreams(1), p3.waitForRemoteStreams(1) ]); - } else { - await Promise.all([ p2.waitForRemoteStreams(2), p3.waitForRemoteStreams(2) ]); - } - - // Pin local video and verify avatars are displayed - await p3.getFilmstrip().pinParticipant(p3); - - await p3.assertThumbnailShowsAvatar(p1, false, false, true); - await p3.assertThumbnailShowsAvatar(p2, false, true); - - const p1EndpointId = await p1.getEndpointId(); - const p2EndpointId = await p2.getEndpointId(); - - expect(await p3.getFilmstrip().getAvatar(p1EndpointId)).toBe(p1ThumbSrc); - - // Click on p1's video - await p3.getFilmstrip().pinParticipant(p1); - - // The avatar should be on large video and display name instead of an avatar, local video displayed - await p3.driver.waitUntil( - async () => await p3.getLargeVideo().getResource() === p1EndpointId, { - timeout: 2000, - timeoutMsg: `Large video did not switch to ${p1.name}` - }); - - await p3.assertDisplayNameVisibleOnStage( - await p3.getFilmstrip().getRemoteDisplayName(p1EndpointId)); - - // p2 has the default avatar - await p3.assertThumbnailShowsAvatar(p2, false, true); - await p3.assertThumbnailShowsAvatar(p3, true); - - // Click on p2's video - await p3.getFilmstrip().pinParticipant(p2); - - // The avatar should be on large video and display name instead of an avatar, local video displayed - await p3.driver.waitUntil( - async () => await p3.getLargeVideo().getResource() === p2EndpointId, { - timeout: 2000, - timeoutMsg: `Large video did not switch to ${p2.name}` - }); - - await p3.assertDisplayNameVisibleOnStage( - await p3.getFilmstrip().getRemoteDisplayName(p2EndpointId) - ); - - await p3.assertThumbnailShowsAvatar(p1, false, false, true); - await p3.assertThumbnailShowsAvatar(p3, true); - - await p3.hangup(); - - // Unmute p1's and p2's videos - await unmuteVideoAndCheck(p1, p2); - }); - - it('email persistence', async () => { - let { p1 } = ctx; - - if (p1.driver.isFirefox) { - // strangely this test when FF is involved, missing source mapping from jvb - // and fails with an error of: expected number of remote streams:1 in 15s for participant1 - return; - } - - await p1.getToolbar().clickProfileButton(); - - expect(await p1.getSettingsDialog().getEmail()).toBe(EMAIL); - - await p1.hangup(); - - await ensureTwoParticipants({ - skipDisplayName: true - }); - p1 = ctx.p1; - - await p1.getToolbar().clickProfileButton(); - - expect(await p1.getSettingsDialog().getEmail()).toBe(EMAIL); - }); -}); diff --git a/tests/specs/misc/breakoutRooms.spec.ts b/tests/specs/misc/breakoutRooms.spec.ts deleted file mode 100644 index f55480424f..0000000000 --- a/tests/specs/misc/breakoutRooms.spec.ts +++ /dev/null @@ -1,486 +0,0 @@ -import type { ChainablePromiseElement } from 'webdriverio'; - -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { - checkSubject, - ensureThreeParticipants, - ensureTwoParticipants, - hangupAllParticipants -} from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -const MAIN_ROOM_NAME = 'Main room'; -const BREAKOUT_ROOMS_LIST_ID = 'breakout-rooms-list'; -const LIST_ITEM_CONTAINER = 'list-item-container'; - -describe('Breakout rooms', () => { - it('check support', async () => { - await ensureTwoParticipants(); - - if (!await ctx.p1.isBreakoutRoomsSupported()) { - ctx.skipSuiteTests = 'The environment does not support breakout rooms.'; - } - }); - - it('add breakout room', async () => { - const { p1, p2 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // there should be no breakout rooms initially, list is sent with a small delay - await p1.driver.pause(2000); - expect(await p1BreakoutRooms.getRoomsCount()).toBe(0); - - // add one breakout room - await p1BreakoutRooms.addBreakoutRoom(); - - await p1.driver.waitUntil( - async () => await p1BreakoutRooms.getRoomsCount() === 1, { - timeout: 5000, - timeoutMsg: 'No breakout room added for p1' - }); - - - // second participant should also see one breakout room - await p2.driver.waitUntil( - async () => await p2.getBreakoutRooms().getRoomsCount() === 1, { - timeout: 5000, - timeoutMsg: 'No breakout room seen by p2' - }); - }); - - it('join breakout room', async () => { - const { p1, p2 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // there should be one breakout room - await p1.driver.waitUntil( - async () => await p1BreakoutRooms.getRoomsCount() === 1, { - timeout: 5000, - timeoutMsg: 'No breakout room seen by p1' - }); - - const roomsList = await p1BreakoutRooms.getRooms(); - - expect(roomsList.length).toBe(1); - - // join the room - await roomsList[0].joinRoom(); - - // the participant should see the main room as the only breakout room - await p1.driver.waitUntil( - async () => { - if (await p1BreakoutRooms.getRoomsCount() !== 1) { - return false; - } - - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].name === MAIN_ROOM_NAME; - }, { - timeout: 5000, - timeoutMsg: 'P1 did not join breakout room' - }); - - // the second participant should see one participant in the breakout room - await p2.driver.waitUntil( - async () => { - const list = await p2.getBreakoutRooms().getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].participantCount === 1; - }, { - timeout: 5000, - timeoutMsg: 'P2 is not seeing p1 in the breakout room' - }); - }); - - it('leave breakout room', async () => { - const { p1, p2 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // leave room - await p1BreakoutRooms.leaveBreakoutRoom(); - - // there should be one breakout room and that should not be the main room - await p1.driver.waitUntil( - async () => { - if (await p1BreakoutRooms.getRoomsCount() !== 1) { - return false; - } - - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].name !== MAIN_ROOM_NAME; - }, { - timeout: 5000, - timeoutMsg: 'P1 did not leave breakout room' - }); - - // the second participant should see no participants in the breakout room - await p2.driver.waitUntil( - async () => { - const list = await p2.getBreakoutRooms().getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].participantCount === 0; - }, { - timeout: 5000, - timeoutMsg: 'P2 is seeing p1 in the breakout room' - }); - }); - - it('remove breakout room', async () => { - const { p1, p2 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // remove the room - await (await p1BreakoutRooms.getRooms())[0].removeRoom(); - - // there should be no breakout rooms - await p1.driver.waitUntil( - async () => await p1BreakoutRooms.getRoomsCount() === 0, { - timeout: 5000, - timeoutMsg: 'Breakout room was not removed for p1' - }); - - // the second participant should also see no breakout rooms - await p2.driver.waitUntil( - async () => await p2.getBreakoutRooms().getRoomsCount() === 0, { - timeout: 5000, - timeoutMsg: 'Breakout room was not removed for p2' - }); - }); - - it('auto assign', async () => { - await ensureThreeParticipants(); - const { p1, p2 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // create two rooms - await p1BreakoutRooms.addBreakoutRoom(); - await p1BreakoutRooms.addBreakoutRoom(); - - // there should be two breakout rooms - await p1.driver.waitUntil( - async () => await p1BreakoutRooms.getRoomsCount() === 2, { - timeout: 5000, - timeoutMsg: 'Breakout room was not created by p1' - }); - - // auto assign participants to rooms - await p1BreakoutRooms.autoAssignToBreakoutRooms(); - - // each room should have one participant - await p1.driver.waitUntil( - async () => { - if (await p1BreakoutRooms.getRoomsCount() !== 2) { - return false; - } - - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 2) { - return false; - } - - return list[0].participantCount === 1 && list[1].participantCount === 1; - }, { - timeout: 5000, - timeoutMsg: 'P1 did not auto assigned participants to breakout rooms' - }); - - // the second participant should see one participant in the main room - const p2BreakoutRooms = p2.getBreakoutRooms(); - - await p2.driver.waitUntil( - async () => { - if (await p2BreakoutRooms.getRoomsCount() !== 2) { - return false; - } - - const list = await p2BreakoutRooms.getRooms(); - - if (list?.length !== 2) { - return false; - } - - return list[0].participantCount === 1 && list[1].participantCount === 1 - && (list[0].name === MAIN_ROOM_NAME || list[1].name === MAIN_ROOM_NAME); - }, { - timeout: 5000, - timeoutMsg: 'P2 is not seeing p1 in the main room' - }); - }); - - it('close breakout room', async () => { - const { p1, p2, p3 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // there should be two non-empty breakout rooms - await p1.driver.waitUntil( - async () => { - if (await p1BreakoutRooms.getRoomsCount() !== 2) { - return false; - } - - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 2) { - return false; - } - - return list[0].participantCount === 1 && list[1].participantCount === 1; - }, { - timeout: 5000, - timeoutMsg: 'P1 is not seeing two breakout rooms' - }); - - // close the first room - await (await p1BreakoutRooms.getRooms())[0].closeRoom(); - - // there should be two rooms and first one should be empty - await p1.driver.waitUntil( - async () => { - if (await p1BreakoutRooms.getRoomsCount() !== 2) { - return false; - } - - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 2) { - return false; - } - - return list[0].participantCount === 0 || list[1].participantCount === 0; - }, { - timeout: 5000, - timeoutMsg: 'P1 is not seeing an empty breakout room' - }); - - // there should be two participants in the main room, either p2 or p3 got moved to the main room - const checkParticipants = (p: Participant) => - p.driver.waitUntil( - async () => { - const isInBreakoutRoom = await p.isInBreakoutRoom(); - const breakoutRooms = p.getBreakoutRooms(); - - if (isInBreakoutRoom) { - if (await breakoutRooms.getRoomsCount() !== 2) { - return false; - } - - const list = await breakoutRooms.getRooms(); - - if (list?.length !== 2) { - return false; - } - - return list.every(r => { // eslint-disable-line arrow-body-style - return r.name === MAIN_ROOM_NAME ? r.participantCount === 2 : r.participantCount === 0; - }); - } - - if (await breakoutRooms.getRoomsCount() !== 2) { - return false; - } - - const list = await breakoutRooms.getRooms(); - - if (list?.length !== 2) { - return false; - } - - return list[0].participantCount + list[1].participantCount === 1; - }, { - timeout: 5000, - timeoutMsg: `${p.name} is not seeing an empty breakout room and one with one participant` - }); - - await checkParticipants(p2); - await checkParticipants(p3); - }); - - it('send participants to breakout room', async () => { - await hangupAllParticipants(); - - // because the participants rejoin so fast, the meeting is not properly ended, - // so the previous breakout rooms would still be there. - // To avoid this issue we use a different meeting - // Respect room name suffix as it is important in multi-shard testing - ctx.roomName += `new-${ctx.roomName}`; - - await ensureTwoParticipants(); - const { p1, p2 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // there should be no breakout rooms - expect(await p1BreakoutRooms.getRoomsCount()).toBe(0); - - // add one breakout room - await p1BreakoutRooms.addBreakoutRoom(); - - // there should be one empty room - await p1.driver.waitUntil( - async () => await p1BreakoutRooms.getRoomsCount() === 1 - && (await p1BreakoutRooms.getRooms())[0].participantCount === 0, { - timeout: 5000, - timeoutMsg: 'No breakout room added for p1' - }); - - // send the second participant to the first breakout room - await p1BreakoutRooms.sendParticipantToBreakoutRoom(p2, (await p1BreakoutRooms.getRooms())[0].name); - - // there should be one room with one participant - await p1.driver.waitUntil( - async () => { - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].participantCount === 1; - }, { - timeout: 5000, - timeoutMsg: 'P1 is not seeing p2 in the breakout room' - }); - }); - - it('collapse breakout room', async () => { - const { p1 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // there should be one breakout room with one participant - await p1.driver.waitUntil( - async () => { - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].participantCount === 1; - }, { - timeout: 5000, - timeoutMsg: 'P1 is not seeing p2 in the breakout room' - }); - - // get id of the breakout room participant - const breakoutList = p1.driver.$(`#${BREAKOUT_ROOMS_LIST_ID}`); - const breakoutRoomItem = await breakoutList.$$(`.${LIST_ITEM_CONTAINER}`).find( - async el => { - const id = await el.getAttribute('id'); - - return id !== '' && id !== null; - }) as ChainablePromiseElement; - - const pId = await breakoutRoomItem.getAttribute('id'); - const breakoutParticipant = p1.driver.$(`//div[@id="${pId}"]`); - - expect(await breakoutParticipant.isDisplayed()).toBe(true); - - // collapse the first - await (await p1BreakoutRooms.getRooms())[0].collapse(); - - // the participant should not be visible - expect(await breakoutParticipant.isDisplayed()).toBe(false); - - // the collapsed room should still have one participant - expect((await p1BreakoutRooms.getRooms())[0].participantCount).toBe(1); - }); - - it('rename breakout room', async () => { - const myNewRoomName = `breakout-${crypto.randomUUID()}`; - const { p1, p2 } = ctx; - const p1BreakoutRooms = p1.getBreakoutRooms(); - - // let's rename breakout room and see it in local and remote - await (await p1BreakoutRooms.getRooms())[0].renameRoom(myNewRoomName); - - await p1.driver.waitUntil( - async () => { - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].name === myNewRoomName; - }, { - timeout: 5000, - timeoutMsg: 'The breakout room was not renamed for p1' - }); - - await checkSubject(p2, myNewRoomName); - - const p2BreakoutRooms = p2.getBreakoutRooms(); - - // leave room - await p2BreakoutRooms.leaveBreakoutRoom(); - - // there should be one empty room - await p1.driver.waitUntil( - async () => { - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].participantCount === 0; - }, { - timeout: 5000, - timeoutMsg: 'The breakout room not found or not empty for p1' - }); - - await p2.driver.waitUntil( - async () => { - const list = await p2BreakoutRooms.getRooms(); - - return list?.length === 1; - }, { - timeout: 5000, - timeoutMsg: 'The breakout room not seen by p2' - }); - - expect((await p2BreakoutRooms.getRooms())[0].name).toBe(myNewRoomName); - - // send the second participant to the first breakout room - await p1BreakoutRooms.sendParticipantToBreakoutRoom(p2, myNewRoomName); - - // there should be one room with one participant - await p1.driver.waitUntil( - async () => { - const list = await p1BreakoutRooms.getRooms(); - - if (list?.length !== 1) { - return false; - } - - return list[0].participantCount === 1; - }, { - timeout: 5000, - timeoutMsg: 'The breakout room was not rename for p1' - }); - - await checkSubject(p2, myNewRoomName); - }); -}); diff --git a/tests/specs/misc/connectivity.spec.ts b/tests/specs/misc/connectivity.spec.ts deleted file mode 100644 index e1da593251..0000000000 --- a/tests/specs/misc/connectivity.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import { joinMuc, waitForMedia } from '../../helpers/joinMuc'; - -setTestProperties(__filename, { - description: 'This test asserts that the connection to JVB is over UDP and using the same remote port. ', - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Connectivity', () => { - let p1: Participant, p2: Participant; - - it('setup', async () => { - p1 = await joinMuc({ name: 'p1', token: testsConfig.jwt.preconfiguredToken }); - p2 = await joinMuc({ name: 'p2', token: testsConfig.jwt.preconfiguredToken }); - await waitForMedia([ p1, p2 ]); - }); - - it('protocol', async () => { - expect(await getProtocol(p1)).toBe('udp'); - expect(await getProtocol(p2)).toBe('udp'); - }); - - it('port', async () => { - const port1 = await getRemotePort(p1); - const port2 = await getRemotePort(p2); - - expect(Number.isInteger(port1)).toBe(true); - expect(Number.isInteger(port2)).toBe(true); - expect(port1).toBe(port2); - }); -}); - -/** - * Get the remote port of the participant. - * @param participant - */ -async function getRemotePort(participant: Participant) { - const data = await participant.execute(() => APP?.conference?.getStats()?.transport[0]?.ip); - const parts = data.split(':'); - - return parts.length > 1 ? parseInt(parts[1], 10) : ''; -} - -/** - * Get the remote port of the participant. - * @param participant - */ -async function getProtocol(participant: Participant) { - const data = await participant.execute(() => APP?.conference?.getStats()?.transport[0]?.type); - - return data.toLowerCase(); -} diff --git a/tests/specs/misc/dialIn.spec.ts b/tests/specs/misc/dialIn.spec.ts deleted file mode 100644 index aa08da3f20..0000000000 --- a/tests/specs/misc/dialIn.spec.ts +++ /dev/null @@ -1,120 +0,0 @@ -import process from 'node:process'; - -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import { expectations } from '../../helpers/expectations'; -import { ensureOneParticipant } from '../../helpers/participants'; -import { - assertDialInDisplayed, - assertUrlDisplayed, - cleanup, - dialIn, - isDialInEnabled, verifyMoreNumbersPage, - waitForAudioFromDialInParticipant -} from '../helpers/DialIn'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1' ] -}); - -/** - * This test is configured with two options: - * 1. The dialIn.enabled expectation. If set to true we assert the config.js settings for dial-in are set, the dial-in - * panel (including the PIN number) is displayed in the UI, and the "more numbers" page is displayed. If it's set to - * false we assert the config.js settings are not set, and the PIN is not displayed. - * 2. The DIAL_IN_REST_URL environment variable. If this is set and the environment supports dial-in, we invite a - * dial-in participant via this URL and assert that it joins the conference and sends media. - */ -describe('Dial-in', () => { - it('join participant', async () => { - // The same cases are covered for JaaS in jaas/dial/dialin.spec.ts. - if (testsConfig.jaas.enabled) { - ctx.skipSuiteTests = 'JaaS is configured.'; - - return; - } - - await ensureOneParticipant(); - expect(await ctx.p1.isInMuc()).toBe(true); - }); - - it('dial in config.js values', async function() { - if (expectations.dialIn.enabled === true) { - expect(await isDialInEnabled(ctx.p1)).toBe(expectations.dialIn.enabled); - } else { - // eslint-disable-next-line @typescript-eslint/no-invalid-this - this.skip(); - } - }); - - it('open/close invite dialog', async () => { - await ctx.p1.getInviteDialog().open(); - await ctx.p1.getInviteDialog().clickCloseButton(); - await ctx.p1.getInviteDialog().waitTillOpen(true); - }); - - it('dial-in displayed', async function() { - if (expectations.dialIn.enabled !== null) { - await assertDialInDisplayed(ctx.p1, expectations.dialIn.enabled); - } else { - // eslint-disable-next-line @typescript-eslint/no-invalid-this - this.skip(); - } - }); - - it('skip the rest if dial-in is not expected', async () => { - if (!expectations.dialIn.enabled) { - ctx.skipSuiteTests = 'Dial-in is not expected'; - } - }); - - it('url displayed', () => assertUrlDisplayed(ctx.p1)); - - - it('view more numbers page', async () => { - await verifyMoreNumbersPage(ctx.p1); - }); - - it('retrieve pin', async () => { - let dialInPin: string; - - try { - dialInPin = await ctx.p1.getDialInPin(); - } catch (e) { - console.error('dial-in.test.no-pin'); - ctx.skipSuiteTests = 'No dial-in pin is available.'; - throw e; - } - - if (dialInPin.length === 0) { - console.error('dial-in.test.no-pin'); - ctx.skipSuiteTests = 'The dial-in pin is empty.'; - throw new Error('no pin'); - } - - expect(dialInPin.length >= 8).toBe(true); - }); - - it('skip the rest if a dial-in URL is not configured', async () => { - if (!process.env.DIAL_IN_REST_URL) { - ctx.skipSuiteTests = 'DIAL_IN_REST_URL is not set.'; - } - }); - - it('invite dial-in participant', async () => { - await dialIn(await ctx.p1.getDialInPin()); - }); - - it('wait for audio from dial-in participant', async () => { - const { p1 } = ctx; - - if (!await p1.isInMuc()) { - // local participant did not join abort - return; - } - - await waitForAudioFromDialInParticipant(p1); - - await cleanup(p1); - }); -}); diff --git a/tests/specs/misc/followMe.spec.ts b/tests/specs/misc/followMe.spec.ts deleted file mode 100644 index cf2cd14d98..0000000000 --- a/tests/specs/misc/followMe.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureThreeParticipants, ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Follow me', () => { - it('joining the meeting', async () => { - await ensureTwoParticipants(); - - const { p1 } = ctx; - - await p1.getToolbar().clickSettingsButton(); - - const settings = p1.getSettingsDialog(); - - await settings.waitForDisplay(); - await settings.setFollowMe(true); - await settings.submit(); - }); - - it('follow me checkbox visible only for moderators', async () => { - const { p2 } = ctx; - - if (!await p2.isModerator()) { - await p2.getToolbar().clickSettingsButton(); - - const settings = p2.getSettingsDialog(); - - await settings.waitForDisplay(); - expect(await settings.isFollowMeDisplayed()).toBe(false); - - await settings.clickCloseButton(); - } - }); - - it('filmstrip commands', async () => { - const { p1, p2 } = ctx; - - const p1Filmstrip = p1.getFilmstrip(); - const p2Filmstrip = p2.getFilmstrip(); - - await p1Filmstrip.toggle(); - - await p1Filmstrip.assertRemoteVideosHidden(); - await p2Filmstrip.assertRemoteVideosHidden(); - }); - - it('tile view', async () => { - await ensureThreeParticipants(); - - const { p1, p2, p3 } = ctx; - - await p1.waitForTileViewDisplayed(); - - await p1.getToolbar().clickExitTileViewButton(); - - await Promise.all([ - p1.waitForTileViewDisplayed(true), - p2.waitForTileViewDisplayed(true), - p3.waitForTileViewDisplayed(true) - ]); - - await p1.getToolbar().clickEnterTileViewButton(); - - await Promise.all([ - p1.waitForTileViewDisplayed(), - p2.waitForTileViewDisplayed(), - p3.waitForTileViewDisplayed() - ]); - }); - - it('next on stage', async () => { - const { p1, p2, p3 } = ctx; - - await p1.getFilmstrip().pinParticipant(p2); - - const p2Filmstrip = p2.getFilmstrip(); - const localVideoId = await p2Filmstrip.getLocalVideoId(); - - await p2.driver.waitUntil( - async () => await localVideoId === await p2.getLargeVideo().getId(), - { - timeout: 5_000, - timeoutMsg: 'The pinned participant is not displayed on stage for p2' - }); - - const p2VideoIdOnp3 = await p3.getFilmstrip().getRemoteVideoId(await p2.getEndpointId()); - - await p3.driver.waitUntil( - async () => p2VideoIdOnp3 === await p3.getLargeVideo().getId(), - { - timeout: 5_000, - timeoutMsg: 'The pinned participant is not displayed on stage for p3' - }); - }); -}); diff --git a/tests/specs/misc/polls.spec.ts b/tests/specs/misc/polls.spec.ts deleted file mode 100644 index 2bfb910bb1..0000000000 --- a/tests/specs/misc/polls.spec.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Polls', () => { - it('joining the meeting', async () => { - await ensureTwoParticipants(); - }); - it('create poll', async () => { - const { p1 } = ctx; - - await p1.getToolbar().clickChatButton(); - expect(await p1.getChatPanel().isOpen()).toBe(true); - - expect(await p1.getChatPanel().isPollsTabVisible()).toBe(false); - - await p1.getChatPanel().openPollsTab(); - expect(await p1.getChatPanel().isPollsTabVisible()).toBe(true); - - // create poll - await p1.getChatPanel().clickCreatePollButton(); - await p1.getChatPanel().waitForNewPollInput(); - }); - - it('fill in poll', async () => { - const { p1 } = ctx; - - await p1.getChatPanel().fillPollQuestion('My Poll question?'); - - await p1.getChatPanel().waitForOptionInput(0); - await p1.getChatPanel().waitForOptionInput(1); - await p1.getChatPanel().fillPollOption(0, 'First option'); - await p1.getChatPanel().fillPollOption(1, 'Second option'); - - - await p1.getChatPanel().clickAddOptionButton(); - await p1.getChatPanel().waitForOptionInput(2); - await p1.getChatPanel().fillPollOption(2, 'Third option'); - - await p1.getChatPanel().clickAddOptionButton(); - await p1.getChatPanel().waitForOptionInput(3); - await p1.getChatPanel().fillPollOption(3, 'Fourth option'); - - await p1.getChatPanel().clickRemoveOptionButton(2); - // we remove the option and reindexing happens, so we check for index 3 - await p1.getChatPanel().waitForOptionInputNonExisting(3); - - expect(await p1.getChatPanel().getOption(2)).toBe('Fourth option'); - }); - - it('save and edit poll', async () => { - const { p1 } = ctx; - - await p1.getChatPanel().clickSavePollButton(); - - await p1.getChatPanel().waitForSendButton(); - - await p1.getChatPanel().clickEditPollButton(); - - await p1.getChatPanel().fillPollOption(0, ' edited!'); - - await p1.getChatPanel().clickSavePollButton(); - - await p1.getChatPanel().waitForSendButton(); - }); - - it('send poll', async () => { - const { p1 } = ctx; - - await p1.getChatPanel().clickSendPollButton(); - }); - - it('vote on poll', async () => { - const { p1 } = ctx; - - // await p1.getNotifications().closePollsNotification(); - - // we have only one poll, so we get its ID - const pollId: string = await p1.driver.waitUntil(() => p1.driver.execute(() => { - return Object.keys(APP.store.getState()['features/polls'].polls)[0]; - }), { timeout: 2000 }); - - // we have just send the poll, so the UI should be in a state for voting - await p1.getChatPanel().voteForOption(pollId, 0); - }); - - it('check for vote', async () => { - const { p1, p2 } = ctx; - const pollId: string = await p1.driver.execute('return Object.keys(APP.store.getState()["features/polls"].polls)[0];'); - - // now let's check on p2 side - await p2.getToolbar().clickChatButton(); - expect(await p2.getChatPanel().isOpen()).toBe(true); - - expect(await p2.getChatPanel().isPollsTabVisible()).toBe(false); - - await p2.getChatPanel().openPollsTab(); - expect(await p2.getChatPanel().isPollsTabVisible()).toBe(true); - - expect(await p2.getChatPanel().isPollVisible(pollId)); - - await p2.getChatPanel().clickSkipPollButton(); - - expect(await p2.getChatPanel().getResult(pollId, 0)).toBe('1 (100%)'); - }); - - it('leave and check for vote', async () => { - await ctx.p2.hangup(); - - await ensureTwoParticipants(); - - const { p1, p2 } = ctx; - const pollId: string = await p1.driver.execute('return Object.keys(APP.store.getState()["features/polls"].polls)[0];'); - - - await p2.getToolbar().clickChatButton(); - await p2.getChatPanel().openPollsTab(); - - expect(await p2.getChatPanel().isPollVisible(pollId)); - - await p2.getChatPanel().clickSkipPollButton(); - - expect(await p2.getChatPanel().getResult(pollId, 0)).toBe('1 (100%)'); - }); -}); diff --git a/tests/specs/misc/subject.spec.ts b/tests/specs/misc/subject.spec.ts deleted file mode 100644 index 3c8fb88164..0000000000 --- a/tests/specs/misc/subject.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureOneParticipant, ensureTwoParticipants } from '../../helpers/participants'; - -const MY_TEST_SUBJECT = 'My Test Subject'; -const SUBJECT_XPATH = '//div[starts-with(@class, "subject-text")]'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Subject', () => { - it('setup', async () => { - await ensureOneParticipant({ - configOverwrite: { - subject: MY_TEST_SUBJECT - } - }); - await ensureTwoParticipants(); - }); - it('subject set locally', async () => await checkSubject(ctx.p1, MY_TEST_SUBJECT)); - it('subject set remotely', async () => await checkSubject(ctx.p2, MY_TEST_SUBJECT)); -}); - -/** - * Check was subject set. - * - * @param participant - * @param subject - */ -async function checkSubject(participant: Participant, subject: string) { - const localTile = participant.driver.$(SUBJECT_XPATH); - - await localTile.moveTo(); - - expect(await localTile.getText()).toBe(subject); -} diff --git a/tests/specs/misc/urlNormalisation.spec.ts b/tests/specs/misc/urlNormalisation.spec.ts deleted file mode 100644 index 1e17175f9f..0000000000 --- a/tests/specs/misc/urlNormalisation.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import { expectations } from '../../helpers/expectations'; -import { joinMuc } from '../../helpers/joinMuc'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1' ] -}); - -describe('URL normalisation', () => { - // If we're not able to create conferences with a custom tenant, we'll only test the room name. - const useTenant = expectations.useTenant; - - const tests = [ - { - hint: '@ sign and .', - // Room as entered in the URL - room: '@example.com', - // Room as normalized in the URL - roomUrl: 'example.com', - // The room part of the MUC JID - roomJid: 'example.com', - // Tenant as entered in the URL - tenant: 'tenant@example.com', - // Tenant as normalized in the URL - tenantUrl: 'tenantexample.com', - // The tenant part of the MUC JID - tenantJid: 'tenantexample_com' - }, - { - hint: 'Dashes', - room: 'foo-bar', - roomUrl: 'foo-bar', - roomJid: 'foo-bar', - tenant: 'tenant-example.com', - tenantUrl: 'tenant-example.com', - tenantJid: 'tenant-example_com' - }, - { - hint: 'Cyrillic', - room: 'фоо-бар', - roomUrl: '%D1%84%D0%BE%D0%BE-%D0%B1%D0%B0%D1%80', - roomJid: '%d1%84%d0%be%d0%be-%d0%b1%d0%b0%d1%80', - tenant: 'обитател', - tenantUrl: '%D0%BE%D0%B1%D0%B8%D1%82%D0%B0%D1%82%D0%B5%D0%BB', - tenantJid: '%d0%be%d0%b1%d0%b8%d1%82%d0%b0%d1%82%d0%b5%d0%bb', - } - ]; - - for (const test of tests) { - it(test.hint, async () => { - const fullRoom = `${test.room}${ctx.roomName}`; - const fullRoomUrl = `${test.roomUrl}${ctx.roomName}`; - const tenant = useTenant ? test.tenant : undefined; - - const p = await joinMuc({ - name: 'p1', - token: testsConfig.jwt.preconfiguredToken, - }, { - tenant: tenant, - roomName: fullRoom - }); - - const currentUrlStr = await p.driver.getUrl(); - const currentUrl = new URL(currentUrlStr); - const path = currentUrl.pathname; - const parts = path.split('/'); - - if (useTenant) { - expect(parts[1]).toBe(test.tenantUrl); - } - expect(parts[2]).toBe(fullRoomUrl); - - const mucJid = (await p.execute(() => APP.conference._room.room.roomjid)).split('@'); - const roomJid = mucJid[0]; - const domain = mucJid[1]; - - expect(roomJid).toBe(`${test.roomJid}${ctx.roomName}`); - if (useTenant) { - expect(domain.startsWith(`conference.${test.tenantJid}.`)).toBe(true); - } - }); - } -}); diff --git a/tests/specs/moderation/grantModerator.spec.ts b/tests/specs/moderation/grantModerator.spec.ts deleted file mode 100644 index fc873354ef..0000000000 --- a/tests/specs/moderation/grantModerator.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { expectations } from '../../helpers/expectations'; -import { ensureOneParticipant, ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - description: 'This test checks the ability of a moderator to grant the "moderator" role to another participant. The\ - test is skipped when the "allModerators" expectation is set.', - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Grant moderator', () => { - let p1: Participant, p2: Participant; - - it('setup', async () => { - if (expectations.moderation.allModerators) { - ctx.skipSuiteTests = 'allModerators is expected'; - - return; - } - - await ensureOneParticipant(); - p1 = ctx.p1; - expect(await p1.isModerator()).toBe(true); - - const functionAvailable = await p1.execute(() => typeof APP.conference._room.grantOwner === 'function'); - - if (expectations.moderation.grantModerator) { - expect(functionAvailable).toBe(true); - } else { - if (!functionAvailable) { - ctx.skipSuiteTests = 'grantModerator is not available and not expected'; - - return; - } - } - - await ensureTwoParticipants(); - p2 = ctx.p2; - expect(await p2.isModerator()).toBe(false); - }); - - it('grant moderator', async () => { - await p1.getFilmstrip().grantModerator(p2); - - await p2.driver.waitUntil( - () => p2.isModerator(), - { - timeout: 3000, - timeoutMsg: 'p2 did not become moderator' - } - ); - - }); -}); diff --git a/tests/specs/moderation/kick.spec.ts b/tests/specs/moderation/kick.spec.ts deleted file mode 100644 index 5fa346ea50..0000000000 --- a/tests/specs/moderation/kick.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { expectations } from '../../helpers/expectations'; -import { ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Kick', () => { - let p1: Participant, p2: Participant; - - it('setup', async () => { - await ensureTwoParticipants(); - p1 = ctx.p1; - p2 = ctx.p2; - - // We verify elsewhere (moderation.spec.ts) that the first participant is a moderator. - if (!await p1.isModerator()) { - ctx.skipSuiteTests = 'the first participant is not a moderator'; - } - }); - - it('kick (p2p disabled)', () => kickAndCheck(p1, p2)); - - it('setup (p2p enabled)', async () => { - await p1.hangup(); - await p2.hangup(); - - await ensureTwoParticipants({ - configOverwrite: { - p2p: { - enabled: true - } - } - }); - p1 = ctx.p1; - p2 = ctx.p2; - }); - - it('kick (p2p enabled)', async () => { - await kickAndCheck(p1, p2); - }); - - it('non-moderator cannot kick', async () => { - if (!expectations.moderation.allModerators) { - await ensureTwoParticipants(); - p2 = ctx.p2; - expect(await p2.isModerator()).toBe(false); - - await p2.execute( - epId => APP.conference._room.kickParticipant(epId, 'for funzies'), - await p1.getEndpointId() - ); - - await p1.driver.pause(3000); - expect(await p1.isInMuc()).toBe(true); - } - }); -}); - -/** - * Kicks the second participant and checks that the participant is removed from the conference and that dialogue is open. - */ -async function kickAndCheck(kicker: Participant, kickee: Participant) { - await kicker.getFilmstrip().kickParticipant(await kickee.getEndpointId()); - await kicker.waitForParticipants(0); - - // check that the kicked participant sees the kick reason dialog - await kickee.driver.waitUntil( - async () => kickee.isLeaveReasonDialogOpen(), { - timeout: 2000, - timeoutMsg: 'No leave reason dialog shown for p2' - }); -} diff --git a/tests/specs/moderation/lobby.spec.ts b/tests/specs/moderation/lobby.spec.ts deleted file mode 100644 index c89cc76ea4..0000000000 --- a/tests/specs/moderation/lobby.spec.ts +++ /dev/null @@ -1,517 +0,0 @@ -import { P1, P3, Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { expectations } from '../../helpers/expectations'; -import { - ensureOneParticipant, - ensureThreeParticipants, - ensureTwoParticipants, - hangupAllParticipants -} from '../../helpers/participants'; -import type { IJoinOptions } from '../../helpers/types'; -import type PreMeetingScreen from '../../pageobjects/PreMeetingScreen'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -describe('Lobby', () => { - it('joining the meeting', async () => { - await ensureOneParticipant(); - - if (!await ctx.p1.execute(() => APP.conference._room.isLobbySupported())) { - ctx.skipSuiteTests = 'The environment does not support lobby.'; - } - }); - - it('enable', async () => { - await ensureTwoParticipants(); - - await enableLobby(); - }); - - it('entering in lobby and approve', async () => { - const { p1, p2 } = ctx; - - await enterLobby(p1, true); - - const { p3 } = ctx; - - await p1.getNotifications().allowLobbyParticipant(); - - const notificationText = await p2.getNotifications().getLobbyParticipantAccessGranted(); - - expect(notificationText.includes(P1)).toBe(true); - expect(notificationText.includes(P3)).toBe(true); - - await p2.getNotifications().closeLobbyParticipantAccessGranted(); - - // ensure 3 participants in the call will check for the third one that muc is joined, ice connected, - // media is being receiving and there are two remote streams - await p3.waitToJoinMUC(); - await p3.waitForIceConnected(); - await p3.waitForSendReceiveData(); - await p3.waitForRemoteStreams(2); - - // now check third one display name in the room, is the one set in the prejoin screen - const name = await p1.getFilmstrip().getRemoteDisplayName(await p3.getEndpointId()); - - expect(name).toBe(P3); - - await p3.hangup(); - }); - - it('entering in lobby and deny', async () => { - const { p1, p2 } = ctx; - - // the first time tests is executed we need to enter display name, - // for next execution that will be locally stored - await enterLobby(p1, false); - - // moderator rejects access - await p1.getNotifications().rejectLobbyParticipant(); - - // deny notification on 2nd participant - const notificationText = await p2.getNotifications().getLobbyParticipantAccessDenied(); - - expect(notificationText.includes(P1)).toBe(true); - expect(notificationText.includes(P3)).toBe(true); - - await p2.getNotifications().closeLobbyParticipantAccessDenied(); - - const { p3 } = ctx; - - // check the denied one is out of lobby, sees the notification about it - await p3.getNotifications().waitForLobbyAccessDeniedNotification(); - - expect(await p3.getLobbyScreen().isLobbyRoomJoined()).toBe(false); - - await p3.hangup(); - }); - - - it('approve from participants pane', async () => { - const { p1 } = ctx; - - const knockingParticipant = await enterLobby(p1, false); - - // moderator allows access - const p1ParticipantsPane = p1.getParticipantsPane(); - - await p1ParticipantsPane.open(); - await p1ParticipantsPane.admitLobbyParticipant(knockingParticipant); - await p1ParticipantsPane.close(); - - const { p3 } = ctx; - - // ensure 3 participants in the call will check for the third one that muc is joined, ice connected, - // media is being receiving and there are two remote streams - await p3.waitToJoinMUC(); - await p3.waitForIceConnected(); - await p3.waitForSendReceiveData(); - await p3.waitForRemoteStreams(2); - - // now check third one display name in the room, is the one set in the prejoin screen - // now check third one display name in the room, is the one set in the prejoin screen - const name = await p1.getFilmstrip().getRemoteDisplayName(await p3.getEndpointId()); - - expect(name).toBe(P3); - - await p3.hangup(); - }); - - it('reject from participants pane', async () => { - const { p1 } = ctx; - - const knockingParticipant = await enterLobby(p1, false); - - // moderator rejects access - const p1ParticipantsPane = p1.getParticipantsPane(); - - await p1ParticipantsPane.open(); - await p1ParticipantsPane.rejectLobbyParticipant(knockingParticipant); - await p1ParticipantsPane.close(); - - const { p3 } = ctx; - - // check the denied one is out of lobby, sees the notification about it - // The third participant should see a warning that his access to the room was denied - await p3.getNotifications().waitForLobbyAccessDeniedNotification(); - - // check Lobby room not left - expect(await p3.getLobbyScreen().isLobbyRoomJoined()).toBe(false); - - await p3.hangup(); - }); - - it('lobby user leave', async () => { - const { p1 } = ctx; - - await enterLobby(p1, false); - - await ctx.p3.hangup(); - - // check that moderator (participant 1) no longer sees notification about participant in lobby - await p1.getNotifications().waitForHideOfKnockingParticipants(); - }); - - it('lobby persistence', async () => { - const { p1, p2 } = ctx; - - await enterLobby(p1, false); - - const { p3 } = ctx; - - expect(await p3.getLobbyScreen().isLobbyRoomJoined()).toBe(true); - - await p1.hangup(); - await p2.hangup(); - - await p3.driver.$('.dialog.leaveReason').isExisting(); - - await p3.driver.waitUntil( - async () => !await p3.getLobbyScreen().isLobbyRoomJoined(), - { - timeout: 2000, - timeoutMsg: 'p3 did not leave lobby' - } - ); - - await p3.hangup(); - }); - - it('disable while participant in lobby', async () => { - await ensureTwoParticipants(); - - const { p1 } = ctx; - - await enableLobby(); - await enterLobby(p1); - - const p1SecurityDialog = p1.getSecurityDialog(); - - await p1.getToolbar().clickSecurityButton(); - await p1SecurityDialog.waitForDisplay(); - - await p1SecurityDialog.toggleLobby(); - await p1SecurityDialog.waitForLobbyEnabled(true); - - const { p3 } = ctx; - - await p3.waitToJoinMUC(); - - expect(await p3.getLobbyScreen().isLobbyRoomJoined()).toBe(false); - }); - - it('change of moderators in lobby', async () => { - // The test below is only correct when the environment is configured to automatically elect a new moderator - // when the moderator leaves. For environments where this is not the case, the test is skipped. - if (!expectations.autoModerator) { - return; - } - await hangupAllParticipants(); - - await ensureTwoParticipants(); - - const { p1, p2 } = ctx; - - // hanging up the first one, which is moderator and second one should be - await p1.hangup(); - - await p2.driver.waitUntil( - () => p2.isModerator(), - { - timeout: 3000, - timeoutMsg: 'p2 is not moderator after p1 leaves' - } - ); - - const p2SecurityDialog = p2.getSecurityDialog(); - - await p2.getToolbar().clickSecurityButton(); - await p2SecurityDialog.waitForDisplay(); - - await p2SecurityDialog.toggleLobby(); - await p2SecurityDialog.waitForLobbyEnabled(); - - // here the important check is whether the moderator sees the knocking participant - await enterLobby(p2, false); - }); - - it('shared password', async () => { - await hangupAllParticipants(); - - await ensureTwoParticipants(); - - const { p1 } = ctx; - - await enableLobby(); - - const p1SecurityDialog = p1.getSecurityDialog(); - - await p1.getToolbar().clickSecurityButton(); - await p1SecurityDialog.waitForDisplay(); - - expect(await p1SecurityDialog.isLocked()).toBe(false); - - const roomPasscode = String(Math.trunc(Math.random() * 1_000_000)); - - await p1SecurityDialog.addPassword(roomPasscode); - - await p1.driver.waitUntil( - () => p1SecurityDialog.isLocked(), - { - timeout: 2000, - timeoutMsg: 'room did not lock for p1' - } - ); - - await enterLobby(p1, false); - - const { p3 } = ctx; - - // now fill in password - const lobbyScreen = p3.getLobbyScreen(); - - await lobbyScreen.enterPassword(roomPasscode); - - await p3.waitToJoinMUC(); - await p3.waitForIceConnected(); - await p3.waitForSendReceiveData(); - }); - - it('enable with more than two participants', async () => { - await hangupAllParticipants(); - - await ensureThreeParticipants(); - - await enableLobby(); - - // we need to check remote participants as isInMuc has not changed its value as - // the bug is triggered by presence with status 322 which is not handled correctly - const { p1, p2, p3 } = ctx; - - await p1.waitForRemoteStreams(2); - await p2.waitForRemoteStreams(2); - await p3.waitForRemoteStreams(2); - }); - - it('moderator leaves while lobby enabled', async () => { - // The test below is only correct when the environment is configured to automatically elect a new moderator - // when the moderator leaves. For environments where this is not the case, the test is skipped. - if (!expectations.autoModerator) { - return; - } - const { p1, p2, p3 } = ctx; - - await p3.hangup(); - await p1.hangup(); - - await p2.driver.waitUntil( - () => p2.isModerator(), - { - timeout: 3000, - timeoutMsg: 'p2 is not moderator after p1 leaves' - } - ); - - const lobbyScreen = p2.getLobbyScreen(); - - expect(await lobbyScreen.isLobbyRoomJoined()).toBe(true); - }); - - it('reject and approve in pre-join', async () => { - await hangupAllParticipants(); - - await ensureTwoParticipants(); - await enableLobby(); - - const { p1, p2 } = ctx; - - const knockingParticipant = await enterLobby(p1, true, true); - - // moderator rejects access - const p1ParticipantsPane = p1.getParticipantsPane(); - - await p1ParticipantsPane.open(); - await p1ParticipantsPane.rejectLobbyParticipant(knockingParticipant); - await p1ParticipantsPane.close(); - - const { p3 } = ctx; - - // check the denied one is out of lobby, sees the notification about it - // The third participant should see a warning that his access to the room was denied - await p3.getNotifications().waitForLobbyAccessDeniedNotification(); - - // check Lobby room left - expect(await p3.getLobbyScreen().isLobbyRoomJoined()).toBe(false); - - // try again entering the lobby with the third one and approve it - // check that everything is fine in the meeting - await p3.getNotifications().closeLocalLobbyAccessDenied(); - - // let's retry to enter the lobby and approve this time - const lobbyScreen = p3.getPreJoinScreen(); - - // click join button - await lobbyScreen.getJoinButton().click(); - await lobbyScreen.waitToJoinLobby(); - - // check that moderator (participant 1) sees notification about participant in lobby - const name = await p1.getNotifications().getKnockingParticipantName(); - - expect(name).toBe(P3); - expect(await lobbyScreen.isLobbyRoomJoined()).toBe(true); - - await p1ParticipantsPane.open(); - await p1ParticipantsPane.admitLobbyParticipant(knockingParticipant); - await p1ParticipantsPane.close(); - - await p3.waitForParticipants(2); - await p3.waitForRemoteStreams(2); - - expect(await p3.getFilmstrip().countVisibleThumbnails()).toBe(3); - - // Check that there are no gaps in the filmstrip after joining from lobby - await p1.getFilmstrip().assertNoGapsInFilmstrip(); - await p2.getFilmstrip().assertNoGapsInFilmstrip(); - await p3.getFilmstrip().assertNoGapsInFilmstrip(); - }); -}); - -/** - * Enable lobby and check that it is enabled. - */ -async function enableLobby() { - const { p1, p2 } = ctx; - - const p1SecurityDialog = p1.getSecurityDialog(); - - await p1.getToolbar().clickSecurityButton(); - await p1SecurityDialog.waitForDisplay(); - - expect(await p1SecurityDialog.isLobbyEnabled()).toBe(false); - - await p1SecurityDialog.toggleLobby(); - await p1SecurityDialog.waitForLobbyEnabled(); - - expect((await p2.getNotifications().getLobbyEnabledText()).includes(p1.name)).toBe(true); - - await p2.getNotifications().closeLobbyEnabled(); - - const p2SecurityDialog = p2.getSecurityDialog(); - - await p2.getToolbar().clickSecurityButton(); - await p2SecurityDialog.waitForDisplay(); - - // lobby is visible to moderators only, this depends on whether deployment is all moderators or not - if (await p2.isModerator()) { - await p2SecurityDialog.waitForLobbyEnabled(); - } else { - expect(await p2SecurityDialog.isLobbySectionPresent()).toBe(false); - } - - // let's close the security dialog, or we will not be able to click - // on popups for allow/deny participants - await p1SecurityDialog.clickCloseButton(); - await p2SecurityDialog.clickCloseButton(); -} - -/** - * Expects that lobby is enabled for the room we will try to join. - * Lobby UI is shown, enter display name and join. - * Checks Lobby UI and also that when joining the moderator sees corresponding notifications. - * - * @param participant The participant that is moderator in the meeting. - * @param enterDisplayName whether to enter display name. We need to enter display name only the first time when - * a participant sees the lobby screen, next time visiting the page display name will be pre-filled - * from local storage. - * @param usePreJoin - * @return the participant name knocking. - */ -async function enterLobby(participant: Participant, enterDisplayName = false, usePreJoin = false) { - const options: IJoinOptions = { }; - - if (usePreJoin) { - options.configOverwrite = { - prejoinConfig: { - enabled: true - } - }; - } - - await ensureThreeParticipants({ - ...options, - skipDisplayName: true, - skipWaitToJoin: true, - skipInMeetingChecks: true - }); - - const { p3 } = ctx; - let screen: PreMeetingScreen; - - // WebParticipant participant3 = getParticipant3(); - // ParentPreMeetingScreen lobbyScreen; - if (usePreJoin) { - screen = p3.getPreJoinScreen(); - } else { - screen = p3.getLobbyScreen(); - } - - // participant 3 should be now on pre-join screen - await screen.waitForLoading(); - - const displayNameInput = screen.getDisplayNameInput(); - - // check display name is visible - expect(await displayNameInput.isExisting()).toBe(true); - expect(await displayNameInput.isDisplayed()).toBe(true); - - const joinButton = screen.getJoinButton(); - - expect(await joinButton.isExisting()).toBe(true); - - if (enterDisplayName) { - let classes = await joinButton.getAttribute('class'); - - if (!usePreJoin) { - // check join button is disabled - expect(classes.includes('disabled')).toBe(true); - } - - // TODO check that password is hidden as the room does not have password - // this check needs to be added once the functionality exists - - // enter display name - await screen.enterDisplayName(P3); - - // check join button is enabled - classes = await joinButton.getAttribute('class'); - expect(classes.includes('disabled')).toBe(false); - } - - // click join button - await screen.getJoinButton().click(); - await screen.waitToJoinLobby(); - - // check no join button - await p3.driver.waitUntil( - async () => !await joinButton.isExisting() || !await joinButton.isDisplayed() || !await joinButton.isEnabled(), - { - timeout: 2_000, - timeoutMsg: 'Join button is still available for p3' - }); - - // new screen, is password button shown - const passwordButton = screen.getPasswordButton(); - - expect(await passwordButton.isExisting()).toBe(true); - expect(await passwordButton.isEnabled()).toBe(true); - - // check that moderator (participant 1) sees notification about participant in lobby - const name = await participant.getNotifications().getKnockingParticipantName(); - - expect(name).toBe(P3); - expect(await screen.isLobbyRoomJoined()).toBe(true); - - return name; -} diff --git a/tests/specs/moderation/lockRoom.spec.ts b/tests/specs/moderation/lockRoom.spec.ts deleted file mode 100644 index 32e120f31b..0000000000 --- a/tests/specs/moderation/lockRoom.spec.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { expectations } from '../../helpers/expectations'; -import { ensureOneParticipant, ensureTwoParticipants, joinSecondParticipant } from '../../helpers/participants'; -import type SecurityDialog from '../../pageobjects/SecurityDialog'; - -setTestProperties(__filename, { - description: '1. Set a room password (assert the image changes to locked). \ - 2. Join with a second participant. \ - 3. Assert password is required (and padlock is locked). \ - 4. Assert wrong password fails. \ - 5. Unlock the room (assert the padlock is unlocked) \ - 6. Assert room is unlocked and the padlock is unlocked.', - usesBrowsers: [ 'p1', 'p2' ] -}); - - -describe('Lock room', () => { - let p1: Participant, p2: Participant; - let roomKey: string; - - it('setup', async () => { - if (!expectations.moderation.setPasswordAvailable) { - ctx.skipSuiteTests = 'setPasswordAvailable is not expected to be available'; - - return; - } - - await ensureOneParticipant(); - p1 = ctx.p1; - - roomKey = `${Math.trunc(Math.random() * 1_000_000)}`; - await setPassword(p1, roomKey); - }); - it('enter participant in locked room', async () => { - // first enter wrong pin then correct one - await joinSecondParticipant({ - skipWaitToJoin: true - }); - - p2 = ctx.p2; - - const p2PasswordDialog = p2.getPasswordDialog(); - - // Submit a wrong password - await p2PasswordDialog.waitForDialog(); - await p2PasswordDialog.submitPassword(`${roomKey}1234`); - - // give some time to the password prompt to disappear and send the password - // TODO: wait until the dialog is not displayed? Assert the room is not joined? - await p2.driver.pause(500); - - // Submit the correct password - await p2PasswordDialog.waitForDialog(); - await p2PasswordDialog.submitPassword(roomKey); - - await p2.waitToJoinMUC(); - - const p2SecurityDialog = p2.getSecurityDialog(); - - await p2.getToolbar().clickSecurityButton(); - await p2SecurityDialog.waitForDisplay(); - - await waitForRoomLockState(p2SecurityDialog, true); - }); - - it('unlock room', async () => { - await p2.hangup(); - - await removePassword(p1); - }); - - it('join the unlocked room', async () => { - // Just enter the room and check that is not locked. - await ensureTwoParticipants(); - p2 = ctx.p2; - - const p2SecurityDialog = p2.getSecurityDialog(); - - await p2.getToolbar().clickSecurityButton(); - await p2SecurityDialog.waitForDisplay(); - - await waitForRoomLockState(p2SecurityDialog, false); - await p2SecurityDialog.clickCloseButton(); - }); - - it('set password while participants are in the room', async () => { - // Both participants are in unlocked room, lock it and see whether the - // change is reflected on the second participant icon. - roomKey = `${Math.trunc(Math.random() * 1_000_000)}`; - await setPassword(p1, roomKey); - - const p2SecurityDialog = p2.getSecurityDialog(); - - await p2.getToolbar().clickSecurityButton(); - await p2SecurityDialog.waitForDisplay(); - - await waitForRoomLockState(p2SecurityDialog, true); - await removePassword(p1); - await waitForRoomLockState(p2SecurityDialog, false); - }); - it('unlock after participant enter wrong password', async () => { - // P1 locks the room. Participant tries to enter using wrong password. - // P1 unlocks the room and Participant submits the password prompt with no password entered and - // should enter of unlocked room. - await p2.hangup(); - roomKey = `${Math.trunc(Math.random() * 1_000_000)}`; - await setPassword(p1, roomKey); - await joinSecondParticipant({ - skipWaitToJoin: true - }); - p2 = ctx.p2; - - // wait for password prompt - const p2PasswordDialog = p2.getPasswordDialog(); - - await p2PasswordDialog.waitForDialog(); - await p2PasswordDialog.submitPassword(`${roomKey}1234`); - - // give sometime to the password prompt to disappear and send the password - await p2.driver.pause(500); - - // wait for password prompt - await p2PasswordDialog.waitForDialog(); - - await removePassword(p1); - - await p2PasswordDialog.clickOkButton(); - await p2.waitToJoinMUC(); - - const p2SecurityDialog = p2.getSecurityDialog(); - - await p2.getToolbar().clickSecurityButton(); - await p2SecurityDialog.waitForDisplay(); - - await waitForRoomLockState(p2SecurityDialog, false); - }); -}); - -/** - * Set a room password via the UI. - */ -async function setPassword(p: Participant, password: string) { - const securityDialog = p.getSecurityDialog(); - - await p.getToolbar().clickSecurityButton(); - await securityDialog.waitForDisplay(); - await waitForRoomLockState(securityDialog, false); - await securityDialog.addPassword(password); - await securityDialog.clickCloseButton(); - await p.getToolbar().clickSecurityButton(); - await securityDialog.waitForDisplay(); - await waitForRoomLockState(securityDialog, true); - await securityDialog.clickCloseButton(); -} - -/** - * Remove the room password via the UI. - */ -async function removePassword(p: Participant) { - const securityDialog = p.getSecurityDialog(); - - await p.getToolbar().clickSecurityButton(); - await securityDialog.waitForDisplay(); - await securityDialog.removePassword(); - await waitForRoomLockState(securityDialog, false); - await securityDialog.clickCloseButton(); -} - -/** - * Waits for the room to be locked or unlocked. - * @param securityDialog - * @param locked - */ -function waitForRoomLockState(securityDialog: SecurityDialog, locked: boolean) { - return securityDialog.participant.driver.waitUntil( - async () => await securityDialog.isLocked() === locked, - { - timeout: 3_000, // 3 seconds - timeoutMsg: `Timeout waiting for the room to unlock for ${securityDialog.participant.name}.` - } - ); -} diff --git a/tests/specs/moderation/moderation.spec.ts b/tests/specs/moderation/moderation.spec.ts deleted file mode 100644 index d538e323e5..0000000000 --- a/tests/specs/moderation/moderation.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import { expectations } from '../../helpers/expectations'; -import { joinMuc } from '../../helpers/joinMuc'; - -setTestProperties(__filename, { - description: 'This test asserts that participants have the expected role ("moderator" or not). Failures here\ - most likely indicate that the environment or test framework is misconfigured.', - usesBrowsers: [ 'p1', 'p2' ] -}); - -// Just make sure that users are given moderator rights as specified in the expectations config. -describe('Moderation', () => { - let p1: Participant, p2: Participant; - - it('setup', async () => { - p1 = await joinMuc({ name: 'p1', token: testsConfig.jwt.preconfiguredToken }); - p2 = await joinMuc({ name: 'p2', token: testsConfig.jwt.preconfiguredToken }); - }); - it('first moderator', async () => { - if (expectations.moderation.firstModerator) { - expect(await p1.isModerator()).toBe(true); - } else { - expect(await p1.isModerator()).toBe(false); - } - }); - it('all moderators', async () => { - if (expectations.moderation.allModerators) { - expect(await p1.isModerator()).toBe(true); - expect(await p2.isModerator()).toBe(true); - } - }); - it('auto moderator promotion', async () => { - if (expectations.moderation.autoModerator && !expectations.moderation.allModerators) { - expect(await p1.isModerator()).toBe(true); - expect(await p2.isModerator()).toBe(false); - await p1.hangup(); - await p2.driver.waitUntil(async () => (await p2.isModerator())); - } - }); -}); diff --git a/tests/specs/ui/chatPanel.spec.ts b/tests/specs/ui/chatPanel.spec.ts deleted file mode 100644 index 78949abba2..0000000000 --- a/tests/specs/ui/chatPanel.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ensureOneParticipant } from '../../helpers/participants'; - -describe('Chat panel', () => { - it('join participant', () => ensureOneParticipant()); - - it('start closed', async () => { - expect(await ctx.p1.getChatPanel().isOpen()).toBe(false); - }); - it('open', async () => { - const { p1 } = ctx; - - await p1.getToolbar().clickChatButton(); - expect(await p1.getChatPanel().isOpen()).toBe(true); - }); - it('use shortcut to close', async () => { - const chatPanel = ctx.p1.getChatPanel(); - - await chatPanel.pressShortcut(); - expect(await chatPanel.isOpen()).toBe(false); - }); - it('use shortcut to open', async () => { - const chatPanel = ctx.p1.getChatPanel(); - - await chatPanel.pressShortcut(); - expect(await chatPanel.isOpen()).toBe(true); - }); - it('use button to open', async () => { - const { p1 } = ctx; - - await p1.getToolbar().clickCloseChatButton(); - expect(await p1.getChatPanel().isOpen()).toBe(false); - }); -}); diff --git a/tests/specs/ui/displayName.spec.ts b/tests/specs/ui/displayName.spec.ts deleted file mode 100644 index 80b6fd90bb..0000000000 --- a/tests/specs/ui/displayName.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Display name', () => { - it('joining the meeting', () => ensureTwoParticipants({ skipDisplayName: true })); - - it('check change', async () => { - const { p1, p2 } = ctx; - - // default remote display name - const defaultDisplayName = await p1.execute(() => config.defaultRemoteDisplayName); - const p1EndpointId = await p1.getEndpointId(); - const p2EndpointId = await p2.getEndpointId(); - - // Checks whether default display names are set and shown, when both sides still miss the display name. - expect(await p1.getFilmstrip().getRemoteDisplayName(p2EndpointId)).toBe(defaultDisplayName); - expect(await p2.getFilmstrip().getRemoteDisplayName(p1EndpointId)).toBe(defaultDisplayName); - - const randomName = `Name${Math.trunc(Math.random() * 1_000_000)}`; - - await p2.setLocalDisplayName(randomName); - expect(await p2.getLocalDisplayName()).toBe(randomName); - expect(await p1.getFilmstrip().getRemoteDisplayName(p2EndpointId)).toBe(randomName); - }); - - it('check persistence', async () => { - const { p2 } = ctx; - const randomName = `Name${Math.trunc(Math.random() * 1_000_000)}`; - - await p2.setLocalDisplayName(randomName); - - expect(await p2.getLocalDisplayName()).toBe(randomName); - - await p2.hangup(); - - await ensureTwoParticipants({ - skipDisplayName: true - }); - - expect(await p2.getLocalDisplayName()).toBe(randomName); - }); -}); diff --git a/tests/specs/ui/endConference.spec.ts b/tests/specs/ui/endConference.spec.ts deleted file mode 100644 index eeccacd3fe..0000000000 --- a/tests/specs/ui/endConference.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Hangup', () => { - it('joining the meeting', () => ensureTwoParticipants()); - - it('hangup call and check', async () => { - const { p1 } = ctx; - const url = await p1.driver.getUrl(); - - await p1.getToolbar().clickHangupButton(); - - await p1.driver.waitUntil( - async () => await p1.driver.getUrl() !== url, - { - timeout: 5000, - timeoutMsg: 'p1 did not navigate away from the conference' - } - ); - }); -}); diff --git a/tests/specs/ui/lockRoomDigitsOnly.spec.ts b/tests/specs/ui/lockRoomDigitsOnly.spec.ts deleted file mode 100644 index 5b359c028b..0000000000 --- a/tests/specs/ui/lockRoomDigitsOnly.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import { expectations } from '../../helpers/expectations'; -import { joinMuc } from '../../helpers/joinMuc'; - -setTestProperties(__filename, { - description: ' Tests that the digits only password feature works. When the roomPasswordNumberOfDigits config \ - option is set, the UI should only allow setting the password to a string of digits (with the given length).' -}); -describe('Lock room with digits only', () => { - let p: Participant; - - it('setup', async () => { - if (!expectations.moderation.setPasswordAvailable) { - ctx.skipSuiteTests = 'setPasswordAvailable is not expected to be available'; - - return; - } - - p = await joinMuc({ - name: 'p1', - token: testsConfig.jwt.preconfiguredToken - }, { - configOverwrite: { - roomPasswordNumberOfDigits: 5 - } - }); - }); - - it('config value', async () => { - expect(await p.execute( - () => APP.store.getState()['features/base/config'].roomPasswordNumberOfDigits)).toBe(5); - }); - it('set an invalid password', async () => { - const securityDialog = p.getSecurityDialog(); - - await p.getToolbar().clickSecurityButton(); - await securityDialog.waitForDisplay(); - - expect(await securityDialog.isLocked()).toBe(false); - - // Set a non-numeric password. - await securityDialog.addPassword('AAAAA'); - - expect(await securityDialog.isLocked()).toBe(false); - await securityDialog.clickCloseButton(); - }); - it('set a valid password', async () => { - const securityDialog = p.getSecurityDialog(); - - await p.getToolbar().clickSecurityButton(); - await securityDialog.waitForDisplay(); - - await securityDialog.addPassword('12345'); - await securityDialog.clickCloseButton(); - - await p.getToolbar().clickSecurityButton(); - await securityDialog.waitForDisplay(); - - expect(await securityDialog.isLocked()).toBe(true); - }); -}); diff --git a/tests/specs/ui/oneOnOne.spec.ts b/tests/specs/ui/oneOnOne.spec.ts deleted file mode 100644 index 0a51f4a536..0000000000 --- a/tests/specs/ui/oneOnOne.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { - ensureThreeParticipants, - ensureTwoParticipants -} from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2', 'p3' ] -}); - -const ONE_ON_ONE_CONFIG_OVERRIDES = { - configOverwrite: { - disable1On1Mode: false, - toolbarConfig: { - timeout: 500, - alwaysVisible: false - } - } -}; - -describe('One-on-one (1on1) mode', () => { - it('filmstrip hidden in 1on1', async () => { - await ensureTwoParticipants(ONE_ON_ONE_CONFIG_OVERRIDES); - - const { p1, p2 } = ctx; - - await configureToolbarsToHideQuickly(p1); - await configureToolbarsToHideQuickly(p2); - - await p1.getFilmstrip().verifyRemoteVideosDisplay(false); - await p2.getFilmstrip().verifyRemoteVideosDisplay(false); - }); - - it('filmstrip visible with more than 2', async () => { - await ensureThreeParticipants(ONE_ON_ONE_CONFIG_OVERRIDES); - - const { p1, p2, p3 } = ctx; - - await configureToolbarsToHideQuickly(p3); - - await p1.getFilmstrip().verifyRemoteVideosDisplay(true); - await p2.getFilmstrip().verifyRemoteVideosDisplay(true); - await p3.getFilmstrip().verifyRemoteVideosDisplay(true); - }); - - it('filmstrip display when returning to 1on1', async () => { - const { p1, p2, p3 } = ctx; - - await p2.getFilmstrip().pinParticipant(p2); - - await p3.hangup(); - - await p1.getFilmstrip().verifyRemoteVideosDisplay(false); - await p2.getFilmstrip().verifyRemoteVideosDisplay(true); - }); - - it('filmstrip visible on self view focus', async () => { - const { p1 } = ctx; - - await p1.getFilmstrip().pinParticipant(p1); - await p1.getFilmstrip().verifyRemoteVideosDisplay(true); - - await p1.getFilmstrip().unpinParticipant(p1); - await p1.getFilmstrip().verifyRemoteVideosDisplay(false); - }); - - it('filmstrip hover show videos', async () => { - const { p1 } = ctx; - - await p1.getFilmstrip().hoverOverLocalVideo(); - - await p1.getFilmstrip().verifyRemoteVideosDisplay(true); - }); -}); - -/** - * Hangs up all participants (p1, p2 and p3) - * @returns {Promise} - */ -function configureToolbarsToHideQuickly(participant: Participant): Promise { - return participant.execute(() => { - APP.UI.dockToolbar(false); - APP.UI.showToolbar(250); - }); -} diff --git a/tests/specs/ui/preJoin.spec.ts b/tests/specs/ui/preJoin.spec.ts deleted file mode 100644 index dfb1d55a0a..0000000000 --- a/tests/specs/ui/preJoin.spec.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureOneParticipant, joinFirstParticipant, joinSecondParticipant } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Pre-join screen', () => { - it('display name required', async () => { - await joinFirstParticipant({ - configOverwrite: { - prejoinConfig: { - enabled: true, - }, - requireDisplayName: true - }, - skipDisplayName: true, - skipWaitToJoin: true - }); - - const p1PreJoinScreen = ctx.p1.getPreJoinScreen(); - - await p1PreJoinScreen.waitForLoading(); - - const joinButton = p1PreJoinScreen.getJoinButton(); - - await joinButton.waitForDisplayed(); - await joinButton.click(); - - const error = p1PreJoinScreen.getErrorOnJoin(); - - await error.waitForDisplayed(); - - await ctx.p1.hangup(); - }); - - it('without lobby', async () => { - await joinFirstParticipant({ - configOverwrite: { - prejoinConfig: { - enabled: true, - } - }, - skipDisplayName: true, - skipWaitToJoin: true - }); - - const p1PreJoinScreen = ctx.p1.getPreJoinScreen(); - - await p1PreJoinScreen.waitForLoading(); - - const joinButton = p1PreJoinScreen.getJoinButton(); - - await joinButton.waitForDisplayed(); - - await ctx.p1.hangup(); - }); - - it('without audio', async () => { - await joinFirstParticipant({ - configOverwrite: { - prejoinConfig: { - enabled: true, - } - }, - skipDisplayName: true, - skipWaitToJoin: true - }); - - const { p1 } = ctx; - - const p1PreJoinScreen = p1.getPreJoinScreen(); - - await p1PreJoinScreen.waitForLoading(); - - await p1PreJoinScreen.getJoinOptions().click(); - - const joinWithoutAudioBtn = p1PreJoinScreen.getJoinWithoutAudioButton(); - - await joinWithoutAudioBtn.waitForClickable(); - await joinWithoutAudioBtn.click(); - - await p1.waitToJoinMUC(); - - await p1.driver.$('//div[contains(@class, "audio-preview")]//div[contains(@class, "toolbox-icon") ' - + 'and contains(@class, "toggled") and contains(@class, "disabled")]') - .waitForDisplayed(); - - await ctx.p1.hangup(); - }); - - it('with lobby', async () => { - await ensureOneParticipant(); - - const { p1 } = ctx; - - const p1SecurityDialog = p1.getSecurityDialog(); - - await p1.getToolbar().clickSecurityButton(); - await p1SecurityDialog.waitForDisplay(); - - expect(await p1SecurityDialog.isLobbyEnabled()).toBe(false); - - await p1SecurityDialog.toggleLobby(); - await p1SecurityDialog.waitForLobbyEnabled(); - - await joinSecondParticipant({ - configOverwrite: { - prejoinConfig: { - enabled: true, - } - }, - skipDisplayName: true, - skipWaitToJoin: true - }); - - const p1PreJoinScreen = ctx.p2.getPreJoinScreen(); - - await p1PreJoinScreen.waitForLoading(); - - const joinButton = p1PreJoinScreen.getJoinButton(); - - await joinButton.waitForDisplayed(); - - }); -}); diff --git a/tests/specs/ui/selfView.spec.ts b/tests/specs/ui/selfView.spec.ts deleted file mode 100644 index 62c51b7730..0000000000 --- a/tests/specs/ui/selfView.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { ensureTwoParticipants } from '../../helpers/participants'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Self view', () => { - it('joining the meeting', () => ensureTwoParticipants()); - - it('hide from menu', async () => { - const { p1 } = ctx; - - await checkSelfViewHidden(p1, false); - - await p1.getFilmstrip().hideSelfView(); - - await checkSelfViewHidden(p1, true, true); - - await p1.getToolbar().clickEnterTileViewButton(); - - await checkSelfViewHidden(p1, true); - }); - - it('show from settings', async () => { - const { p1 } = ctx; - - await toggleSelfViewFromSettings(p1, false); - - await checkSelfViewHidden(p1, false); - }); - - it('hide from settings', async () => { - const { p1 } = ctx; - - await toggleSelfViewFromSettings(p1, true); - await checkSelfViewHidden(p1, true, true); - }); - - it('check in alone meeting', async () => { - const { p1, p2 } = ctx; - - await checkSelfViewHidden(p1, true); - await p2.hangup(); - await checkSelfViewHidden(p1, true); - }); -}); - -/** - * Toggles the self view option from the settings dialog. - */ -async function toggleSelfViewFromSettings(participant: Participant, hide: boolean) { - await participant.getToolbar().clickSettingsButton(); - - const settings = participant.getSettingsDialog(); - - await settings.waitForDisplay(); - await settings.setHideSelfView(hide); - await settings.submit(); -} - -/** - * Checks whether the local self view is displayed or not. - */ -async function checkSelfViewHidden(participant: Participant, hidden: boolean, checkNotification = false) { - if (checkNotification) { - await participant.getNotifications().waitForReEnableSelfViewNotification(); - await participant.getNotifications().closeReEnableSelfViewNotification(); - } - - await participant.getFilmstrip().assertSelfViewIsHidden(hidden); -} diff --git a/tests/specs/ui/tileView.spec.ts b/tests/specs/ui/tileView.spec.ts deleted file mode 100644 index e7f27984cb..0000000000 --- a/tests/specs/ui/tileView.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Participant } from '../../helpers/Participant'; -import { setTestProperties } from '../../helpers/TestProperties'; -import { config as testsConfig } from '../../helpers/TestsConfig'; -import { joinMuc } from '../../helpers/joinMuc'; - -/** - * The CSS selector for local video when outside of tile view. It should - * be in a container separate from remote videos so remote videos can - * scroll while local video stays docked. - */ -const FILMSTRIP_VIEW_LOCAL_VIDEO_CSS_SELECTOR = '#filmstripLocalVideo #localVideoContainer'; - -/** - * The CSS selector for local video tile view is enabled. It should display - * at the end of all the other remote videos, as the last tile. - */ -const TILE_VIEW_LOCAL_VIDEO_CSS_SELECTOR = '.remote-videos #localVideoContainer'; - -setTestProperties(__filename, { - usesBrowsers: [ 'p1', 'p2' ] -}); - -describe('Tile view', () => { - let p1: Participant, p2: Participant; - - before('join the meeting', async () => { - p1 = await joinMuc({ name: 'p1', token: testsConfig.jwt.preconfiguredToken }); - p2 = await joinMuc({ name: 'p2' }); - }); - it('entering tile view', async () => { - await p1.getToolbar().clickEnterTileViewButton(); - await p1.waitForTileViewDisplayed(); - }); - it('exit tile view by pinning', async () => { - await p1.getFilmstrip().pinParticipant(p2); - await p1.waitForTileViewDisplayed(true); - }); - it('local video is displayed in tile view', async () => { - await p1.getToolbar().clickEnterTileViewButton(); - await p1.waitForTileViewDisplayed(); - await p1.driver.$(TILE_VIEW_LOCAL_VIDEO_CSS_SELECTOR).waitForDisplayed({ timeout: 3000 }); - await p1.driver.$(FILMSTRIP_VIEW_LOCAL_VIDEO_CSS_SELECTOR).waitForDisplayed({ - timeout: 3000, - reverse: true - }); - }); - it('exit tile view by clicking "exit tile view"', async () => { - await p1.getToolbar().clickExitTileViewButton(); - await p1.waitForTileViewDisplayed(true); - }); - it('local video display independently from remote', async () => { - await p1.driver.$(TILE_VIEW_LOCAL_VIDEO_CSS_SELECTOR).waitForDisplayed({ - timeout: 3000, - reverse: true - }); - await p1.driver.$(FILMSTRIP_VIEW_LOCAL_VIDEO_CSS_SELECTOR).waitForDisplayed({ timeout: 3000 }); - }); -}); diff --git a/tests/specs/ui/videoLayout.spec.ts b/tests/specs/ui/videoLayout.spec.ts deleted file mode 100644 index ac518b4eb0..0000000000 --- a/tests/specs/ui/videoLayout.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ensureOneParticipant } from '../../helpers/participants'; - -describe('Video layout', () => { - it('join participant', () => ensureOneParticipant()); - - it('check', async () => { - const { p1 } = ctx; - - const innerWidth = parseInt(await p1.execute('return window.innerWidth'), 10); - const innerHeight = parseInt(await p1.execute('return window.innerHeight'), 10); - - const largeVideo = p1.driver.$('//div[@id="largeVideoContainer"]'); - const filmstrip = p1.driver.$('//div[contains(@class, "filmstrip")]'); - let filmstripWidth; - - if (!await filmstrip.isExisting() || !await filmstrip.isDisplayed()) { - filmstripWidth = 0; - } else { - filmstripWidth = await filmstrip.getSize('width'); - } - - const largeVideoSize = await largeVideo.getSize(); - - expect((largeVideoSize.width === (innerWidth - filmstripWidth)) || (largeVideoSize.height === innerHeight)) - .toBe(true); - }); -});