import { test, expect } from '@playwright/test'; // FIX 6: matched song title in the service agenda links to the SongDB edit modal // (route('songs.index')#song-); FIX 5: songs whose default arrangement has no // content slides show a "Keine Inhaltsfolien" indicator. // // These tests depend on synced service data. When no editable service / matched song // exists, they skip gracefully (same pattern as service-edit-songs.spec.ts). async function navigateToEditPage(page): Promise { await page.goto('/services'); await page.waitForLoadState('networkidle'); const editButton = page.getByTestId('service-list-edit-button').first(); const hasEditableService = await editButton.isVisible().catch(() => false); if (!hasEditableService) { return false; } await editButton.click(); await page.waitForLoadState('networkidle'); return true; } test('matched song title links to SongDB edit hash', async ({ page }) => { const navigated = await navigateToEditPage(page); if (!navigated) { test.skip(); } // A matched title renders as an Inertia (an with data-testid). const titleLink = page.locator('a[data-testid="song-agenda-title"]').first(); const hasMatched = await titleLink.isVisible().catch(() => false); if (!hasMatched) { test.skip(); } const href = await titleLink.getAttribute('href'); expect(href).toBeTruthy(); // route('songs.index') + '#song-' expect(href).toMatch(/\/songs(\/index)?#song-\d+$/); }); test('clicking matched song title opens the edit modal on the Songs page', async ({ page }) => { const navigated = await navigateToEditPage(page); if (!navigated) { test.skip(); } const titleLink = page.locator('a[data-testid="song-agenda-title"]').first(); const hasMatched = await titleLink.isVisible().catch(() => false); if (!hasMatched) { test.skip(); } await titleLink.click(); await page.waitForLoadState('networkidle'); // We land on the Songs page with #song- and the edit modal auto-opens. expect(new URL(page.url()).pathname).toContain('/songs'); expect(page.url()).toMatch(/#song-\d+$/); const editModal = page.getByTestId('song-list-edit-modal'); await expect(editModal).toBeVisible({ timeout: 5000 }); }); test('unmatched song title stays plain text (no link)', async ({ page }) => { const navigated = await navigateToEditPage(page); if (!navigated) { test.skip(); } // An unmatched row has a request-creation button; its title is a , not . const requestButton = page.getByTestId('song-request-creation').first(); const hasUnmatched = await requestButton.isVisible().catch(() => false); if (!hasUnmatched) { test.skip(); } const unmatchedRow = page .getByTestId('song-agenda-item') .filter({ has: page.getByTestId('song-request-creation') }) .first(); const plainTitle = unmatchedRow.locator('span[data-testid="song-agenda-title"]'); await expect(plainTitle).toBeVisible(); await expect(unmatchedRow.locator('a[data-testid="song-agenda-title"]')).toHaveCount(0); }); test('song without content slides shows "Keine Inhaltsfolien" indicator', async ({ page }) => { const navigated = await navigateToEditPage(page); if (!navigated) { test.skip(); } const noContent = page.getByTestId('song-no-content').first(); const hasNoContent = await noContent.isVisible().catch(() => false); if (!hasNoContent) { test.skip(); } await expect(noContent).toBeVisible(); await expect(noContent).toContainText('Keine Inhaltsfolien'); });