Files
GerbilManager/gerbil-manager-web/e2e/mock-data.ts
Gulum 55c298ad1f UI-POLISH-1: namenlose Tiere + Leerwert-Konsistenz
- de.ts: nameless = '(ohne Namen)' (neuer Platzhalter-String)
- GerbilsPage: g.name || t.nameless in Karten-Name + Checkbox-Aria
- GerbilDetailPage: g.name || nameless im h2-Header; g.causeOfDeath/notes via || null (leer-string-sicher wie Herkunft)
- AnimalPicker: g.name || nameless im Picker-Button

e2e: +1 nameless-stub in mock-data; 2 neue Tests (Liste + Detail-Header)

Gate: vitest 82/82, e2e 130/130, tsc clean
2026-06-06 17:32:26 +02:00

297 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* QA-1: Seed-Daten für den Mock-Modus — geformt exakt nach dem DATA-2-Vertrag
* (camelCase-DTOs, Gridify-paged Listen). Datensatz angelehnt an Kellys
* FEAT-4-Verifikationsdaten (mehrgenerationiger Stammbaum inkl. gemeinsamem
* Vorfahren Anton), erweitert um Becken/Kontakte/Gesundheit/Gewicht für die
* FEAT-2/FEAT-6-Flüsse.
*/
import type { Contact, Enclosure, Gerbil, Litter } from '../src/api/types'
import type { InboxRequest } from '../src/api/requests'
export interface HealthRecordRow {
id: string
gerbilId: string
date: string
type: string
description: string
veterinarian: string | null
createdAt: string
}
export interface WeightRecordRow {
id: string
gerbilId: string
date: string
weightGrams: number
notes: string | null
}
/** WEB-0b: CMS-Block (data ist das typ-spezifische JSON-Objekt). */
export interface MockBlock {
id: string
order: number
type: string
data: Record<string, unknown>
}
/** WEB-0b: CMS-Seite der öffentlichen Webseite. */
export interface MockPage {
id: string
slug: string
title: string
seoDescription: string | null
status: 'Draft' | 'Published'
blocks: MockBlock[]
}
/** ABGABE: Abgabevertrag (mirrors SaleContract in src/api/contracts.ts). */
export interface MockContract {
id: string
contactId: string
price: number
handoverDate: string
contractDate: string
fileName: string
createdAt: string
gerbilIds: string[]
url: string
}
export interface MockDb {
gerbils: Gerbil[]
litters: Litter[]
enclosures: Enclosure[]
contacts: Contact[]
colorVarieties: { id: string; name: string; canonicalGenotype: string | null; sortOrder: number }[]
healthRecords: HealthRecordRow[]
weightRecords: WeightRecordRow[]
pages: MockPage[]
// INBOX-1: Anfragen-Posteingang. Die Flags steuern die Fehlerpfade des Mocks
// (Specs können sie pro Test umlegen): KI-Entwurf 503 / Sync+Send Mail-Fehler.
requests: InboxRequest[]
aiConfigured: boolean
mailConfigured: boolean
// ABGABE: Verträge + KI-Inserat-Flag
contracts: MockContract[]
saleAdConfigured: boolean
}
function gerbil(
id: string,
name: string,
gender: 'male' | 'female',
dateOfBirth: string,
litterId: string | null,
colorVarietyId: string | null,
genotype: string | null = null,
): Gerbil {
return {
id,
name,
gender,
status: 'Active',
dateOfBirth,
dateOfDeath: null,
causeOfDeath: null,
goHomeDate: null,
litterId,
enclosureId: null,
colorVarietyId,
originContactId: null,
receiverContactId: null,
originBreeder: null,
// SEARCH-2b: backend stores a normalized name (lowercase, [\s._-] stripped).
nameSearch: name.toLowerCase().replace(/[\s._-]/g, ''),
genotype,
notes: null,
// BESTAND-FILTER: default = eigener Bestand; einzelne externe Ahnen unten gesetzt.
isResident: true,
}
}
/** Frischer, unabhängiger Datenbestand pro Test. */
export function seedDb(): MockDb {
const gerbils: Gerbil[] = [
{
...gerbil('kruemel', 'Krümel', 'female', '2025-03-12', 'w-kruemel', 'cv-agouti', 'Aa CC DD EE GG Pp spsp rere'),
enclosureId: 'enc-gross',
originContactId: 'con-meier',
originBreeder: 'Clan-Kleine-Chaoten',
},
{ ...gerbil('fridolin', 'Fridolin', 'male', '2023-05-01', 'w-fridolin', 'cv-schwarz', 'aa CC DD EE GG PP spsp rere'), enclosureId: 'enc-gross', originBreeder: 'Zoohandlung Meier' },
gerbil('luna', 'Luna', 'female', '2023-08-15', 'w-luna', 'cv-gold', 'AA CC DD EE GG pp spsp rere'),
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'),
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'),
gerbil('frieda', 'Frieda', 'female', '2020-01-18', null, 'cv-gold'),
gerbil('emil', 'Emil', 'male', '2017-03-03', 'w-emil', 'cv-agouti'),
// BESTAND-FILTER: externe Ahnen (Gründertiere fremder Zuchten, nur für den Stammbaum).
{ ...gerbil('hilde', 'Hilde', 'female', '2017-11-11', null, 'cv-schwarz'), isResident: false, originBreeder: 'Zoohandlung Meier' },
{ ...gerbil('max', 'Max', 'male', '2015-08-08', null, 'cv-agouti'), isResident: false, originBreeder: 'Zoohandlung Meier' },
// Statistik: Verstorbene + Abgegebene für Verluste/Bestandskurve
{ ...gerbil('willi', 'Willi', 'male', '2019-09-09', null, 'cv-schwarz'), status: 'Deceased', dateOfDeath: '2022-04-04' },
{ ...gerbil('rosa', 'Rosa', 'female', '2020-02-02', null, 'cv-gold'), status: 'Deceased', dateOfDeath: '2023-08-15' },
{ ...gerbil('pauli', 'Pauli', 'male', '2023-05-01', null, 'cv-himalaya'), status: 'GivenAway', goHomeDate: '2023-07-15', receiverContactId: 'con-huber' },
// ABGABE: zwei Tiere zur Abgabe im Quarantänebecken (enc-leer ist leer, kein Konflikt
// mit dem Becken-Belegungstest der Großbecken-2-Tiere-Assertion).
{
...gerbil('sale-balu', 'Balu Abgabe', 'male', '2024-03-12', null, 'cv-agouti'),
status: 'ForSale' as const,
enclosureId: 'enc-leer',
notes: 'ruhig, nimmt Leckerlis aus der Hand',
},
{
...gerbil('sale-benny', 'Benny Abgabe', 'male', '2024-03-12', null, 'cv-schwarz-schecke'),
status: 'ForSale' as const,
enclosureId: 'enc-leer',
notes: 'neugieriger Entdecker',
},
// UI-POLISH-1: Import-Stub ohne Namen — testet den '(ohne Namen)'-Platzhalter in Liste + Detail.
gerbil('nameless-stub', '', 'male', '2023-01-01', null, null),
]
const litters: Litter[] = [
{ id: 'w-kruemel', name: 'Wurf K', date: '2025-03-12', totalBorn: 5, expectedGoHomeDate: '2025-04-16', notes: null, fatherId: 'fridolin', motherId: 'luna' },
{ id: 'w-fridolin', name: 'Wurf F', date: '2023-05-01', totalBorn: 4, expectedGoHomeDate: null, notes: null, fatherId: 'balu', motherId: 'maja' },
{ id: 'w-luna', name: 'Wurf L', date: '2023-08-15', totalBorn: 6, expectedGoHomeDate: null, notes: null, fatherId: 'karlsson', motherId: 'smilla' },
{ id: 'w-balu', name: 'Wurf B', date: '2021-04-20', totalBorn: 3, expectedGoHomeDate: null, notes: null, fatherId: 'anton', motherId: 'greta' },
// Anton ist auch Karlssons Vater -> gemeinsamer Vorfahre (Inzucht-Demo)
{ id: 'w-karlsson', name: 'Wurf C', date: '2022-02-02', totalBorn: 5, expectedGoHomeDate: null, notes: null, fatherId: 'anton', motherId: 'frieda' },
{ id: 'w-anton', name: 'Wurf A', date: '2019-07-07', totalBorn: 4, expectedGoHomeDate: null, notes: null, fatherId: 'emil', motherId: 'hilde' },
{ id: 'w-emil', name: 'Wurf E', date: '2017-03-03', totalBorn: 2, expectedGoHomeDate: null, notes: null, fatherId: 'max', motherId: null },
]
const enclosures: Enclosure[] = [
{ id: 'enc-gross', name: 'Großbecken', notes: '120×50 cm' },
{ id: 'enc-leer', name: 'Quarantänebecken', notes: null },
]
// FEAT-13: contactInfo (Freitext) wurde durch strukturierte Felder ersetzt.
const contacts: Contact[] = [
{ id: 'con-meier', name: 'Zoohandlung Meier', email: 'meier@example.de', phone: null, address: 'Hauptstraße 1, 12345 Musterstadt', notes: null },
{ id: 'con-huber', name: 'Familie Huber', email: null, phone: '0151 2345678', address: null, notes: null },
{ id: 'con-frei', name: 'Züchterin Frei', email: null, phone: null, address: null, notes: 'unverknüpft' },
]
const colorVarieties = [
{ id: 'cv-agouti', name: 'Agouti', canonicalGenotype: 'AA CC DD EE GG PP spsp rere', sortOrder: 1 },
{ id: 'cv-schwarz', name: 'Schwarz', canonicalGenotype: 'aa CC DD EE GG PP spsp rere', sortOrder: 2 },
{ id: 'cv-gold', name: 'Gold', canonicalGenotype: 'AA CC DD EE GG pp spsp rere', sortOrder: 3 },
{ id: 'cv-blau', name: 'Blau', canonicalGenotype: 'aa CC dd EE GG PP spsp rere', sortOrder: 4 },
{ id: 'cv-himalaya', name: 'Himalaya', canonicalGenotype: 'AA chch DD EE GG PP spsp rere', sortOrder: 5 },
{ id: 'cv-schwarz-schecke', name: 'Schwarz Schecke', canonicalGenotype: 'aa CC DD EE GG PP Spsp rere', sortOrder: 6 },
]
const healthRecords: HealthRecordRow[] = [
{
id: 'hr-1',
gerbilId: 'kruemel',
date: '2026-01-15',
type: 'Vaccination',
description: 'Jahresimpfung',
veterinarian: 'Dr. Vogel',
createdAt: '2026-01-15T10:00:00Z',
},
]
const weightRecords: WeightRecordRow[] = [
{ id: 'wr-1', gerbilId: 'kruemel', date: '2026-05-01', weightGrams: 78, notes: null },
{ id: 'wr-2', gerbilId: 'kruemel', date: '2026-05-20', weightGrams: 82, notes: null },
]
// WEB-0b: die 6 Webseiten-Seiten (wie vom Backend geseedet), mit ein paar Blöcken.
const pages: MockPage[] = [
{
id: 'page-start',
slug: 'start',
title: 'Startseite',
seoDescription: 'Willkommen bei unserer Rennmauszucht.',
status: 'Published',
blocks: [
{ id: 'blk-start-1', order: 0, type: 'Heading', data: { text: 'Willkommen', level: 2 } },
{ id: 'blk-start-2', order: 1, type: 'RichText', data: { markdown: 'Schön, dass du da bist.' } },
],
},
{ id: 'page-zucht', slug: 'ueber-die-zucht', title: 'Über die Zucht', seoDescription: null, status: 'Draft', blocks: [] },
{
id: 'page-abgabe',
slug: 'abgabetiere',
title: 'Abgabetiere',
seoDescription: null,
status: 'Published',
blocks: [
{ id: 'blk-abgabe-1', order: 0, type: 'AbgabetiereList', data: { mode: 'auto', intro: 'Diese Tiere suchen ein Zuhause.' } },
],
},
{ id: 'page-bedingungen', slug: 'abgabebedingungen', title: 'Abgabebedingungen', seoDescription: null, status: 'Draft', blocks: [] },
{ id: 'page-farben', slug: 'farben-genetik', title: 'Farben & Genetik', seoDescription: null, status: 'Draft', blocks: [] },
{ id: 'page-kontakt', slug: 'kontakt', title: 'Kontakt', seoDescription: null, status: 'Draft', blocks: [] },
]
// INBOX-1: Anfragen (neueste zuerst nach receivedAt sortierbar)
const requests: InboxRequest[] = [
{
id: 'req-anna',
gmailMessageId: '<anna-1@mail.example>',
threadId: 'thr-1',
fromAddress: 'anna@example.de',
fromName: 'Anna Albrecht',
subject: 'Anfrage: Pärchen zur Abgabe?',
bodyText:
'Hallo,\n\nich habe euer Inserat gesehen — sind die beiden Agouti-Jungs noch zu haben?\n\nViele Grüße\nAnna',
receivedAt: '2026-06-05T18:30:00Z',
status: 'New',
assignedContactId: null,
draftReply: null,
answeredAt: null,
},
{
id: 'req-ben',
gmailMessageId: '<ben-1@mail.example>',
threadId: 'thr-2',
fromAddress: 'ben@example.org',
fromName: 'Ben Berger',
subject: 'Frage zur Haltung',
bodyText: 'Guten Tag, was für ein Becken empfehlt ihr für zwei Rennmäuse?',
receivedAt: '2026-06-04T09:00:00Z',
status: 'InProgress',
assignedContactId: null,
draftReply: 'Hallo Ben, wir empfehlen mindestens 100×50 cm …',
answeredAt: null,
},
{
id: 'req-clara',
gmailMessageId: '<clara-1@mail.example>',
threadId: null,
fromAddress: 'clara@example.com',
fromName: null,
subject: 'Danke!',
bodyText: 'Die beiden sind super angekommen — danke nochmal!',
receivedAt: '2026-06-01T12:00:00Z',
status: 'Answered',
assignedContactId: 'con-meier',
draftReply: null,
answeredAt: '2026-06-02T08:00:00Z',
},
]
return {
gerbils,
litters,
enclosures,
contacts,
colorVarieties,
healthRecords,
weightRecords,
pages,
requests,
aiConfigured: true,
mailConfigured: true,
contracts: [],
saleAdConfigured: true,
}
}