Files
upstream-jitsi-meet/tests/specs/misc/recordingTranscriptionDialog.spec.ts
upstream-mirror 1d2bfcac0c
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s
snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
2026-09-15 15:56:32 +05:00

194 lines
7.4 KiB
TypeScript

import { setTestProperties } from '../../helpers/TestProperties';
import { expectations } from '../../helpers/expectations';
import { ensureOneParticipant } from '../../helpers/participants';
setTestProperties(__filename, {
description: 'Unified Recording & Transcription dialog structure',
usesBrowsers: [ 'p1' ],
useJaas: true
});
describe('Recording & Transcription dialog', () => {
it('setup', async () => {
if (!expectations.jaas.recordingEnabled) {
ctx.skipSuiteTests = 'Recording is not enabled in this environment';
return;
}
if (!expectations.moderation.firstModerator) {
ctx.skipSuiteTests = 'First participant must be a moderator for these tests';
return;
}
await ensureOneParticipant();
expect(await ctx.p1.isModerator()).toBe(true);
});
it('dialog title is "Record & Transcribe"', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
expect(await dialog.getTitle()).toBe('Record & Transcribe');
await dialog.cancel();
});
it('both sections offer Start buttons when nothing is running', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
expect(await dialog.hasStartRecordingButton()).toBe(true);
expect(await dialog.hasStartTranscriptionButton()).toBe(true);
expect(await dialog.hasStopRecordingButton()).toBe(false);
expect(await dialog.hasStopTranscriptionButton()).toBe(false);
await dialog.cancel();
});
it('footer shows only "Start both" when nothing is running', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
expect(await dialog.hasStartBothButton()).toBe(true);
expect(await dialog.hasStopBothButton()).toBe(false);
await dialog.cancel();
});
it('start buttons are enabled when a recording service is available', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
// Diagnostics for intermittent failures here. The Start button's enabled state is driven
// by AbstractStartRecordingDialog's own local `this.state.selectedRecordingService` —
// that's plain React state, not redux, so APP.store.getState() can't see it.
// state['features/recording'].selectedRecordingService (read here previously) is a
// write-only mirror: it's only ever set by dispatch, when a user manually changes the
// dropdown via _onSelectedRecordingServiceChanged, and nothing reads it back into this
// component — so it reads '' in this test regardless of the real bug, which is exactly
// why it looked identical across every prior failure and told us nothing. Read the
// dropdown's own rendered text instead: it's rendered straight from the real local state.
await dialog.toggleRecordingOptions();
const diagnostics = await p1.execute(() => ({
recordingServiceConfig: config.recordingService,
localRecordingConfig: config.localRecording,
reduxRecordingServiceConfig: APP.store.getState()['features/base/config'].recordingService,
reduxLocalRecordingConfig: APP.store.getState()['features/base/config'].localRecording,
hasDropboxToken: Boolean(APP.store.getState()['features/dropbox'].token)
}));
const renderedSelectedService = await dialog.getSelectedService();
await p1.log(`Recording dialog diagnostics: ${JSON.stringify({ ...diagnostics, renderedSelectedService })}`);
expect(await dialog.isStartRecordingEnabled()).toBe(true);
expect(await dialog.isStartBothEnabled()).toBe(true);
await dialog.cancel();
});
it('options accordions are collapsed by default', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
expect(await dialog.hasRecordingOptions()).toBe(true);
expect(await dialog.hasTranscriptionOptions()).toBe(true);
expect(await dialog.isRecordingOptionsExpanded()).toBe(false);
expect(await dialog.isTranscriptionOptionsExpanded()).toBe(false);
// The dropdowns are only rendered once the accordions are expanded.
expect(await dialog.hasServiceSelect()).toBe(false);
expect(await dialog.hasLanguageSelect()).toBe(false);
await dialog.cancel();
});
it('expanding recording options reveals the storage service dropdown', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
await dialog.toggleRecordingOptions();
expect(await dialog.isRecordingOptionsExpanded()).toBe(true);
expect(await dialog.hasServiceSelect()).toBe(true);
// A service is preselected — the trigger shows its name.
expect((await dialog.getSelectedService()).length).toBeGreaterThan(0);
// Collapsing hides the options again.
await dialog.toggleRecordingOptions();
expect(await dialog.isRecordingOptionsExpanded()).toBe(false);
expect(await dialog.hasServiceSelect()).toBe(false);
await dialog.cancel();
});
it('expanding transcription options allows changing the language', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
await dialog.toggleTranscriptionOptions();
expect(await dialog.isTranscriptionOptionsExpanded()).toBe(true);
expect(await dialog.hasLanguageSelect()).toBe(true);
await dialog.selectLanguage('French');
expect(await dialog.getSelectedLanguage()).toBe('French');
await dialog.selectLanguage('English');
expect(await dialog.getSelectedLanguage()).toBe('English');
await dialog.cancel();
});
it('cancel closes the dialog without errors', async () => {
const p1 = ctx.p1;
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
await dialog.cancel();
await p1.driver.$(
'#dialog-title'
).waitForExist({ reverse: true, timeout: 3000, timeoutMsg: 'Dialog did not close after cancel' });
});
it('dialog reopens cleanly after cancel — button is still in toolbar', async () => {
const p1 = ctx.p1;
// Verify the button is still accessible and the dialog can be opened again.
expect(await p1.getToolbar().hasRecordingButton()).toBe(true);
const dialog = p1.getRecordingTranscriptionDialog();
await p1.getToolbar().clickRecordingButton();
await dialog.waitForDisplay();
expect(await dialog.getTitle()).toBe('Record & Transcribe');
await dialog.cancel();
});
});