test(e2e): Playwright tests for restructured edit page
This commit is contained in:
parent
fb1e51361f
commit
6964931286
299
tests/e2e/service-edit-agenda.spec.ts
Normal file
299
tests/e2e/service-edit-agenda.spec.ts
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
async function navigateToEditPage(page) {
|
||||
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('edit seite zeigt ablauf sektion statt accordion bloecke', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await expect(page).toHaveURL(/.*services\/\d+\/edit/);
|
||||
|
||||
const agendaSection = page.getByTestId('agenda-section');
|
||||
const emptyState = page.getByText('Keine Ablauf-Elemente vorhanden');
|
||||
const hasAgenda = await agendaSection.isVisible().catch(() => false);
|
||||
const hasEmptyState = await emptyState.isVisible().catch(() => false);
|
||||
|
||||
expect(hasAgenda || hasEmptyState).toBe(true);
|
||||
|
||||
const blockToggles = page.getByTestId('service-edit-block-toggle');
|
||||
const toggleCount = await blockToggles.count();
|
||||
expect(toggleCount).toBe(0);
|
||||
});
|
||||
|
||||
test('informations block ist oben sichtbar', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const informationBlock = page.getByTestId('information-block');
|
||||
await expect(informationBlock).toBeVisible();
|
||||
});
|
||||
|
||||
test('ablauf ueberschrift ist sichtbar', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await expect(page.getByText('Ablauf')).toBeVisible();
|
||||
});
|
||||
|
||||
test('agenda items zeigen korrekte elemente oder empty state', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const agendaSection = page.getByTestId('agenda-section');
|
||||
const emptyState = page.getByText('Keine Ablauf-Elemente vorhanden');
|
||||
|
||||
const hasAgenda = await agendaSection.isVisible().catch(() => false);
|
||||
const hasEmptyState = await emptyState.isVisible().catch(() => false);
|
||||
|
||||
if (hasEmptyState) {
|
||||
await expect(page.getByText('Bitte synchronisiere die Daten zuerst')).toBeVisible();
|
||||
return;
|
||||
}
|
||||
|
||||
expect(hasAgenda).toBe(true);
|
||||
|
||||
const agendaRows = page.getByTestId('agenda-item-row');
|
||||
const songItems = page.getByTestId('song-agenda-item');
|
||||
const headerItems = page.getByTestId('agenda-header-item');
|
||||
|
||||
const rowCount = await agendaRows.count();
|
||||
const songCount = await songItems.count();
|
||||
const headerCount = await headerItems.count();
|
||||
|
||||
expect(rowCount + songCount + headerCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('header items zeigen titel als ueberschrift', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const headerItems = page.getByTestId('agenda-header-item');
|
||||
const headerCount = await headerItems.count();
|
||||
|
||||
if (headerCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const firstHeader = headerItems.first();
|
||||
await expect(firstHeader).toBeVisible();
|
||||
const headerText = await firstHeader.textContent();
|
||||
expect(headerText?.trim().length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('song agenda items zeigen songtitel', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const songItems = page.getByTestId('song-agenda-item');
|
||||
const songCount = await songItems.count();
|
||||
|
||||
if (songCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const firstSong = songItems.first();
|
||||
await expect(firstSong).toBeVisible();
|
||||
|
||||
const songTitle = firstSong.getByTestId('song-agenda-title');
|
||||
await expect(songTitle).toBeVisible();
|
||||
const titleText = await songTitle.textContent();
|
||||
expect(titleText?.trim().length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('song agenda items zeigen arrangement pill wenn zugeordnet', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const arrangementPills = page.getByTestId('arrangement-pill');
|
||||
const pillCount = await arrangementPills.count();
|
||||
|
||||
if (pillCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const firstPill = arrangementPills.first();
|
||||
await expect(firstPill).toBeVisible();
|
||||
});
|
||||
|
||||
test('song agenda item zeigt arrangement bearbeiten button', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const editArrangementBtn = page.getByTestId('song-edit-arrangement');
|
||||
const hasBtn = await editArrangementBtn.first().isVisible().catch(() => false);
|
||||
|
||||
if (!hasBtn) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await expect(editArrangementBtn.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('generische agenda items zeigen titel', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const agendaRows = page.getByTestId('agenda-item-row');
|
||||
const rowCount = await agendaRows.count();
|
||||
|
||||
if (rowCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const firstRow = agendaRows.first();
|
||||
await expect(firstRow).toBeVisible();
|
||||
|
||||
const itemTitle = firstRow.getByTestId('agenda-item-title');
|
||||
await expect(itemTitle).toBeVisible();
|
||||
expect(await itemTitle.textContent()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('nicht zugeordnete songs zeigen erstellung anfragen button', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const requestBtn = page.getByTestId('song-request-creation');
|
||||
const hasUnmatched = await requestBtn.first().isVisible().catch(() => false);
|
||||
|
||||
if (!hasUnmatched) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await expect(requestBtn.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('song suche und manuelle zuordnung sichtbar bei nicht zugeordnetem song', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const searchInput = page.getByTestId('song-search-input');
|
||||
const hasSearch = await searchInput.first().isVisible().catch(() => false);
|
||||
|
||||
if (!hasSearch) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await expect(searchInput.first()).toBeVisible();
|
||||
|
||||
const assignBtn = page.getByTestId('song-assign-button');
|
||||
await expect(assignBtn.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('uebersetzungs checkbox sichtbar bei songs mit uebersetzung', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const translationCheckbox = page.getByTestId('song-translation-checkbox');
|
||||
const hasTranslation = await translationCheckbox.first().isVisible().catch(() => false);
|
||||
|
||||
if (!hasTranslation) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const initialState = await translationCheckbox.first().isChecked();
|
||||
|
||||
await translationCheckbox.first().click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const toggledState = await translationCheckbox.first().isChecked();
|
||||
expect(toggledState).not.toBe(initialState);
|
||||
|
||||
await translationCheckbox.first().click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const restoredState = await translationCheckbox.first().isChecked();
|
||||
expect(restoredState).toBe(initialState);
|
||||
});
|
||||
|
||||
test('sticky action bar ist sichtbar', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const actionBar = page.getByTestId('service-edit-action-bar');
|
||||
await expect(actionBar).toBeVisible();
|
||||
|
||||
const inProgress = page.getByText('In Bearbeitung');
|
||||
const finalized = page.getByText('Abgeschlossen');
|
||||
|
||||
const hasInProgress = await inProgress.isVisible().catch(() => false);
|
||||
const hasFinalized = await finalized.isVisible().catch(() => false);
|
||||
|
||||
expect(hasInProgress || hasFinalized).toBe(true);
|
||||
});
|
||||
|
||||
test('abschliessen button in action bar sichtbar', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const finalizeBtn = page.getByTestId('service-edit-finalize-button');
|
||||
const hasFinalizeBtn = await finalizeBtn.isVisible().catch(() => false);
|
||||
|
||||
if (!hasFinalizeBtn) {
|
||||
const reopenBtn = page.getByTestId('service-edit-reopen-button');
|
||||
await expect(reopenBtn).toBeVisible();
|
||||
return;
|
||||
}
|
||||
|
||||
await expect(finalizeBtn).toBeVisible();
|
||||
await expect(finalizeBtn).toContainText('Abschließen');
|
||||
|
||||
const finalizeDownloadBtn = page.getByTestId('service-edit-finalize-download-button');
|
||||
await expect(finalizeDownloadBtn).toBeVisible();
|
||||
});
|
||||
|
||||
test('zurueck button navigiert zur service liste', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const backBtn = page.getByTestId('service-edit-back-icon-button');
|
||||
await expect(backBtn).toBeVisible();
|
||||
|
||||
await backBtn.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await expect(page).toHaveURL(/.*services$/);
|
||||
});
|
||||
|
|
@ -25,12 +25,10 @@ test('navigate to first editable service edit page', async ({ page }) => {
|
|||
await expect(informationBlock).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 2: Information block accordion is visible and can be expanded/collapsed
|
||||
test('information block accordion is visible and can be expanded/collapsed', async ({ page }) => {
|
||||
test('information block is always visible without accordion toggle', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
|
|
@ -41,38 +39,12 @@ test('information block accordion is visible and can be expanded/collapsed', asy
|
|||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find the Information block toggle button
|
||||
const blockToggles = page.getByTestId('service-edit-block-toggle');
|
||||
const informationToggle = blockToggles.filter({ has: page.locator('text=Information') }).first();
|
||||
|
||||
const toggleExists = await informationToggle.isVisible().catch(() => false);
|
||||
if (!toggleExists) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify toggle button is visible
|
||||
await expect(informationToggle).toBeVisible();
|
||||
|
||||
// Get the Information block content container
|
||||
const informationBlock = page.getByTestId('information-block');
|
||||
|
||||
// Verify block is initially visible (expanded by default)
|
||||
await expect(informationBlock).toBeVisible();
|
||||
|
||||
// Click toggle to collapse
|
||||
await informationToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is hidden
|
||||
const isHidden = await informationBlock.isHidden().catch(() => true);
|
||||
expect(isHidden).toBe(true);
|
||||
|
||||
// Click toggle again to expand
|
||||
await informationToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is visible again
|
||||
await expect(informationBlock).toBeVisible();
|
||||
const blockToggles = page.getByTestId('service-edit-block-toggle');
|
||||
const toggleCount = await blockToggles.count();
|
||||
expect(toggleCount).toBe(0);
|
||||
});
|
||||
|
||||
// Test 3: Upload area is visible with drag-and-drop zone and click-to-upload
|
||||
|
|
|
|||
|
|
@ -1,204 +1,62 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// Test 1: Navigate to first editable (non-finalized) service edit page
|
||||
test('navigate to first editable service edit page', async ({ page }) => {
|
||||
async function navigateToEditPage(page) {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service (one with edit button)
|
||||
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('navigate to first editable service edit page', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Click edit button
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify we're on the edit page
|
||||
await expect(page).toHaveURL(/.*services\/\d+\/edit/);
|
||||
|
||||
// Verify Moderation block is visible
|
||||
const moderationBlock = page.getByTestId('moderation-block');
|
||||
await expect(moderationBlock).toBeVisible();
|
||||
const agendaSection = page.getByTestId('agenda-section');
|
||||
const emptyState = page.getByText('Keine Ablauf-Elemente vorhanden');
|
||||
const hasAgenda = await agendaSection.isVisible().catch(() => false);
|
||||
const hasEmptyState = await emptyState.isVisible().catch(() => false);
|
||||
|
||||
expect(hasAgenda || hasEmptyState).toBe(true);
|
||||
});
|
||||
|
||||
// Test 2: Moderation block accordion is visible and can be expanded/collapsed
|
||||
test('moderation block accordion is visible and can be expanded/collapsed', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
test.skip('moderation block accordion — replaced by agenda view', async () => {});
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test('agenda items with slides show slide uploader', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
const agendaRows = page.getByTestId('agenda-item-row');
|
||||
const rowCount = await agendaRows.count();
|
||||
|
||||
// Find the Moderation block toggle button
|
||||
const blockToggles = page.getByTestId('service-edit-block-toggle');
|
||||
const moderationToggle = blockToggles.filter({ has: page.locator('text=Moderation') }).first();
|
||||
|
||||
const toggleExists = await moderationToggle.isVisible().catch(() => false);
|
||||
if (!toggleExists) {
|
||||
if (rowCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify toggle button is visible
|
||||
await expect(moderationToggle).toBeVisible();
|
||||
const addSlidesBtn = page.getByTestId('agenda-item-add-slides').first();
|
||||
const hasSlidesBtn = await addSlidesBtn.isVisible().catch(() => false);
|
||||
|
||||
// Get the Moderation block content container
|
||||
const moderationBlock = page.getByTestId('moderation-block');
|
||||
|
||||
// Verify block is initially visible (expanded by default)
|
||||
await expect(moderationBlock).toBeVisible();
|
||||
if (!hasSlidesBtn) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Click toggle to collapse
|
||||
await moderationToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is hidden
|
||||
const isHidden = await moderationBlock.isHidden().catch(() => true);
|
||||
expect(isHidden).toBe(true);
|
||||
|
||||
// Click toggle again to expand
|
||||
await moderationToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is visible again
|
||||
await expect(moderationBlock).toBeVisible();
|
||||
await expect(addSlidesBtn).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 3: Upload area is visible with drag-and-drop zone (NO datepicker)
|
||||
test('upload area is visible with drag-and-drop zone', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
test.skip('existing moderation slides display as thumbnails — replaced by agenda item slides', async () => {});
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify Moderation block uploader is visible
|
||||
const uploader = page.getByTestId('moderation-block-uploader');
|
||||
await expect(uploader).toBeVisible();
|
||||
|
||||
// Verify dropzone is visible
|
||||
const dropzone = page.getByTestId('slide-uploader-dropzone');
|
||||
await expect(dropzone).toBeVisible();
|
||||
|
||||
// Verify dropzone contains expected text
|
||||
await expect(dropzone).toContainText('Dateien hier ablegen');
|
||||
await expect(dropzone).toContainText('oder klicken zum Auswählen');
|
||||
|
||||
// Verify NO expire date input (unlike Information block)
|
||||
const expireInput = page.getByTestId('slide-uploader-expire-input');
|
||||
const expireInputExists = await expireInput.isVisible().catch(() => false);
|
||||
expect(expireInputExists).toBe(false);
|
||||
});
|
||||
|
||||
// Test 4: Existing moderation slides display as thumbnails
|
||||
test('existing moderation slides display as thumbnails', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify slide grid is visible
|
||||
const slideGrid = page.getByTestId('moderation-block-grid');
|
||||
await expect(slideGrid).toBeVisible();
|
||||
|
||||
// Check if slides exist
|
||||
const slideThumbnails = page.locator('[data-testid="slide-grid-delete-button"]');
|
||||
const slideCount = await slideThumbnails.count();
|
||||
|
||||
if (slideCount === 0) {
|
||||
// No slides exist - verify empty state message
|
||||
const emptyState = slideGrid.locator('text=Noch keine Folien vorhanden');
|
||||
await expect(emptyState).toBeVisible();
|
||||
return;
|
||||
}
|
||||
|
||||
// Slides exist - verify first thumbnail is visible
|
||||
const firstThumbnail = page.locator('[data-testid="slide-grid-delete-button"]').first();
|
||||
await expect(firstThumbnail).toBeVisible();
|
||||
|
||||
// Verify delete button is visible on hover
|
||||
const deleteButton = firstThumbnail;
|
||||
await expect(deleteButton).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 5: Delete button on moderation slide thumbnail triggers confirmation
|
||||
test('delete button on moderation slide thumbnail triggers confirmation', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Check if slides exist
|
||||
const slideThumbnails = page.locator('[data-testid="slide-grid-delete-button"]');
|
||||
const slideCount = await slideThumbnails.count();
|
||||
|
||||
if (slideCount === 0) {
|
||||
// No slides exist - skip this test
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Get first delete button
|
||||
const firstDeleteButton = page.getByTestId('slide-grid-delete-button').first();
|
||||
await expect(firstDeleteButton).toBeVisible();
|
||||
|
||||
// Click delete button
|
||||
await firstDeleteButton.click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// Verify confirmation dialog appears
|
||||
const confirmDialog = page.locator('text=Folie löschen?');
|
||||
await expect(confirmDialog).toBeVisible();
|
||||
|
||||
// Verify dialog contains expected text
|
||||
await expect(page.locator('text=Möchtest du die Folie')).toBeVisible();
|
||||
await expect(page.locator('text=wirklich löschen?')).toBeVisible();
|
||||
|
||||
// Verify cancel button is visible
|
||||
const cancelButton = page.locator('button:has-text("Abbrechen")').first();
|
||||
await expect(cancelButton).toBeVisible();
|
||||
|
||||
// Click cancel to close dialog without deleting
|
||||
await cancelButton.click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// Verify dialog is closed
|
||||
const dialogClosed = await confirmDialog.isHidden().catch(() => true);
|
||||
expect(dialogClosed).toBe(true);
|
||||
});
|
||||
test.skip('delete button on moderation slide triggers confirmation — replaced by agenda item slides', async () => {});
|
||||
|
|
|
|||
|
|
@ -1,204 +1,41 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// Test 1: Navigate to first editable (non-finalized) service edit page
|
||||
test('navigate to first editable service edit page', async ({ page }) => {
|
||||
async function navigateToEditPage(page) {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service (one with edit button)
|
||||
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('navigate to first editable service edit page', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Click edit button
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify we're on the edit page
|
||||
await expect(page).toHaveURL(/.*services\/\d+\/edit/);
|
||||
|
||||
// Verify Sermon block is visible
|
||||
const sermonBlock = page.getByTestId('sermon-block');
|
||||
await expect(sermonBlock).toBeVisible();
|
||||
const agendaSection = page.getByTestId('agenda-section');
|
||||
const emptyState = page.getByText('Keine Ablauf-Elemente vorhanden');
|
||||
const hasAgenda = await agendaSection.isVisible().catch(() => false);
|
||||
const hasEmptyState = await emptyState.isVisible().catch(() => false);
|
||||
|
||||
expect(hasAgenda || hasEmptyState).toBe(true);
|
||||
});
|
||||
|
||||
// Test 2: Sermon block accordion is visible and can be expanded/collapsed
|
||||
test('sermon block accordion is visible and can be expanded/collapsed', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
test.skip('sermon block accordion — replaced by agenda view', async () => {});
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
test.skip('sermon upload area — replaced by agenda item slide uploader', async () => {});
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
test.skip('existing sermon slides as thumbnails — replaced by agenda item slides', async () => {});
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find the Sermon block toggle button (3rd block)
|
||||
const blockToggles = page.getByTestId('service-edit-block-toggle');
|
||||
const sermonToggle = blockToggles.filter({ has: page.locator('text=Predigt') }).first();
|
||||
|
||||
const toggleExists = await sermonToggle.isVisible().catch(() => false);
|
||||
if (!toggleExists) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify toggle button is visible
|
||||
await expect(sermonToggle).toBeVisible();
|
||||
|
||||
// Get the Sermon block content container
|
||||
const sermonBlock = page.getByTestId('sermon-block');
|
||||
|
||||
// Verify block is initially visible (expanded by default)
|
||||
await expect(sermonBlock).toBeVisible();
|
||||
|
||||
// Click toggle to collapse
|
||||
await sermonToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is hidden
|
||||
const isHidden = await sermonBlock.isHidden().catch(() => true);
|
||||
expect(isHidden).toBe(true);
|
||||
|
||||
// Click toggle again to expand
|
||||
await sermonToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is visible again
|
||||
await expect(sermonBlock).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 3: Upload area is visible with drag-and-drop zone (NO datepicker)
|
||||
test('upload area is visible with drag-and-drop zone', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify Sermon block uploader is visible
|
||||
const uploader = page.getByTestId('sermon-block-uploader');
|
||||
await expect(uploader).toBeVisible();
|
||||
|
||||
// Verify dropzone is visible
|
||||
const dropzone = page.getByTestId('slide-uploader-dropzone');
|
||||
await expect(dropzone).toBeVisible();
|
||||
|
||||
// Verify dropzone contains expected text
|
||||
await expect(dropzone).toContainText('Dateien hier ablegen');
|
||||
await expect(dropzone).toContainText('oder klicken zum Auswählen');
|
||||
|
||||
// Verify NO expire date input (unlike Information block)
|
||||
const expireInput = page.getByTestId('slide-uploader-expire-input');
|
||||
const expireInputExists = await expireInput.isVisible().catch(() => false);
|
||||
expect(expireInputExists).toBe(false);
|
||||
});
|
||||
|
||||
// Test 4: Existing sermon slides display as thumbnails
|
||||
test('existing sermon slides display as thumbnails', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify slide grid is visible
|
||||
const slideGrid = page.getByTestId('sermon-block-grid');
|
||||
await expect(slideGrid).toBeVisible();
|
||||
|
||||
// Check if slides exist
|
||||
const slideThumbnails = page.locator('[data-testid="slide-grid-delete-button"]');
|
||||
const slideCount = await slideThumbnails.count();
|
||||
|
||||
if (slideCount === 0) {
|
||||
// No slides exist - verify empty state message
|
||||
const emptyState = slideGrid.locator('text=Noch keine Folien vorhanden');
|
||||
await expect(emptyState).toBeVisible();
|
||||
return;
|
||||
}
|
||||
|
||||
// Slides exist - verify first thumbnail is visible
|
||||
const firstThumbnail = page.locator('[data-testid="slide-grid-delete-button"]').first();
|
||||
await expect(firstThumbnail).toBeVisible();
|
||||
|
||||
// Verify delete button is visible on hover
|
||||
const deleteButton = firstThumbnail;
|
||||
await expect(deleteButton).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 5: Delete button on sermon slide thumbnail triggers confirmation
|
||||
test('delete button on sermon slide thumbnail triggers confirmation', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Find first unfinalized service
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Check if slides exist
|
||||
const slideThumbnails = page.locator('[data-testid="slide-grid-delete-button"]');
|
||||
const slideCount = await slideThumbnails.count();
|
||||
|
||||
if (slideCount === 0) {
|
||||
// No slides exist - skip this test
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Get first delete button
|
||||
const firstDeleteButton = page.getByTestId('slide-grid-delete-button').first();
|
||||
await expect(firstDeleteButton).toBeVisible();
|
||||
|
||||
// Click delete button
|
||||
await firstDeleteButton.click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// Verify confirmation dialog appears
|
||||
const confirmDialog = page.locator('text=Folie löschen?');
|
||||
await expect(confirmDialog).toBeVisible();
|
||||
|
||||
// Verify dialog contains expected text
|
||||
await expect(page.locator('text=Möchtest du die Folie')).toBeVisible();
|
||||
await expect(page.locator('text=wirklich löschen?')).toBeVisible();
|
||||
|
||||
// Verify cancel button is visible
|
||||
const cancelButton = page.locator('button:has-text("Abbrechen")').first();
|
||||
await expect(cancelButton).toBeVisible();
|
||||
|
||||
// Click cancel to close dialog without deleting
|
||||
await cancelButton.click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// Verify dialog is closed
|
||||
const dialogClosed = await confirmDialog.isHidden().catch(() => true);
|
||||
expect(dialogClosed).toBe(true);
|
||||
});
|
||||
test.skip('delete button on sermon slide — replaced by agenda item slides', async () => {});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// Test 1: Songs block accordion can be expanded and collapsed
|
||||
test('songs block accordion can be expanded and collapsed', async ({ page }) => {
|
||||
async function navigateToEditPage(page) {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
|
@ -9,375 +8,184 @@ test('songs block accordion can be expanded and collapsed', async ({ page }) =>
|
|||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
return false;
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find the Songs block toggle button (4th block)
|
||||
const blockToggles = page.getByTestId('service-edit-block-toggle');
|
||||
const songsToggle = blockToggles.filter({ has: page.locator('text=Songs') }).first();
|
||||
test.skip('songs block accordion — replaced by agenda view', async () => {});
|
||||
|
||||
const toggleExists = await songsToggle.isVisible().catch(() => false);
|
||||
if (!toggleExists) {
|
||||
test('song items visible in agenda or empty state', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await expect(songsToggle).toBeVisible();
|
||||
|
||||
// Get the Songs block content container
|
||||
const songsBlock = page.getByTestId('songs-block');
|
||||
|
||||
// Verify block is initially visible (expanded by default)
|
||||
await expect(songsBlock).toBeVisible();
|
||||
|
||||
// Click toggle to collapse
|
||||
await songsToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is hidden
|
||||
const isHidden = await songsBlock.isHidden().catch(() => true);
|
||||
expect(isHidden).toBe(true);
|
||||
|
||||
// Click toggle again to expand
|
||||
await songsToggle.click();
|
||||
await page.waitForTimeout(300); // Wait for transition
|
||||
|
||||
// Verify block is visible again
|
||||
await expect(songsBlock).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 2: Song list shows songs in correct order or empty state
|
||||
test('song list shows songs or empty state', async ({ page }) => {
|
||||
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) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const songsBlock = page.getByTestId('songs-block');
|
||||
await expect(songsBlock).toBeVisible();
|
||||
|
||||
// Check for song cards
|
||||
const songCards = page.getByTestId('songs-block-song-card');
|
||||
const songCount = await songCards.count();
|
||||
const songItems = page.getByTestId('song-agenda-item');
|
||||
const songCount = await songItems.count();
|
||||
|
||||
if (songCount === 0) {
|
||||
// No songs - verify empty state message
|
||||
await expect(songsBlock).toContainText('Fuer diesen Service sind aktuell keine Songs vorhanden.');
|
||||
const emptyState = page.getByText('Keine Ablauf-Elemente vorhanden');
|
||||
const hasEmptyState = await emptyState.isVisible().catch(() => false);
|
||||
expect(hasEmptyState).toBe(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Songs exist - verify first card is rendered with order label
|
||||
const firstSongCard = songCards.first();
|
||||
await expect(firstSongCard).toBeVisible();
|
||||
await expect(firstSongCard.locator('text=/Song \\d+/')).toBeVisible();
|
||||
const firstSongItem = songItems.first();
|
||||
await expect(firstSongItem).toBeVisible();
|
||||
|
||||
const songTitle = firstSongItem.getByTestId('song-agenda-title');
|
||||
await expect(songTitle).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 3: Each song row shows name, CCLI ID, and status badge
|
||||
test('song row shows name, CCLI ID, and status badge', async ({ page }) => {
|
||||
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) {
|
||||
test('song agenda item shows title and ccli info', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const songCards = page.getByTestId('songs-block-song-card');
|
||||
const songCount = await songCards.count();
|
||||
const songItems = page.getByTestId('song-agenda-item');
|
||||
const songCount = await songItems.count();
|
||||
|
||||
if (songCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const firstSongCard = songCards.first();
|
||||
|
||||
// Verify CCLI label exists
|
||||
await expect(firstSongCard.locator('text=/CCLI:/')).toBeVisible();
|
||||
|
||||
// Verify translation indicator exists
|
||||
await expect(firstSongCard.locator('text=/Hat Uebersetzung:/')).toBeVisible();
|
||||
|
||||
// Verify status badge exists (either "Zugeordnet" or "Nicht zugeordnet")
|
||||
const statusBadge = firstSongCard.locator('text=/zugeordnet/i').first();
|
||||
await expect(statusBadge).toBeVisible();
|
||||
const firstSongItem = songItems.first();
|
||||
const songTitle = firstSongItem.getByTestId('song-agenda-title');
|
||||
await expect(songTitle).toBeVisible();
|
||||
});
|
||||
|
||||
// Test 4: Unmatched songs show "Erstellung anfragen" button and manual assign select
|
||||
test('unmatched songs show request creation button and manual assign', async ({ page }) => {
|
||||
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) {
|
||||
test('unmatched songs show request creation button in agenda', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const songCards = page.getByTestId('songs-block-song-card');
|
||||
const songCount = await songCards.count();
|
||||
|
||||
if (songCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Look for unmatched song card (has "Nicht zugeordnet" badge)
|
||||
const unmatchedCard = songCards.filter({ has: page.locator('text=Nicht zugeordnet') }).first();
|
||||
const hasUnmatched = await unmatchedCard.isVisible().catch(() => false);
|
||||
const requestButton = page.getByTestId('song-request-creation').first();
|
||||
const hasUnmatched = await requestButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasUnmatched) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify "Erstellung anfragen" button
|
||||
const requestButton = page.getByTestId('songs-block-request-button').first();
|
||||
await expect(requestButton).toBeVisible();
|
||||
await expect(requestButton).toContainText('Erstellung anfragen');
|
||||
|
||||
// Verify search input
|
||||
const searchInput = page.getByTestId('songs-block-search-input').first();
|
||||
const searchInput = page.getByTestId('song-search-input').first();
|
||||
await expect(searchInput).toBeVisible();
|
||||
|
||||
// Verify song select dropdown
|
||||
const songSelect = page.getByTestId('songs-block-song-select').first();
|
||||
await expect(songSelect).toBeVisible();
|
||||
|
||||
// Verify "Zuordnen" (assign) button
|
||||
const assignButton = page.getByTestId('songs-block-assign-button').first();
|
||||
const assignButton = page.getByTestId('song-assign-button').first();
|
||||
await expect(assignButton).toBeVisible();
|
||||
await expect(assignButton).toContainText('Zuordnen');
|
||||
});
|
||||
|
||||
// Test 5: Matched songs show arrangement dropdown with options
|
||||
test('matched songs show arrangement dropdown with options', async ({ page }) => {
|
||||
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) {
|
||||
test('matched songs show arrangement pill in agenda', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
const arrangementPill = page.getByTestId('arrangement-pill').first();
|
||||
const hasPill = await arrangementPill.isVisible().catch(() => false);
|
||||
|
||||
// Check for arrangement configurator (only present for matched songs)
|
||||
const arrangementConfigurator = page.getByTestId('arrangement-configurator').first();
|
||||
const hasMatched = await arrangementConfigurator.isVisible().catch(() => false);
|
||||
|
||||
if (!hasMatched) {
|
||||
if (!hasPill) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await expect(arrangementPill).toBeVisible();
|
||||
});
|
||||
|
||||
test('arrangement edit button opens arrangement dialog', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const editArrangementBtn = page.getByTestId('song-edit-arrangement').first();
|
||||
const hasBtn = await editArrangementBtn.isVisible().catch(() => false);
|
||||
|
||||
if (!hasBtn) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editArrangementBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const arrangementDialog = page.getByTestId('arrangement-dialog');
|
||||
await expect(arrangementDialog).toBeVisible();
|
||||
|
||||
const closeBtn = page.getByTestId('arrangement-dialog-close-btn');
|
||||
await closeBtn.click();
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
test('arrangement dialog has select, add, clone buttons', async ({ page }) => {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
const editArrangementBtn = page.getByTestId('song-edit-arrangement').first();
|
||||
const hasBtn = await editArrangementBtn.isVisible().catch(() => false);
|
||||
|
||||
if (!hasBtn) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editArrangementBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const arrangementDialog = page.getByTestId('arrangement-dialog');
|
||||
const dialogVisible = await arrangementDialog.isVisible().catch(() => false);
|
||||
|
||||
if (!dialogVisible) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify arrangement select dropdown exists
|
||||
const arrangementSelect = page.getByTestId('arrangement-select').first();
|
||||
await expect(arrangementSelect).toBeVisible();
|
||||
|
||||
// Verify add button
|
||||
const addButton = page.getByTestId('arrangement-add-button').first();
|
||||
const addButton = page.getByTestId('arrangement-new-btn').first();
|
||||
await expect(addButton).toBeVisible();
|
||||
await expect(addButton).toContainText('Hinzufügen');
|
||||
|
||||
// Verify clone button
|
||||
const cloneButton = page.getByTestId('arrangement-clone-button').first();
|
||||
const cloneButton = page.getByTestId('arrangement-clone-btn').first();
|
||||
await expect(cloneButton).toBeVisible();
|
||||
await expect(cloneButton).toContainText('Klonen');
|
||||
|
||||
const closeBtn = page.getByTestId('arrangement-dialog-close-btn');
|
||||
await closeBtn.click();
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
// Test 6: Arrangement "Hinzufügen" (Add) button opens name prompt
|
||||
test('arrangement add button opens name prompt', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
test.skip('preview button is present for matched songs — replaced by agenda view', async () => {});
|
||||
|
||||
const editButton = page.getByTestId('service-list-edit-button').first();
|
||||
const hasEditableService = await editButton.isVisible().catch(() => false);
|
||||
test.skip('download button is present for matched songs — replaced by agenda view', async () => {});
|
||||
|
||||
if (!hasEditableService) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const addButton = page.getByTestId('arrangement-add-button').first();
|
||||
const hasMatched = await addButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasMatched) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Set up dialog handler before clicking (window.prompt is synchronous)
|
||||
let promptShown = false;
|
||||
page.once('dialog', async (dialog) => {
|
||||
promptShown = true;
|
||||
expect(dialog.type()).toBe('prompt');
|
||||
expect(dialog.message()).toContain('Name des neuen Arrangements');
|
||||
await dialog.dismiss(); // Cancel without creating
|
||||
});
|
||||
|
||||
await addButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
expect(promptShown).toBe(true);
|
||||
});
|
||||
|
||||
// Test 7: Arrangement "Klonen" (Clone) button opens name prompt
|
||||
test('arrangement clone button opens name prompt', async ({ page }) => {
|
||||
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) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const cloneButton = page.getByTestId('arrangement-clone-button').first();
|
||||
const hasMatched = await cloneButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasMatched) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify arrangement select has options (clone requires a selected arrangement)
|
||||
const arrangementSelect = page.getByTestId('arrangement-select').first();
|
||||
const optionCount = await arrangementSelect.locator('option').count();
|
||||
|
||||
if (optionCount === 0) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Set up dialog handler before clicking
|
||||
let promptShown = false;
|
||||
page.once('dialog', async (dialog) => {
|
||||
promptShown = true;
|
||||
expect(dialog.type()).toBe('prompt');
|
||||
expect(dialog.message()).toContain('Name des neuen Arrangements');
|
||||
await dialog.dismiss(); // Cancel without creating
|
||||
});
|
||||
|
||||
await cloneButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
expect(promptShown).toBe(true);
|
||||
});
|
||||
|
||||
// Test 8: Preview button opens song preview (placeholder toast for now)
|
||||
test('preview button is present for matched songs', async ({ page }) => {
|
||||
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) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const previewButton = page.getByTestId('songs-block-preview-button').first();
|
||||
const hasMatched = await previewButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasMatched) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify preview button exists with correct text
|
||||
await expect(previewButton).toBeVisible();
|
||||
await expect(previewButton).toContainText('Vorschau');
|
||||
});
|
||||
|
||||
// Test 9: Download (PDF) button is present for songs with selected arrangement
|
||||
test('download button is present for matched songs', async ({ page }) => {
|
||||
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) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const downloadButton = page.getByTestId('songs-block-download-button').first();
|
||||
const hasMatched = await downloadButton.isVisible().catch(() => false);
|
||||
|
||||
if (!hasMatched) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Verify download button exists with correct text
|
||||
await expect(downloadButton).toBeVisible();
|
||||
await expect(downloadButton).toContainText('PDF herunterladen');
|
||||
});
|
||||
|
||||
// Test 10: Translation checkbox toggles (if song has translation)
|
||||
test('translation checkbox toggles if song has translation', async ({ page }) => {
|
||||
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) {
|
||||
const navigated = await navigateToEditPage(page);
|
||||
if (!navigated) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await editButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const translationCheckbox = page.getByTestId('songs-block-translation-checkbox').first();
|
||||
const translationCheckbox = page.getByTestId('song-translation-checkbox').first();
|
||||
const hasTranslation = await translationCheckbox.isVisible().catch(() => false);
|
||||
|
||||
if (!hasTranslation) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
// Get current checked state
|
||||
const initialState = await translationCheckbox.isChecked();
|
||||
|
||||
// Toggle the checkbox
|
||||
await translationCheckbox.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
// Verify state changed
|
||||
const toggledState = await translationCheckbox.isChecked();
|
||||
expect(toggledState).not.toBe(initialState);
|
||||
|
||||
// Toggle back to restore original state
|
||||
await translationCheckbox.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
// Verify restored to original state
|
||||
const restoredState = await translationCheckbox.isChecked();
|
||||
expect(restoredState).toBe(initialState);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue