Der Name in Bestandsübersicht, Depotbuchungen und Stammdaten führt jetzt auf
/wertpapiere/papier/{id}: Kennzahlen über die ganze Historie, Stammdaten und
Kurs, Bestand je Depot, Wertentwicklung und die Buchungen eines Zeitraums.
Depot::bestand() und Depot::entwicklung() nehmen dafür eine Wertpapiernummer
entgegen – die Detailseite rechnet nicht selbst, sondern bekommt dieselben
Zahlen wie die Übersicht. Neu sind Wertpapier::kurseckwerte() und
Depotbuchung::datumsgrenzen().
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
146 lines
5.5 KiB
JavaScript
146 lines
5.5 KiB
JavaScript
// @ts-check
|
||
const { test, expect } = require('@playwright/test')
|
||
|
||
/*
|
||
* Vom Namen in der Depotübersicht zur Detailseite des Wertpapiers: Stammdaten,
|
||
* Kennzahlen und darunter die Buchungen eines Zeitraums – voreingestellt das
|
||
* laufende Jahr.
|
||
*/
|
||
|
||
const BENUTZER = process.env.E2E_USER || 'e2e'
|
||
const PASSWORT = process.env.E2E_PASSWORD || 'e2e-testpasswort'
|
||
|
||
const MARKE = Date.now().toString().slice(-6)
|
||
const DEPOT = `E2E Detaildepot ${MARKE}`
|
||
const GIRO = `E2E Detailgiro ${MARKE}`
|
||
const PAPIER = `E2E Detailaktie ${MARKE}`
|
||
|
||
// Wie im Test des Wertpapiergeschäfts: Ein Papier wird über seine Kennung
|
||
// wiedergefunden, feste Kennungen hingen den zweiten Lauf an den ersten.
|
||
const ISIN = `DE0007${MARKE}`
|
||
|
||
// Die Zeiträume rechnen mit dem Tagesdatum, nicht mit festen Jahreszahlen –
|
||
// sonst liefe der Test am 1. Januar ins Leere.
|
||
const HEUTE = new Date()
|
||
const JAHR = HEUTE.getFullYear()
|
||
const DIESES_JAHR = `${JAHR}-03-04`
|
||
const VORJAHR = `${JAHR - 1}-03-04`
|
||
|
||
async function anmelden(page) {
|
||
await page.goto('/login')
|
||
if (page.url().includes('/einrichtung')) {
|
||
throw new Error(
|
||
'Instanz ist noch nicht eingerichtet: ' +
|
||
'docker compose exec -u www-data php php scripts/e2e-benutzer.php'
|
||
)
|
||
}
|
||
await page.fill('#benutzername', BENUTZER)
|
||
await page.fill('#passwort', PASSWORT)
|
||
await page.click('button[type="submit"]')
|
||
await expect(page).toHaveURL(/\/$/)
|
||
}
|
||
|
||
async function kontoAnlegen(page, name, kontoart, anfangssaldo) {
|
||
await page.goto('/konten/neu')
|
||
await page.fill('#name', name)
|
||
await page.selectOption('#kontoart', kontoart)
|
||
await page.fill('#anfangssaldo', anfangssaldo)
|
||
await page.click('.formular button[type="submit"]')
|
||
await expect(page).toHaveURL(/\/konten\/\d+\/bearbeiten/)
|
||
}
|
||
|
||
/** Ein Kauf über die Maske unter *Wertpapiere*. */
|
||
async function kaufErfassen(page, datum, stueck, kurs, neuesPapier) {
|
||
await page.goto('/wertpapiere/buchungen/neu')
|
||
await page.selectOption('#konto_id', { label: DEPOT })
|
||
await page.selectOption('#vorgang', 'kauf')
|
||
await page.fill('#datum', datum)
|
||
|
||
if (neuesPapier) {
|
||
await page.fill('#wertpapier_name', PAPIER)
|
||
await page.fill('#isin', ISIN)
|
||
} else {
|
||
await page.selectOption('#wertpapier_id', { label: `${PAPIER} (${ISIN})` })
|
||
}
|
||
|
||
await page.fill('#stueck', stueck)
|
||
await page.fill('#kurs', kurs)
|
||
await page.selectOption('#verrechnungskonto_id', { label: GIRO })
|
||
await page.click('.formular button[type="submit"]')
|
||
await expect(page.locator('.meldung-erfolg')).toBeVisible()
|
||
}
|
||
|
||
test.describe('Detailseite eines Wertpapiers', () => {
|
||
test.beforeAll(async ({ browser }) => {
|
||
const page = await browser.newPage()
|
||
await anmelden(page)
|
||
|
||
await kontoAnlegen(page, GIRO, 'bank', '10.000,00')
|
||
await kontoAnlegen(page, DEPOT, 'depot', '0,00')
|
||
|
||
// Zwei Käufe in zwei Jahren – der Zeitraumfilter muss sie trennen.
|
||
await kaufErfassen(page, VORJAHR, '4', '50', true)
|
||
await kaufErfassen(page, DIESES_JAHR, '6', '100', false)
|
||
|
||
// Ohne Kurs bliebe die Bewertung offen; der Kurs kommt von Hand. Der
|
||
// Name steht in der Stammdatenliste in einem Eingabefeld und nicht als
|
||
// Text – die Zeile wird deshalb über den Feldwert gesucht.
|
||
await page.goto('/wertpapiere/stammdaten')
|
||
const zeile = page.locator('tr').filter({ has: page.locator(`input[value="${PAPIER}"]`) })
|
||
await zeile.locator('input[name="kurs"]').fill('120')
|
||
await zeile.getByRole('button', { name: 'Setzen' }).click()
|
||
await expect(page.locator('.meldung-erfolg')).toBeVisible()
|
||
|
||
await page.close()
|
||
})
|
||
|
||
test.beforeEach(async ({ page }) => {
|
||
await anmelden(page)
|
||
})
|
||
|
||
test('Der Name in der Übersicht führt zu den Details', async ({ page }) => {
|
||
await page.goto('/wertpapiere')
|
||
await page.locator('tr', { hasText: PAPIER }).getByRole('link', { name: PAPIER }).click()
|
||
|
||
await expect(page).toHaveURL(/\/wertpapiere\/papier\/\d+/)
|
||
await expect(page.locator('h1')).toHaveText(PAPIER)
|
||
|
||
// Stammdaten und Kurs stehen in je einer Kachel.
|
||
await expect(page.locator('.kachel', { hasText: 'Stammdaten' }).locator('.merkmale'))
|
||
.toContainText(ISIN)
|
||
await expect(page.locator('.kachel', { hasText: 'Letzter Kurs' }).locator('.merkmale'))
|
||
.toContainText('120,00')
|
||
|
||
// Zehn Stück für 800 €, bewertet mit 1.200,00 €.
|
||
const kennzahlen = page.locator('.kennzahlenleiste')
|
||
await expect(kennzahlen).toContainText('10')
|
||
await expect(kennzahlen).toContainText('1.200,00')
|
||
await expect(kennzahlen).toContainText('800,00')
|
||
|
||
// Der Bestand steht je Depot – hier liegt alles in einem.
|
||
const bestand = page.locator('.kachel', { hasText: 'Bestand je Depot' })
|
||
await expect(bestand).toContainText(DEPOT)
|
||
await expect(bestand).toContainText('800,00')
|
||
})
|
||
|
||
test('Die Buchungen folgen dem gewählten Zeitraum', async ({ page }) => {
|
||
await page.goto('/wertpapiere')
|
||
await page.locator('tr', { hasText: PAPIER }).getByRole('link', { name: PAPIER }).click()
|
||
|
||
const liste = page.locator('table.liste').last()
|
||
|
||
// Voreingestellt ist das laufende Jahr: nur der Kauf von diesem Jahr.
|
||
await expect(page.locator('#zeitraum')).toHaveValue('aktuelles_jahr')
|
||
await expect(liste).toContainText(`04.03.${JAHR}`)
|
||
await expect(liste).not.toContainText(`04.03.${JAHR - 1}`)
|
||
|
||
await page.selectOption('#zeitraum', 'letztes_jahr')
|
||
await page.click('.filterleiste button[type="submit"]')
|
||
|
||
await expect(page.locator('table.liste').last()).toContainText(`04.03.${JAHR - 1}`)
|
||
await expect(page.locator('table.liste').last()).not.toContainText(`04.03.${JAHR}`)
|
||
|
||
// Die Kennzahlen oben gelten weiter für die ganze Historie.
|
||
await expect(page.locator('.kennzahlenleiste')).toContainText('800,00')
|
||
})
|
||
})
|