mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
test(api): use the real caps in the limiter mocks, and drop a stale pointer
Three consent-surface tests mocked the shared AI-consent bucket at 60 where it is 20, and the analytics-read and MCP mocks named 60 against real caps of 120. Nothing asserts the number today, so nothing was wrong on the wire — but the mocked verdict now carries `limit` all the way to `X-RateLimit-Limit`, and the first test that reads that header off a mock would pin the fiction. The response-shape file's header pointed at a document that is not in the repo; it says what it means directly instead. It also now records the one thing the gate cannot see: `meta` is a loose object on purpose, so undeclared keys inside it survive the parse and the strip comparison does not reach them.
This commit is contained in:
1 parent
cf9e8b8790
commit
6f718121c7
7 files changed
+19
-12
No files matched your search
@@ -114,7 +114,7 @@ describe("POST /api/consent/ai", () => {
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(checkConsentRateLimit).mockResolvedValue({
|
||||
allowed: false,
|
||||
limit: 60,
|
||||
limit: 20,
|
||||
remaining: 0,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
|
||||
@@ -104,7 +104,7 @@ describe("GET /api/consent/ai/latest", () => {
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(checkConsentRateLimit).mockResolvedValue({
|
||||
allowed: false,
|
||||
limit: 60,
|
||||
limit: 20,
|
||||
remaining: 0,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
@@ -203,7 +203,7 @@ describe("DELETE /api/consent/ai/latest", () => {
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(checkConsentRateLimit).mockResolvedValue({
|
||||
allowed: false,
|
||||
limit: 60,
|
||||
limit: 20,
|
||||
remaining: 0,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
|
||||
@@ -84,7 +84,7 @@ describe("POST /api/consent/ai/web", () => {
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(checkConsentRateLimit).mockResolvedValue({
|
||||
allowed: false,
|
||||
limit: 60,
|
||||
limit: 20,
|
||||
remaining: 0,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
|
||||
@@ -117,7 +117,7 @@ beforeEach(() => {
|
||||
// v1.15.20 — default to an allowing analytics-read budget.
|
||||
vi.mocked(checkAnalyticsReadRateLimit).mockResolvedValue({
|
||||
allowed: true,
|
||||
limit: 60,
|
||||
limit: 120,
|
||||
remaining: 119,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
|
||||
@@ -103,7 +103,7 @@ beforeEach(() => {
|
||||
// v1.15.20 — default to an allowing analytics-read budget.
|
||||
vi.mocked(checkAnalyticsReadRateLimit).mockResolvedValue({
|
||||
allowed: true,
|
||||
limit: 60,
|
||||
limit: 120,
|
||||
remaining: 119,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
@@ -230,7 +230,7 @@ describe("GET /api/insights/correlations", () => {
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(checkAnalyticsReadRateLimit).mockResolvedValue({
|
||||
allowed: false,
|
||||
limit: 60,
|
||||
limit: 120,
|
||||
remaining: 0,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
|
||||
@@ -156,7 +156,7 @@ beforeEach(() => {
|
||||
vi.mocked(isApiGloballyEnabled).mockResolvedValue(true);
|
||||
vi.mocked(checkMcpRateLimit).mockResolvedValue({
|
||||
allowed: true,
|
||||
limit: 60,
|
||||
limit: 120,
|
||||
remaining: 119,
|
||||
resetAt: Date.now() + 60_000,
|
||||
});
|
||||
@@ -353,7 +353,7 @@ describe("/mcp — rate limit", () => {
|
||||
validToken();
|
||||
vi.mocked(checkMcpRateLimit).mockResolvedValue({
|
||||
allowed: false,
|
||||
limit: 60,
|
||||
limit: 120,
|
||||
remaining: 0,
|
||||
resetAt: Date.now() + 30_000,
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* five domains against a three-domain contract while the body was invalid
|
||||
* against its own published schema.
|
||||
*
|
||||
* Two responses are covered — the ones the audit found broken:
|
||||
* Two responses are covered — the two that were broken:
|
||||
*
|
||||
* - `GET /api/sync/changes`, the multi-domain delta the native client mirrors
|
||||
* its whole history from.
|
||||
@@ -17,9 +17,16 @@
|
||||
*
|
||||
* The check is stricter than `safeParse` alone. Zod strips undeclared keys
|
||||
* rather than refusing them, so a pass would say nothing about a field the
|
||||
* server sends and the contract omits — exactly the direction both High
|
||||
* findings drifted in. Comparing the parsed value back to the raw body catches
|
||||
* server sends and the contract omits — exactly the direction both of those
|
||||
* drifted in. Comparing the parsed value back to the raw body catches
|
||||
* the strip: if anything was dropped, the schema is short of the wire.
|
||||
*
|
||||
* One limit worth knowing before leaning on that half: `meta` is declared as a
|
||||
* loose object, deliberately, because real refusals put `removedIn`,
|
||||
* `replacedBy` and per-integration context there. Loose keys survive the parse,
|
||||
* so the strip comparison does not reach inside `meta`. A `meta` field that
|
||||
* ever becomes load-bearing for a client needs its own declaration and its own
|
||||
* assertion.
|
||||
*/
|
||||
import { NextRequest } from "next/server";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
Reference in new issue
Block a user