import { expect, test, type Page } from '@playwright/test'; import { getShellRouteByPageId, resolveShellNavPage, shellRouteManifest, type ShellPageId, } from '../src/platform/shell/route-manifest'; async function selectProfile(page: Page, baseURL: string, profileId = 1) { const response = await page.request.post(new URL('/api/profiles/select', baseURL).toString(), { data: { profile_id: profileId }, }); expect(response.ok()).toBe(true); } async function waitForShellRoute(page: Page, pageId: string) { const route = getShellRouteByPageId(pageId as ShellPageId); if (route?.kind === 'react') { await expect .poll(async () => page.evaluate(() => document.querySelector('.page.active')?.id ?? ''), { timeout: 15000, }) .toBe('webui-react-root'); return; } await expect .poll(async () => page.evaluate(() => document.querySelector('.page.active')?.id ?? '')) .toBe(`${pageId}-page`); } function getExpectedNavPage(pageId: ShellPageId): string { return resolveShellNavPage(pageId); } async function expectNavHighlight(page: Page, pageId: ShellPageId) { const navPage = getExpectedNavPage(pageId); const activeNavPage = await page.evaluate(() => { return document.querySelector('.nav-button.active')?.getAttribute('data-page') ?? ''; }); expect(activeNavPage).toBe(navPage); } async function verifyIssuesRoute(page: Page) { const appRoot = page.locator('#webui-react-root'); await expect(appRoot).toBeVisible(); await expect(page.getByTestId('issues-board')).toContainText('Issues'); } function expectedUrlPattern(path: string, pageId: ShellPageId): RegExp { if (pageId === 'issues') { return /\/issues(?:\?status=open&category=all)?$/; } if (pageId === 'stats') { return /\/stats(?:\?range=7d)?$/; } if (pageId === 'import') { return /\/import\/album$/; } return new RegExp(`${path.replace('/', '\\/')}$`); } test('direct load activates all known shell routes', async ({ page, baseURL }) => { if (!baseURL) { test.skip(); return; } await selectProfile(page, baseURL); for (const route of shellRouteManifest) { const routePage = await page.context().newPage(); try { await routePage.goto(new URL(route.path, baseURL).toString(), { waitUntil: 'domcontentloaded', }); await waitForShellRoute(routePage, route.pageId); await expect(routePage).toHaveURL(expectedUrlPattern(route.path, route.pageId)); await expectNavHighlight(routePage, route.pageId); if (route.pageId === 'issues') { await verifyIssuesRoute(routePage); } } finally { await routePage.close(); } } }); test('browser history restores shell routes', async ({ page, baseURL }) => { if (!baseURL) { test.skip(); return; } await selectProfile(page, baseURL); await page.goto(new URL('/discover', baseURL).toString(), { waitUntil: 'domcontentloaded' }); await waitForShellRoute(page, 'discover'); await page.evaluate(() => { (window as typeof window & { __spaNavMarker?: string }).__spaNavMarker = 'persist'; }); await page.getByRole('link', { name: 'Issues' }).click(); await expect .poll(async () => page.evaluate( () => (window as typeof window & { __spaNavMarker?: string }).__spaNavMarker ?? null, ), ) .toBe('persist'); await waitForShellRoute(page, 'issues'); await expect(page).toHaveURL(/\/issues(?:\?status=open&category=all)?$/); await page.goBack(); await waitForShellRoute(page, 'discover'); await expect(page).toHaveURL(/\/discover$/); await page.goForward(); await waitForShellRoute(page, 'issues'); await expect(page).toHaveURL(/\/issues(?:\?status=open&category=all)?$/); }); test('browser history leaves artist detail when going back to library', async ({ page, baseURL, }) => { if (!baseURL) { test.skip(); return; } await selectProfile(page, baseURL); await page.goto(new URL('/library', baseURL).toString(), { waitUntil: 'domcontentloaded' }); await waitForShellRoute(page, 'library'); await expect.poll(async () => page.locator('.library-artist-card').count()).toBeGreaterThan(0); await page.locator('.library-artist-card').first().click(); await waitForShellRoute(page, 'artist-detail'); await expect(page).toHaveURL(/\/artist-detail\/library\/[^/]+$/); await page.goBack(); await waitForShellRoute(page, 'library'); await expect(page).toHaveURL(/\/library$/); });