test/deckscore.test.js
Rama main · réplica de lectura del repositorio original.
import { test } from "node:test";
import assert from "node:assert/strict";
import { scoreDeck } from "../src/deckscore.js";
/**
* A deterministic score for a generated deck.
*
* Content quality is answered by a person reading the deck on the gateway, and
* that is right and does not scale — so it happens rarely and nothing
* accumulates between times. This measures the half that needs no model and no
* opinion, and returns one number so two runs can be set beside each other.
*
* It does not claim a high score means a good deck. Every component is
* necessary and none is sufficient. It exists so a deck broken in a way
* somebody already found once cannot quietly come back.
*/
const slide = (over = {}) => ({
type: "bullets",
section: 0,
headline: "A headline",
bullets: ["A complete first point.", "A complete second point.", "A third."],
...over,
});
const deckOf = (slides) => ({ title: "T", sections: ["A"], slides });
/** themeMatrix needs a render; without one that component reports null rather
* than inventing a number, which is what these unit-level cases exercise. */
const score = (deck, opts) => scoreDeck(deck, opts);
test("a clean deck scores well and reports nothing", async () => {
const r = await score(deckOf([slide(), slide(), slide()]));
assert.ok(r.score >= 90, `expected a high score, got ${r.score}: ${r.findings.join("; ")}`);
assert.equal(r.components.intact, 1);
assert.equal(r.components.whole, 1);
});
test("a missing section is counted and named", async () => {
const r = await score(deckOf([slide(), slide({ section: undefined })]));
assert.ok(r.components.intact < 1, "a slide with no section is not intact");
assert.ok(r.findings.some((f) => /carry no section/.test(f)), r.findings.join("; "));
});
test("a field cut mid-sentence drags `whole` down and is quoted back", async () => {
const cut = "This speaker note runs on for a good while and then simply stops at its cap without";
const r = await score(deckOf([slide({ speaker_note: cut }), slide(), slide()]));
assert.ok(r.components.whole < 1, "a truncated field must register");
assert.ok(r.findings.some((f) => /ends mid-sentence/.test(f)), r.findings.join("; "));
});
test("a headline is a label, not a truncated sentence", async () => {
// The first version of this scorer counted the deck's own title as broken
// and reported `whole` at 0% for every deck. A noun phrase ends without a
// full stop by design.
const long = "Perovskite Solar Cells: Stability Challenges and Commercial Viability";
const r = await score(deckOf([slide({ headline: long }), slide(), slide()]));
assert.equal(r.components.whole, 1, r.findings.join("; "));
});
test("a placeholder slide is the loudest failure", async () => {
const withPlaceholder = deckOf([
slide(),
slide({ headline: "PLACEHOLDER — regenerate this slide", bullets: ["PLACEHOLDER", "PLACEHOLDER", "PLACEHOLDER"] }),
]);
const clean = await score(deckOf([slide(), slide()]));
const dirty = await score(withPlaceholder);
assert.ok(dirty.components.intact <= clean.components.intact, "a placeholder cannot score as well as prose");
});
test("monotony is caught: eight of the same slide is not a deck", async () => {
const same = Array.from({ length: 8 }, () => slide());
const r = await score(deckOf(same));
assert.ok(r.components.varied < 1, `expected a variety penalty: ${JSON.stringify(r.components)}`);
assert.ok(r.findings.some((f) => /monotony/.test(f)), r.findings.join("; "));
});
test("without research the grounding component is skipped, not failed", async () => {
// A deck written from an upload has no notes.md and must not be punished for
// it — the weight is redistributed instead.
const r = await score(deckOf([slide(), slide()]), { research: "" });
assert.equal(r.components.grounded, null);
assert.ok(r.score != null && r.score > 0, "the remaining components still yield a score");
});