diff --git a/apps/electron-backend-e2e/src/electron-test-fixtures.ts b/apps/electron-backend-e2e/src/electron-test-fixtures.ts index 247f1e10c..8353aef3d 100644 --- a/apps/electron-backend-e2e/src/electron-test-fixtures.ts +++ b/apps/electron-backend-e2e/src/electron-test-fixtures.ts @@ -569,35 +569,22 @@ async function clickButtonToggleOption( toggleGroup: Locator, label: string ): Promise { - const radio = toggleGroup.getByRole('radio', { - name: label, - exact: true, - }); - - if ((await radio.count()) > 0) { - await expect(radio.first()).toBeVisible(); - await radio.first().click(); - return; - } - - const button = toggleGroup.getByRole('button', { - name: label, - exact: true, - }); - - if ((await button.count()) > 0) { - await expect(button.first()).toBeVisible(); - await button.first().click(); - return; - } - const toggle = toggleGroup .locator('mat-button-toggle') .filter({ hasText: flexibleTextPattern(label) }) .first(); await expect(toggle).toBeVisible(); - await toggle.click(); + + if (!(await isButtonToggleSelected(toggle))) { + await toggle.click(); + } + + await expect + .poll(() => isButtonToggleSelected(toggle), { + timeout: 10000, + }) + .toBe(true); } export function channelItemByTitle(page: Page, title: string): Locator { @@ -616,6 +603,25 @@ export function contentCardByTitle(page: Page, title: string): Locator { }); } +export async function expectVisibleContentCardTitle( + page: Page, + title: string +): Promise { + await expect + .poll( + async () => { + const titles = await visibleContentCardTitles(page); + return titles.some( + (visibleTitle) => + normalizeVisibleText(visibleTitle) === + normalizeVisibleText(title) + ); + }, + { timeout: 20000 } + ) + .toBe(true); +} + export function gridListCardByTitle(page: Page, title: string): Locator { return page.locator('.category-content-layout mat-card').filter({ has: page.locator('.title', { @@ -1372,3 +1378,34 @@ function flexibleTextPattern(value: string): RegExp { 'i' ); } + +async function isButtonToggleSelected(toggle: Locator): Promise { + try { + return await toggle.evaluate((element) => { + const host = element as HTMLElement; + const selectedDescendant = host.querySelector( + '[aria-checked="true"], [aria-pressed="true"]' + ); + + return ( + host.classList.contains('mat-button-toggle-checked') || + host.getAttribute('aria-checked') === 'true' || + host.getAttribute('aria-pressed') === 'true' || + selectedDescendant !== null + ); + }); + } catch { + return false; + } +} + +async function visibleContentCardTitles(page: Page): Promise { + return page + .locator('app-content-card h3') + .allInnerTexts() + .then((titles) => titles.map((title) => title.trim()).filter(Boolean)); +} + +function normalizeVisibleText(value: string): string { + return value.trim().replace(/\s+/g, ' ').toLowerCase(); +} diff --git a/apps/electron-backend-e2e/src/favorites.e2e.ts b/apps/electron-backend-e2e/src/favorites.e2e.ts index 858aaa38b..aacbdceff 100644 --- a/apps/electron-backend-e2e/src/favorites.e2e.ts +++ b/apps/electron-backend-e2e/src/favorites.e2e.ts @@ -11,6 +11,7 @@ import { contentCardByTitle, defaultXtreamPassword, defaultXtreamUsername, + expectVisibleContentCardTitle, expect, importM3uPlaylistFromNativeDialog, launchElectronApp, @@ -159,18 +160,18 @@ test.describe('Electron Favorites', () => { await expect(channelItemByTitle(app.mainWindow, liveTitle)).toHaveCount(1); await switchUnifiedCollectionContent(app.mainWindow, 'Movies'); - await expect(contentCardByTitle(app.mainWindow, movieTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, movieTitle); await switchUnifiedCollectionContent(app.mainWindow, 'Series'); - await expect(contentCardByTitle(app.mainWindow, seriesTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, seriesTitle); await switchUnifiedCollectionScope(app.mainWindow, 'All playlists'); await switchUnifiedCollectionContent(app.mainWindow, 'Live TV'); await expect(channelItemByTitle(app.mainWindow, liveTitle)).toHaveCount(1); await switchUnifiedCollectionContent(app.mainWindow, 'Movies'); - await expect(contentCardByTitle(app.mainWindow, movieTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, movieTitle); await switchUnifiedCollectionContent(app.mainWindow, 'Series'); - await expect(contentCardByTitle(app.mainWindow, seriesTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, seriesTitle); const restarted = await restartElectronApp(app, dataDir); app.electronApp = restarted.electronApp; @@ -189,13 +190,9 @@ test.describe('Electron Favorites', () => { channelItemByTitle(app.mainWindow, liveTitle) ).toHaveCount(1); await switchUnifiedCollectionContent(app.mainWindow, 'Movies'); - await expect( - contentCardByTitle(app.mainWindow, movieTitle) - ).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, movieTitle); await switchUnifiedCollectionContent(app.mainWindow, 'Series'); - await expect( - contentCardByTitle(app.mainWindow, seriesTitle) - ).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, seriesTitle); } finally { await closeElectronApp(app); } diff --git a/apps/electron-backend-e2e/src/recent.e2e.ts b/apps/electron-backend-e2e/src/recent.e2e.ts index cb996d86e..2bae352ed 100644 --- a/apps/electron-backend-e2e/src/recent.e2e.ts +++ b/apps/electron-backend-e2e/src/recent.e2e.ts @@ -11,6 +11,7 @@ import { contentCardByTitle, defaultXtreamPassword, defaultXtreamUsername, + expectVisibleContentCardTitle, expect, importM3uPlaylistFromNativeDialog, launchElectronApp, @@ -160,17 +161,17 @@ test.describe('Electron Recently Viewed', () => { await openPlaylistRecent(app.mainWindow); await expect(channelItemByTitle(app.mainWindow, liveTitle)).toHaveCount(1); await switchUnifiedCollectionContent(app.mainWindow, 'Movies'); - await expect(contentCardByTitle(app.mainWindow, movieTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, movieTitle); await switchUnifiedCollectionContent(app.mainWindow, 'Series'); - await expect(contentCardByTitle(app.mainWindow, seriesTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, seriesTitle); await switchUnifiedCollectionScope(app.mainWindow, 'All playlists'); await switchUnifiedCollectionContent(app.mainWindow, 'Live TV'); await expect(channelItemByTitle(app.mainWindow, liveTitle)).toHaveCount(1); await switchUnifiedCollectionContent(app.mainWindow, 'Movies'); - await expect(contentCardByTitle(app.mainWindow, movieTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, movieTitle); await switchUnifiedCollectionContent(app.mainWindow, 'Series'); - await expect(contentCardByTitle(app.mainWindow, seriesTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, seriesTitle); const restarted = await restartElectronApp(app, dataDir); app.electronApp = restarted.electronApp; @@ -184,9 +185,9 @@ test.describe('Electron Recently Viewed', () => { await switchUnifiedCollectionContent(app.mainWindow, 'Live TV'); await expect(channelItemByTitle(app.mainWindow, liveTitle)).toHaveCount(1); await switchUnifiedCollectionContent(app.mainWindow, 'Movies'); - await expect(contentCardByTitle(app.mainWindow, movieTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, movieTitle); await switchUnifiedCollectionContent(app.mainWindow, 'Series'); - await expect(contentCardByTitle(app.mainWindow, seriesTitle)).toHaveCount(1); + await expectVisibleContentCardTitle(app.mainWindow, seriesTitle); await switchUnifiedCollectionContent(app.mainWindow, 'Live TV'); await clearRecentItems(app.mainWindow);