- Route Issues to the React host even while the shell is still booting - Ignore stale bootstrap work when navigation changes mid-load - Clear artist-detail state when leaving the page so browser back can reach Library - Add smoke coverage for the artist-detail back-navigation path
133 lines
3.9 KiB
TypeScript
133 lines
3.9 KiB
TypeScript
import { expect, test, type Page } from '@playwright/test';
|
|
|
|
import { 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) {
|
|
if (pageId === 'issues') {
|
|
await expect
|
|
.poll(async () => page.evaluate(() => document.querySelector('.page.active')?.id ?? ''), {
|
|
timeout: 15000,
|
|
})
|
|
.toBe('webui-react-root');
|
|
await expect(page.getByTestId('issues-board')).toBeVisible({ timeout: 15000 });
|
|
return;
|
|
}
|
|
|
|
await expect
|
|
.poll(async () =>
|
|
page.evaluate(() => document.querySelector('.page.active')?.id ?? ''),
|
|
)
|
|
.toBe(`${pageId}-page`);
|
|
}
|
|
|
|
function getExpectedNavPage(pageId: ShellPageId): string {
|
|
if (pageId === 'artist-detail') {
|
|
return '';
|
|
}
|
|
|
|
return 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): RegExp {
|
|
if (path === '/issues') {
|
|
return /\/issues(?:\?status=open&category=all)?$/;
|
|
}
|
|
|
|
return new RegExp(`${path.replace('/', '\\/')}$`);
|
|
}
|
|
|
|
test('direct load activates all known top-level 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));
|
|
await expectNavHighlight(routePage, route.pageId);
|
|
|
|
if (route.pageId === 'issues') {
|
|
await verifyIssuesRoute(routePage);
|
|
}
|
|
} finally {
|
|
await routePage.close();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('browser history restores top-level 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.getByRole('button', { name: 'Issues' }).click();
|
|
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$/);
|
|
|
|
await page.goBack();
|
|
await waitForShellRoute(page, 'library');
|
|
await expect(page).toHaveURL(/\/library$/);
|
|
});
|