Fix QA review 2719: optional coatType/petSizeCategory, CoatType union, null guards
- Make coatType and petSizeCategory optional on Pet (?:) — they may not be set
- Remove "single" and "short" from COAT_TYPES (not in CoatType union)
- Use { name: "Add" } instead of /add/i to target the + button specifically
- Add optional chaining to puppyCutSpans[0]?.closest() (noUncheckedIndexedAccess)
- Add optional chaining to petsData[0]?.id ?? "" in PetProfiles
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -39,8 +39,8 @@ export interface Pet {
|
|||||||
cutStyle: string | null;
|
cutStyle: string | null;
|
||||||
shampooPreference: string | null;
|
shampooPreference: string | null;
|
||||||
specialCareNotes: string | null;
|
specialCareNotes: string | null;
|
||||||
coatType: string | null;
|
coatType?: string | null;
|
||||||
petSizeCategory: string | null;
|
petSizeCategory?: string | null;
|
||||||
preferredCuts: string[];
|
preferredCuts: string[];
|
||||||
medicalAlerts: MedicalAlert[];
|
medicalAlerts: MedicalAlert[];
|
||||||
temperamentScore?: number;
|
temperamentScore?: number;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ describe("PetForm", () => {
|
|||||||
render(<PetForm pet={BASE_PET} onSave={onSave} onCancel={onCancel} />);
|
render(<PetForm pet={BASE_PET} onSave={onSave} onCancel={onCancel} />);
|
||||||
const input = screen.getByPlaceholderText(/type a cut name/i);
|
const input = screen.getByPlaceholderText(/type a cut name/i);
|
||||||
fireEvent.change(input, { target: { value: "Teddy Bear" } });
|
fireEvent.change(input, { target: { value: "Teddy Bear" } });
|
||||||
fireEvent.click(screen.getByRole("button", { name: /add/i }));
|
fireEvent.click(screen.getByRole("button", { name: "Add" }));
|
||||||
expect(screen.getByText("Teddy Bear")).toBeTruthy();
|
expect(screen.getByText("Teddy Bear")).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ describe("PetForm", () => {
|
|||||||
};
|
};
|
||||||
render(<PetForm pet={petWithCuts} onSave={onSave} onCancel={onCancel} />);
|
render(<PetForm pet={petWithCuts} onSave={onSave} onCancel={onCancel} />);
|
||||||
const puppyCutSpans = screen.getAllByText("Puppy Cut");
|
const puppyCutSpans = screen.getAllByText("Puppy Cut");
|
||||||
const puppyCutTag = puppyCutSpans[0].closest("span");
|
const puppyCutTag = puppyCutSpans[0]?.closest("span");
|
||||||
if (!puppyCutTag) return;
|
if (!puppyCutTag) return;
|
||||||
const removeBtn = puppyCutTag.querySelector("button");
|
const removeBtn = puppyCutTag.querySelector("button");
|
||||||
if (!removeBtn) return;
|
if (!removeBtn) return;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState } from "react";
|
|||||||
import { X, Save, Plus, Star } from "lucide-react";
|
import { X, Save, Plus, Star } from "lucide-react";
|
||||||
import type { Pet, MedicalAlert, CoatType, AlertSeverity } from "@groombook/types";
|
import type { Pet, MedicalAlert, CoatType, AlertSeverity } from "@groombook/types";
|
||||||
|
|
||||||
const COAT_TYPES: CoatType[] = ["double", "single", "wire", "curly", "smooth", "long", "short", "hairless"];
|
const COAT_TYPES: CoatType[] = ["double", "wire", "curly", "smooth", "long", "hairless"];
|
||||||
const SEVERITY_OPTIONS: AlertSeverity[] = ["low", "medium", "high"];
|
const SEVERITY_OPTIONS: AlertSeverity[] = ["low", "medium", "high"];
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function PetProfiles({ sessionId, readOnly }: Props) {
|
|||||||
setAppointments(apptsData);
|
setAppointments(apptsData);
|
||||||
|
|
||||||
if (petsData.length > 0 && !selectedPetId) {
|
if (petsData.length > 0 && !selectedPetId) {
|
||||||
setSelectedPetId(petsData[0].id);
|
setSelectedPetId(petsData[0]?.id ?? "");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(e instanceof Error ? e.message : "Failed to load data");
|
setError(e instanceof Error ? e.message : "Failed to load data");
|
||||||
|
|||||||
Reference in New Issue
Block a user