Files
HamHam/tests/e2e/admin.spec.ts

124 lines
6.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect } from '@playwright/test';
import { readFile } from 'node:fs/promises';
import { exportRecipes } from '../../src/lib/import';
import { pasta } from '../fixtures';
test('admin creates and edits recipes with recoverable drafts and image upload', async ({
page,
}) => {
await page.goto('/admin');
await page.getByRole('textbox', { name: 'Benutzername' }).fill('testadmin');
await page.getByLabel('Passwort', { exact: true }).fill(process.env.TEST_PASSWORD!);
await page.getByRole('button', { name: 'Anmelden', exact: true }).click();
await expect(page.getByRole('heading', { name: 'Hallo, testadmin.' })).toBeVisible();
await page.getByRole('link', { name: 'Neues Rezept' }).click();
await page
.getByRole('textbox', { name: 'Rezepttitel', exact: true })
.fill('Browser-Küchenrezept');
await page
.getByRole('textbox', { name: 'Beschreibung', exact: true })
.fill('Ein echtes Rezept aus dem grafischen Editor.');
page.on('dialog', (d) => d.accept());
await page.reload();
await expect(page.getByRole('textbox', { name: 'Rezepttitel', exact: true })).toHaveValue(
'Browser-Küchenrezept',
);
await page.getByLabel('Titelbild hochladen').setInputFiles('public/images/garden.jpg');
await expect(page.getByRole('img', { name: 'Titelbild', exact: true })).toBeVisible();
await page.getByRole('checkbox', { name: /Rezept veröffentlichen/ }).check();
await page.getByRole('button', { name: 'Zutaten', exact: true }).click();
await page.getByRole('textbox', { name: 'Zutat 1', exact: true }).fill('Kartoffeln');
await page.getByRole('spinbutton', { name: 'Menge 1', exact: true }).fill('400');
await page.getByRole('button', { name: 'Zutat hinzufügen' }).click();
await page.getByRole('textbox', { name: 'Zutat 2', exact: true }).fill('Salz');
await page.getByRole('combobox', { name: 'Einheit 2', exact: true }).selectOption('');
await page.getByRole('button', { name: 'Zubereitung', exact: true }).click();
await page.getByRole('textbox', { name: 'Schritttitel 1' }).fill('Kartoffeln kochen');
await page.getByRole('textbox', { name: 'Anleitung 1' }).fill('In Salzwasser weich kochen.');
await page.getByRole('button', { name: 'Kartoffeln', exact: true }).click();
await page.getByRole('button', { name: 'Timer hinzufügen' }).click();
await page.getByText('Bilder zu Schritt 1 (0)', { exact: true }).click();
await page.getByLabel('Schritt 1: Bild hochladen').setInputFiles('public/images/garden.jpg');
await expect(page.getByRole('img', { name: 'Schritt 1: Bild 1', exact: true })).toBeVisible();
await page.getByRole('button', { name: 'Live-Vorschau', exact: true }).click();
await expect(page.locator('.editor-preview')).toContainText('400 g Kartoffeln');
await page.screenshot({ path: 'docs/screenshots/editor-desktop.png', fullPage: true });
await page.getByRole('button', { name: 'Rezept speichern' }).click();
await expect(page).toHaveURL(/\/admin\/rezepte\/[a-f0-9-]{36}$/);
await page.getByRole('button', { name: 'Das Rezept', exact: true }).click();
await page
.getByRole('textbox', { name: 'Rezepttitel', exact: true })
.fill('Browser-Küchenrezept verbessert');
const saved = page.waitForResponse(
(r) => r.url().includes('/api/recipes/') && r.request().method() === 'PUT',
);
await page.getByRole('button', { name: 'Rezept speichern' }).click();
expect((await saved).status()).toBe(200);
await expect(page.getByRole('status')).toContainText('erfolgreich gespeichert');
await page.goto('/admin');
await expect(
page.getByRole('heading', { name: 'Browser-Küchenrezept verbessert' }),
).toBeVisible();
const downloadPromise = page.waitForEvent('download');
await page
.getByRole('link', { name: 'Browser-Küchenrezept verbessert als JSON exportieren' })
.click();
const download = await downloadPromise;
const data = JSON.parse(await readFile((await download.path())!, 'utf8'));
expect(data.recipes[0].title).toBe('Browser-Küchenrezept verbessert');
const stepImage = data.recipes[0].steps[0].images[0];
expect(stepImage).toMatch(/^\/media\/.+\.webp$/);
expect(
(
await page.request.delete('/api/media', {
headers: { origin: 'http://localhost:3100' },
data: { name: stepImage.split('/').at(-1) },
})
).status(),
).toBe(409);
await page.getByRole('button', { name: 'Browser-Küchenrezept verbessert löschen' }).click();
await page.getByRole('button', { name: 'Endgültig löschen' }).click();
await expect(page.getByRole('heading', { name: 'Browser-Küchenrezept verbessert' })).toHaveCount(
0,
);
expect(
(
await page.request.delete('/api/media', {
headers: { origin: 'http://localhost:3100' },
data: { name: stepImage.split('/').at(-1) },
})
).status(),
).toBe(200);
await page.getByRole('button', { name: 'Abmelden' }).click();
await expect(page.getByRole('heading', { name: 'Willkommen zurück.' })).toBeVisible();
});
test('JSON and XML import with a real preview, duplicate prevention and export', async ({
page,
}) => {
await page.goto('/admin');
await page.getByLabel('Benutzername').fill('testadmin');
await page.getByLabel('Passwort', { exact: true }).fill(process.env.TEST_PASSWORD!);
await page.getByRole('button', { name: 'Anmelden', exact: true }).click();
for (const format of ['json', 'xml'] as const) {
await page.getByRole('button', { name: 'Importieren', exact: true }).click();
await page.getByLabel('Importformat').selectOption(format);
const recipe = {
...pasta,
id: undefined,
title: `Importierte ${format.toUpperCase()} Pasta`,
published: false,
};
await page.getByLabel('Rezeptdaten').fill(exportRecipes([recipe], format));
await page.getByRole('button', { name: 'Importvorschau prüfen' }).click();
await expect(page.locator('.import-preview')).toContainText(recipe.title);
await expect(page.locator('.import-preview')).toContainText('200 g Pasta');
await page.getByRole('button', { name: '1 Rezept(e) jetzt importieren' }).click();
await expect(page.getByRole('heading', { name: recipe.title })).toBeVisible();
await page.reload();
}
await page.getByRole('button', { name: 'Importieren', exact: true }).click();
await page.getByLabel('Rezeptdaten').fill(exportRecipes([pasta], 'json'));
await page.getByRole('button', { name: 'Importvorschau prüfen' }).click();
await expect(page.getByText('Duplikat – Import gesperrt')).toBeVisible();
await expect(page.getByRole('button', { name: '1 Rezept(e) jetzt importieren' })).toBeDisabled();
});