turn an assertion as retryable with expect.poll

This commit is contained in:
Valere
2026-04-22 18:06:12 +02:00
parent 1b9682869a
commit 5c4d6d0317
6 changed files with 62 additions and 71 deletions

View File

@@ -127,15 +127,23 @@ async function expectVideoTilesCount(page: Page, count: number): Promise<void> {
// There should be 5 video elements, visible and autoplaying // There should be 5 video elements, visible and autoplaying
await expect(page.locator("video")).toHaveCount(count); await expect(page.locator("video")).toHaveCount(count);
const blockDisplayCount = await page await expect
.locator("video") .poll(
.evaluateAll( async () => {
(videos: Element[]) => return await page
videos.filter( .locator("video")
(v: Element) => window.getComputedStyle(v).display === "block", .evaluateAll(
).length, (videos: Element[]) =>
); videos.filter(
expect(blockDisplayCount).toBe(count); (v: Element) => window.getComputedStyle(v).display === "block",
).length,
);
},
{
timeout: 10000,
},
)
.toBe(count);
} }
export const SpaHelpers = { export const SpaHelpers = {

View File

@@ -72,15 +72,7 @@ modePairs.forEach(([rtcMode1, rtcMode2]) => {
const videoElements = await frame.locator("video").all(); const videoElements = await frame.locator("video").all();
expect(videoElements.length).toBe(2); expect(videoElements.length).toBe(2);
const blockDisplayCount = await frame await TestHelpers.expectVisibleVideoCount(frame, 2);
.locator("video")
.evaluateAll(
(videos: Element[]) =>
videos.filter(
(v: Element) => window.getComputedStyle(v).display === "block",
).length,
);
expect(blockDisplayCount).toBe(2);
} }
// await florian.page.pause(); // await florian.page.pause();

View File

@@ -75,18 +75,11 @@ widgetTest(
await expect(frame.getByText("Waiting for media...")).not.toBeVisible(); await expect(frame.getByText("Waiting for media...")).not.toBeVisible();
// There should be 2 video elements, visible and autoplaying // There should be 2 video elements, visible and autoplaying
const videoElements = await frame.locator("video").all(); await expect(frame.locator("video")).toHaveCount(2, {
expect(videoElements.length).toBe(2); timeout: 10000,
});
const blockDisplayCount = await frame await TestHelpers.expectVisibleVideoCount(frame, 2);
.locator("video")
.evaluateAll(
(videos: Element[]) =>
videos.filter(
(v: Element) => window.getComputedStyle(v).display === "block",
).length,
);
expect(blockDisplayCount).toBe(2);
} }
}, },
); );

View File

@@ -71,32 +71,20 @@ widgetTest(
}); });
// There should be 2 video elements, visible and autoplaying // There should be 2 video elements, visible and autoplaying
await expect(frame.locator("video")).toHaveCount(2); await expect(frame.locator("video")).toHaveCount(2, {
timeout: 10000,
});
const blockDisplayCount = await frame await TestHelpers.expectVisibleVideoCount(frame, 2);
.locator("video")
.evaluateAll(
(videos: Element[]) =>
videos.filter(
(v: Element) => window.getComputedStyle(v).display === "block",
).length,
);
expect(blockDisplayCount).toBe(2);
} }
// now we switch the mode for timo (second joiner on multi-sfu HOST2 but currently HOST1) // now we switch the mode for timo (second joiner on multi-sfu HOST2 but currently HOST1)
await TestHelpers.setEmbeddedElementCallRtcMode(timo.page, "compat"); await TestHelpers.setEmbeddedElementCallRtcMode(timo.page, "compat");
await timo.page.waitForTimeout(3000); await timo.page.waitForTimeout(3000);
const blockDisplayCount = await timo.page
.locator('iframe[title="Element Call"]') await TestHelpers.expectVisibleVideoCount(
.contentFrame() timo.page.locator('iframe[title="Element Call"]').contentFrame(),
.locator("video") 2,
.evaluateAll( );
(videos: Element[]) =>
videos.filter(
(v: Element) => window.getComputedStyle(v).display === "block",
).length,
);
expect(blockDisplayCount).toBe(2);
}, },
); );

View File

@@ -93,15 +93,7 @@ widgetTest("Create and join a group call", async ({ addUser, browserName }) => {
await expect(frame.locator("video")).toHaveCount(5); await expect(frame.locator("video")).toHaveCount(5);
await expect(frame.locator("video[autoplay]")).toHaveCount(5); await expect(frame.locator("video[autoplay]")).toHaveCount(5);
const blockDisplayCount = await frame await TestHelpers.expectVisibleVideoCount(frame, 5);
.locator("video")
.evaluateAll(
(videos: Element[]) =>
videos.filter(
(v: Element) => window.getComputedStyle(v).display === "block",
).length,
);
expect(blockDisplayCount).toBe(5);
}), }),
); );
@@ -128,18 +120,10 @@ widgetTest("Create and join a group call", async ({ addUser, browserName }) => {
timeout: 10000, timeout: 10000,
}); });
const blockDisplayCount = await frame
.locator("video")
.evaluateAll(
(videos: Element[]) =>
videos.filter(
(v: Element) => window.getComputedStyle(v).display === "block",
).length,
);
// out of 5 ONLY 4 are visible (display:block) !! // out of 5 ONLY 4 are visible (display:block) !!
// XXX we need to be better at our HTML markup and accessibility, it would make // XXX we need to be better at our HTML markup and accessibility, it would make
// this kind of stuff way easier to test if we could look out for aria attributes. // this kind of stuff way easier to test if we could look out for aria attributes.
expect(blockDisplayCount).toBe(4); // ✅ Retryable assertion for visible videos
await TestHelpers.expectVisibleVideoCount(frame, 4);
} }
}); });

View File

@@ -10,6 +10,7 @@ import {
expect, expect,
type JSHandle, type JSHandle,
type Page, type Page,
type FrameLocator,
} from "@playwright/test"; } from "@playwright/test";
import { type MatrixClient } from "matrix-js-sdk"; import { type MatrixClient } from "matrix-js-sdk";
@@ -110,8 +111,8 @@ export class TestHelpers {
await expect( await expect(
page.getByRole("heading", { name: `Welcome ${username}` }), page.getByRole("heading", { name: `Welcome ${username}` }),
).toBeVisible({ ).toBeVisible({
// Increase timeout here // Increase timeout here :/ flaky
timeout: 10000, timeout: 15000,
}); });
await this.maybeDismissBrowserNotSupportedToast(page); await this.maybeDismissBrowserNotSupportedToast(page);
@@ -322,4 +323,29 @@ export class TestHelpers {
): Promise<void> { ): Promise<void> {
await page.getByRole("option", { name: `Open room ${roomName}` }).click(); await page.getByRole("option", { name: `Open room ${roomName}` }).click();
} }
public static async expectVisibleVideoCount(
frame: FrameLocator,
count: number,
): Promise<void> {
// ✅ Retryable assertion for visible videos
await expect
.poll(
async () => {
return await frame
.locator("video")
.evaluateAll(
(videos: Element[]) =>
videos.filter(
(v: Element) =>
window.getComputedStyle(v).display === "block",
).length,
);
},
{
timeout: 10000,
},
)
.toBe(count);
}
} }