From 20587b349504187dbb646ad6bc329a69c5d5c969 Mon Sep 17 00:00:00 2001 From: Timo <16718859+toger5@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:57:26 +0800 Subject: [PATCH] Start voice call in PiP (not in fullscreen) (#34055) * start voice call in pip * Update jest.config.ts * fix "join" button to use correct intent * Add regression test for join button * Update RoomHeader-test.tsx * fmt * Add playwright test * Fix expected intent on "join" button press * Add additional pip check to exising: `should be able to join a ${callType} call in progress` test * Update RoomHeader-test.tsx --- .../playwright/e2e/voip/element-call.spec.ts | 33 ++++++++++- .../views/rooms/RoomHeader/RoomHeader.tsx | 2 +- apps/web/src/stores/RoomViewStore.tsx | 9 ++- .../rooms/RoomHeader/RoomHeader-test.tsx | 27 ++++++++- .../unit-tests/stores/RoomViewStore-test.ts | 57 ++++++++++++++++++- 5 files changed, 123 insertions(+), 5 deletions(-) diff --git a/apps/web/playwright/e2e/voip/element-call.spec.ts b/apps/web/playwright/e2e/voip/element-call.spec.ts index 9675779c1f..c90ae306f3 100644 --- a/apps/web/playwright/e2e/voip/element-call.spec.ts +++ b/apps/web/playwright/e2e/voip/element-call.spec.ts @@ -217,8 +217,23 @@ test.describe("Element Call", () => { const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); - expect(hash.get("intent")).toEqual("join_existing"); + const expectedIntent = callType === "voice" ? "join_existing_voice" : "join_existing"; + expect(hash.get("intent")).toEqual(expectedIntent); expect(hash.get("skipLobby")).toEqual(null); + + // pip layout check + switch (callType) { + case "voice": { + const pipContainer = page.getByTestId("widget-pip-container"); + await expect(pipContainer).toBeVisible(); + break; + } + case "video": { + const pipContainer = page.getByTestId("widget-pip-container"); + await expect(pipContainer).not.toBeVisible(); + break; + } + } }); }); @@ -336,6 +351,22 @@ test.describe("Element Call", () => { expect(hash.get("skipLobby")).toEqual("true"); }); + test("should start a voice call in PiP", async ({ page, user, room, app }) => { + await app.viewRoomById(room.roomId); + await expect(page.getByText("Bob joined the room")).toBeVisible(); + + await page.getByRole("button", { name: "Voice call" }).click(); + await page.getByRole("menuitem", { name: "Element Call" }).click(); + + const frameUrlStr = await page.locator("iframe").getAttribute("src"); + await expect(frameUrlStr).toBeDefined(); + + // The call should be presented in the picture-in-picture container, right in the room we started it + // from, rather than taking over the room view. + const pipContainer = page.getByTestId("widget-pip-container"); + await expect(pipContainer).toBeVisible(); + }); + test("should be able to join a call in progress", async ({ page, user, bot, room, app }) => { await app.viewRoomById(room.roomId); await expect(page.getByText("Bob joined the room")).toBeVisible(); diff --git a/apps/web/src/components/views/rooms/RoomHeader/RoomHeader.tsx b/apps/web/src/components/views/rooms/RoomHeader/RoomHeader.tsx index dbdb0f619a..4f7d0b9c1e 100644 --- a/apps/web/src/components/views/rooms/RoomHeader/RoomHeader.tsx +++ b/apps/web/src/components/views/rooms/RoomHeader/RoomHeader.tsx @@ -118,7 +118,7 @@ function RoomHeaderButtons({ >