import test from "node:test"; import assert from "node:assert/strict"; import request from "supertest"; import {setup,signup} from "./helpers.js"; test("activity calendar is authenticated, validates dates, and only links owned events",async()=>{ const {app,agent,db}=await setup();const {csrf}=await signup(agent,"calendar@example.com"); const other=request.agent(app);await signup(other,"private-calendar@example.com"); const owner=(await db.query("SELECT id FROM users WHERE email=$1",["calendar@example.com"])).rows[0].id; const privateId=(await db.query("SELECT id FROM users WHERE email=$1",["private-calendar@example.com"])).rows[0].id; const p=(await db.query("INSERT INTO roast_plans(user_id,name,plan,created_at) VALUES($1,'Burundi',$2,'2026-09-05T12:00:00Z') RETURNING id",[owner,{fields:{"0.1":"Burundi"}}])).rows[0]; await db.query("INSERT INTO actual_roasts(user_id,roast_plan_id,filename,original_content,parsed,created_at) VALUES($1,$2,'batch.alog','{}',$3,'2026-10-01')",[owner,p.id,{roast:{title:"Roasted earlier",roastDate:"2026-09-04"}}]); await db.query("INSERT INTO cupping_sessions(user_id,roast_plan_id,data,created_at) VALUES($1,$2,$3,'2026-09-07')",[owner,p.id,{ritual_started_at_iso:"2026-09-06T12:00:00Z"}]); await db.query("INSERT INTO brews(user_id,method,brewed_at) VALUES($1,'v60','2026-09-01T02:00:00Z')",[owner]); await db.query("INSERT INTO brews(user_id,method,brewed_at) VALUES($1,'PRIVATE','2026-09-04')",[privateId]); const path="/api/activity?month=2026-09&timeZone=America%2FNew_York"; assert.equal((await request(app).get(path)).status,401); assert.equal((await agent.get("/api/activity?month=2026-13")).status,400); assert.equal((await agent.get("/api/activity?month=2026-09&timeZone=nope")).status,400); const result=await agent.get(path);assert.equal(result.status,200); assert.deepEqual(result.body.events.map(e=>e.kind),["roast","plan","cupping"]); assert.equal(result.body.events[0].date,"2026-09-04"); assert.equal(result.body.events[0].planHref,"/app?plan="+p.id); assert.equal((await agent.get("/api/activity?month=2026-08&timeZone=America%2FNew_York")).body.events[0].kind,"brew"); assert.equal((await agent.get("/home")).status,200);assert.equal((await request(app).get("/home")).status,302); assert.equal((await agent.get("/coffees")).headers.location,"/home"); assert.equal((await agent.get("/")).headers.location,"/home"); }); test("Bean Bro streaming preserves auth, CSRF, final suggestion validation and errors",async()=>{ const {app,agent}=await setup({}, {runPlanChat:async({onText,messages})=>{ onText?.("First crack: 392°F"); if(messages[0].content==="fail")throw new Error("Provider disconnected"); return {reply:"First crack: 392°F, illustrative.",suggestions:[{fields:{"bad":"secret","4.4":"1:20"},reason:"Test",evidenceRoastIds:["private"]}]}; }}); const {csrf}=await signup(agent,"stream@example.com"); const body={plan:{fields:{"1.4":"8:45"}},messages:[{role:"user",content:"FC?"}]}; assert.equal((await request(app).post("/api/plan-chat").set("accept","text/event-stream").send(body)).status,401); assert.equal((await agent.post("/api/plan-chat").set("accept","text/event-stream").send(body)).status,403); const response=await agent.post("/api/plan-chat").set("x-csrf-token",csrf).set("accept","text/event-stream").send(body); assert.equal(response.status,200);assert.match(response.headers["content-type"],/text\/event-stream/); assert.match(response.text,/event: reply/);assert.match(response.text,/392°F/);assert.match(response.text,/event: done/); assert.ok(!response.text.includes("private"));assert.ok(!response.text.includes("secret")); body.messages[0].content="fail"; const failed=await agent.post("/api/plan-chat").set("x-csrf-token",csrf).set("accept","text/event-stream").send(body); assert.match(failed.text,/event: error/);assert.match(failed.text,/Provider disconnected/);assert.ok(!failed.text.includes("event: done")); });