194 lines
7.4 KiB
TypeScript
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();
|
|
});
|
|
});
|