mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
test(labs): integration coverage for biomarker target-range and delete
Drive the biomarker resource route against a real Postgres: PUT persists a new reference window and rejects an inverted one, and DELETE drops the marker together with its readings while leaving another user's marker and readings intact.
This commit is contained in:
1 parent
f17131dbdf
commit
1cb7f0933c
1 file changed
+172
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Integration suite for the biomarker resource route
|
||||
* (`/api/biomarkers/{id}`) against a real Postgres.
|
||||
*
|
||||
* Covers the two detail-page mutations:
|
||||
* - PUT adjusts the target range (and rejects an inverted window),
|
||||
* - DELETE drops the marker together with its readings in one
|
||||
* userId-narrowed transaction, leaving another user's marker untouched.
|
||||
*/
|
||||
import { NextRequest } from "next/server";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { cookieJar } from "./mock-next-headers";
|
||||
import { getPrismaClient, truncateAllTables } from "./setup";
|
||||
|
||||
const USER_ID = "user-biomarker-detail-test";
|
||||
const OTHER_USER_ID = "user-biomarker-other-test";
|
||||
|
||||
vi.mock("next/headers", async () => {
|
||||
const { cookieJar, headerJar } = await import("./mock-next-headers");
|
||||
return {
|
||||
headers: vi.fn(async () => ({
|
||||
get: (name: string) => headerJar.get(name.toLowerCase()) ?? null,
|
||||
})),
|
||||
cookies: vi.fn(async () => ({
|
||||
get: (name: string) => {
|
||||
const value = cookieJar.get(name);
|
||||
return value ? { name, value } : undefined;
|
||||
},
|
||||
set: (name: string, value: string) => {
|
||||
cookieJar.set(name, value);
|
||||
},
|
||||
delete: (name: string) => {
|
||||
cookieJar.delete(name);
|
||||
},
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("@/lib/db-compat", () => ({
|
||||
ensureDbCompatibility: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
beforeEach(async () => {
|
||||
await truncateAllTables(getPrismaClient());
|
||||
cookieJar.clear();
|
||||
const prisma = getPrismaClient();
|
||||
await prisma.user.createMany({
|
||||
data: [
|
||||
{ id: USER_ID, username: "bm-detail", email: "bm-detail@example.test" },
|
||||
{
|
||||
id: OTHER_USER_ID,
|
||||
username: "bm-other",
|
||||
email: "bm-other@example.test",
|
||||
},
|
||||
],
|
||||
});
|
||||
const session = await prisma.session.create({
|
||||
data: { userId: USER_ID, expiresAt: new Date(Date.now() + 60 * 60 * 1000) },
|
||||
});
|
||||
cookieJar.set("healthlog_session", session.id);
|
||||
});
|
||||
|
||||
const params = (id: string) => ({ params: Promise.resolve({ id }) });
|
||||
|
||||
function putReq(id: string, body: unknown): NextRequest {
|
||||
return new NextRequest(`http://localhost/api/biomarkers/${id}`, {
|
||||
method: "PUT",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
function delReq(id: string): NextRequest {
|
||||
return new NextRequest(`http://localhost/api/biomarkers/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
async function seedMarkerWithReadings(userId: string, name: string) {
|
||||
const prisma = getPrismaClient();
|
||||
const marker = await prisma.biomarker.create({
|
||||
data: { userId, name, unit: "mg/dL", lowerBound: 0, upperBound: 100 },
|
||||
});
|
||||
await prisma.labResult.createMany({
|
||||
data: [
|
||||
{
|
||||
userId,
|
||||
biomarkerId: marker.id,
|
||||
analyte: name,
|
||||
unit: "mg/dL",
|
||||
value: 95,
|
||||
takenAt: new Date("2026-06-20T08:00:00.000Z"),
|
||||
},
|
||||
{
|
||||
userId,
|
||||
biomarkerId: marker.id,
|
||||
analyte: name,
|
||||
unit: "mg/dL",
|
||||
value: 88,
|
||||
takenAt: new Date("2026-05-20T08:00:00.000Z"),
|
||||
},
|
||||
],
|
||||
});
|
||||
return marker;
|
||||
}
|
||||
|
||||
describe("PUT /api/biomarkers/{id} — target range (real Postgres)", () => {
|
||||
it("persists an updated reference window", async () => {
|
||||
const { PUT } = await import("@/app/api/biomarkers/[id]/route");
|
||||
const marker = await seedMarkerWithReadings(USER_ID, "LDL");
|
||||
|
||||
const res = await PUT(
|
||||
putReq(marker.id, { lowerBound: 10, upperBound: 50 }),
|
||||
params(marker.id),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const row = await getPrismaClient().biomarker.findUnique({
|
||||
where: { id: marker.id },
|
||||
});
|
||||
expect(row?.lowerBound).toBe(10);
|
||||
expect(row?.upperBound).toBe(50);
|
||||
});
|
||||
|
||||
it("422s an inverted target range and leaves the bounds untouched", async () => {
|
||||
const { PUT } = await import("@/app/api/biomarkers/[id]/route");
|
||||
const marker = await seedMarkerWithReadings(USER_ID, "HbA1c");
|
||||
|
||||
const res = await PUT(
|
||||
putReq(marker.id, { lowerBound: 80, upperBound: 20 }),
|
||||
params(marker.id),
|
||||
);
|
||||
expect(res.status).toBe(422);
|
||||
|
||||
const row = await getPrismaClient().biomarker.findUnique({
|
||||
where: { id: marker.id },
|
||||
});
|
||||
expect(row?.lowerBound).toBe(0);
|
||||
expect(row?.upperBound).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("DELETE /api/biomarkers/{id} (real Postgres)", () => {
|
||||
it("drops the marker together with its readings", async () => {
|
||||
const { DELETE } = await import("@/app/api/biomarkers/[id]/route");
|
||||
const marker = await seedMarkerWithReadings(USER_ID, "Ferritin");
|
||||
|
||||
const res = await DELETE(delReq(marker.id), params(marker.id));
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const prisma = getPrismaClient();
|
||||
expect(await prisma.biomarker.count({ where: { id: marker.id } })).toBe(0);
|
||||
expect(
|
||||
await prisma.labResult.count({ where: { biomarkerId: marker.id } }),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("404s another user's marker and leaves it (and its readings) intact", async () => {
|
||||
const { DELETE } = await import("@/app/api/biomarkers/[id]/route");
|
||||
const foreign = await seedMarkerWithReadings(OTHER_USER_ID, "TSH");
|
||||
|
||||
const res = await DELETE(delReq(foreign.id), params(foreign.id));
|
||||
expect(res.status).toBe(404);
|
||||
|
||||
const prisma = getPrismaClient();
|
||||
expect(await prisma.biomarker.count({ where: { id: foreign.id } })).toBe(1);
|
||||
expect(
|
||||
await prisma.labResult.count({ where: { biomarkerId: foreign.id } }),
|
||||
).toBe(2);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user