From dfdb5bb8ad15123aa44d70dc93513994612519bb Mon Sep 17 00:00:00 2001 From: 4gray <4gray@users.noreply.github.com> Date: Sat, 13 Jun 2026 16:04:54 +0200 Subject: [PATCH] fix(playlist): save xtream details in pwa - save Xtream playlist details through browser-safe metadata persistence in PWA\n- keep PWA Xtream data source cache in sync with current playlist metadata\n- cover dialog close timing, stale cache, and PWA data-source bootstrap regression --- apps/web-e2e/src/xtream.e2e.ts | 72 +++++++++++++++++- .../playlist-info.component.html | 1 - .../playlist-info.component.spec.ts | 73 ++++++++++++++++-- .../playlist-info/playlist-info.component.ts | 20 +++-- .../src/lib/data-sources/index.spec.ts | 30 ++++++++ .../pwa-xtream-data-source.spec.ts | 72 ++++++++++++++++++ .../data-sources/pwa-xtream-data-source.ts | 74 ++++++++++++++++++- 7 files changed, 322 insertions(+), 20 deletions(-) diff --git a/apps/web-e2e/src/xtream.e2e.ts b/apps/web-e2e/src/xtream.e2e.ts index 908abf780..f2a64f928 100644 --- a/apps/web-e2e/src/xtream.e2e.ts +++ b/apps/web-e2e/src/xtream.e2e.ts @@ -80,9 +80,7 @@ async function addXtreamPortal( 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(name); await dialog.locator('#serverUrl').fill(MOCK_SERVER); @@ -94,6 +92,35 @@ async function addXtreamPortal( await page.waitForURL(/xtreams.*vod/); } +async function openPlaylistDetailsDialog(page: Page, title: string) { + const playlistSettingsButton = page.getByRole('button', { + name: 'Playlist Settings', + }); + + if (await playlistSettingsButton.isVisible()) { + await playlistSettingsButton.click(); + } else { + await page + .locator('app-playlist-switcher .playlist-switcher-trigger') + .click(); + + const switcherMenu = page.getByRole('menu').filter({ hasText: title }); + const sourceRow = switcherMenu + .locator('.playlist-item') + .filter({ hasText: title }) + .first(); + await expect(sourceRow).toBeVisible(); + await sourceRow + .getByRole('button', { name: 'Playlist actions' }) + .click(); + await page.getByRole('menuitem', { name: 'Playlist info' }).click(); + } + + const dialog = page.locator('mat-dialog-container'); + await expect(dialog).toBeVisible(); + return dialog; +} + // --------------------------------------------------------------------------- // Test setup // --------------------------------------------------------------------------- @@ -439,6 +466,45 @@ test('@xtream add portal and see it in the playlist list', async ({ page }) => { ).toBeVisible(); }); +test('@xtream playlist details edit is retained in the PWA browser context', async ({ + page, +}) => { + await addXtreamPortal(page, { name: 'Editable PWA Xtream Portal' }); + + let dialog = await openPlaylistDetailsDialog( + page, + 'Editable PWA Xtream Portal' + ); + await dialog + .locator('input[formcontrolname="title"]') + .fill('Edited PWA Xtream Portal'); + await dialog + .locator('input[formcontrolname="serverUrl"]') + .fill(MOCK_SERVER); + await dialog.locator('input[formcontrolname="username"]').fill('minimal'); + await dialog.locator('input[formcontrolname="password"]').fill('minimal'); + await dialog.getByRole('button', { name: 'Save', exact: true }).click(); + await expect(dialog).toBeHidden(); + + await expect( + page.getByText('Edited PWA Xtream Portal', { exact: false }) + ).toBeVisible(); + + dialog = await openPlaylistDetailsDialog(page, 'Edited PWA Xtream Portal'); + await expect(dialog.locator('input[formcontrolname="title"]')).toHaveValue( + 'Edited PWA Xtream Portal' + ); + await expect( + dialog.locator('input[formcontrolname="serverUrl"]') + ).toHaveValue(MOCK_SERVER); + await expect( + dialog.locator('input[formcontrolname="username"]') + ).toHaveValue('minimal'); + await expect( + dialog.locator('input[formcontrolname="password"]') + ).toHaveValue('minimal'); +}); + test('@xtream minimal scenario — reduced item count', async ({ request }) => { const response = await request.get( `${MOCK_SERVER}/player_api.php?username=minimal&password=minimal&action=get_live_categories` diff --git a/libs/playlist/shared/ui/src/lib/recent-playlists/playlist-info/playlist-info.component.html b/libs/playlist/shared/ui/src/lib/recent-playlists/playlist-info/playlist-info.component.html index c356317c3..3de3d1bfb 100644 --- a/libs/playlist/shared/ui/src/lib/recent-playlists/playlist-info/playlist-info.component.html +++ b/libs/playlist/shared/ui/src/lib/recent-playlists/playlist-info/playlist-info.component.html @@ -182,7 +182,6 @@