- populate COPYRIGHT (title/author/copyright/CCLI) + blank slides on every song; songHasContent ignores locked sections - foreground info/moderation images now bundle-relative (fixes blank images) - pre-added .probundle injection: Zip64-fix + verbatim .pro extraction (fixes empty bundle) - nametag subtitle split (text + subtitle); smaller non-bold render - skip songs with no content slides at export with German warning - link service agenda songs to SongDB edit modal via #song-<id> - allow CCLI import of metadata-only songs (no lyric sections) - expose has_content_slides on service songs; show "Keine Inhaltsfolien"
110 lines
3.6 KiB
TypeScript
110 lines
3.6 KiB
TypeScript
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-<id>); 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<boolean> {
|
|
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 <Link> (an <a> 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-<id>'
|
|
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-<id> 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 <span>, not <a>.
|
|
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');
|
|
});
|