// @ts-check const { test, expect } = require('@playwright/test') const BENUTZER = process.env.E2E_USER || 'e2e' const PASSWORT = process.env.E2E_PASSWORD || 'e2e-testpasswort' async function anmelden(page) { await page.goto('/login') await page.fill('#benutzername', BENUTZER) await page.fill('#passwort', PASSWORT) await page.click('button[type="submit"]') await expect(page).toHaveURL(/\/$/) } /* Klick auf das Rechnersymbol – es sitzt rechts im Feld. */ async function symbolKlicken(feld) { const box = await feld.boundingBox() if (!box) throw new Error('Feld nicht sichtbar') await feld.page().mouse.click(box.x + box.width - 12, box.y + box.height / 2) } test.describe('Taschenrechner an Betragsfeldern (#126)', () => { test.beforeEach(async ({ page }) => { await anmelden(page) }) test('Symbol im Feld öffnet den Rechner, Enter überträgt das Ergebnis', async ({ page }) => { await page.goto('/konten/neu') const feld = page.locator('#anfangssaldo') await feld.fill('') const bild = await feld.evaluate((el) => getComputedStyle(el).backgroundImage) expect(bild).toContain('data:image/svg+xml') await symbolKlicken(feld) const rechner = page.locator('.rechner') await expect(rechner).toBeVisible() const eingabe = rechner.locator('.rechner-eingabe') const ergebnis = rechner.locator('.rechner-ergebnis') await expect(eingabe).toBeFocused() // Am Feld, rechtsbündig – darunter oder, fehlt dort der Platz, darüber. const feldBox = await feld.boundingBox() const rechnerBox = await rechner.boundingBox() if (!feldBox || !rechnerBox) throw new Error('nicht sichtbar') const darunter = rechnerBox.y - (feldBox.y + feldBox.height) const darueber = feldBox.y - (rechnerBox.y + rechnerBox.height) expect((darunter >= 0 && darunter < 20) || (darueber >= 0 && darueber < 20)).toBe(true) expect(Math.abs(rechnerBox.x + rechnerBox.width - (feldBox.x + feldBox.width))).toBeLessThan(2) // Ergebnis nach jedem Tastendruck, Punkt vor Strich, Klammern. await page.keyboard.type('12,5*2') await expect(ergebnis).toHaveText('25') await page.keyboard.type('+(3-1)/4') await expect(eingabe).toHaveValue('12,5×2+(3−1)÷4') await expect(ergebnis).toHaveText('25,5') // Unvollständig: das letzte Ergebnis bleibt gedämpft stehen. await page.keyboard.type('+') await expect(ergebnis).toHaveClass(/veraltet/) await expect(ergebnis).toHaveText('25,5') // Buchstaben gehören nicht in eine Rechnung. await page.keyboard.type('q') await expect(eingabe).toHaveValue('12,5×2+(3−1)÷4+') // Backspace links, Entf rechts der Schreibmarke, Pfeile bewegen sie. await page.keyboard.press('Backspace') await page.keyboard.press('ArrowLeft') await page.keyboard.press('ArrowLeft') await page.keyboard.press('Delete') await expect(eingabe).toHaveValue('12,5×2+(3−1)4') await expect(ergebnis).toHaveClass(/fehler/) await page.keyboard.type('*') await expect(eingabe).toHaveValue('12,5×2+(3−1)×4') await expect(ergebnis).toHaveText('33') await page.keyboard.press('Enter') await expect(rechner).toBeHidden() await expect(feld).toHaveValue('33,00') await expect(feld).toBeFocused() }) test('C löscht, Escape schließt ohne Übernahme, Alt+R öffnet mit dem Feldwert', async ({ page }) => { await page.goto('/konten/neu') const feld = page.locator('#anfangssaldo') await feld.fill('1.234,50') await feld.focus() await page.keyboard.press('Alt+r') const rechner = page.locator('.rechner') const eingabe = rechner.locator('.rechner-eingabe') await expect(rechner).toBeVisible() await expect(eingabe).toHaveValue('1234,5') await page.keyboard.press('c') await expect(eingabe).toHaveValue('') await page.keyboard.type('7/0') await expect(rechner.locator('.rechner-ergebnis')).toHaveText('Division durch 0') await page.keyboard.press('Escape') await expect(rechner).toBeHidden() await expect(feld).toBeFocused() await expect(feld).toHaveValue('1.234,50') }) test('Tasten lassen sich auch anklicken', async ({ page }) => { await page.goto('/konten/neu') const feld = page.locator('#kreditlimit') await feld.fill('') await symbolKlicken(feld) const rechner = page.locator('.rechner') for (const taste of ['9', '÷', '4', '=']) { await rechner.locator(`button[data-taste="${taste}"]`).click() } await expect(rechner.locator('.rechner-eingabe')).toHaveValue('2,25') await expect(rechner.locator('.rechner-eingabe')).toBeFocused() await rechner.getByRole('button', { name: 'Übernehmen' }).click() await expect(feld).toHaveValue('2,25') }) test('Im modalen Dialog: Escape schließt nur den Rechner', async ({ page }) => { await page.goto('/vorlagen') await page.click('#neu-knopf') const dialog = page.locator('#neudialog') await expect(dialog).toBeVisible() const feld = dialog.locator('#betrag') await feld.fill('') await symbolKlicken(feld) const rechner = dialog.locator('.rechner') await expect(rechner).toBeVisible() await page.keyboard.type('19,99*3') await page.keyboard.press('Escape') await expect(rechner).toBeHidden() await expect(dialog).toBeVisible() await symbolKlicken(feld) await page.keyboard.type('19,99*3') await page.keyboard.press('Enter') await expect(dialog).toBeVisible() await expect(feld).toHaveValue('59,97') }) })