import { expect } from '@playwright/test'; import { test } from '../fixtures/ids'; import { CleanupRegistry } from '../fixtures/cleanup'; import { adminApi } from '../fixtures/api'; // Regression coverage for the slug-vs-UUID bug: every per-app tab // (`/admin/apps/[slug]/...`) must accept the URL slug and not surface // the "Cannot parse `app_id` with value ``" error. The original // report was the Queues tab, but the bug surface spans six backend // files — see AUDIT.md's Phase 1 plan in chore/audit branch. // // Each tab is hit in isolation against a freshly-created app so the // test doesn't depend on the dev-seeded `default` app being present. const PARSE_ERROR = /Cannot parse|UUID parsing failed/i; const cleanup = new CleanupRegistry(); test.afterEach(async () => { await cleanup.run(); }); test.describe('per-app tab navigation accepts slug URLs', () => { test('every tab loads without an app_id parse error', async ({ page, uniqueSlug }) => { const slug = uniqueSlug('nav'); const api = await adminApi(); try { const res = await api.post('/api/v1/admin/apps', { data: { slug, name: slug } }); expect(res.ok()).toBe(true); } finally { await api.dispose(); } cleanup.app(slug); const tabs = [ { path: `/admin/apps/${slug}`, label: 'main (triggers/secrets/topics)' }, { path: `/admin/apps/${slug}/queues`, label: 'queues' }, { path: `/admin/apps/${slug}/files`, label: 'files' }, { path: `/admin/apps/${slug}/dead-letters`, label: 'dead-letters' }, { path: `/admin/apps/${slug}/users`, label: 'app users' }, { path: `/admin/apps/${slug}/users/invitations`, label: 'app invitations' } ]; for (const tab of tabs) { await page.goto(tab.path); // Network must settle so any error banner from the failed // API call has rendered before we assert its absence. await page.waitForLoadState('networkidle'); await expect( page.getByText(PARSE_ERROR), `expected no app_id parse error on ${tab.label} (${tab.path})` ).toHaveCount(0); } }); test('queues tab specifically — the original bug report', async ({ page, uniqueSlug }) => { // The bug surfaced on the queues tab. Pin a focused test so a // regression on just that page is easy to spot in CI output. const slug = uniqueSlug('queues'); const api = await adminApi(); try { const res = await api.post('/api/v1/admin/apps', { data: { slug, name: slug } }); expect(res.ok()).toBe(true); } finally { await api.dispose(); } cleanup.app(slug); await page.goto(`/admin/apps/${slug}/queues`); await page.waitForLoadState('networkidle'); await expect(page.getByText(PARSE_ERROR)).toHaveCount(0); // Positive assertion: the empty-state copy renders. If the API // call fails, this string never appears because the page bails // into the error branch. await expect(page.getByText('No queues in this app yet', { exact: false })).toBeVisible(); }); });