import test from "node:test"; import assert from "node:assert/strict"; import request from "supertest"; import { setup, signup } from "./helpers.js"; import { blankPlan } from "../shared/fields.js"; import { cleanSuggestions } from "../shared/workspace.js"; test("workspace groups own coffee history and surfaces tasting, inventory and experiment actions", async () => { const { app, agent, db } = await setup(); const { csrf } = await signup(agent, "history@example.com"); const other = request.agent(app); const { csrf: otherCsrf } = await signup(other, "private@example.com"); await other .post("/api/plans") .set("x-csrf-token", otherCsrf) .send({ plan: { ...blankPlan(), fields: { 0.1: "Private coffee" } } }); const p = blankPlan(); p.fields["0.1"] = "Burundi"; p.experiment = { expected: "More sweetness" }; const saved = ( await agent.post("/api/plans").set("x-csrf-token", csrf).send({ plan: p }) ).body.plan; const owner = ( await db.query("SELECT user_id FROM roast_plans WHERE id=$1", [saved.id]) ).rows[0].user_id; await db.query( "INSERT INTO actual_roasts(user_id,roast_plan_id,filename,original_content,parsed,after,created_at) VALUES($1,$2,'batch.alog','{}',$3,$4,'2020-01-01')", [ owner, saved.id, { roast: { title: "Fruit batch" }, derived: { developmentS: 80 } }, { favorite: "yes", sweetness: "4" }, ], ); const result = await agent.get("/api/workspace"); assert.equal(result.status, 200); assert.equal(result.body.coffees.length, 1); assert.equal(result.body.coffees[0].roasts[0].after.favorite, "yes"); assert.ok(result.body.actions.some((a) => a.kind === "taste")); assert.ok(result.body.actions.some((a) => a.kind === "experiment")); assert.equal((await request(app).get("/api/workspace")).status, 401); for (const route of ["/home"]) { assert.equal((await agent.get(route)).status, 200); assert.equal((await request(app).get(route)).status, 302); } assert.equal((await request(app).get("/workspace.html")).status, 302); }); test("revision history is owned, restores planning inputs and retains current consumption and chat", async () => { const { app, agent } = await setup(); const { csrf } = await signup(agent, "revisions@example.com"); const other = request.agent(app); const { csrf: otherCsrf } = await signup(other, "stranger@example.com"); const p = blankPlan(); p.fields["4.1"] = "light"; const saved = ( await agent .post("/api/plans") .set("x-csrf-token", csrf) .send({ plan: p, name: "Original" }) ).body.plan; p.fields["4.1"] = "medium"; p.inventory.consumed = { weightG: 500 }; p.assistant = { messages: [{ role: "user", content: "Remember this" }] }; assert.equal( ( await agent .put("/api/plans/" + saved.id) .set("x-csrf-token", csrf) .send({ plan: p, name: "Variation" }) ).status, 200, ); const path = "/api/plans/" + saved.id; const revisions = (await agent.get(path + "/revisions")).body.revisions; assert.equal(revisions.length, 1); assert.equal((await other.get(path + "/revisions")).status, 404); assert.equal((await request(app).get(path + "/revisions")).status, 401); assert.equal( (await agent.post(path + "/restore").send({ revisionId: revisions[0].id })) .status, 403, ); assert.equal( ( await other .post(path + "/restore") .set("x-csrf-token", otherCsrf) .send({ revisionId: revisions[0].id }) ).status, 404, ); const restored = await agent .post(path + "/restore") .set("x-csrf-token", csrf) .send({ revisionId: revisions[0].id }); assert.equal(restored.status, 200); assert.equal(restored.body.plan.plan.fields["4.1"], "light"); assert.equal(restored.body.plan.plan.inventory.consumed.weightG, 500); assert.equal( restored.body.plan.plan.assistant.messages[0].content, "Remember this", ); assert.equal((await agent.get(path + "/revisions")).body.revisions.length, 2); }); test("Bean Bro uses only matching account evidence and filters proposed changes", async () => { let context; const { app, agent, db } = await setup( {}, { runPlanChat: async (args) => { context = args; return { reply: "Try this", suggestions: [ { fields: { 4.4: "1:25", 0.1: "Hijacked" }, evidenceRoastIds: ["foreign-id"], }, ], model: "test:coach", }; }, }, ); const { csrf } = await signup(agent, "evidence@example.com"); const other = request.agent(app); const { csrf: otherCsrf } = await signup(other, "other-evidence@example.com"); const p = blankPlan(); p.fields["0.1"] = "Burundi"; await other .post("/api/plans") .set("x-csrf-token", otherCsrf) .send({ plan: p }); const saved = ( await agent.post("/api/plans").set("x-csrf-token", csrf).send({ plan: p }) ).body.plan; const owner = ( await db.query("SELECT user_id FROM roast_plans WHERE id=$1", [saved.id]) ).rows[0].user_id; await db.query( "INSERT INTO actual_roasts(user_id,roast_plan_id,filename,original_content,parsed,after) VALUES($1,$2,'owned.alog','{}',$3,$4)", [ owner, saved.id, { roast: { title: "Owned batch" } }, { cupNotes: "Juicy", sweetness: "4" }, ], ); const result = await agent .post("/api/plan-chat") .set("x-csrf-token", csrf) .send({ plan: p, messages: [{ role: "user", content: "Suggest an experiment" }], }); assert.equal(result.status, 200); assert.equal(context.evidence.roasts.length, 1); assert.equal(context.evidence.roasts[0].after.cupNotes, "Juicy"); assert.deepEqual(result.body.suggestions[0].fields, { 4.4: "1:25" }); assert.deepEqual(result.body.suggestions[0].evidenceRoastIds, []); assert.deepEqual( cleanSuggestions([ { fields: { 4.4: "nonsense", 4.1: "invalid", 4.2: "999" } }, ]), [], ); }); test("Bean Bro connection test is admin-only and uses the selected model", async () => { let called = false; const { app, agent } = await setup( {}, { runPlanChat: async () => { called = true; return { reply: "Connected", model: "test:coach" }; }, }, ); const { csrf } = await signup(agent, "member@example.com"); assert.equal( (await agent.post("/api/admin/llm/test").set("x-csrf-token", csrf)).status, 403, ); assert.equal(called, false); const admin = request.agent(app); const result = await admin.post("/api/auth/bootstrap").send({ setupToken: "a-secure-bootstrap-token", email: "snowspeeder@gmail.com", password: "a very secure admin password", }); const token = result.body.csrfToken; assert.equal((await admin.post("/api/admin/llm/test")).status, 403); const checked = await admin .post("/api/admin/llm/test") .set("x-csrf-token", token); assert.equal(checked.status, 200); assert.equal(checked.body.model, "test:coach"); }); test("manual roast completion validates milestones, stays private and is idempotent", async () => { const { app, agent, db } = await setup(); const { csrf } = await signup(agent, "manual@example.com"); const other = request.agent(app); const { csrf: otherCsrf } = await signup(other, "other-manual@example.com"); const p = blankPlan(); p.roastDay = { startedAt: Date.now() - 600000, events: { charge: { timeS: 0, tempF: "345" }, fc: { timeS: 500, tempF: "360" }, drop: { timeS: 580, tempF: "375" }, }, }; const saved = ( await agent.post("/api/plans").set("x-csrf-token", csrf).send({ plan: p }) ).body.plan; const route = "/api/roasts/manual"; assert.equal( (await request(app).post(route).send({ planId: saved.id })).status, 401, ); assert.equal( (await agent.post(route).send({ planId: saved.id })).status, 403, ); assert.equal( ( await other .post(route) .set("x-csrf-token", otherCsrf) .send({ planId: saved.id }) ).status, 404, ); const result = await agent .post(route) .set("x-csrf-token", csrf) .send({ planId: saved.id }); assert.equal(result.status, 201); assert.equal( ( await agent .post(route) .set("x-csrf-token", csrf) .send({ planId: saved.id }) ).body.roast.id, result.body.roast.id, ); const detail = (await agent.get("/api/roasts/" + result.body.roast.id)).body .roast; assert.equal(detail.roast.manual, true); assert.equal(detail.parsed.derived.developmentS, 80); assert.equal( (await other.get("/api/roasts/" + result.body.roast.id)).status, 404, ); const download = await agent.get( "/api/roasts/" + result.body.roast.id + "/download", ); assert.equal(download.body.format, "roast-planner-manual-record"); assert.equal( ( await agent.get( "/api/roasts/" + result.body.roast.id + "/download?variant=updated", ) ).status, 400, ); p.roastDay.events.drop.timeS = 400; await agent .put("/api/plans/" + saved.id) .set("x-csrf-token", csrf) .send({ plan: p }); assert.equal( ( await agent .post(route) .set("x-csrf-token", csrf) .send({ planId: saved.id }) ).status, 400, ); }); test("manual roast targets remain captured when its source plan changes", async () => { const { agent } = await setup(); const { csrf } = await signup(agent, "snapshot@example.com"); const p = blankPlan(); p.fields["4.1"] = "light"; p.experiment = { expected: "More fruit" }; p.roastDay = { startedAt: Date.now() - 600000, events: { fc: { timeS: 480, tempF: "360" }, drop: { timeS: 560, tempF: "375" }, }, }; const saved = ( await agent.post("/api/plans").set("x-csrf-token", csrf).send({ plan: p }) ).body.plan; const r = ( await agent .post("/api/roasts/manual") .set("x-csrf-token", csrf) .send({ planId: saved.id }) ).body.roast; p.fields["4.1"] = "dark"; p.experiment.expected = "More body"; await agent .put("/api/plans/" + saved.id) .set("x-csrf-token", csrf) .send({ plan: p }); const detail = (await agent.get("/api/roasts/" + r.id)).body.roast; assert.equal(detail.hasPlanSnapshot, true); assert.equal(detail.plan.fields["4.1"], "light"); assert.equal(detail.plan.experiment.expected, "More fruit"); });