Skip to content

Commit 088acab

Browse files
test(video-player): wait for widget after tab clicks, fix poster race (#2232)
2 parents 9347dc1 + 84e9b46 commit 088acab

3 files changed

Lines changed: 29 additions & 8 deletions

File tree

automation/run-e2e/lib/mendix-helpers.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ export async function navigateToPage(page, path, timeout = 30_000) {
4141
await waitForMendixApp(page, timeout);
4242
}
4343

44+
export async function waitFrames(page, n = 2) {
45+
for (let i = 0; i < n; i++) {
46+
await page.evaluate(() => new Promise(r => requestAnimationFrame(r)));
47+
}
48+
}
49+
4450
export async function checkAccessibility(page, selector, options = {}) {
4551
const AxeBuilder = (await import("@axe-core/playwright")).default;
4652
let builder = new AxeBuilder({ page }).withTags(options.tags || ["wcag21aa"]);

packages/pluggableWidgets/accessibility-helper-web/e2e/AccessibilityHelper.spec.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ test.describe("with single target", () => {
5757
});
5858
test.describe("with multiple targets", () => {
5959
test("sets attributes when condition is true", async ({ page }) => {
60-
await page.click(".mx-name-actionButton2");
6160
await page.click(".mx-name-actionButton2");
6261
await waitForMendixApp(page);
6362
await page.click(".mx-name-radioButtons2 input:first-child");
@@ -88,7 +87,6 @@ test.describe("with single target", () => {
8887
});
8988

9089
test("updates target attributes using a NF", async ({ page }) => {
91-
await page.click(".mx-name-actionButton2");
9290
await page.click(".mx-name-actionButton2");
9391
await waitForMendixApp(page);
9492
await page.click(".mx-name-radioButtons2 input:first-child");
@@ -117,7 +115,6 @@ test.describe("with single target", () => {
117115
test("sets target attributes even though target is conditionally shown after being hidden", async ({
118116
page
119117
}) => {
120-
await page.click(".mx-name-actionButton2");
121118
await page.click(".mx-name-actionButton2");
122119
await waitForMendixApp(page);
123120
await page.click(".mx-name-radioButtons2 input:first-child");

packages/pluggableWidgets/video-player-web/e2e/VideoPlayer.spec.js

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { test, expect } from "@mendix/run-e2e/fixtures";
2-
import { waitForDataReady } from "@mendix/run-e2e/mendix-helpers";
2+
import { waitForWidget, waitFrames } from "@mendix/run-e2e/mendix-helpers";
33

44
test.describe("Video Player", () => {
55
test.beforeEach(async ({ page }) => {
@@ -41,6 +41,7 @@ test.describe("Tab page", () => {
4141

4242
test("renders youtube video", async ({ page }) => {
4343
await page.locator(".mx-name-tabPage1").click();
44+
await waitForWidget(page, "videoPlayer1");
4445
await expect(
4546
page.locator(".widget-video-player.widget-video-player-container.mx-name-videoPlayer1.size-box iframe")
4647
).toBeVisible();
@@ -52,6 +53,7 @@ test.describe("Tab page", () => {
5253

5354
test("renders vimeo video", async ({ page }) => {
5455
await page.locator(".mx-name-tabPage5").click();
56+
await waitForWidget(page, "videoPlayer5");
5557
await expect(
5658
page.locator(".widget-video-player.widget-video-player-container.mx-name-videoPlayer5.size-box iframe")
5759
).toBeVisible();
@@ -63,6 +65,7 @@ test.describe("Tab page", () => {
6365

6466
test("renders dailymotion video", async ({ page }) => {
6567
await page.locator(".mx-name-tabPage4").click();
68+
await waitForWidget(page, "videoPlayer4");
6669
await expect(
6770
page.locator(".widget-video-player.widget-video-player-container.mx-name-videoPlayer4.size-box iframe")
6871
).toBeVisible();
@@ -74,6 +77,7 @@ test.describe("Tab page", () => {
7477

7578
test("renders html5 video", async ({ page }) => {
7679
await page.locator(".mx-name-tabPage3").click();
80+
await waitForWidget(page, "videoPlayer3");
7781
await expect(
7882
page.locator(".widget-video-player.widget-video-player-container.mx-name-videoPlayer3.size-box video")
7983
).toBeVisible();
@@ -112,7 +116,21 @@ test.describe("External video", () => {
112116
await widget.scrollIntoViewIfNeeded();
113117
await expect(widget).toBeVisible();
114118
await expect(videoLocator).toHaveAttribute("poster", /.+/);
115-
await waitForDataReady(page);
119+
// Wait for poster image to decode in-page before screenshotting.
120+
// page.evaluate with a separate Image() is unreliable — the promise can
121+
// resolve before the <video> element itself has rendered the poster frame.
122+
await videoLocator.evaluate(el =>
123+
el.poster
124+
? new Promise(r => {
125+
const i = new Image();
126+
i.onload = i.onerror = r;
127+
i.src = el.poster;
128+
if (i.complete) r();
129+
})
130+
: Promise.resolve()
131+
);
132+
// Wait two animation frames so the browser flushes layout and paints the poster frame.
133+
await waitFrames(page, 2);
116134
await expect(widget).toHaveScreenshot("videoPlayerExternalPoster.png");
117135
});
118136

@@ -122,21 +140,21 @@ test.describe("External video", () => {
122140
});
123141

124142
test("renders video aspect ratio correctly", async ({ page }) => {
125-
await expect(page.locator(".mx-name-videoPlayer1")).toBeVisible();
143+
await waitForWidget(page, "videoPlayer1");
126144
const videoElement = await page.locator(".mx-name-videoPlayer1").first().boundingBox();
127145
const { width, height } = videoElement;
128146
const aspectRatio = Number(width / height);
129147
expect(aspectRatio).toBeCloseTo(16 / 9, 0.1);
130148

131149
await page.locator(".mx-name-tabPage2").click();
132-
await expect(page.locator(".mx-name-videoPlayer3")).toBeVisible();
150+
await waitForWidget(page, "videoPlayer3");
133151
const videoElement2 = await page.locator(".mx-name-videoPlayer3").first().boundingBox();
134152
const { width: width2, height: height2 } = videoElement2;
135153
const aspectRatio2 = Number(width2 / height2);
136154
expect(aspectRatio2).toBeCloseTo(3 / 2, 0.1);
137155

138156
await page.locator(".mx-name-tabPage3").click();
139-
await expect(page.locator(".mx-name-videoPlayer5")).toBeVisible();
157+
await waitForWidget(page, "videoPlayer5");
140158
const videoElement3 = await page.locator(".mx-name-videoPlayer5").first().boundingBox();
141159
const { width: width3, height: height3 } = videoElement3;
142160
expect(width3).toEqual(height3);

0 commit comments

Comments
 (0)