Der Herkunfts-Verlauf nennt jetzt auch, wenn ein Wert aus einer Quelle VERWORFEN wurde — mit Grund und was stattdessen verwendet wurde (⚠-Markierung), z. B.: - „⚠ Vater-Kandidat ‚Danielle' (*04.03.2020) verworfen — falsches Geschlecht für die Vaterrolle; ‚Hagrid Rubeus' verwendet." (Molly) - „⚠ Geschlecht weiblich aus ‚Wurfchronik.docx' verworfen — abweichend; männlich aus ‚Alberto Kids.xlsx' verwendet (Mehrheit)." (Solice) - „⚠ Vater ‚Jasper Jacob' (*2018) verworfen — unplausibel (7 Jahre älter); kein Ersatz." / DOB-Remap: „⚠ Geburtsdatum 22.08.2018 verworfen — per manueller Entscheidung korrigiert; 14.07.2019 verwendet." (Kazuya) Import: generischer _format_discard()-Helfer; Verwerfungen aus Mehrheitsentscheid, pick_parent_ref-Ablehnungen (explain_pick_rejections), Rollen-Normalisierung, Eltern-Alter-Sanity-Check und DOB-Remaps werden über _discarded/_prov_args an die Tiere gehängt; Gerbil-Provenance wird in einem finalen Pass gebaut (nachdem alle Verwerfungen feststehen). Frontend hebt ⚠-Zeilen ab (+ Legende). Tests grün (python merge/extract, vitest 129, playwright 8, dotnet 212). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
113 lines
5.0 KiB
TypeScript
113 lines
5.0 KiB
TypeScript
/** NACHVERFOLGUNG: "Datenherkunft"-Button in der Tierakte öffnet den
|
|
* Nachverfolgungs-Dialog mit Quelldateien, Datensatzanzahl und Hinweisen. */
|
|
import { de, expect, skipUnlessMock, test } from './fixtures'
|
|
|
|
const p = de.provenance
|
|
|
|
test('Tierakte: "Datenherkunft"-Button öffnet den Nachverfolgungs-Dialog', async ({ page }) => {
|
|
skipUnlessMock()
|
|
await page.goto('/rennmaeuse/kruemel')
|
|
|
|
// Button in den Aktionen öffnet den Dialog.
|
|
await page.getByRole('button', { name: p.button }).click()
|
|
const dialog = page.getByRole('dialog', { name: p.dialogTitle })
|
|
await expect(dialog).toBeVisible()
|
|
|
|
// VERLAUF: chronologischer, dateibezogener Verlauf als Primärinhalt.
|
|
await expect(dialog).toContainText(p.historyTitle)
|
|
await expect(dialog).toContainText('In „Stammbaum von Krümel.xlsx“ gefunden.')
|
|
await expect(dialog).toContainText('Geburtsdatum (12.03.2025) aus „Stammbaum von Krümel.xlsx“.')
|
|
await expect(dialog).toContainText(
|
|
'Auch in „Wurfchronik-Detail.docx“ gefunden → Datensätze zusammengeführt.',
|
|
)
|
|
|
|
// VERWORFEN: eine Quelle wurde verworfen — mit Grund und verwendetem Ersatz.
|
|
await expect(dialog).toContainText(p.discardLegend)
|
|
await expect(dialog).toContainText(
|
|
'⚠ Geburtsdatum 14.06.2015 aus „Wurfchronik-Detail.docx“ verworfen — abweichend; 12.03.2025 aus „Stammbaum von Krümel.xlsx“ verwendet (Mehrheit).',
|
|
)
|
|
await expect(dialog).toContainText(
|
|
'⚠ Vater „Jayjay“ (*19.06.2013) verworfen — unplausibel (9 Jahre älter als das Kind); kein Ersatz.',
|
|
)
|
|
// Die Verwerfen-Zeile ist visuell als solche markiert (eigene CSS-Klasse).
|
|
await expect(dialog.locator('.provenance__history-step--discard').first()).toBeVisible()
|
|
|
|
// Quelldateien werden angezeigt.
|
|
await expect(dialog).toContainText(p.sourceFilesTitle)
|
|
await expect(dialog).toContainText('Stammbaum von Krümel.xlsx')
|
|
await expect(dialog).toContainText('Wurfchronik-Detail.docx')
|
|
|
|
// Zusammenführungs-Info + Wurfchronik-Hinweis.
|
|
await expect(dialog).toContainText(p.mergedCount(2))
|
|
await expect(dialog).toContainText(p.fromWurfchronik)
|
|
|
|
// Eltern-Herkunft (übersetzte Methode/Konfidenz).
|
|
await expect(dialog).toContainText(p.methods['chart-position'])
|
|
await expect(dialog).toContainText(p.confidences.medium)
|
|
|
|
// Hinweis aus dem Import.
|
|
await expect(dialog).toContainText('aus 2 Datensätzen zusammengeführt')
|
|
|
|
// Schließen (Footer-Button — Header-Button trägt dasselbe aria-label).
|
|
await dialog.locator('.provenance__actions').getByRole('button', { name: p.close }).click()
|
|
await expect(dialog).not.toBeVisible()
|
|
})
|
|
|
|
test('Tierakte: Tier ohne Importdaten zeigt "Keine Herkunftsdaten"', async ({ page }) => {
|
|
skipUnlessMock()
|
|
// Luna hat keine provenance im Mock → Leer-Zustand.
|
|
await page.goto('/rennmaeuse/luna')
|
|
|
|
await page.getByRole('button', { name: p.button }).click()
|
|
const dialog = page.getByRole('dialog', { name: p.dialogTitle })
|
|
await expect(dialog).toBeVisible()
|
|
await expect(dialog).toContainText(p.empty)
|
|
})
|
|
|
|
test('Kontakt: "Datenherkunft"-Button öffnet den Nachverfolgungs-Dialog', async ({ page }) => {
|
|
skipUnlessMock()
|
|
await page.goto('/kontakte/con-meier')
|
|
|
|
await page.getByRole('button', { name: p.button }).click()
|
|
const dialog = page.getByRole('dialog', { name: p.dialogTitle })
|
|
await expect(dialog).toBeVisible()
|
|
|
|
// VERLAUF: dateibezogene Schritte des Kontakts.
|
|
await expect(dialog).toContainText(p.historyTitle)
|
|
await expect(dialog).toContainText('In „Stammbaum von Krümel.xlsx“ als Züchter erkannt.')
|
|
|
|
// Quelldateien + Zusammenführung + Kontakt-Rolle-Hinweise.
|
|
await expect(dialog).toContainText(p.sourceFilesTitle)
|
|
await expect(dialog).toContainText('Wurfchronik Teil 1_page_0001.md')
|
|
await expect(dialog).toContainText(p.mergedCount(2))
|
|
await expect(dialog).toContainText(p.fromWurfchronik)
|
|
await expect(dialog).toContainText('als Züchter erkannt')
|
|
await expect(dialog).toContainText('als Abnehmer erkannt')
|
|
|
|
await dialog.locator('.provenance__actions').getByRole('button', { name: p.close }).click()
|
|
await expect(dialog).not.toBeVisible()
|
|
})
|
|
|
|
test('Wurf: "Datenherkunft"-Button öffnet den Nachverfolgungs-Dialog', async ({ page }) => {
|
|
skipUnlessMock()
|
|
await page.goto('/wuerfe/w-kruemel')
|
|
|
|
await page.getByRole('button', { name: p.button }).click()
|
|
const dialog = page.getByRole('dialog', { name: p.dialogTitle })
|
|
await expect(dialog).toBeVisible()
|
|
|
|
// VERLAUF: dateibezogene Schritte des Wurfs.
|
|
await expect(dialog).toContainText(p.historyTitle)
|
|
await expect(dialog).toContainText('Wurf aus Wurfchronik „Wurfchronik Teil 1_page_0009.md“.')
|
|
|
|
await expect(dialog).toContainText(p.sourceFilesTitle)
|
|
await expect(dialog).toContainText('Wurfchronik Teil 1_page_0009.md')
|
|
await expect(dialog).toContainText(p.mergedCount(2))
|
|
await expect(dialog).toContainText(p.fromWurfchronik)
|
|
await expect(dialog).toContainText('aus Wurfchronik')
|
|
await expect(dialog).toContainText('Geschwister-Würfe zusammengeführt')
|
|
|
|
await dialog.locator('.provenance__actions').getByRole('button', { name: p.close }).click()
|
|
await expect(dialog).not.toBeVisible()
|
|
})
|