init
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
2025-09-02 14:49:16 +08:00
commit 38ba663466
2885 changed files with 391107 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
import { ensureTwoParticipants } from '../../helpers/participants';
describe('Audio only', () => {
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);
}

View File

@@ -0,0 +1,41 @@
import { ensureTwoParticipants } from '../../helpers/participants';
describe('DisplayName', () => {
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);
});
});

View File

@@ -0,0 +1,20 @@
import { ensureTwoParticipants } from '../../helpers/participants';
describe('End Conference', () => {
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'
}
);
});
});

View File

@@ -0,0 +1,52 @@
import process from 'node:process';
import { ensureOneParticipant, ensureTwoParticipants } from '../../helpers/participants';
import { cleanup, isDialInEnabled, waitForAudioFromDialInParticipant } from '../helpers/DialIn';
describe('Fake Dial-In', () => {
it('join participant', async () => {
// we execute fake dial in only if the real dial in is not enabled
// check rest url is not configured
if (process.env.DIAL_IN_REST_URL) {
ctx.skipSuiteTests = true;
return;
}
await ensureOneParticipant();
// check dial-in is enabled, so skip
if (await isDialInEnabled(ctx.p1)) {
ctx.skipSuiteTests = true;
}
});
it('open invite dialog', async () => {
await ctx.p1.getInviteDialog().open();
await ctx.p1.getInviteDialog().clickCloseButton();
});
it('invite second participant', async () => {
if (!await ctx.p1.isInMuc()) {
// local participant did not join abort
return;
}
await ensureTwoParticipants();
});
it('wait for audio from second participant', async () => {
const { p1 } = ctx;
if (!await p1.isInMuc()) {
// local participant did not join abort
return;
}
await waitForAudioFromDialInParticipant(p1);
await cleanup(p1);
});
});

View File

@@ -0,0 +1,42 @@
import { ensureOneParticipant, ensureTwoParticipants } from '../../helpers/participants';
describe('Grant moderator', () => {
it('joining the meeting', async () => {
await ensureOneParticipant();
if (await ctx.p1.execute(() => typeof APP.conference._room.grantOwner !== 'function')) {
ctx.skipSuiteTests = true;
return;
}
await ensureTwoParticipants();
});
it('grant moderator and validate', async () => {
const { p1, p2 } = ctx;
if (!await p1.isModerator()) {
ctx.skipSuiteTests = true;
return;
}
if (await p2.isModerator()) {
ctx.skipSuiteTests = true;
return;
}
await p1.getFilmstrip().grantModerator(p2);
await p2.driver.waitUntil(
() => p2.isModerator(),
{
timeout: 3000,
timeoutMsg: 'p2 did not become moderator'
}
);
});
});

View File

@@ -0,0 +1,44 @@
import { ensureTwoParticipants } from '../../helpers/participants';
describe('Kick', () => {
it('joining the meeting', async () => {
await ensureTwoParticipants();
if (!await ctx.p1.isModerator()) {
ctx.skipSuiteTests = true;
}
});
it('kick and check', () => kickParticipant2AndCheck());
it('kick p2p and check', async () => {
await ensureTwoParticipants({
configOverwrite: {
p2p: {
enabled: true
}
}
});
await kickParticipant2AndCheck();
});
});
/**
* Kicks the second participant and checks that the participant is removed from the conference and that dialog is open.
*/
async function kickParticipant2AndCheck() {
const { p1, p2 } = ctx;
await p1.getFilmstrip().kickParticipant(await p2.getEndpointId());
await p1.waitForParticipants(0);
// check that the kicked participant sees the kick reason dialog
// let's wait for this to appear at least 2 seconds
await p2.driver.waitUntil(
async () => p2.isLeaveReasonDialogOpen(), {
timeout: 2000,
timeoutMsg: 'No leave reason dialog shown for p2'
});
}

View File

