snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-15 15:56:32 +05:00
commit 1d2bfcac0c
3159 changed files with 464524 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
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);
});
});

View File

@@ -0,0 +1,46 @@
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);
});
});

View File

@@ -0,0 +1,25 @@
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'
}
);
});
});

View File

@@ -0,0 +1,63 @@
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);
});
});

View File

@@ -0,0 +1,46 @@
import { setTestProperties } from '../../helpers/TestProperties';
import { ensureTwoParticipants } from '../../helpers/participants';
setTestProperties(__filename, {
description: 'Checks the filmstrip visibility when joining from a mobile browser.',
usesBrowsers: [ 'p1', 'p2' ]
});
describe('Filmstrip on a mobile browser', () => {
before(async () => {
// Make p2's Chrome look like an iPhone so Platform.OS resolves to 'ios' and isMobileBrowser()
// returns true. emulate() persists for the session.
await multiRemoteBrowser.getInstance('p2').emulate('device', 'iPhone 15');
});
it('filmstrip and self view are visible when joining a 1:1 call', async () => {
await ensureTwoParticipants({
configOverwrite: {
// The deployment config may show the deep linking page on a mobile browser; disable it.
deeplinking: {
disabled: true
},
// The default config for tests disables 1-on-1 mode, enable it to test it.
disable1On1Mode: false
}
});
const { p2 } = ctx;
// Make sure the mobile emulation is in effect, otherwise the test silently degrades into
// testing the desktop UI.
expect(await p2.execute(() => navigator.userAgent)).toContain('iPhone');
expect(await p2.execute(() => window.innerWidth)).toBeLessThan(500);
// The whole filmstrip (including the self view) must not be hidden when joining a 1:1 call
// on a narrow/mobile client.
await p2.getFilmstrip().assertVisible();
await p2.getFilmstrip().assertSelfViewIsHidden(false);
// On mobile browsers the remote thumbnails are hidden in 1-on-1 mode even when the toolbar is
// visible (the remote participant is already on the stage), as opposed to desktop where their
// visibility follows the toolbar one.
await p2.getFilmstrip().verifyRemoteVideosDisplay(false);
});
});

View File

@@ -0,0 +1,86 @@
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<void>}
*/
function configureToolbarsToHideQuickly(participant: Participant): Promise<void> {
return participant.execute(() => {
APP.UI.dockToolbar(false);
APP.UI.showToolbar(250);
});
}

View File

@@ -0,0 +1,130 @@
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,
skipPrejoinButtonClick: 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,
skipPrejoinButtonClick: 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,
skipPrejoinButtonClick: 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,
skipPrejoinButtonClick: true
});
const p1PreJoinScreen = ctx.p2.getPreJoinScreen();
await p1PreJoinScreen.waitForLoading();
const joinButton = p1PreJoinScreen.getJoinButton();
await joinButton.waitForDisplayed();
});
});

View File

@@ -0,0 +1,73 @@
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);
}

View File

@@ -0,0 +1,58 @@
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 });
});
});

View File

@@ -0,0 +1,27 @@
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);
});
});