Build coffee history and experiment workflows with Ask Bean Bro
Test and deploy / test-and-deploy (push) Successful in 1m21s

This commit is contained in:
snowspeeder committed 2026-09-06 18:43:33 -04:00
1 parent 1fd53091ac
commit 8c21750356
28 files changed
+3848 -384

No files matched your search

+314
View File
@@ -0,0 +1,314 @@
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, "[email protected]");
const other = request.agent(app);
const { csrf: otherCsrf } = await signup(other, "[email protected]");
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", "/coffees"]) {
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, "[email protected]");
const other = request.agent(app);
const { csrf: otherCsrf } = await signup(other, "[email protected]");
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, "[email protected]");
const other = request.agent(app);
const { csrf: otherCsrf } = await signup(other, "[email protected]");
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, "[email protected]");
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: "[email protected]",
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, "[email protected]");
const other = request.agent(app);
const { csrf: otherCsrf } = await signup(other, "[email protected]");
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, "[email protected]");
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");
});