mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2025-12-30 03:12:29 +00:00
feat(tests): Adds desktop sharing test.
This commit is contained in:
@@ -5,6 +5,7 @@ const AUDIO_UNMUTE = 'Unmute microphone';
|
||||
const CHAT = 'Open chat';
|
||||
const CLOSE_CHAT = 'Close chat';
|
||||
const CLOSE_PARTICIPANTS_PANE = 'Close participants pane';
|
||||
const DESKTOP = 'Start sharing your screen';
|
||||
const HANGUP = 'Leave the meeting';
|
||||
const OVERFLOW_MENU = 'More actions menu';
|
||||
const OVERFLOW = 'More actions';
|
||||
@@ -12,6 +13,7 @@ const PARTICIPANTS = 'Open participants pane';
|
||||
const PROFILE = 'Edit your profile';
|
||||
const RAISE_HAND = 'Raise your hand';
|
||||
const SETTINGS = 'Open settings';
|
||||
const STOP_DESKTOP = 'Stop sharing your screen';
|
||||
const ENTER_TILE_VIEW_BUTTON = 'Enter tile view';
|
||||
const EXIT_TILE_VIEW_BUTTON = 'Exit tile view';
|
||||
const VIDEO_QUALITY = 'Manage video quality';
|
||||
@@ -164,6 +166,20 @@ export default class Toolbar extends BasePageObject {
|
||||
await this.getButton(CLOSE_CHAT).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the desktop sharing button that starts desktop sharing.
|
||||
*/
|
||||
async clickDesktopSharingButton() {
|
||||
await this.getButton(DESKTOP).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the desktop sharing button to stop it.
|
||||
*/
|
||||
async clickStopDesktopSharingButton() {
|
||||
await this.getButton(STOP_DESKTOP).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the tile view button which enables tile layout.
|
||||
*/
|
||||
|
||||
353
tests/specs/4way/desktopSharing.spec.ts
Normal file
353
tests/specs/4way/desktopSharing.spec.ts
Normal file
@@ -0,0 +1,353 @@
|
||||
import { SET_AUDIO_ONLY } from '../../../react/features/base/audio-only/actionTypes';
|
||||
import type { Participant } from '../../helpers/Participant';
|
||||
import {
|
||||
ensureFourParticipants,
|
||||
ensureOneParticipant,
|
||||
ensureThreeParticipants,
|
||||
ensureTwoParticipants
|
||||
} from '../../helpers/participants';
|
||||
|
||||
describe('Desktop sharing - ', () => {
|
||||
it('start', async () => {
|
||||
await ensureTwoParticipants(ctx, {
|
||||
configOverwrite: {
|
||||
p2p: {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
});
|
||||
const { p1, p2 } = ctx;
|
||||
|
||||
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.driver.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(ctx);
|
||||
const { p1, p2, p3 } = ctx;
|
||||
|
||||
// Check if a remote screen share tile is created on all participants.
|
||||
await checkForScreensharingTile(p2, p1);
|
||||
await checkForScreensharingTile(p2, p2);
|
||||
await checkForScreensharingTile(p2, p2);
|
||||
|
||||
expect(await p3.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
});
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
// 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.
|
||||
expect(await p1.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
|
||||
// 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(ctx);
|
||||
|
||||
await checkForScreensharingTile(p1, p3);
|
||||
await checkForScreensharingTile(p2, p3);
|
||||
|
||||
// The large video should be playing on p3.
|
||||
expect(await p3.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
});
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
// 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(ctx);
|
||||
|
||||
await checkForScreensharingTile(p1, p3);
|
||||
await checkForScreensharingTile(p2, p3);
|
||||
|
||||
// The large video should be playing on p3.
|
||||
expect(await p3.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 Promise.all([ ctx.p1.hangup(), ctx.p2.hangup(), ctx.p3.hangup() ]);
|
||||
|
||||
await ensureOneParticipant(ctx, {
|
||||
configOverwrite: {
|
||||
p2p: {
|
||||
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(ctx);
|
||||
const { p2, p3 } = ctx;
|
||||
|
||||
// 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);
|
||||
|
||||
expect(await p2.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
expect(await p3.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
|
||||
// p3 leaves the call.
|
||||
await p3.hangup();
|
||||
|
||||
// Make sure p2 see's p1's share after the call switches back to p2p.
|
||||
await checkForScreensharingTile(p1, p2);
|
||||
expect(await p2.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
|
||||
// p2 starts share when in p2p.
|
||||
await p2.getToolbar().clickDesktopSharingButton();
|
||||
|
||||
// Makes sure p2's share is visible on p1.
|
||||
await checkForScreensharingTile(p2, p1);
|
||||
expect(await p1.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 Promise.all([ ctx.p1.hangup(), ctx.p2.hangup(), ctx.p3.hangup() ]);
|
||||
|
||||
await ensureOneParticipant(ctx);
|
||||
const { p1 } = ctx;
|
||||
|
||||
// a workaround to directly set audio only mode without going through the rest of the settings in the UI
|
||||
await p1.driver.execute(type => {
|
||||
APP.store.dispatch({
|
||||
type,
|
||||
audioOnly: true
|
||||
});
|
||||
APP.conference.onToggleAudioOnly();
|
||||
}, SET_AUDIO_ONLY);
|
||||
await p1.getToolbar().clickAudioMuteButton();
|
||||
|
||||
await ensureThreeParticipants(ctx, { 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(async () =>
|
||||
await p1.driver.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 Promise.all([ ctx.p1.hangup(), ctx.p2.hangup(), ctx.p3.hangup() ]);
|
||||
|
||||
await ensureOneParticipant(ctx, {
|
||||
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.driver.execute(type => {
|
||||
APP.store.dispatch({
|
||||
type,
|
||||
audioOnly: true
|
||||
});
|
||||
APP.conference.onToggleAudioOnly();
|
||||
}, SET_AUDIO_ONLY);
|
||||
|
||||
await ensureTwoParticipants(ctx, {
|
||||
skipInMeetingChecks: true,
|
||||
configOverwrite: {
|
||||
startWithAudioMuted: true
|
||||
}
|
||||
});
|
||||
await ensureThreeParticipants(ctx, {
|
||||
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.driver.execute(() => APP.UI.getLargeVideoID())).toBe(`${await p3.getEndpointId()}-v1`);
|
||||
|
||||
// the video should be playing
|
||||
await p1.driver.waitUntil(async () =>
|
||||
await p1.driver.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 Promise.all([ ctx.p1.hangup(), ctx.p2.hangup(), ctx.p3.hangup() ]);
|
||||
|
||||
await ensureThreeParticipants(ctx);
|
||||
const { p1, p2, p3 } = ctx;
|
||||
|
||||
await p3.getToolbar().clickDesktopSharingButton();
|
||||
|
||||
await p1.getToolbar().clickAudioMuteButton();
|
||||
await p3.getToolbar().clickAudioMuteButton();
|
||||
|
||||
await ensureFourParticipants(ctx, {
|
||||
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.driver.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
|
||||
|
||||
const p1EndpointId = await p1.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.driver.$(`//span[@id='participant_${p1EndpointId}']//span[@class='connection_ninja']`)
|
||||
.waitForDisplayed({
|
||||
timeout: 15_000
|
||||
});
|
||||
|
||||
const p2EndpointId = await p2.getEndpointId();
|
||||
|
||||
await p4.driver.waitUntil(async () =>
|
||||
await p4.driver.execute(epId => JitsiMeetJS.app.testing.isRemoteVideoReceived(`${epId}`),
|
||||
p2EndpointId) && await p4.driver.$(
|
||||
`//span[@id="participant_${p2EndpointId}" and contains(@class, "display-video")]`).isExisting(), {
|
||||
timeout: 15_000,
|
||||
timeoutMsg: 'expected remote video to be received 15s'
|
||||
});
|
||||
|
||||
await p4.driver.waitUntil(async () =>
|
||||
await p4.driver.execute(epId => JitsiMeetJS.app.testing.isRemoteVideoReceived(`${epId}`),
|
||||
p2EndpointId) && await p4.driver.$(
|
||||
`//span[@id="participant_${p2EndpointId}" and contains(@class, "display-video")]`).isExisting(), {
|
||||
timeout: 15_000,
|
||||
timeoutMsg: 'expected remote video to be received 15s'
|
||||
});
|
||||
|
||||
// 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.driver.$(`//span[@id='participant_${p2EndpointId}']//span[@class='connection_ninja']`)
|
||||
.waitForDisplayed({
|
||||
timeout: 15_000
|
||||
});
|
||||
|
||||
await p4.driver.waitUntil(async () =>
|
||||
await p4.driver.execute(epId => JitsiMeetJS.app.testing.isRemoteVideoReceived(`${epId}`),
|
||||
p1EndpointId) && await p4.driver.$(
|
||||
`//span[@id="participant_${p1EndpointId}" and contains(@class, "display-video")]`).isExisting(), {
|
||||
timeout: 15_000,
|
||||
timeoutMsg: 'expected remote video to be received 15s'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if a screensharing tile is displayed on the observer.
|
||||
*/
|
||||
async function checkForScreensharingTile(sharer: Participant, observer: Participant, reverse = false) {
|
||||
await observer.driver.$(`//span[@id='participant_${await sharer.getEndpointId()}-v1']`).waitForDisplayed({
|
||||
timeout: 3_000,
|
||||
reverse
|
||||
});
|
||||
}
|
||||
@@ -17,6 +17,8 @@ const allure = require('allure-commandline');
|
||||
// we need it to be able to reuse jitsi-meet code in tests
|
||||
require.extensions['.web.ts'] = require.extensions['.ts'];
|
||||
|
||||
const usingGrid = Boolean(new URL(import.meta.url).searchParams.get('grid'));
|
||||
|
||||
const chromeArgs = [
|
||||
'--allow-insecure-localhost',
|
||||
'--use-fake-ui-for-media-stream',
|
||||
@@ -33,7 +35,8 @@ const chromeArgs = [
|
||||
// Avoids - "You are checking for animations on an inactive tab, animations do not run for inactive tabs"
|
||||
// when executing waitForStable()
|
||||
'--disable-renderer-backgrounding',
|
||||
`--use-file-for-fake-audio-capture=${process.env.REMOTE_RESOURCE_PATH || 'tests/resources'}/fakeAudioStream.wav`
|
||||
`--use-file-for-fake-audio-capture=${
|
||||
usingGrid ? process.env.REMOTE_RESOURCE_PATH : 'tests/resources'}/fakeAudioStream.wav`
|
||||
];
|
||||
|
||||
if (process.env.RESOLVER_RULES) {
|
||||
|
||||
@@ -21,7 +21,10 @@ if (process.env.HEADLESS === 'true') {
|
||||
|
||||
const ffExcludes = [
|
||||
'specs/2way/iFrameParticipantsPresence.spec.ts', // FF does not support uploading files (uploadFile)
|
||||
'specs/3way/activeSpeaker.spec.ts' // FF does not support setting a file as mic input
|
||||
|
||||
// FF does not support setting a file as mic input, no dominant speaker events
|
||||
'specs/3way/activeSpeaker.spec.ts',
|
||||
'specs/4way/desktopSharing.spec.ts'
|
||||
];
|
||||
|
||||
const mergedConfig = merge(defaultConfig, {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { merge } from 'lodash-es';
|
||||
import { URL } from 'url';
|
||||
|
||||
// @ts-ignore
|
||||
import { config as defaultConfig } from './wdio.conf.ts';
|
||||
import { config as defaultConfig } from './wdio.conf.ts?grid=true';
|
||||
|
||||
const gridUrl = new URL(process.env.GRID_HOST_URL as string);
|
||||
const protocol = gridUrl.protocol.replace(':', '');
|
||||
|
||||
Reference in New Issue
Block a user