snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
56
tests/specs/moderation/grantModerator.spec.ts
Normal file
56
tests/specs/moderation/grantModerator.spec.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
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 grantOwnerType = await p1.execute(() => typeof APP.conference._room.grantOwner);
|
||||
const functionAvailable = grantOwnerType === 'function';
|
||||
|
||||
if (expectations.moderation.grantModerator) {
|
||||
expect(grantOwnerType).toBe('function');
|
||||
} 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'
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
76
tests/specs/moderation/kick.spec.ts
Normal file
76
tests/specs/moderation/kick.spec.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Participant } from '../../helpers/Participant';
|
||||
import { setTestProperties } from '../../helpers/TestProperties';
|
||||
import { expectations } from '../../helpers/expectations';
|
||||
import { ensureTwoParticipants } from '../../helpers/participants';
|
||||
|
||||
setTestProperties(__filename, {
|
||||
retry: true,
|
||||
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'
|
||||
});
|
||||
}
|
||||
512
tests/specs/moderation/lobby.spec.ts
Normal file
512
tests/specs/moderation/lobby.spec.ts
Normal file
@@ -0,0 +1,512 @@
|
||||
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';
|
||||
|
||||
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).toContain(P1);
|
||||
expect(notificationText).toContain(P3);
|
||||
|
||||
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.waitForReceiveMedia();
|
||||
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).toContain(P1);
|
||||
expect(notificationText).toContain(P3);
|
||||
|
||||
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.waitForReceiveMedia();
|
||||
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('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.waitForReceiveMedia();
|
||||
});
|
||||
|
||||
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()).toContain(p1.name);
|
||||
|
||||
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 = { };
|
||||
|
||||
options.configOverwrite = {
|
||||
prejoinConfig: {
|
||||
enabled: usePreJoin
|
||||
}
|
||||
};
|
||||
|
||||
await ensureThreeParticipants({
|
||||
...options,
|
||||
skipDisplayName: true,
|
||||
skipWaitToJoin: true,
|
||||
skipInMeetingChecks: true,
|
||||
skipPrejoinButtonClick: true
|
||||
});
|
||||
|
||||
const { p3 } = ctx;
|
||||
let screen;
|
||||
|
||||
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).toContain('disabled');
|
||||
}
|
||||
|
||||
// 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).not.toContain('disabled');
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
183
tests/specs/moderation/lockRoom.spec.ts
Normal file
183
tests/specs/moderation/lockRoom.spec.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
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}.`
|
||||
}
|
||||
);
|
||||
}
|
||||
42
tests/specs/moderation/moderation.spec.ts
Normal file
42
tests/specs/moderation/moderation.spec.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
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()));
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user