snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
224
tests/specs/jaas/recording.spec.ts
Normal file
224
tests/specs/jaas/recording.spec.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import { Participant } from '../../helpers/Participant';
|
||||
import { setTestProperties } from '../../helpers/TestProperties';
|
||||
import { config as testsConfig } from '../../helpers/TestsConfig';
|
||||
import WebhookProxy from '../../helpers/WebhookProxy';
|
||||
import { expectations } from '../../helpers/expectations';
|
||||
import { joinJaasMuc, generateJaasToken as t } from '../../helpers/jaas';
|
||||
|
||||
setTestProperties(__filename, {
|
||||
requireWebhookProxy: true,
|
||||
retry: true,
|
||||
useJaas: true
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the recording and live-streaming functionality of JaaS (including relevant webhooks) exercising the iFrame API
|
||||
* commands and functions.
|
||||
* TODO: also assert "this meeting is being recorded" notifications are show/played?
|
||||
*/
|
||||
describe('Recording and live-streaming', () => {
|
||||
const tenant = testsConfig.jaas.tenant;
|
||||
const customerId = tenant?.replace('vpaas-magic-cookie-', '');
|
||||
let recordingEnabled: boolean;
|
||||
let liveStreamingEnabled: boolean;
|
||||
let p: Participant;
|
||||
let webhooksProxy: WebhookProxy;
|
||||
|
||||
it('setup', async () => {
|
||||
webhooksProxy = ctx.webhooksProxy;
|
||||
p = await joinJaasMuc({ iFrameApi: true, token: t({ moderator: true }) }, { roomName: ctx.roomName });
|
||||
|
||||
recordingEnabled = Boolean(await p.execute(() => config.recordingService?.enabled));
|
||||
expect(recordingEnabled).toBe(expectations.jaas.recordingEnabled);
|
||||
|
||||
liveStreamingEnabled = Boolean(await p.execute(() => config.liveStreaming?.enabled));
|
||||
expect(liveStreamingEnabled).toBe(expectations.jaas.liveStreamingEnabled);
|
||||
|
||||
if (liveStreamingEnabled && !process.env.YTUBE_TEST_STREAM_KEY) {
|
||||
liveStreamingEnabled = false;
|
||||
console.log('Skipping live-streaming tests because YTUBE_TEST_STREAM_KEY is not set.');
|
||||
}
|
||||
|
||||
await p.switchToMainFrame();
|
||||
});
|
||||
|
||||
/**
|
||||
* Starts recording and asserts that the expected iFrame and JaaS events are received.
|
||||
* @param command whether to use the "command" or the "function" iFrame API.
|
||||
*/
|
||||
async function startRecording(command: boolean) {
|
||||
await p.getIframeAPI().addEventListener('recordingStatusChanged');
|
||||
await p.getIframeAPI().addEventListener('recordingLinkAvailable');
|
||||
|
||||
if (command) {
|
||||
await p.getIframeAPI().executeCommand('startRecording', {
|
||||
mode: 'file'
|
||||
});
|
||||
} else {
|
||||
await p.getIframeAPI().startRecording({
|
||||
mode: 'file'
|
||||
});
|
||||
}
|
||||
|
||||
const jaasEvent: {
|
||||
customerId: string;
|
||||
eventType: string;
|
||||
} = await webhooksProxy.waitForEvent('RECORDING_STARTED');
|
||||
|
||||
expect('RECORDING_STARTED').toBe(jaasEvent.eventType);
|
||||
expect(jaasEvent.customerId).toBe(customerId);
|
||||
|
||||
webhooksProxy.clearCache();
|
||||
|
||||
const iFrameEvent = await p.driver.waitUntil(() =>
|
||||
p.getIframeAPI().getEventResult('recordingStatusChanged'), {
|
||||
timeout: 5000,
|
||||
timeoutMsg: 'recordingStatusChanged event not received'
|
||||
});
|
||||
|
||||
expect(iFrameEvent.mode).toBe('file');
|
||||
expect(iFrameEvent.on).toBe(true);
|
||||
|
||||
const linkEvent = await p.driver.waitUntil(() =>
|
||||
p.getIframeAPI().getEventResult('recordingLinkAvailable'), {
|
||||
timeout: 5000,
|
||||
timeoutMsg: 'recordingLinkAvailable event not received'
|
||||
});
|
||||
|
||||
expect(linkEvent.link).toStartWith('https://', 'recording link');
|
||||
expect(linkEvent.link).toContain(tenant);
|
||||
expect(linkEvent.ttl).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops recording and asserts that the expected iFrame and JaaS events are received.
|
||||
* @param command whether to use the "command" or the "function" iFrame API.
|
||||
*/
|
||||
async function stopRecording(command: boolean) {
|
||||
if (command) {
|
||||
await p.getIframeAPI().executeCommand('stopRecording', 'file');
|
||||
} else {
|
||||
await p.getIframeAPI().stopRecording('file');
|
||||
}
|
||||
|
||||
const jaasEndedEvent: {
|
||||
customerId: string;
|
||||
eventType: string;
|
||||
} = await webhooksProxy.waitForEvent('RECORDING_ENDED');
|
||||
|
||||
expect('RECORDING_ENDED').toBe(jaasEndedEvent.eventType);
|
||||
expect(jaasEndedEvent.customerId).toBe(customerId);
|
||||
|
||||
const jaasUploadedEvent: {
|
||||
customerId: string;
|
||||
data: {
|
||||
initiatorId: string;
|
||||
participants: Array<string>;
|
||||
};
|
||||
eventType: string;
|
||||
} = await webhooksProxy.waitForEvent('RECORDING_UPLOADED');
|
||||
|
||||
const jwtPayload = p.getToken()?.payload;
|
||||
|
||||
expect(jaasUploadedEvent.data.initiatorId).toBe(jwtPayload?.context?.user?.id);
|
||||
expect(jaasUploadedEvent.data.participants.some(
|
||||
// @ts-ignore
|
||||
e => e.id === jwtPayload?.context?.user?.id)).toBe(true);
|
||||
|
||||
webhooksProxy.clearCache();
|
||||
|
||||
const iFrameEvent = (await p.getIframeAPI().getEventResult('recordingStatusChanged'));
|
||||
|
||||
expect(iFrameEvent.mode).toBe('file');
|
||||
expect(iFrameEvent.on).toBe(false);
|
||||
|
||||
await p.getIframeAPI().clearEventResults('recordingStatusChanged');
|
||||
}
|
||||
|
||||
it('start/stop recording using the iFrame command', async () => {
|
||||
if (!recordingEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
await startRecording(true);
|
||||
await stopRecording(true);
|
||||
|
||||
// to avoid rate limits
|
||||
await p.driver.pause(30000);
|
||||
});
|
||||
|
||||
it('start/stop recording using the iFrame function', async () => {
|
||||
if (!recordingEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
await startRecording(false);
|
||||
await stopRecording(false);
|
||||
|
||||
// to avoid rate limits
|
||||
await p.driver.pause(30000);
|
||||
});
|
||||
|
||||
it('start/stop live-streaming using the iFrame command', async () => {
|
||||
if (!liveStreamingEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
await p.getIframeAPI().addEventListener('recordingStatusChanged');
|
||||
|
||||
await p.getIframeAPI().executeCommand('startRecording', {
|
||||
youtubeBroadcastID: process.env.YTUBE_TEST_BROADCAST_ID,
|
||||
mode: 'stream',
|
||||
youtubeStreamKey: process.env.YTUBE_TEST_STREAM_KEY
|
||||
});
|
||||
|
||||
const jaasEvent: {
|
||||
customerId: string;
|
||||
eventType: string;
|
||||
} = await webhooksProxy.waitForEvent('LIVE_STREAM_STARTED');
|
||||
|
||||
expect('LIVE_STREAM_STARTED').toBe(jaasEvent.eventType);
|
||||
expect(jaasEvent.customerId).toBe(customerId);
|
||||
|
||||
const iFrameEvent = await p.driver.waitUntil(async () => {
|
||||
const e = await p.getIframeAPI().getEventResult('recordingStatusChanged');
|
||||
|
||||
return e && e.mode === 'stream' && e.on === true ? e : false;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeoutMsg: 'recordingStatusChanged event with mode=stream, on=true not received'
|
||||
});
|
||||
|
||||
expect(iFrameEvent.mode).toBe('stream');
|
||||
expect(iFrameEvent.on).toBe(true);
|
||||
|
||||
if (process.env.YTUBE_TEST_BROADCAST_ID) {
|
||||
const liveStreamUrl = await p.getIframeAPI().getLivestreamUrl();
|
||||
|
||||
expect(liveStreamUrl.livestreamUrl).toBeDefined();
|
||||
}
|
||||
|
||||
await p.getIframeAPI().executeCommand('stopRecording', 'stream');
|
||||
|
||||
const jaasEndedEvent: {
|
||||
customerId: string;
|
||||
eventType: string;
|
||||
} = await webhooksProxy.waitForEvent('LIVE_STREAM_ENDED');
|
||||
|
||||
expect(jaasEndedEvent.eventType).toBe('LIVE_STREAM_ENDED');
|
||||
expect(jaasEndedEvent.customerId).toBe(customerId);
|
||||
|
||||
const iFrameEndedEvent = await p.driver.waitUntil(async () => {
|
||||
const e = await p.getIframeAPI().getEventResult('recordingStatusChanged');
|
||||
|
||||
return e && e.mode === 'stream' && e.on === false ? e : false;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeoutMsg: 'recordingStatusChanged event with mode=stream, on=false not received'
|
||||
});
|
||||
|
||||
expect(iFrameEndedEvent.mode).toBe('stream');
|
||||
expect(iFrameEndedEvent.on).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user