Files
planer/e2e/aufgaben.spec.ts
T
Florian WildeandClaude Opus 5 6e1f2791cd test: Benachrichtigungen end-to-end und in der Datenbank absichern
Die Einstellung haelt ueber das Neuladen, ohne eingeschalteten Weg geht
nichts hinaus, und ein unsinniger Vorlauf wird auch dann abgewiesen, wenn
er an der Oberflaeche vorbei hereinkommt.

Der Anmeldehelfer liegt jetzt einmal in e2e/hilfe.ts und fasst nach: ein
Klick, der vor der Hydratation ankommt, verpufft folgenlos — das hat die
Testlaeufe unter Last wiederholt scheitern lassen.

Der Integrationstest prueft die drei neuen Tabellen samt Kaskade.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:28:32 +02:00

178 lines
6.9 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 { PrismaPg } from '@prisma/adapter-pg'
import { expect, test } from '@playwright/test'
import { PrismaClient } from '../src/generated/prisma/client.js'
import { anmelden, EMAIL, PASSWORT, VERBINDUNG } from './hilfe'
/**
* Der Weg, der in M2 wirklich zählt: erfassen, einsortieren, abhaken.
*
* Alle Testdaten tragen ein gemeinsames Präfix und werden am Ende entfernt,
* damit die Entwicklungsdatenbank hinterher aussieht wie vorher.
*/
const PRAEFIX = `E2E-${Date.now()}`
const db = new PrismaClient({ adapter: new PrismaPg({ connectionString: VERBINDUNG }) })
test.describe('Aufgaben', () => {
test.skip(
!EMAIL || !PASSWORT || !VERBINDUNG,
'Ohne ADMIN_EMAIL, ADMIN_PASSWORT und DATABASE_URL gibt es kein Testkonto.',
)
test.afterAll(async () => {
await db.aufgabe.deleteMany({ where: { titel: { startsWith: PRAEFIX } } })
await db.projekt.deleteMany({ where: { name: { startsWith: PRAEFIX } } })
await db.auditEintrag.deleteMany({ where: { aktion: { startsWith: 'aufgabe.' } } })
await db.$disconnect()
})
test('erfasst schnell, sortiert ein und hakt ab', async ({ page }) => {
const titel = `${PRAEFIX} Angebot schreiben`
await anmelden(page)
// --- Erfassen: ein Feld genügt --------------------------------------
await page.goto('/inbox')
await page.getByLabel('Neue Aufgabe').fill(titel)
await page.getByRole('button', { name: 'Erfassen' }).click()
const zeile = page.locator('li').filter({ hasText: titel })
await expect(zeile).toBeVisible()
// Ohne Bereich liegt sie in der Inbox – genau das ist der Unterschied.
await expect(zeile.getByText('Inbox')).toBeVisible()
// --- Einsortieren ----------------------------------------------------
const bereich = await db.bereich.findFirst({
where: { aktiv: true },
orderBy: { reihenfolge: 'asc' },
select: { id: true, name: true },
})
expect(bereich).not.toBeNull()
await zeile.getByLabel('Einsortieren nach').selectOption(bereich!.id)
await expect(page.getByText(`liegt jetzt in ${bereich!.name}`)).toBeVisible()
// Aus der Inbox ist sie damit verschwunden.
await page.goto('/inbox')
await expect(page.locator('li').filter({ hasText: titel })).toHaveCount(0)
// --- Abhaken ---------------------------------------------------------
await page.goto('/aufgaben')
const inListe = page.locator('li').filter({ hasText: titel })
await expect(inListe).toBeVisible()
await inListe.getByRole('button', { name: 'Als erledigt abhaken' }).click()
// Auf die Bestätigung warten, bevor es weitergeht: der Klick stößt eine
// Server Action an, und ohne diesen Haltepunkt navigiert der Test
// gelegentlich schneller, als gespeichert wird.
await expect(page.getByText('ist jetzt erledigt')).toBeVisible()
// Erledigtes fällt aus der Standardansicht heraus.
await page.goto('/aufgaben')
await expect(page.locator('li').filter({ hasText: titel })).toHaveCount(0)
// Mit Filter "Alle" ist sie wieder da.
await page.goto('/aufgaben?status=ERLEDIGT')
await expect(page.locator('li').filter({ hasText: titel })).toBeVisible()
const gespeichert = await db.aufgabe.findFirst({ where: { titel } })
expect(gespeichert?.status).toBe('ERLEDIGT')
expect(gespeichert?.erledigtAm).not.toBeNull()
})
test('macht aus einer Idee eine Aufgabe', async ({ page }) => {
const titel = `${PRAEFIX} Blog aufsetzen`
await anmelden(page)
await page.goto('/ideen')
await page.getByLabel('Neue Idee').fill(titel)
await page.getByRole('button', { name: 'Erfassen' }).click()
const zeile = page.locator('li').filter({ hasText: titel })
await expect(zeile).toBeVisible()
await zeile.getByRole('button', { name: 'Zur Aufgabe machen' }).click()
await expect(page.getByText('ist jetzt eine Aufgabe')).toBeVisible()
const danach = await db.aufgabe.findFirst({ where: { titel } })
expect(danach?.typ).toBe('AUFGABE')
// Aus der Ideenliste ist sie damit verschwunden.
await page.goto('/ideen')
await expect(page.locator('li').filter({ hasText: titel })).toHaveCount(0)
})
test('hält Ideen aus der Aufgabenliste heraus', async ({ page }) => {
const idee = `${PRAEFIX} Nur eine Idee`
const aufgabe = `${PRAEFIX} Eine echte Aufgabe`
await db.aufgabe.createMany({
data: [
{ titel: idee, typ: 'IDEE' },
{ titel: aufgabe, typ: 'AUFGABE' },
],
})
await anmelden(page)
// In der Aufgabenliste hat die Idee nichts zu suchen.
await page.goto('/aufgaben')
await expect(page.locator('li').filter({ hasText: aufgabe })).toBeVisible()
await expect(page.locator('li').filter({ hasText: idee })).toHaveCount(0)
// Auch nicht in der Inbox, obwohl beide keinen Bereich haben.
await page.goto('/inbox')
await expect(page.locator('li').filter({ hasText: aufgabe })).toBeVisible()
await expect(page.locator('li').filter({ hasText: idee })).toHaveCount(0)
// Wer ausdrücklich danach filtert, sieht sie sehr wohl.
await page.goto('/aufgaben?typ=IDEE')
await expect(page.locator('li').filter({ hasText: idee })).toBeVisible()
await expect(page.locator('li').filter({ hasText: aufgabe })).toHaveCount(0)
})
test('filtert nach Bereich und über die Adresszeile', async ({ page }) => {
await anmelden(page)
const bereich = await db.bereich.findFirst({
where: { aktiv: true },
select: { id: true, name: true },
})
const drin = `${PRAEFIX} Gehört dazu`
const draussen = `${PRAEFIX} Gehört nicht dazu`
await db.aufgabe.createMany({
data: [
{ titel: drin, bereichId: bereich!.id },
{ titel: draussen, bereichId: null },
],
})
await page.goto(`/aufgaben?bereich=${bereich!.id}`)
await expect(page.locator('li').filter({ hasText: drin })).toBeVisible()
await expect(page.locator('li').filter({ hasText: draussen })).toHaveCount(0)
// Nur Inbox zeigt genau die andere.
await page.goto('/aufgaben?bereich=inbox')
await expect(page.locator('li').filter({ hasText: draussen })).toBeVisible()
await expect(page.locator('li').filter({ hasText: drin })).toHaveCount(0)
})
test('zeigt den Fortschritt eines Projekts', async ({ page }) => {
const projektName = `${PRAEFIX} Website neu`
const projekt = await db.projekt.create({ data: { name: projektName } })
await db.aufgabe.createMany({
data: [
{ titel: `${PRAEFIX} Entwurf`, projektId: projekt.id, status: 'ERLEDIGT' },
{ titel: `${PRAEFIX} Umsetzung`, projektId: projekt.id, status: 'OFFEN' },
// Verworfenes zählt bewusst gar nicht mit.
{ titel: `${PRAEFIX} Verworfen`, projektId: projekt.id, status: 'VERWORFEN' },
],
})
await anmelden(page)
await page.goto(`/projekte/${projekt.id}`)
await expect(page.getByRole('heading', { name: projektName })).toBeVisible()
await expect(page.getByText('1 von 2 erledigt (50 %)')).toBeVisible()
})
})