@@ -0,0 +1,189 @@
import { ensureOneParticipant, ensureTwoParticipants, joinSecondParticipant } from '../../helpers/participants';
import type SecurityDialog from '../../pageobjects/SecurityDialog';
let roomKey: string;
/**
* 1. Lock the room (make sure the image changes to locked)
* 2. Join with a second browser/tab
* 3. Make sure we are required to enter a password.
* (Also make sure the padlock is locked)
* 4. Enter wrong password, make sure we are not joined in the room
* 5. Unlock the room (Make sure the padlock is unlocked)
* 6. Join again and make sure we are not asked for a password and that
* the padlock is unlocked.
*/
describe('Lock Room', () => {
it('joining the meeting', () => ensureOneParticipant());
it('locks the room', () => participant1LockRoom());
it('enter participant in locked room', async () => {
// first enter wrong pin then correct one
await joinSecondParticipant({
skipWaitToJoin: true,
skipInMeetingChecks: true
});
const { p2 } = ctx;
// 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 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 () => {
// Unlock room. Check whether room is still locked. Click remove and check whether it is unlocked.
await ctx.p2.hangup();
await participant1UnlockRoom();
});
it('enter participant in unlocked room', async () => {
// Just enter the room and check that is not locked.
// if we fail to unlock the room this one will detect it
// as participant will fail joining
await ensureTwoParticipants();
const { p2 } = ctx;
const p2SecurityDialog = p2.getSecurityDialog();
await p2.getToolbar().clickSecurityButton();
await p2SecurityDialog.waitForDisplay();
await waitForRoomLockState(p2SecurityDialog, false);
await p2SecurityDialog.clickCloseButton();
});
it('update locked state while participants in room', async () => {
// Both participants are in unlocked room, lock it and see whether the
// change is reflected on the second participant icon.
await participant1LockRoom();
const { p2 } = ctx;
const p2SecurityDialog = p2.getSecurityDialog();
await p2.getToolbar().clickSecurityButton();
await p2SecurityDialog.waitForDisplay();
await waitForRoomLockState(p2SecurityDialog, true);
await participant1UnlockRoom();
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 ctx.p2.hangup();
await participant1LockRoom();
await joinSecondParticipant({
skipWaitToJoin: true,
skipInMeetingChecks: true
});
const { p2 } = ctx;
// 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 participant1UnlockRoom();
await p2PasswordDialog.clickOkButton();
await p2.waitToJoinMUC();
const p2SecurityDialog = p2.getSecurityDialog();
await p2.getToolbar().clickSecurityButton();
await p2SecurityDialog.waitForDisplay();
await waitForRoomLockState(p2SecurityDialog, false);
});
});
/**
* Participant1 locks the room.
*/
async function participant1LockRoom() {
roomKey = `${Math.trunc(Math.random() * 1_000_000)}`;
const { p1 } = ctx;
const p1SecurityDialog = p1.getSecurityDialog();
await p1.getToolbar().clickSecurityButton();
await p1SecurityDialog.waitForDisplay();
await waitForRoomLockState(p1SecurityDialog, false);
await p1SecurityDialog.addPassword(roomKey);
await p1SecurityDialog.clickCloseButton();
await p1.getToolbar().clickSecurityButton();
await p1SecurityDialog.waitForDisplay();
await waitForRoomLockState(p1SecurityDialog, true);
await p1SecurityDialog.clickCloseButton();
}
/**
* Participant1 unlocks the room.
*/
async function participant1UnlockRoom() {
const { p1 } = ctx;
const p1SecurityDialog = p1.getSecurityDialog();
await p1.getToolbar().clickSecurityButton();
await p1SecurityDialog.waitForDisplay();
await p1SecurityDialog.removePassword();
await waitForRoomLockState(p1SecurityDialog, false);
await p1SecurityDialog.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}.`
}
);
}

View File

@@ -0,0 +1,138 @@
import type { Participant } from '../../helpers/Participant';
import {
checkForScreensharingTile,
ensureOneParticipant,
ensureTwoParticipants,
joinSecondParticipant,
muteAudioAndCheck,
unmuteAudioAndCheck,
unmuteVideoAndCheck
} from '../../helpers/participants';
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());
}

View File

@@ -0,0 +1,125 @@
import { ensureOneParticipant, joinFirstParticipant, joinSecondParticipant } from '../../helpers/participants';
describe('PreJoin', () => {
it('display name required', async () => {
await joinFirstParticipant({
configOverwrite: {
prejoinConfig: {
enabled: true,
},
requireDisplayName: true
},
skipDisplayName: true,
skipWaitToJoin: true,
skipInMeetingChecks: 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,
skipInMeetingChecks: 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,
skipInMeetingChecks: 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,
skipInMeetingChecks: true
});
const p1PreJoinScreen = ctx.p2.getPreJoinScreen();
await p1PreJoinScreen.waitForLoading();
const joinButton = p1PreJoinScreen.getJoinButton();
await joinButton.waitForDisplayed();
});
});

View File

@@ -0,0 +1,68 @@
import type { Participant } from '../../helpers/Participant';
import { ensureTwoParticipants } from '../../helpers/participants';
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);
}

View File

@@ -0,0 +1,29 @@
import type { Participant } from '../../helpers/Participant';
import { ensureTwoParticipants } from '../../helpers/participants';
describe('Single port', () => {
it('joining the meeting', () => ensureTwoParticipants());
it('test', async () => {
const { p1, p2 } = ctx;
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) : '';
}

View File

@@ -0,0 +1,41 @@
import { ensureTwoParticipants, muteVideoAndCheck, unmuteVideoAndCheck } from '../../helpers/participants';
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);
});
});

View File

@@ -0,0 +1,32 @@
import type { Participant } from '../../helpers/Participant';
import { ensureTwoParticipants } from '../../helpers/participants';
const MY_TEST_SUBJECT = 'My Test Subject';
const SUBJECT_XPATH = '//div[starts-with(@class, "subject-text")]';
describe('Subject', () => {
it('joining the meeting', () => ensureTwoParticipants({
configOverwrite: {
subject: MY_TEST_SUBJECT
}
}));
it('check', async () => {
await checkSubject(ctx.p1, MY_TEST_SUBJECT);
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);
}

View File

@@ -0,0 +1,39 @@
import { ensureTwoParticipants } from '../../helpers/participants';
describe('SwitchVideo', () => {
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();
}

View File

@@ -0,0 +1,26 @@
import type { Participant } from '../../helpers/Participant';
import { ensureTwoParticipants } from '../../helpers/participants';
describe('UDP', () => {
it('joining the meeting', () => ensureTwoParticipants());
it('check', async () => {
const { p1, p2 } = ctx;
// just in case wait 1500, this is the interval we use for `config.pcStatsInterval`
await p1.driver.pause(1500);
expect(await getProtocol(p1)).toBe('udp');
expect(await getProtocol(p2)).toBe('udp');
});
});
/**
* 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();
}

View File

@@ -0,0 +1,41 @@
import { multiremotebrowser } from '@wdio/globals';
import { config } from '../../helpers/TestsConfig';
import { ensureTwoParticipants } from '../../helpers/participants';
describe('URL Normalisation', () => {
it('joining the meeting', async () => {
// if we are running with token this becomes ugly to match the URL
if (config.jwt.preconfiguredToken) {
ctx.skipSuiteTests = true;
return;
}
// a hack to extract the baseUrl that the test will use
const baseUrl = multiremotebrowser.getInstance('p1').options.baseUrl;
if (!baseUrl) {
throw new Error('baseUrl is not set');
}
await ensureTwoParticipants({
forceTenant: 'tenant@example.com',
roomName: `${ctx.roomName}@example.com`
});
});
it('check', async () => {
const currentUrlStr = await ctx.p1.driver.getUrl();
const currentUrl = new URL(currentUrlStr);
const path = currentUrl.pathname;
const parts = path.split('/');
expect(parts[1]).toBe('tenantexample.com');
// @ts-ignore
expect(parts[2]).toBe(`${ctx.roomName}example.com`);
});
});