Rebuild printable roast plans and remove machine-based adjustments
Test and deploy / test-and-deploy (push) Successful in 2m28s
Test and deploy / test-and-deploy (push) Successful in 2m28s
This commit is contained in:
1 parent
e9f2393c96
commit
824a964f9d
30 files changed
+1721
-908
No files matched your search
@@ -0,0 +1,106 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { blankPlan } from "../shared/fields.js";
|
||||
import { computeLedger } from "../shared/ledger.js";
|
||||
import {
|
||||
buildPlanCurve,
|
||||
curveSegments,
|
||||
curveWarnings,
|
||||
} from "../shared/curve.js";
|
||||
import { renderReportHtml } from "../shared/report.js";
|
||||
import { parseDuration } from "../shared/time.js";
|
||||
function plan() {
|
||||
const p = blankPlan();
|
||||
Object.assign(p.fields, {
|
||||
0.1: "Burundi",
|
||||
0.4: "500",
|
||||
1.4: "8:45",
|
||||
4.1: "light",
|
||||
4.2: "12",
|
||||
4.3: "1:38",
|
||||
3.2: "-0:30",
|
||||
1.7: "-0:05",
|
||||
});
|
||||
return p;
|
||||
}
|
||||
test("light development does not silently collapse to 1:03; explicit override wins", () => {
|
||||
const p = plan();
|
||||
let l = computeLedger(p);
|
||||
assert.equal(l.rawC, 63);
|
||||
assert.equal(l.C, 75);
|
||||
assert.ok(l.warnings.some((w) => w.includes("below 1:15")));
|
||||
p.fields["4.4"] = "1:20";
|
||||
assert.equal(computeLedger(p).C, 80);
|
||||
});
|
||||
test("machine profiles cannot modify plan timing or temperature defaults", () => {
|
||||
const p = plan(),
|
||||
l = computeLedger(p);
|
||||
const machine = {
|
||||
pace: { value: 1.8 },
|
||||
n: 99,
|
||||
medians: { firstCrackTempC: 140, turningPointS: 10 },
|
||||
};
|
||||
assert.deepEqual(computeLedger(p, machine), l);
|
||||
assert.deepEqual(buildPlanCurve(p, l, machine), buildPlanCurve(p, l));
|
||||
assert.equal(buildPlanCurve(p, l)[3].tempC, 200);
|
||||
});
|
||||
test("default development average rise declines and cubic segments do not overshoot", () => {
|
||||
const p = plan(),
|
||||
l = computeLedger(p),
|
||||
points = buildPlanCurve(p, l);
|
||||
assert.deepEqual(curveWarnings(points), []);
|
||||
for (const s of curveSegments(points).segments) {
|
||||
for (let t = 0; t <= 1; t += 0.01) {
|
||||
const v =
|
||||
(1 - t) ** 3 * s.a.tempC +
|
||||
3 * (1 - t) ** 2 * t * s.c1.tempC +
|
||||
3 * (1 - t) * t * t * s.c2.tempC +
|
||||
t ** 3 * s.b.tempC;
|
||||
assert.ok(
|
||||
v >= Math.min(s.a.tempC, s.b.tempC) - 1e-8 &&
|
||||
v <= Math.max(s.a.tempC, s.b.tempC) + 1e-8,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
test("explicit flick-producing targets are preserved and flagged", () => {
|
||||
const p = plan();
|
||||
p.temps.drop.tempC = "230";
|
||||
const points = buildPlanCurve(p, computeLedger(p));
|
||||
assert.equal(points.at(-1).tempC, 230);
|
||||
assert.ok(curveWarnings(points).length);
|
||||
});
|
||||
test("negative timings and implausible density are surfaced", () => {
|
||||
const p = plan();
|
||||
p.fields["1.6"] = "-10:00";
|
||||
p.fields["5.2"] = "76.14";
|
||||
const l = computeLedger(p);
|
||||
assert.equal(l.A, null);
|
||||
assert.ok(l.warnings.some((w) => w.includes("761.4")));
|
||||
assert.equal(parseDuration("1:99"), null);
|
||||
assert.equal(parseDuration("9".repeat(400)), null);
|
||||
});
|
||||
test("standalone report has Fahrenheit, grams, graph annotations and escapes untrusted content", () => {
|
||||
const p = plan();
|
||||
p.fields["0.1"] = "</title><script>alert(1)</script>";
|
||||
p.afterRoast.cupNotes = "<img src=x onerror=alert(1)>";
|
||||
const html = renderReportHtml(p);
|
||||
assert.ok(html.startsWith("<!doctype html>"));
|
||||
assert.ok(html.includes("440 g"));
|
||||
assert.ok(html.includes("500 g"));
|
||||
assert.ok(html.includes("392°F"));
|
||||
assert.ok(html.includes("Development · 1:15"));
|
||||
assert.ok(html.includes("8:45"));
|
||||
assert.ok(html.includes("Maillard"));
|
||||
assert.ok(html.includes("@media print"));
|
||||
assert.ok(!html.includes("<script>"));
|
||||
assert.ok(!html.includes("<img"));
|
||||
assert.ok(!html.includes("°C"));
|
||||
assert.ok(!html.includes("Hottop"));
|
||||
assert.ok(!html.includes("<script src"));
|
||||
});
|
||||
test("incomplete plans export without NaN, Infinity or invented output weight", () => {
|
||||
const html = renderReportHtml(blankPlan());
|
||||
assert.ok(!/NaN|Infinity/.test(html));
|
||||
assert.ok(!html.includes("0 g"));
|
||||
});
|
||||
Reference in new issue
Block a user