mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
test(api): parse real responses against the schemas that publish them
Response drift was structurally undetectable. `openapi:check` proves the YAML matches the registry and the route-coverage guard proves the verb is listed; both pass when the registered schema disagrees with what `apiSuccess()` sends, and the coverage guard says so in its own doc comment. That is how `/api/sync/changes` shipped five domains against a three-domain contract and how the error envelope went years without declaring the field the multi-issue 422 was built for. Two bodies, the two that were broken: a full `/api/sync/changes` page with live and soft-deleted rows in all five domains, its `cursorExpired` short-circuit (a second shape under the same schema), and a 422 carrying more than one issue. `safeParse` alone would not have caught either finding, because Zod strips undeclared keys instead of refusing them — a schema short of the wire parses cleanly. So the parsed value is compared back to the raw body; a strip means the contract is missing something the server sends. Removing `cycleDays` / `cycles` from the sync schema, or `details` from the envelope, fails all three cases.
This commit is contained in:
1 parent
0cd996e7de
commit
4993352cc9
2 files changed
+307
-1
No files matched your search
@@ -236,7 +236,15 @@ const syncChangesQuery = z
|
||||
})
|
||||
.meta({ id: "SyncChangesQuery" });
|
||||
|
||||
const syncChangesResponse = z
|
||||
/**
|
||||
* Exported so a test can `safeParse` a real `/api/sync/changes` body against
|
||||
* it. Nothing else checks a response SHAPE against its published schema —
|
||||
* `openapi:check` proves the YAML matches the registry, and the route-coverage
|
||||
* guard proves the path is listed, so a schema that disagrees with what
|
||||
* `apiSuccess()` sends passes both. That is how this endpoint went five
|
||||
* domains wide against a three-domain contract.
|
||||
*/
|
||||
export const syncChangesResponse = z
|
||||
.object({
|
||||
serverNow: z.iso.datetime({ offset: true }),
|
||||
cursor: z
|
||||
|
||||
Reference in new issue
Block a user