From 344aac21f99fa235d1da9a3efe81c5c3f08b8cac Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Thu, 10 Sep 2026 14:15:38 +0200 Subject: [PATCH] Force undelegated mode in tests --- playwright/reconnect.spec.ts | 8 ++++++++ playwright/spa-call-sticky.spec.ts | 12 +++++++++++- playwright/spa-helpers.ts | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/playwright/reconnect.spec.ts b/playwright/reconnect.spec.ts index bd4dd1996..81e70b9cc 100644 --- a/playwright/reconnect.spec.ts +++ b/playwright/reconnect.spec.ts @@ -7,6 +7,8 @@ Please see LICENSE in the repository root for full details. import { expect, test } from "@playwright/test"; +import { SpaHelpers } from "./spa-helpers"; + // Skip test for Firefox, due to page.keyboard.press("Tab") not reliable on headless mode test.skip( ({ browserName }) => browserName === "firefox", @@ -17,6 +19,12 @@ test("can only interact with header and footer while reconnecting", async ({ page, }) => { await page.goto("/"); + + // The reconnecting state is entered via the probablyLeft timer, which + // mirrors the delayed leave event's timeout. With delegation that timeout + // is one hour, putting it out of reach of the clock fast-forward below. + // Keep the leave client-managed so its short timeout applies. + await SpaHelpers.disableLeaveDelegation(page); await page.getByTestId("home_callName").click(); await page.getByTestId("home_callName").fill("Test call"); await page.getByTestId("home_displayName").click(); diff --git a/playwright/spa-call-sticky.spec.ts b/playwright/spa-call-sticky.spec.ts index 1dbda735b..b45399da2 100644 --- a/playwright/spa-call-sticky.spec.ts +++ b/playwright/spa-call-sticky.spec.ts @@ -19,6 +19,7 @@ async function setupTwoUserSpaCall( browser: Browser, page: Page, browserName: string, + opts: { disableGuestLeaveDelegation?: boolean } = {}, ): Promise<{ guestPage: Page }> { test.skip( browserName === "firefox", @@ -52,6 +53,9 @@ async function setupTwoUserSpaCall( await guestPage.goto("/"); + if (opts.disableGuestLeaveDelegation) + await SpaHelpers.disableLeaveDelegation(guestPage); + let pevaraHasSentStickyEvent = false; const pevaraResolver = Promise.withResolvers(); @@ -102,7 +106,13 @@ test("One to One rejoin after improper leave does not crash EC", async ({ page, browserName, }) => { - const { guestPage } = await setupTwoUserSpaCall(browser, page, browserName); + // With delegation, the backend sends the guest's delayed leave event within + // moments of the improper leave, so the stale membership this test needs + // would be cleaned up before the rejoin. Keep the guest's leave + // client-managed so the stale membership lingers. + const { guestPage } = await setupTwoUserSpaCall(browser, page, browserName, { + disableGuestLeaveDelegation: true, + }); await SpaHelpers.expectVideoTilesCount(page, 2); await SpaHelpers.expectVideoTilesCount(guestPage, 2); diff --git a/playwright/spa-helpers.ts b/playwright/spa-helpers.ts index 5f99e32d3..71150b8ba 100644 --- a/playwright/spa-helpers.ts +++ b/playwright/spa-helpers.ts @@ -111,6 +111,24 @@ async function setRtcModeFromSettings( await page.getByTestId("modal_close").click(); } +/** + * Makes the delayed-leave delegation support probes fail so that the client + * manages its delayed leave event itself instead of delegating it to the + * backend. + * + * Must be installed before the page joins a call. + */ +async function disableLeaveDelegation(page: Page): Promise { + // Covers both the transport probe (/delegate_delayed_leave) + // and the homeserver probe (MSC4195, .../rtc/livekit/delegate_delayed_leave). + await page.route("**/delegate_delayed_leave", async (route) => + route.fulfill({ + status: 404, + headers: { "Access-Control-Allow-Origin": "*" }, + }), + ); +} + /** * Expect a certain number of video tiles to be present and visible. */ @@ -133,5 +151,6 @@ export const SpaHelpers = { createCall, getCallInviteLink, joinCallFromInviteLink, + disableLeaveDelegation, expectVideoTilesCount, };