Files
healer-man/scripts/coa-reference/flight-text.test.mjs

78 lines
3.3 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { resolveArchiveDescriptions } from "./flight-text.mjs";
function textRow(id, text) {
return `${id}:T${Buffer.byteLength(text, "utf8").toString(16)},${text}`;
}
function flightPush(value) {
return `<script>self.__next_f.push(${JSON.stringify(value)});</script>`;
}
function builderHtml(...chunks) {
return [flightPush([0]), ...chunks.map((chunk) => flightPush([1, chunk]))].join("");
}
test("resolves exact Flight text references across split chunks using UTF-8 byte lengths", () => {
const firstText = "Mycelial ring: café 🌱\nsecond line";
const secondText = "Spirit stable — restored";
const stream = `${textRow("17f", firstText)}${textRow("180", secondText)}`;
const splitA = stream.slice(0, 8);
const splitB = stream.slice(8, 36);
const splitC = stream.slice(36);
const classes = [{
classId: 12,
untouched: { note: "unchanged" },
nodes: [
{
id: 7221,
description: "$17F",
rankDescriptions: [{ rank: 1, spellId: 1, description: "$180" }],
spellId: 1,
},
{
id: 7222,
description: "$$180",
rankDescriptions: [{ rank: 1, spellId: 2, description: "Literal $d placeholder" }],
},
],
}];
const resolved = resolveArchiveDescriptions(classes, builderHtml(splitA, splitB, splitC));
assert.notEqual(resolved, classes);
assert.notEqual(resolved[0], classes[0]);
assert.equal(resolved[0].nodes[0].description, firstText);
assert.equal(resolved[0].nodes[0].rankDescriptions[0].description, secondText);
assert.equal(resolved[0].nodes[0].spellId, 1);
assert.deepEqual(resolved[0].untouched, classes[0].untouched);
assert.equal(resolved[0].nodes[1].description, "$$180");
assert.equal(resolved[0].nodes[1].rankDescriptions[0].description, "Literal $d placeholder");
assert.equal(classes[0].nodes[0].description, "$17F");
assert.equal(classes[0].nodes[0].rankDescriptions[0].description, "$180");
});
test("resolves node descriptions inside nested tab collections and preserves escaped dollar text", () => {
const stream = textRow("abc", "\u003cstrong\u003eArchive text\u003c/strong\u003e");
const classes = [{
classId: 13,
tabs: [{ tabId: 1, nodes: [{ id: 1, description: "$abc", rankDescriptions: [] }] }],
}];
const resolved = resolveArchiveDescriptions(classes, builderHtml(stream));
assert.equal(resolved[0].tabs[0].nodes[0].description, "<strong>Archive text</strong>");
});
test("rejects missing exact references with their source field", () => {
const classes = [{ classId: 12, nodes: [{ id: 7221, description: "$dead", rankDescriptions: [] }] }];
assert.throws(
() => resolveArchiveDescriptions(classes, builderHtml(textRow("1", "one"))),
/description reference \$dead at classes\[0\]\.nodes\[0\]\.description has no Flight text row/,
);
});
test("rejects truncated UTF-8 text records and malformed Flight push JSON", () => {
const classes = [{ classId: 12, nodes: [] }];
assert.throws(() => resolveArchiveDescriptions(classes, builderHtml("1:T20,short")), /text row 1 declares 20 bytes but is truncated/);
assert.throws(() => resolveArchiveDescriptions(classes, '<script>self.__next_f.push([1,"unterminated]);</script>'), /push argument array is unterminated/);
});