226 lines
7.9 KiB
TypeScript
226 lines
7.9 KiB
TypeScript
import { setTestProperties } from '../../helpers/TestProperties';
|
|
import { ensureOneParticipant } from '../../helpers/participants';
|
|
|
|
setTestProperties(__filename, {
|
|
usesBrowsers: [ 'p1' ]
|
|
});
|
|
|
|
/**
|
|
* Reads the current virtual-background slice of the Redux store.
|
|
*/
|
|
async function getVBState() {
|
|
return ctx.p1.execute(() => APP.store.getState()['features/virtual-background']);
|
|
}
|
|
|
|
/**
|
|
* Opens the virtual background dialog via the toolbar button and waits for it to be displayed.
|
|
*/
|
|
async function openVBDialog() {
|
|
await ctx.p1.getToolbar().clickVirtualBackgroundButton();
|
|
await ctx.p1.getVirtualBackgroundDialog().waitForDisplay();
|
|
}
|
|
|
|
/**
|
|
* Waits until backgroundEffectEnabled settles to the expected value.
|
|
* Needed because jitsiTrack.setEffect() is async — an effect load failure can briefly flip the
|
|
* flag to true before rolling it back to false.
|
|
* When expecting true, the value must remain stable for stabilityWindow ms to avoid passing on
|
|
* the optimistic pre-apply dispatch.
|
|
*
|
|
* @param {boolean} expected - The expected settled value.
|
|
* @param {number} timeout - How long to wait in ms.
|
|
* @param {number} stabilityWindow - How long the expected value must remain unchanged (ms).
|
|
*/
|
|
async function waitForEffectEnabled(expected: boolean, timeout = 8000, stabilityWindow = 500): Promise<void> {
|
|
let matchedAt: number | undefined;
|
|
const requiredStableMs = expected ? stabilityWindow : 0;
|
|
|
|
await ctx.p1.driver.waitUntil(
|
|
async () => {
|
|
const state = await getVBState();
|
|
|
|
if (state.backgroundEffectEnabled !== expected) {
|
|
matchedAt = undefined;
|
|
|
|
return false;
|
|
}
|
|
|
|
if (requiredStableMs === 0) {
|
|
return true;
|
|
}
|
|
|
|
const now = Date.now();
|
|
|
|
if (matchedAt === undefined) {
|
|
matchedAt = now;
|
|
|
|
return false;
|
|
}
|
|
|
|
return now - matchedAt >= requiredStableMs;
|
|
},
|
|
{ timeout, timeoutMsg: `backgroundEffectEnabled did not settle to ${expected} within ${timeout}ms` }
|
|
);
|
|
}
|
|
|
|
describe('Virtual backgrounds', () => {
|
|
it('joining the meeting', async () => {
|
|
await ensureOneParticipant({
|
|
configOverwrite: {
|
|
disableVirtualBackground: false
|
|
}
|
|
});
|
|
});
|
|
|
|
it('open virtual background dialog', async () => {
|
|
await openVBDialog();
|
|
expect(await ctx.p1.getVirtualBackgroundDialog().isDisplayed()).toBe(true);
|
|
});
|
|
|
|
it('select none — aria-checked and redux state', async () => {
|
|
const vbDialog = ctx.p1.getVirtualBackgroundDialog();
|
|
|
|
await vbDialog.clickNone();
|
|
expect(await vbDialog.isNoneChecked()).toBe(true);
|
|
expect(await vbDialog.isBlurChecked()).toBe(false);
|
|
expect(await vbDialog.isSlightBlurChecked()).toBe(false);
|
|
|
|
await vbDialog.confirm();
|
|
await waitForEffectEnabled(false);
|
|
|
|
const state = await getVBState();
|
|
|
|
expect(state.backgroundEffectEnabled).toBe(false);
|
|
expect(state.selectedThumbnail).toBe('none');
|
|
});
|
|
|
|
it('select slight blur — aria-checked and redux state', async () => {
|
|
await openVBDialog();
|
|
const vbDialog = ctx.p1.getVirtualBackgroundDialog();
|
|
|
|
await vbDialog.clickSlightBlur();
|
|
expect(await vbDialog.isSlightBlurChecked()).toBe(true);
|
|
expect(await vbDialog.isNoneChecked()).toBe(false);
|
|
expect(await vbDialog.isBlurChecked()).toBe(false);
|
|
|
|
await vbDialog.confirm();
|
|
|
|
// This is the first real (non-preview) effect enable in the suite, so — like
|
|
// "select full blur" below — it pays the cold-start cost of spinning up the
|
|
// segmentation worker on the actual conference track. The default 8s timeout is
|
|
// tuned for a warm worker and flakes on this one.
|
|
await waitForEffectEnabled(true, 15000);
|
|
|
|
const state = await getVBState();
|
|
|
|
expect(state.backgroundEffectEnabled).toBe(true);
|
|
expect(state.backgroundType).toBe('blur');
|
|
expect(state.blurValue).toBe(8);
|
|
expect(state.selectedThumbnail).toBe('slight-blur');
|
|
});
|
|
|
|
it('select full blur — aria-checked and redux state', async () => {
|
|
await openVBDialog();
|
|
const vbDialog = ctx.p1.getVirtualBackgroundDialog();
|
|
|
|
await vbDialog.clickBlur();
|
|
expect(await vbDialog.isBlurChecked()).toBe(true);
|
|
expect(await vbDialog.isNoneChecked()).toBe(false);
|
|
expect(await vbDialog.isSlightBlurChecked()).toBe(false);
|
|
|
|
await vbDialog.confirm();
|
|
|
|
// Wait long enough for the async setEffect() to complete without rolling back.
|
|
// A false value here would mean the effect threw and backgroundEffectEnabled was reset.
|
|
await waitForEffectEnabled(true, 15000);
|
|
|
|
const state = await getVBState();
|
|
|
|
expect(state.backgroundEffectEnabled).toBe(true);
|
|
expect(state.backgroundType).toBe('blur');
|
|
expect(state.blurValue).toBe(25);
|
|
expect(state.selectedThumbnail).toBe('blur');
|
|
});
|
|
|
|
it('disable background — redux state correct', async () => {
|
|
await openVBDialog();
|
|
const vbDialog = ctx.p1.getVirtualBackgroundDialog();
|
|
|
|
await vbDialog.clickNone();
|
|
await vbDialog.confirm();
|
|
|
|
await waitForEffectEnabled(false);
|
|
|
|
const state = await getVBState();
|
|
|
|
expect(state.backgroundEffectEnabled).toBe(false);
|
|
expect(state.selectedThumbnail).toBe('none');
|
|
});
|
|
|
|
it('rapid switching before confirm — only last selection applied', async () => {
|
|
await openVBDialog();
|
|
const vbDialog = ctx.p1.getVirtualBackgroundDialog();
|
|
|
|
// Click through several blur options quickly without confirming between them
|
|
await vbDialog.clickBlur();
|
|
await vbDialog.clickNone();
|
|
await vbDialog.clickSlightBlur();
|
|
await vbDialog.clickBlur();
|
|
await vbDialog.clickSlightBlur();
|
|
|
|
// Slight blur should be the active selection in the dialog
|
|
expect(await vbDialog.isSlightBlurChecked()).toBe(true);
|
|
expect(await vbDialog.isBlurChecked()).toBe(false);
|
|
expect(await vbDialog.isNoneChecked()).toBe(false);
|
|
|
|
await vbDialog.confirm();
|
|
await waitForEffectEnabled(true);
|
|
|
|
const state = await getVBState();
|
|
|
|
expect(state.selectedThumbnail).toBe('slight-blur');
|
|
expect(state.backgroundType).toBe('blur');
|
|
expect(state.blurValue).toBe(8);
|
|
});
|
|
|
|
it('cancel discards selection — redux state unchanged', async () => {
|
|
// Precondition: slight-blur is applied from the previous test
|
|
const stateBefore = await getVBState();
|
|
|
|
await openVBDialog();
|
|
const vbDialog = ctx.p1.getVirtualBackgroundDialog();
|
|
|
|
await vbDialog.clickBlur();
|
|
expect(await vbDialog.isBlurChecked()).toBe(true);
|
|
|
|
await vbDialog.cancel();
|
|
|
|
const stateAfter = await getVBState();
|
|
|
|
expect(stateAfter.selectedThumbnail).toBe(stateBefore.selectedThumbnail);
|
|
expect(stateAfter.backgroundEffectEnabled).toBe(stateBefore.backgroundEffectEnabled);
|
|
expect(stateAfter.backgroundType).toBe(stateBefore.backgroundType);
|
|
});
|
|
|
|
it('persistence across reopen — previously applied thumbnail shown as selected', async () => {
|
|
// Apply full blur
|
|
await openVBDialog();
|
|
await ctx.p1.getVirtualBackgroundDialog().clickBlur();
|
|
await ctx.p1.getVirtualBackgroundDialog().confirm();
|
|
await waitForEffectEnabled(true, 15000);
|
|
|
|
// Reopen and verify blur is still aria-checked
|
|
await openVBDialog();
|
|
const vbDialog = ctx.p1.getVirtualBackgroundDialog();
|
|
|
|
expect(await vbDialog.isBlurChecked()).toBe(true);
|
|
expect(await vbDialog.isSlightBlurChecked()).toBe(false);
|
|
expect(await vbDialog.isNoneChecked()).toBe(false);
|
|
|
|
// Clean up
|
|
await vbDialog.clickNone();
|
|
await vbDialog.confirm();
|
|
await waitForEffectEnabled(false);
|
|
});
|
|
});
|