diff --git a/e2e/woche.spec.ts b/e2e/woche.spec.ts new file mode 100644 index 0000000..94d7394 --- /dev/null +++ b/e2e/woche.spec.ts @@ -0,0 +1,126 @@ +import { PrismaPg } from '@prisma/adapter-pg' +import { expect, test, type Page } from '@playwright/test' +import { PrismaClient } from '../src/generated/prisma/client.js' + +/** + * Wochenansicht und Zeitblöcke. + * + * Ohne echtes Kalenderkonto lässt sich der Schreibweg zum Anbieter nicht + * prüfen — er scheitert dann und der Zeitblock trägt einen Fehler. Genau das + * ist aber selbst prüfenswert: Die Planung muss auch dann überleben, wenn der + * Kalender nicht erreichbar ist. + */ + +const EMAIL = process.env.ADMIN_EMAIL ?? '' +const PASSWORT = process.env.ADMIN_PASSWORT ?? '' +const PRAEFIX = `E2E-W-${Date.now()}` + +const verbindung = process.env.DATABASE_URL ?? '' +const db = new PrismaClient({ adapter: new PrismaPg({ connectionString: verbindung }) }) + +test.describe('Woche', () => { + test.skip( + !EMAIL || !PASSWORT || !verbindung, + 'Ohne ADMIN_EMAIL, ADMIN_PASSWORT und DATABASE_URL gibt es kein Testkonto.', + ) + + test.afterAll(async () => { + await db.zeitblock.deleteMany({ + where: { aufgabe: { titel: { startsWith: PRAEFIX } } }, + }) + await db.aufgabe.deleteMany({ where: { titel: { startsWith: PRAEFIX } } }) + await db.kalenderkonto.deleteMany({ where: { extKontoId: { startsWith: PRAEFIX } } }) + await db.auditEintrag.deleteMany({ where: { aktion: { startsWith: 'zeitblock.' } } }) + await db.$disconnect() + }) + + async function anmelden(seite: Page): Promise { + await seite.goto('/anmelden') + await seite.getByLabel('E-Mail-Adresse').fill(EMAIL) + await seite.getByLabel('Passwort').fill(PASSWORT) + await seite.getByRole('button', { name: 'Mit Passwort anmelden' }).click() + await expect(seite.getByRole('heading', { name: /Guten Tag/ })).toBeVisible() + } + + test('weist ohne verbundenen Kalender darauf hin', async ({ page }) => { + await db.kalenderkonto.deleteMany({}) + await anmelden(page) + await page.goto('/woche') + + await expect(page.getByRole('heading', { name: 'Woche' })).toBeVisible() + await expect(page.getByText('Noch kein Kalender verbunden')).toBeVisible() + await expect( + page.getByText('Ohne verbundenen Kalender lässt sich nichts'), + ).toBeVisible() + }) + + test('zeigt einen Zeitblock im Raster und plant ihn wieder aus', async ({ page }) => { + const benutzer = await db.benutzer.findUniqueOrThrow({ where: { email: EMAIL } }) + + // Ein Kalenderkonto ohne gültige Tokens: die Ansicht funktioniert, der + // Schreibweg zum Anbieter nicht. + const konto = await db.kalenderkonto.create({ + data: { + benutzerId: benutzer.id, + anbieter: 'GRAPH', + anzeigename: `${PRAEFIX} Testkalender`, + extKontoId: `${PRAEFIX}-konto`, + }, + }) + + const aufgabe = await db.aufgabe.create({ + data: { titel: `${PRAEFIX} Angebot schreiben`, aufwandMinuten: 60 }, + }) + + // Zeitblock auf 10:00 Uhr des Montags dieser Woche legen. + const jetzt = new Date() + const montag = new Date(jetzt) + montag.setUTCHours(0, 0, 0, 0) + montag.setUTCDate(montag.getUTCDate() - ((montag.getUTCDay() + 6) % 7)) + const beginn = new Date(montag.getTime() + 10 * 60 * 60 * 1000) + + await db.zeitblock.create({ + data: { + aufgabeId: aufgabe.id, + kalenderkontoId: konto.id, + beginn, + ende: new Date(beginn.getTime() + 60 * 60 * 1000), + }, + }) + await db.aufgabe.update({ + where: { id: aufgabe.id }, + data: { status: 'GEPLANT' }, + }) + + await anmelden(page) + await page.goto('/woche') + + const block = page.getByTitle(new RegExp(`${PRAEFIX} Angebot schreiben`)) + await expect(block).toBeVisible() + + // Ausplanen: der Block verschwindet, die Aufgabe fällt zurück auf offen. + await block.getByRole('button', { name: 'Ausplanen' }).click() + await expect(page.getByText('ausgeplant')).toBeVisible() + + await expect + .poll(async () => db.zeitblock.count({ where: { aufgabeId: aufgabe.id } })) + .toBe(0) + + const danach = await db.aufgabe.findUniqueOrThrow({ where: { id: aufgabe.id } }) + expect(danach.status).toBe('OFFEN') + }) + + test('lässt sich durch die Wochen blättern', async ({ page }) => { + await anmelden(page) + await page.goto('/woche') + + await page.getByRole('link', { name: 'Weiter' }).click() + await expect(page).toHaveURL(/versatz=1/) + + await page.getByRole('link', { name: 'Zurück' }).click() + await expect(page).toHaveURL(/versatz=0/) + + await page.getByRole('link', { name: 'Diese Woche' }).click() + await expect(page).toHaveURL(/\/woche$/) + }) +})