From 45c3f87f01b5d8d6d09a463e49fb3364850d45ac Mon Sep 17 00:00:00 2001 From: Gulum Date: Thu, 20 Aug 2026 00:22:59 +0200 Subject: [PATCH] =?UTF-8?q?fix(akte):=20falscher=20Hinweis=20=E2=80=9EWeic?= =?UTF-8?q?ht=20vom=20eingetragenen=20Farbschlag=20ab"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Beim Prod-Nachtest aufgefallen: Bei Schecken meldete die Akte eine Abweichung, obwohl eingetragener und errechneter Farbschlag identisch angezeigt wurden (JackJack: „Saphir Schecke" vs. „Saphir Schecke"). Zwei Ursachen: - Der Vergleich schnitt „Schecke"/„Rex" nur auf der ERRECHNETEN Seite ab, nicht auf der eingetragenen (die den Zusatz über formatVarietyName trägt). Jetzt werden beide Seiten gleich normalisiert. - formatVarietyName hängte den Modifier auch an, wenn der Katalogname ihn schon trägt („Schwarz Schecke" → „Schwarz Schecke Schecke"). Tests: 3 vitest-Fälle zu formatVarietyName, e2e SCHECKE-MISMATCH mit Gegenprobe (Mock-Tier mit echter Abweichung zeigt den Hinweis weiter). Co-Authored-By: Claude Opus 5 (1M context) --- gerbil-manager-web/e2e/mock-data.ts | 4 ++++ gerbil-manager-web/e2e/tiere.spec.ts | 17 +++++++++++++++++ .../src/genetics/__tests__/genetics.test.ts | 17 +++++++++++++++++ gerbil-manager-web/src/genetics/catalog.ts | 9 +++++++-- .../src/pages/GerbilDetailPage.tsx | 15 +++++++++++++-- 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/gerbil-manager-web/e2e/mock-data.ts b/gerbil-manager-web/e2e/mock-data.ts index b43ae72..ccb25e4 100644 --- a/gerbil-manager-web/e2e/mock-data.ts +++ b/gerbil-manager-web/e2e/mock-data.ts @@ -168,6 +168,10 @@ export function seedDb(): MockDb { gerbil('balu', 'Balu', 'male', '2021-04-20', 'w-balu', 'cv-agouti'), gerbil('maja', 'Maja', 'female', '2021-06-11', null, 'cv-schwarz-schecke', 'aa CC DD EE GG PP Spsp rere'), gerbil('karlsson', 'Karlsson', 'male', '2022-02-02', 'w-karlsson', 'cv-blau'), + // FARBSCHLAG-MISMATCH: eingetragen „Schwarz Schecke", Gencode ergibt Agouti Schecke + // → der Hinweis „Weicht vom eingetragenen Farbschlag ab" MUSS hier erscheinen. + gerbil('mismatch-maus', 'Mismatch Maus', 'female', '2023-02-02', null, 'cv-schwarz-schecke', + 'AA CC DD EE GG PP Spsp rere'), gerbil('smilla', 'Smilla', 'female', '2022-09-30', null, 'cv-himalaya'), gerbil('anton', 'Anton', 'male', '2019-07-07', 'w-anton', 'cv-agouti'), gerbil('greta', 'Greta', 'female', '2019-05-23', null, 'cv-schwarz'), diff --git a/gerbil-manager-web/e2e/tiere.spec.ts b/gerbil-manager-web/e2e/tiere.spec.ts index cef4de9..2b7323b 100644 --- a/gerbil-manager-web/e2e/tiere.spec.ts +++ b/gerbil-manager-web/e2e/tiere.spec.ts @@ -241,6 +241,23 @@ test('Detailseite: Abgabedatum steht direkt unter dem Abnehmer, auch bei Verstor await expect(goHomeRow.locator('.ak-kv-value')).toHaveText('15.01.2022') }) +test('Detailseite: Farbschlag-Hinweis nur bei echter Abweichung (SCHECKE-MISMATCH)', async ({ + page, +}) => { + skipUnlessMock() + // Maja: eingetragen „Schwarz Schecke", Gencode ergibt genau das → KEIN Hinweis. + // (Vorher wurde der Zusatz „Schecke" nur auf der errechneten Seite abgeschnitten, + // dadurch bekam jede Schecke faelschlich „Weicht vom eingetragenen Farbschlag ab".) + await page.goto('/rennmaeuse/maja') + const genetik = page.locator('.ak-card', { hasText: t.detail.genetics }).first() + await expect(genetik.getByText(t.detail.resolvedPrefix, { exact: false })).toBeVisible() + await expect(page.getByText(t.detail.farbschlagMismatch)).toBeHidden() + + // Gegenprobe: bei echter Abweichung erscheint der Hinweis weiter. + await page.goto('/rennmaeuse/mismatch-maus') + await expect(page.getByText(t.detail.farbschlagMismatch)).toBeVisible() +}) + /** QOL-ELTERN: Vater/Mutter im Abstammungs-Block des Tier-Formulars setzen. */ async function pickParent(page: Page, legend: string, name: string) { const group = page.getByRole('group', { name: legend }) diff --git a/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts b/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts index e13458b..7ea5075 100644 --- a/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts +++ b/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts @@ -24,6 +24,7 @@ import { combineLocus } from '../punnett' import { LOCI, type LocusKey } from '../loci' import { farbschlagFor, + formatVarietyName, genotypeToFarbschlag, representativeGenotype, BASE_COLORS, @@ -963,6 +964,22 @@ describe('GEN-6: C-Locus-Zygotie Platin / Saphir / Platin-Hell (bde4ec70 / f89e9 }) }) +describe('formatVarietyName: Modifier nicht doppeln', () => { + it('haengt „Schecke" an einen Basisnamen an', () => { + expect(formatVarietyName('Saphir', 'aa Cc[chm] DD E- G- pp Spsp')).toBe('Saphir Schecke') + }) + + it('doppelt „Schecke" NICHT, wenn der Katalogname es schon traegt', () => { + // Sonst „Schwarz Schecke Schecke" — und der Akten-Vergleich „eingetragen vs. errechnet" + // meldete eine Abweichung, obwohl beides dasselbe ist. + expect(formatVarietyName('Schwarz Schecke', 'aa CC DD EE GG PP Spsp rere')).toBe('Schwarz Schecke') + }) + + it('ohne Gencode bleibt der Name unveraendert', () => { + expect(formatVarietyName('Saphir', null)).toBe('Saphir') + }) +}) + describe('Schreibfehler-Alias c[hm] == c[chm] (Ticket 2322c2a8, Jay *24.10.2021)', () => { it('c[hm] parst als c[chm] und ergibt Zobel, nicht Zobel-Hell', () => { // Die Quell-Charts (Alberto Kids / Pukas Kids) schreiben „aa c[chm]c[hm] …" — diff --git a/gerbil-manager-web/src/genetics/catalog.ts b/gerbil-manager-web/src/genetics/catalog.ts index 7f5cb86..ffdc850 100644 --- a/gerbil-manager-web/src/genetics/catalog.ts +++ b/gerbil-manager-web/src/genetics/catalog.ts @@ -365,8 +365,13 @@ export function formatVarietyName(baseName: string, genotypeStr: string | null | try { const g = fromDisplayString(genotypeStr) const modifiers: string[] = [] - if (locusToken(g, 'Sp') === 'Sp') modifiers.push('Schecke') - if (locusToken(g, 'Re') === 'Re') modifiers.push('Rex') + // Einen Modifier NICHT doppeln, wenn der Katalogname ihn schon traegt: Bestaende mit + // Namen wie „Schwarz Schecke" ergaeben sonst „Schwarz Schecke Schecke" — und der + // Vergleich mit dem errechneten Farbschlag meldet dann eine Abweichung, die es nicht gibt. + const words = baseName.toLowerCase().split(/[\s-]+/) + const alreadyNamed = (modifier: string) => words.includes(modifier.toLowerCase()) + if (locusToken(g, 'Sp') === 'Sp' && !alreadyNamed('Schecke')) modifiers.push('Schecke') + if (locusToken(g, 'Re') === 'Re' && !alreadyNamed('Rex')) modifiers.push('Rex') return [baseName, ...modifiers].join(' ') } catch { return baseName diff --git a/gerbil-manager-web/src/pages/GerbilDetailPage.tsx b/gerbil-manager-web/src/pages/GerbilDetailPage.tsx index 7818622..62765ed 100644 --- a/gerbil-manager-web/src/pages/GerbilDetailPage.tsx +++ b/gerbil-manager-web/src/pages/GerbilDetailPage.tsx @@ -55,6 +55,11 @@ function describeGenotype(genotype: string | null): { display: string; farbschla } /** A labelled key/value row inside a card (semantic dt/dd, styled as a grid). */ +/** „Saphir Schecke" → „Saphir": Modifier-Zusaetze fuer den Namensvergleich abschneiden. */ +function stripVarietyModifiers(name: string): string { + return name.replace(' Schecke', '').replace(' Rex', '').trim() +} + function Kv({ label, children }: { label: string; children: ReactNode }) { return (
@@ -594,10 +599,16 @@ export default function GerbilDetailPage() { return ( <> {resolvedFarbschlag} + {/* Vergleich OHNE die Modifier-Zusaetze auf BEIDEN Seiten: der + eingetragene Name traegt „Schecke"/„Rex" bereits (formatVarietyName + haengt sie aus dem Gencode an), der errechnete ebenfalls. Vorher wurde + der Zusatz nur rechts entfernt → jede Schecke bekam faelschlich den + Hinweis „Weicht vom eingetragenen Farbschlag ab" (z. B. JackJack: + „Saphir Schecke" vs. „Saphir Schecke"). */} {storedColorName && resolvedFarbschlag !== de.genetics.unknownFarbschlag && - storedColorName !== - resolvedFarbschlag.replace(' Schecke', '').replace(' Rex', '') && ( + stripVarietyModifiers(storedColorName) !== + stripVarietyModifiers(resolvedFarbschlag) && ( ⚠ {t.detail.farbschlagMismatch} )}