Steuerkram/tests/e2e/specs/dashboard-detail.spec.js

88 lines
3.4 KiB
JavaScript

// @ts-check
// Hotspot: Detailansichten hinter den Dashboard-Kacheln (Issue #167).
//
// Die Kachelzahlen sind Links auf /dashboard/buchungen/{gruppe}/{jahr}[/{monat}].
// Ob die verlinkte Liste tatsächlich auf den angezeigten Kachelwert summiert,
// lässt sich nur am gerenderten Dashboard prüfen — die Summenlogik selbst deckt
// tests/80_DashboardEuerAbgleichTest.php ab.
//
// Die Tests lesen ausschließlich; es werden keine Daten angelegt oder verändert.
const { test, expect } = require('@playwright/test')
const { gotoOk, parseMoney } = require('../helpers/app')
/** Liest Kachelwert und Ziel-URL der Jahreszahl einer Kachel. */
async function kachel(page, ueberschrift) {
const karte = page.locator('.stat-card', { hasText: ueberschrift }).first()
await expect(karte, `Kachel "${ueberschrift}" nicht gefunden`).toHaveCount(1)
const link = karte.locator('.stat-value a').first()
return {
wert: parseMoney(await link.textContent()),
url: await link.getAttribute('href'),
}
}
test.describe('Detailansichten der Dashboard-Kacheln', () => {
for (const [ueberschrift, gruppe] of [
['Umsatz', 'einnahmen'],
['Ausgaben', 'ausgaben'],
['Gewinn / Verlust', 'ergebnis'],
]) {
test(`Kachel "${ueberschrift}" führt auf die Buchungen, die sie aufsummiert`, async ({ page }) => {
await gotoOk(page, '/dashboard')
const { wert, url } = await kachel(page, ueberschrift)
expect(url).toContain(`/dashboard/buchungen/${gruppe}/`)
expect(Number.isNaN(wert)).toBe(false)
await gotoOk(page, url)
// Ohne Buchungen im laufenden Jahr gibt es nichts zu vergleichen.
const leer = await page.locator('text=Keine Buchungen in diesem Zeitraum.').count()
if (leer > 0) {
expect(wert).toBeCloseTo(0, 2)
return
}
const summe = parseMoney(await page.locator('tfoot tr td').last().textContent())
expect(summe, `Listensumme weicht vom Kachelwert ab (${ueberschrift})`).toBeCloseTo(wert, 2)
})
}
test('Monatszahlen verlinken auf denselben Monat', async ({ page }) => {
await gotoOk(page, '/dashboard')
const karte = page.locator('.stat-card', { hasText: 'Umsatz' }).first()
const monatsLinks = karte.locator('.stat-meta a')
await expect(monatsLinks).toHaveCount(2)
for (let i = 0; i < 2; i++) {
const url = await monatsLinks.nth(i).getAttribute('href')
// Vormonat und laufender Monat: /…/{jahr}/{monat}
expect(url).toMatch(/\/dashboard\/buchungen\/einnahmen\/\d{4}\/\d{1,2}$/)
const erwartet = parseMoney(await monatsLinks.nth(i).textContent())
await gotoOk(page, url)
const leer = await page.locator('text=Keine Buchungen in diesem Zeitraum.').count()
if (leer > 0) {
expect(erwartet).toBeCloseTo(0, 2)
} else {
const summe = parseMoney(await page.locator('tfoot tr td').last().textContent())
expect(summe).toBeCloseTo(erwartet, 2)
}
await gotoOk(page, '/dashboard')
}
})
test('Unbekannte Gruppe führt zurück aufs Dashboard', async ({ page }) => {
await page.goto('/dashboard/buchungen/unsinn/2026')
expect(new URL(page.url()).pathname).toBe('/dashboard')
await expect(page.locator('body')).toContainText('Unbekannte Auswertung.')
})
test('Ungültiger Monat führt zurück aufs Dashboard', async ({ page }) => {
await page.goto('/dashboard/buchungen/einnahmen/2026/13')
expect(new URL(page.url()).pathname).toBe('/dashboard')
await expect(page.locator('body')).toContainText('Ungültiger Monat.')
})
})