Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb2c70efe1 |
@@ -183,6 +183,23 @@ GroomBook API is a Hono-based REST service (TypeScript/Node.js) powering the pet
|
|||||||
| TC-API-14.4 | Update group notes | PATCH /api/appointment-groups/{id} with notes | 200 OK, notes updated |
|
| TC-API-14.4 | Update group notes | PATCH /api/appointment-groups/{id} with notes | 200 OK, notes updated |
|
||||||
| TC-API-14.5 | Cancel group | DELETE /api/appointment-groups/{id} | 200 OK, all appointments cancelled |
|
| TC-API-14.5 | Cancel group | DELETE /api/appointment-groups/{id} | 200 OK, all appointments cancelled |
|
||||||
|
|
||||||
|
### 4.15 Public Booking Flow (Scheduling Engine Buffer Integration)
|
||||||
|
|
||||||
|
| # | Scenario | Steps | Expected |
|
||||||
|
|---|----------|-------|----------|
|
||||||
|
| TC-API-15.1 | List active services | GET /api/book/services | 200 OK, list of active services with name, price, duration |
|
||||||
|
| TC-API-15.2 | Get availability — missing params | GET /api/book/availability | 400 Bad Request, error indicating required params |
|
||||||
|
| TC-API-15.3 | Get availability — invalid date | GET /api/book/availability?serviceId=uuid&date=invalid | 400 Bad Request, date must be YYYY-MM-DD |
|
||||||
|
| TC-API-15.4 | Get availability — service not found | GET /api/book/availability?serviceId=nonexistent&date=2026-06-01 | 404 Not Found |
|
||||||
|
| TC-API-15.5 | Get availability — valid date/service | GET /api/book/availability?serviceId={serviceId}&date=2026-06-01 | 200 OK, array of ISO startTime strings for available slots |
|
||||||
|
| TC-API-15.6 | Availability excludes booked slots | GET /api/book/availability for date with existing appointments | 200 OK, only slots not overlapping booked appointments |
|
||||||
|
| TC-API-15.7 | Availability respects groomer availability | GET /api/book/availability for date with no groomers | 200 OK, empty array |
|
||||||
|
| TC-API-15.8 | Create booking — missing required fields | POST /api/book/appointments with partial data | 400 Bad Request, validation errors |
|
||||||
|
| TC-API-15.9 | Create booking — invalid pet/client/service | POST /api/book/appointments with nonexistent IDs | 400/404 Bad Request |
|
||||||
|
| TC-API-15.10 | Create booking — valid | POST /api/book/appointments with all required fields | 201 Created, appointment object returned |
|
||||||
|
| TC-API-15.11 | Create booking — saves petSizeCategory | POST /api/book/appointments with petSizeCategory | 201 Created, pet's petSizeCategory updated |
|
||||||
|
| TC-API-15.12 | Create booking — saves petCoatType | POST /api/book/appointments with petCoatType | 201 Created, pet's coatType updated |
|
||||||
|
|
||||||
## Pass/Fail Criteria
|
## Pass/Fail Criteria
|
||||||
|
|
||||||
**Pass:**
|
**Pass:**
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import type { AppEnv, StaffRow } from "../middleware/rbac.js";
|
import type { AppEnv, StaffRow } from "../middleware/rbac.js";
|
||||||
import { petsRouter } from "../routes/pets.js";
|
import { petsRouter } from "../routes/pets.js";
|
||||||
|
import { and, eq, exists, or } from "../db/index.js";
|
||||||
|
|
||||||
// ─── Mock staff fixtures ──────────────────────────────────────────────────────
|
// ─── Mock staff fixtures ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -21,8 +22,8 @@ const MANAGER: StaffRow = {
|
|||||||
|
|
||||||
// ─── Mutable mock state ───────────────────────────────────────────────────────
|
// ─── Mutable mock state ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
const CLIENT_ID = "client-uuid-extended";
|
const CLIENT_ID = "11111111-1111-1111-1111-111111111111";
|
||||||
const PET_ID = "pet-uuid-extended";
|
const PET_ID = "22222222-2222-2222-2222-222222222222";
|
||||||
|
|
||||||
let petRows: Record<string, unknown>[] = [];
|
let petRows: Record<string, unknown>[] = [];
|
||||||
let appointmentRows: Record<string, unknown>[] = [];
|
let appointmentRows: Record<string, unknown>[] = [];
|
||||||
@@ -134,7 +135,7 @@ function makeDeleteChainable(): unknown {
|
|||||||
}
|
}
|
||||||
if (prop === "returning") {
|
if (prop === "returning") {
|
||||||
return () => {
|
return () => {
|
||||||
const row = petRows[0];
|
const row = petRows[0]!;
|
||||||
deletedId = row.id as string;
|
deletedId = row.id as string;
|
||||||
return [row];
|
return [row];
|
||||||
};
|
};
|
||||||
@@ -145,7 +146,8 @@ function makeDeleteChainable(): unknown {
|
|||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
vi.mock("../db", () => {
|
vi.mock("../db", async (importOriginal) => {
|
||||||
|
const db = await importOriginal<typeof import("../db/index.js")>();
|
||||||
const pets = new Proxy({ _name: "pets" }, { get: (t, p) => p === "_name" ? "pets" : {} });
|
const pets = new Proxy({ _name: "pets" }, { get: (t, p) => p === "_name" ? "pets" : {} });
|
||||||
const appointments = new Proxy({ _name: "appointments" }, { get: (t, p) => p === "_name" ? "appointments" : {} });
|
const appointments = new Proxy({ _name: "appointments" }, { get: (t, p) => p === "_name" ? "appointments" : {} });
|
||||||
return {
|
return {
|
||||||
@@ -163,10 +165,10 @@ vi.mock("../db", () => {
|
|||||||
}),
|
}),
|
||||||
pets,
|
pets,
|
||||||
appointments,
|
appointments,
|
||||||
and,
|
and: db.and,
|
||||||
eq,
|
eq: db.eq,
|
||||||
exists,
|
exists: db.exists,
|
||||||
or,
|
or: db.or,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,11 @@ export function buildPet(overrides: Partial<PetRow> & { clientId: string }): Pet
|
|||||||
photoKey: null,
|
photoKey: null,
|
||||||
photoUploadedAt: null,
|
photoUploadedAt: null,
|
||||||
image: null,
|
image: null,
|
||||||
|
coatType: null,
|
||||||
|
temperamentScore: null,
|
||||||
|
temperamentFlags: [],
|
||||||
|
medicalAlerts: [],
|
||||||
|
preferredCuts: [],
|
||||||
createdAt: new Date("2025-01-01T00:00:00Z"),
|
createdAt: new Date("2025-01-01T00:00:00Z"),
|
||||||
updatedAt: new Date("2025-01-01T00:00:00Z"),
|
updatedAt: new Date("2025-01-01T00:00:00Z"),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user