mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 11:06:16 -08:00
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:
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);
|
||||
|
||||
Reference in new issue
Block a user