feat(frontend+e2e): Dynamische row-testid fuer DataTable-Zeilen #252

Closed
opened 2026-07-06 16:53:26 +02:00 by niboer · 0 comments
Owner

Problem

E2E-Tests, die auf bestimmte Tabellenzeilen zugreifen muessen (z. B. um ein ActionMenu in einer bestimmten Zeile zu oeffnen), haben derzeit keine stabile Selektionsmoeglichkeit:

  • Text-Filter (getByRole('row').filter({ hasText: 'Name' })) koppelt an Anzeigenamen, ist anfaellig fuer i18n-Aenderungen, Umlaut-Probleme und doppelte Namen
  • Index (.nth(N)) ist zerbrechlich bei Sortierung oder wechselnder Reihenfolge
  • .locator('..') greift nur das <td>, nicht die ganze <tr> — dadurch wird das ActionMenu in einer separaten Zelle nicht gefunden

Konkret aufgetreten in #251: Der invoice-recipient E2E-Test musste von .locator('..') auf getByRole('row').filter({ hasText }) umgestellt werden, weil der ActionMenu-Button in einer anderen Tabellenzelle liegt.

Loesungsvorschlag

1. DataTable-Komponente erweitern

Neues Prop rowIdKey (string, optional) — gibt den Feldnamen der ID an:

let { ..., rowIdKey }: { columns: ColumnConfig[]; data: T[]; rowIdKey?: string; ... } = $props();

Im <tr> wird daraus ein stabiler data-testid generiert:

<tr data-testid={rowIdKey ? 'row-' + row[rowIdKey] : undefined}>

2. Nutzung in allen 7 Seiten mit DataTable

Seite Datentyp rowIdKey
groups/[groupId] (2x) GroupMemberWithPerson personId
groups/+page Group groupId
persons/+page Person personId
events/+page Event eventId
events/[eventId] (4x) EventGuest, EventRole personId, roleId
templates/+page Template templateId
deletion-requests/+page AdminDeletionRequest requestId

3. Nutzung in E2E-Tests

const petraRow = page.getByTestId('row-dbbf1380-d449-42ce-a436-7d8686fa49cb');
await petraRow.getByTestId('action-menu-toggle').click();

4. Dokumentation

  • AGENTS.md: Regel fuer row-testid in DataTables ergaenzen (analog zur bestehenden ActionMenu-Regel)
  • docs/design/04-frontend-architektur.md: rowIdKey-Prop dokumentieren

Vorteile

  • Minimale Aenderung: 1 Prop-Name pro DataTable-Nutzung (kein Callback noetig)
  • Stabil gegenueber Sortierung, Filterung und i18n-Aenderungen
  • Konsistentes Pattern ueber alle 11 DataTable-Instanzen hinweg

Dateien

Datei Aenderung
frontend/src/lib/components/data-table.svelte + rowIdKey-Prop + data-testid im <tr>
7 Seiten-Dateien (11 DataTable-Usages) rowIdKey uebergeben
AGENTS.md Regel ergaenzen
docs/design/04-frontend-architektur.md rowIdKey dokumentieren
## Problem E2E-Tests, die auf bestimmte Tabellenzeilen zugreifen muessen (z. B. um ein ActionMenu in einer bestimmten Zeile zu oeffnen), haben derzeit keine stabile Selektionsmoeglichkeit: - **Text-Filter** (`getByRole('row').filter({ hasText: 'Name' })`) koppelt an Anzeigenamen, ist anfaellig fuer i18n-Aenderungen, Umlaut-Probleme und doppelte Namen - **Index** (`.nth(N)`) ist zerbrechlich bei Sortierung oder wechselnder Reihenfolge - **`.locator('..')`** greift nur das `<td>`, nicht die ganze `<tr>` — dadurch wird das ActionMenu in einer separaten Zelle nicht gefunden Konkret aufgetreten in #251: Der invoice-recipient E2E-Test musste von `.locator('..')` auf `getByRole('row').filter({ hasText })` umgestellt werden, weil der ActionMenu-Button in einer anderen Tabellenzelle liegt. ## Loesungsvorschlag ### 1. DataTable-Komponente erweitern Neues Prop `rowIdKey` (string, optional) — gibt den Feldnamen der ID an: ```svelte let { ..., rowIdKey }: { columns: ColumnConfig[]; data: T[]; rowIdKey?: string; ... } = $props(); ``` Im `<tr>` wird daraus ein stabiler data-testid generiert: ```svelte <tr data-testid={rowIdKey ? 'row-' + row[rowIdKey] : undefined}> ``` ### 2. Nutzung in allen 7 Seiten mit DataTable | Seite | Datentyp | rowIdKey | |---|---|---| | `groups/[groupId]` (2x) | `GroupMemberWithPerson` | `personId` | | `groups/+page` | `Group` | `groupId` | | `persons/+page` | `Person` | `personId` | | `events/+page` | `Event` | `eventId` | | `events/[eventId]` (4x) | `EventGuest`, `EventRole` | `personId`, `roleId` | | `templates/+page` | `Template` | `templateId` | | `deletion-requests/+page` | `AdminDeletionRequest` | `requestId` | ### 3. Nutzung in E2E-Tests ```typescript const petraRow = page.getByTestId('row-dbbf1380-d449-42ce-a436-7d8686fa49cb'); await petraRow.getByTestId('action-menu-toggle').click(); ``` ### 4. Dokumentation - `AGENTS.md`: Regel fuer row-testid in DataTables ergaenzen (analog zur bestehenden ActionMenu-Regel) - `docs/design/04-frontend-architektur.md`: `rowIdKey`-Prop dokumentieren ## Vorteile - Minimale Aenderung: 1 Prop-Name pro DataTable-Nutzung (kein Callback noetig) - Stabil gegenueber Sortierung, Filterung und i18n-Aenderungen - Konsistentes Pattern ueber alle 11 DataTable-Instanzen hinweg ## Dateien | Datei | Aenderung | |---|---| | `frontend/src/lib/components/data-table.svelte` | + rowIdKey-Prop + data-testid im `<tr>` | | 7 Seiten-Dateien (11 DataTable-Usages) | rowIdKey uebergeben | | `AGENTS.md` | Regel ergaenzen | | `docs/design/04-frontend-architektur.md` | rowIdKey dokumentieren |
niboer changed title from feat(e2e+frontend): Dynamische row-testid fuer DataTable-Zeilen to feat(frontend+e2e): Dynamische row-testid fuer DataTable-Zeilen 2026-07-06 17:00:35 +02:00
Sign in to join this conversation.
No description provided.