Im Schreiben-Editor gibt es jetzt den Umschalter Brief/E-Mail. Die E-Mail-Fassung wird aus dem - womoeglich bearbeiteten - Brieftext abgeleitet: ohne Absenderblock, Anschrift und Datumszeile, aber mit dem Bestellungsabsatz. Betreff und Text einzeln kopierbar. Die offene Entscheidung aus dem Issue (mailto oder .eml) ist nach Rueckfrage mit BEIDES beantwortet: - mailto fuer kurze Texte. Der Knopf verschwindet, sobald der kodierte Link 1800 Zeichen uebersteigt - mailto uebergibt den Text in der Adresszeile, deren Laenge nirgends zugesichert ist, und ein halbierter Brief faellt erst beim Empfaenger auf. Die Grenze wird NACH der URL-Kodierung gerechnet; 900 Umlaute sind roh harmlos und kodiert weit drueber. - .eml immer: RFC 5322 mit X-Unsent: 1, quoted-printable fuer den Rumpf, RFC-2047-Kodierung fuer Umlaute im Betreff. Bewusst ohne From-Kopf - ein erfundener Absender wuerde je nach Programm uebernommen. Beide Knoepfe erscheinen nur mit E-Mail-Adresse (aus dem Kontakt uebernommen oder von Hand). Ohne Adresse bleibt das Kopieren. Die Ablage kennt den Unterschied: Eine E-Mail heisst in der Akte "E-Mail: ...", und abgelegt wird die E-Mail-Fassung samt Empfaengeradresse im Kopf der PDF - in der Akte soll stehen, was tatsaechlich hinausging. Sicherung in emailFassung(): Findet sich keine Anrede (frei umgebauter Text), wird NICHTS entfernt. Lieber ein Briefkopf zu viel in der Mail als stillschweigend verlorener Inhalt. Geprueft: 20 Einheitstests, vier End-to-End-Tests auf beiden Geraeteprofilen. 590 Unit-Tests, 81 e2e, null Typfehler. Refs #5
124 lines
4.4 KiB
TypeScript
124 lines
4.4 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
import { PrismaClient } from '@prisma/client'
|
|
import { anmelden } from './hilfen'
|
|
|
|
/**
|
|
* Schreiben als E-Mail — gegen die echte Anwendung.
|
|
*
|
|
* Geprüft wird der Weg, den die Einheitstests nicht sehen: Umschalten auf
|
|
* E-Mail, die abgeleitete Fassung ohne Briefkopf, der .eml-Download und
|
|
* die Ablage, die das Schreiben als E-Mail kennzeichnet.
|
|
*/
|
|
|
|
const KONTAKT = 'Prüfhausen Versicherung (E-Mail-Test)'
|
|
|
|
async function mitDb<T>(arbeit: (db: PrismaClient) => Promise<T>): Promise<T> {
|
|
const db = new PrismaClient()
|
|
try {
|
|
return await arbeit(db)
|
|
} finally {
|
|
await db.$disconnect()
|
|
}
|
|
}
|
|
|
|
async function aufraeumen(): Promise<void> {
|
|
await mitDb(async (db) => {
|
|
await db.dokument.deleteMany({ where: { empfaenger: { contains: 'Prüfhausen' } } })
|
|
await db.frist.deleteMany({ where: { titel: { contains: 'Antwort abwarten' } } })
|
|
await db.kontakt.deleteMany({ where: { name: { contains: 'Prüfhausen' } } })
|
|
})
|
|
}
|
|
|
|
test.describe('Schreiben als E-Mail', () => {
|
|
test.beforeAll(async () => {
|
|
await aufraeumen()
|
|
await mitDb(async (db) => {
|
|
const betreute = await db.betreute.findMany({
|
|
where: { geloeschtAm: null },
|
|
select: { id: true },
|
|
})
|
|
for (const person of betreute) {
|
|
await db.kontakt.create({
|
|
data: {
|
|
betreuteId: person.id,
|
|
name: KONTAKT,
|
|
organisation: KONTAKT,
|
|
rolle: 'SONSTIGES',
|
|
email: 'service@pruefhausen.example',
|
|
},
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
test.afterAll(async () => {
|
|
await aufraeumen()
|
|
})
|
|
|
|
test('leitet die E-Mail-Fassung ohne Briefkopf ab, mit Bestellungsabsatz', async ({
|
|
page,
|
|
}) => {
|
|
await anmelden(page)
|
|
await page.goto('/schreiben/neu?art=FREI')
|
|
|
|
// Kontakt wählen - bringt die E-Mail-Adresse mit.
|
|
await page.locator('select#kontaktAuswahl').selectOption({ label: `${KONTAKT}` })
|
|
await expect(page.locator('input#empfaengerEmail')).toHaveValue(
|
|
'service@pruefhausen.example',
|
|
)
|
|
|
|
await page.getByRole('button', { name: 'Als E-Mail' }).click()
|
|
|
|
const mailtext = await page.locator('textarea#emailText').inputValue()
|
|
// Beginnt mit der Anrede - kein Absenderblock, keine Datumszeile.
|
|
expect(mailtext.startsWith('Sehr geehrte')).toBe(true)
|
|
expect(mailtext).not.toMatch(/^\d{1,2}\.\d{1,2}\.\d{4}$/m)
|
|
// Der Nachweis der Bestellung bleibt drin.
|
|
expect(mailtext).toMatch(/Betreuungsgericht|bestellt/i)
|
|
})
|
|
|
|
test('lädt den .eml-Entwurf herunter', async ({ page }) => {
|
|
await anmelden(page)
|
|
await page.goto('/schreiben/neu?art=FREI')
|
|
await page.locator('select#kontaktAuswahl').selectOption({ label: `${KONTAKT}` })
|
|
await page.getByRole('button', { name: 'Als E-Mail' }).click()
|
|
|
|
const [download] = await Promise.all([
|
|
page.waitForEvent('download'),
|
|
page.getByRole('button', { name: 'Als E-Mail-Entwurf (.eml)' }).click(),
|
|
])
|
|
|
|
expect(download.suggestedFilename()).toMatch(/^\d{4}-\d{2}-\d{2}_.*\.eml$/)
|
|
})
|
|
|
|
test('zeigt ohne Adresse keine Mailprogramm-Knöpfe', async ({ page }) => {
|
|
await anmelden(page)
|
|
await page.goto('/schreiben/neu?art=FREI')
|
|
await page.getByRole('button', { name: 'Als E-Mail' }).click()
|
|
|
|
// Kopieren geht immer, die Programm-Knöpfe nicht.
|
|
await expect(page.getByRole('button', { name: 'Text kopieren' }).last()).toBeVisible()
|
|
await expect(page.getByRole('button', { name: 'Als E-Mail-Entwurf (.eml)' })).toHaveCount(0)
|
|
await expect(page.getByRole('link', { name: 'Im Mailprogramm öffnen' })).toHaveCount(0)
|
|
await expect(page.getByText(/Trag oben eine E-Mail-Adresse ein/)).toBeVisible()
|
|
})
|
|
|
|
test('legt die E-Mail als solche gekennzeichnet in die Akte', async ({ page }) => {
|
|
await anmelden(page)
|
|
await page.goto('/schreiben/neu?art=FREI')
|
|
await page.locator('select#kontaktAuswahl').selectOption({ label: `${KONTAKT}` })
|
|
|
|
await page.locator('input#betreff').fill('Prüfhausen Testanfrage')
|
|
await page.getByRole('button', { name: 'Als E-Mail' }).click()
|
|
await page.getByRole('button', { name: 'In die Akte legen' }).click()
|
|
|
|
await expect(page.getByText('Das Schreiben liegt in der Akte.')).toBeVisible({
|
|
timeout: 30_000,
|
|
})
|
|
|
|
// In der Akte als E-Mail erkennbar, nicht als Brief.
|
|
await page.goto('/dokumente?richtung=AUSGANG')
|
|
await expect(page.locator('body')).toContainText('E-Mail: Prüfhausen Testanfrage')
|
|
})
|
|
})
|