test(e2e): follow the cinematic details in the Electron and web flows

The series menu trigger renders data-testid, so the Electron specs use
an attribute locator instead of getByTestId (data-test-id there). The
back-lane sweep targets the "Episodes" heading, the primary action is
read by its test id (its name now carries the runtime line), the M3U
inset assertion accepts the hero's own 32/20px inset, and the surface
contrast checks measure the flat episode card's artwork, which gets a
light hairline so its edge survives the light theme. The menu-closing
helper checks the panel rather than a backdrop locator that can match
a second overlay.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Fable 5.1 committed 2026-10-03 10:14:28 +02:00
1 parent 25cc6b1ced
commit 36ce98e18c
10 files changed
+145 -66

No files matched your search

+8 -2
View File
@@ -245,11 +245,17 @@ export async function expectSeriesSurfacesInBothThemes(
await expect
.poll(() =>
rasterizedBorderContrast(
shell.locator('[data-testid="series-favorite-toggle"]').first()
shell
.locator('[data-testid="series-favorite-toggle"]')
.first()
)
)
.toBeGreaterThan(1.1);
for (const selector of ['.episode-card', 'mat-button-toggle-group']) {
// The flat card's visible edge is its artwork's hairline.
for (const selector of [
'.episode-card__thumbnail',
'mat-button-toggle-group',
]) {
await expect
.poll(
async () =>
+4 -3
View File
@@ -393,7 +393,7 @@ test('@web @m3u @tmdb browse and watch keep the adjusted volume', async ({
await page.keyboard.press('Escape');
await expect(inlineVideo(page)).toHaveCount(0);
const playButton = page.locator('[data-test-id="m3u-vod-play"]');
const playButton = page.locator('[data-testid="m3u-vod-play"]');
await expect(playButton).toBeVisible();
// Browse → Play remounts the engine without a channel change.
@@ -417,12 +417,13 @@ test('@web @m3u @tmdb browse and watch keep the adjusted volume', async ({
await expect(inlineVideo(page)).toHaveCount(0);
await expect(shell.locator('.shell__back-button')).toHaveCount(0);
// Without the arrow there is no lane to reserve: the hero keeps its own
// inset instead of the 72px column portal details give the Back control.
// inset (32px, or 20px in a pane narrower than 760px) instead of the
// 72px column portal details give the Back control.
expect(
await shell
.locator('.hero__content')
.evaluate((el) => getComputedStyle(el).paddingInlineStart)
).toBe('40px');
).toMatch(/^(20|32)px$/);
await shell.focus();
await page.keyboard.press('Escape');
await expect(playButton).toBeVisible();
+7 -9
View File
@@ -29,9 +29,7 @@ async function addXtreamPortal(page: Page): Promise<void> {
const dialog = page.locator('mat-dialog-container');
await expect(dialog).toBeVisible();
// v0.22 redesign: tabs were replaced with a flat 5-card radio picker.
await dialog
.getByRole('radio', { name: /Xtream credentials/i })
.click();
await dialog.getByRole('radio', { name: /Xtream credentials/i }).click();
await dialog.locator('#title').fill('Self-hosted Xtream');
await dialog.locator('#serverUrl').fill(XTREAM_MOCK_SERVER);
@@ -160,9 +158,9 @@ test('@self-hosted Xtream portal loads through web-backend proxy', async ({
await expect(vodItem).toBeVisible({ timeout: 30_000 });
await vodItem.click();
await expect(page).toHaveURL(/\/workspace\/xtreams\/[^/]+\/vod\/\d+\/\d+/);
await expect(
page.getByRole('button', { name: 'Play', exact: true })
).toBeVisible({ timeout: 15_000 });
const primaryAction = page.locator('[data-testid="vod-primary-action"]');
await expect(primaryAction).toBeVisible({ timeout: 15_000 });
await expect(primaryAction).toContainText('Play');
expect(
consoleErrors.filter((message) =>
@@ -257,9 +255,9 @@ test('@self-hosted M3U User-Agent reaches the provider on import and refresh', a
const row = sourceRowByTitle(page, 'Protected M3U');
await row.hover();
await row.locator('.refresh-btn').click();
await expect(page.locator('.mat-mdc-snack-bar-label').last()).toContainText(
'updated'
);
await expect(
page.locator('.mat-mdc-snack-bar-label').last()
).toContainText('updated');
await page.goto(catalogUrl);
await expect(page.getByText('1. Refreshed UA Channel')).toBeVisible();
expect(received.slice(1)).toEqual([userAgent, userAgent]);