fix(e2e): fix category-management race condition and favorites grid pagination

- toggleManagedCategory: replace manual count-loop with Playwright filter so
  the locator retries internally until Angular re-renders the filtered list
  after the search field is populated (previously called .count() before the
  @for loop had reacted to the updated searchTerm signal)

- favorites Xtream test: pick movie/series titles from the first displayed
  grid card instead of vodFixture.items[0]. The grid sorts by date-desc and
  paginates at 25 items; the first API item may land on page 2 making
  clickGridListCardByTitle time out with "element not found". Reading the
  title from the DOM after navigation ensures we always target a visible card.

- electron-test-fixtures: export waitForFirstGridListCardTitle helper

https://claude.ai/code/session_01VU6ZZTG7YrhKhKBQvBfmpp
This commit is contained in:
Claude committed 2026-03-31 21:58:40 +00:00
1 parent 3f08aba550
commit 78a2dd3766
3 files changed
+28 -25

No files matched your search

@@ -158,28 +158,17 @@ async function toggleManagedCategory(
name: string;
}
): Promise<void> {
const categories = dialog.locator('.category-item');
const count = await categories.count();
// Use Playwright's built-in filter so it retries until Angular re-renders
// the filtered list after the search field is populated.
const categoryRow = dialog
.locator('.category-item')
.filter({
has: dialog.locator('.category-name', {
hasText: targetCategory.name,
}),
})
.first();
for (let index = 0; index < count; index += 1) {
const categoryRow = categories.nth(index);
const name =
(await categoryRow.locator('.category-name').textContent())?.trim() ??
'';
const countText =
(await categoryRow.locator('.item-count').textContent())?.trim() ?? '';
const itemCount = Number.parseInt(countText.replace(/[()]/g, ''), 10) || 0;
if (name !== targetCategory.name) {
continue;
}
await expect(categoryRow).toBeVisible();
await categoryRow.click();
return;
}
throw new Error(
`Could not find category "${targetCategory.name}" with count ${targetCategory.itemCount} in the management dialog.`
);
await expect(categoryRow).toBeVisible({ timeout: 5000 });
await categoryRow.click();
}
@@ -624,6 +624,17 @@ export function gridListCardByTitle(page: Page, title: string): Locator {
});
}
/**
* Waits for the first grid card to appear (skeleton loading done) and returns
* its display title. Use this instead of picking from fixture order, since the
* grid sorts by date-desc and may paginate items off the first page.
*/
export async function waitForFirstGridListCardTitle(page: Page): Promise<string> {
const card = page.locator('.category-content-layout mat-card').first();
await expect(card).toBeVisible({ timeout: 20000 });
return ((await card.locator('.title').textContent()) ?? '').trim();
}
export async function clickGridListCardByTitle(
page: Page,
title: string
@@ -22,6 +22,7 @@ import {
switchUnifiedCollectionContent,
switchUnifiedCollectionScope,
test,
waitForFirstGridListCardTitle,
waitForM3uCatalog,
waitForStalkerCatalog,
waitForXtreamWorkspaceReady,
@@ -116,8 +117,6 @@ test.describe('Electron Favorites', () => {
xtreamCredentials
);
const [liveTitle] = pickDistinctTitles(liveFixture.items, getXtreamTitle);
const [movieTitle] = pickDistinctTitles(vodFixture.items, getXtreamTitle);
const [seriesTitle] = pickDistinctTitles(seriesFixture.items, getXtreamTitle);
const portalTitle = 'Xtream Favorites Source';
const app = await launchElectronApp(dataDir);
@@ -139,6 +138,9 @@ test.describe('Electron Favorites', () => {
app.mainWindow,
vodFixture.categoryName
);
// Pick the title from the first displayed card (grid sorts by date-desc,
// so fixture order ≠ display order; pagination may hide some items).
const movieTitle = await waitForFirstGridListCardTitle(app.mainWindow);
await clickGridListCardByTitle(app.mainWindow, movieTitle);
await addCurrentDetailToFavorites(app.mainWindow);
await goBackFromDetail(app.mainWindow);
@@ -148,6 +150,7 @@ test.describe('Electron Favorites', () => {
app.mainWindow,
seriesFixture.categoryName
);
const seriesTitle = await waitForFirstGridListCardTitle(app.mainWindow);
await clickGridListCardByTitle(app.mainWindow, seriesTitle);
await addCurrentDetailToFavorites(app.mainWindow);
await goBackFromDetail(app.mainWindow);