import assert from "node:assert/strict"; import { spawn } from "node:child_process"; import { once } from "node:events"; import { createServer } from "node:http"; import type { AddressInfo } from "node:net"; import { test } from "node:test"; test("admin action edits attribute changed feedback to the editor", { timeout: 30_000 }, async () => { const adminId = "11111111-1111-4111-8111-111111111111"; const ownerId = "22222222-2222-4222-8222-222222222222"; const sessionId = "33333333-3333-4333-8333-333333333333"; const actionId = "44444444-4444-4444-8444-444444444444"; const user = { id: adminId, email: "admin@example.com", email_confirmed_at: new Date().toISOString(), user_metadata: {} }; const savedReviews: Array> = []; let oldNotes = ["Original feedback"]; const upstream = createServer(async (req, res) => { const url = new URL(req.url!, "http://stub"); res.setHeader("Content-Type", "application/json"); if (url.pathname === "/auth/v1/user") return res.end(JSON.stringify(user)); if (url.pathname === "/rest/v1/users") return res.end(JSON.stringify({ user_id: adminId, account_role: "admin" })); if (url.pathname === "/rest/v1/sessions") return res.end(JSON.stringify({ status: "completed" })); if (url.pathname === "/rest/v1/annotations" && req.method === "GET") { return res.end(JSON.stringify({ user_id: ownerId, score: 5, annotations_notes: oldNotes.map((note) => ({ note })) })); } if (url.pathname === "/rest/v1/rpc/save_action_review") { const chunks: Buffer[] = []; for await (const chunk of req) chunks.push(Buffer.from(chunk)); const body = JSON.parse(Buffer.concat(chunks).toString()) as Record; savedReviews.push(body); oldNotes = body.p_notes as string[]; return res.end("null"); } if (url.pathname === `/api/sessions/${sessionId}/actions/${actionId}` && req.method === "PATCH") return res.end("{}"); res.statusCode = 404; return res.end(JSON.stringify({ error: "Unexpected mock request", path: url.pathname })); }); upstream.listen(0, "127.0.0.1"); await once(upstream, "listening"); const portProbe = createServer(); portProbe.listen(0, "127.0.0.1"); await once(portProbe, "listening"); const port = (portProbe.address() as AddressInfo).port; await new Promise((resolve) => portProbe.close(() => resolve())); const origin = `http://127.0.0.1:${port}`; const upstreamOrigin = `http://127.0.0.1:${(upstream.address() as AddressInfo).port}`; const child = spawn(process.execPath, ["--import", "tsx", "src/server.ts"], { env: { ...process.env, NODE_ENV: "test", PORT: String(port), FRONTEND_URL: origin, BACKEND_URL: origin, ANALYSIS_API_URL: upstreamOrigin, SUPABASE_URL: upstreamOrigin, SUPABASE_ANON_KEY: "test-anon", SUPABASE_SERVICE_ROLE_KEY: "test-service", ANALYSIS_PROXY_SECRET: "x".repeat(32) }, stdio: ["ignore", "pipe", "pipe"], }); try { await new Promise((resolve, reject) => { child.stdout.on("data", (data) => { if (String(data).includes("API listening")) resolve(); }); child.once("exit", (code) => reject(new Error(`API exited: ${code}`))); child.once("error", reject); }); const save = (notes: string[]) => fetch(`${origin}/api/admin/sessions/${sessionId}/actions/${actionId}`, { method: "PATCH", signal: AbortSignal.timeout(10000), headers: { Cookie: "sp_access=access", Origin: origin, "Content-Type": "application/json" }, body: JSON.stringify({ startFrame: 0, endFrame: 10, type: "Shoot", score: 5, notes }), }); assert.equal((await save(["Original feedback"])).status, 200); assert.equal(savedReviews.length, 0, "an action-only edit must preserve the previous feedback author"); assert.equal((await save(["Updated feedback"])).status, 200); assert.equal(savedReviews.length, 1); assert.equal(savedReviews[0].p_user_id, adminId); assert.deepEqual(savedReviews[0].p_notes, ["Updated feedback"]); assert.equal(savedReviews[0].p_session_id, sessionId); assert.equal(savedReviews[0].p_action_id, actionId); } finally { if (child.exitCode === null && child.signalCode === null) { const exited = once(child, "exit"); child.kill(); await exited; } upstream.closeAllConnections(); await new Promise((resolve) => upstream.close(() => resolve())); } });