Line-ending only. Verified: 3667 insertions against 3667 deletions with zero content difference under --ignore-cr-at-eol.
123 lines
4.6 KiB
JavaScript
123 lines
4.6 KiB
JavaScript
"use strict";
|
|
const test = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const { parseCoverageTable, groupByStation } = require("../main.js").__test__;
|
|
|
|
const DOC = [
|
|
"# Script coverage",
|
|
"",
|
|
"#coverage",
|
|
"",
|
|
"## Metadata",
|
|
"",
|
|
"- **Script:** `raw/sources/Webinar script.md`",
|
|
"- **Last synced:** 2026-07-28",
|
|
"",
|
|
"## Coverage",
|
|
"",
|
|
"| Concept | Status | Station | Pinned |",
|
|
"|---|---|---|---|",
|
|
"| [[harness]] | covered | Tools | |",
|
|
"| [[agentic-loops]] | partial | Process | |",
|
|
"| [[levels-of-ai-usage]] | partial | all | |",
|
|
"| [[connections-as-moat]] | absent | — | yes |",
|
|
].join("\n");
|
|
|
|
test("parseCoverageTable reads metadata", () => {
|
|
const { meta } = parseCoverageTable(DOC);
|
|
assert.equal(meta.script, "raw/sources/Webinar script.md");
|
|
assert.equal(meta.lastSynced, "2026-07-28");
|
|
});
|
|
|
|
test("parseCoverageTable reads every data row and skips the header", () => {
|
|
const { rows, errors } = parseCoverageTable(DOC);
|
|
assert.equal(errors.length, 0);
|
|
assert.equal(rows.length, 4);
|
|
assert.deepEqual(rows.map((r) => r.concept), [
|
|
"harness", "agentic-loops", "levels-of-ai-usage", "connections-as-moat",
|
|
]);
|
|
});
|
|
|
|
test("parseCoverageTable normalises stations", () => {
|
|
const { rows } = parseCoverageTable(DOC);
|
|
assert.deepEqual(rows[0].stations, ["Tools"]);
|
|
assert.deepEqual(rows[2].stations, ["all"]);
|
|
assert.deepEqual(rows[3].stations, []);
|
|
});
|
|
|
|
test("parseCoverageTable reads the pinned flag", () => {
|
|
const { rows } = parseCoverageTable(DOC);
|
|
assert.equal(rows[0].pinned, false);
|
|
assert.equal(rows[3].pinned, true);
|
|
});
|
|
|
|
test("parseCoverageTable strips a wikilink alias", () => {
|
|
const doc = "| Concept | Status | Station |\n|---|---|---|\n| [[harness\\|The harness]] | covered | Tools |";
|
|
const { rows } = parseCoverageTable(doc);
|
|
assert.equal(rows[0].concept, "harness");
|
|
});
|
|
|
|
test("parseCoverageTable splits a multi-station cell", () => {
|
|
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | covered | Tools, Memory |";
|
|
const { rows } = parseCoverageTable(doc);
|
|
assert.deepEqual(rows[0].stations, ["Tools", "Memory"]);
|
|
});
|
|
|
|
test("parseCoverageTable rejects an invalid status instead of coercing it", () => {
|
|
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | maybe | Tools |";
|
|
const { rows, errors } = parseCoverageTable(doc);
|
|
assert.equal(rows.length, 0);
|
|
assert.equal(errors.length, 1);
|
|
assert.match(errors[0].reason, /invalid status/);
|
|
assert.equal(errors[0].line, 3);
|
|
});
|
|
|
|
test("parseCoverageTable reports a row with too few columns", () => {
|
|
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | covered |";
|
|
const { rows, errors } = parseCoverageTable(doc);
|
|
assert.equal(rows.length, 0);
|
|
assert.equal(errors.length, 1);
|
|
assert.match(errors[0].reason, /at least 3 columns/);
|
|
});
|
|
|
|
test("parseCoverageTable returns empty results for a document with no table", () => {
|
|
const { rows, errors } = parseCoverageTable("# Nothing\n\nJust prose.");
|
|
assert.equal(rows.length, 0);
|
|
assert.equal(errors.length, 0);
|
|
});
|
|
|
|
test("groupByStation orders all-stations first and no-station last", () => {
|
|
const { rows } = parseCoverageTable(DOC);
|
|
const groups = groupByStation(rows);
|
|
assert.deepEqual(groups.map((g) => g.station), [
|
|
"All stations", "Tools", "Process", "No station",
|
|
]);
|
|
assert.equal(groups[1].rows[0].concept, "harness");
|
|
});
|
|
|
|
test("groupByStation places a multi-station row under its first station only", () => {
|
|
const rows = [{ concept: "x", status: "covered", stations: ["Memory", "Skills"], pinned: false, line: 1 }];
|
|
const groups = groupByStation(rows);
|
|
assert.equal(groups.length, 1);
|
|
assert.equal(groups[0].station, "Memory");
|
|
});
|
|
|
|
const { reconcileConcepts } = require("../main.js").__test__;
|
|
|
|
test("reconcileConcepts finds concept pages with no row", () => {
|
|
const rows = [{ concept: "harness", status: "covered", stations: ["Tools"], pinned: false, line: 1 }];
|
|
const out = reconcileConcepts(rows, ["harness", "brand-new-concept"]);
|
|
assert.deepEqual(out.unsynced, ["brand-new-concept"]);
|
|
assert.deepEqual(out.stale, []);
|
|
});
|
|
|
|
test("reconcileConcepts finds rows whose concept page is gone", () => {
|
|
const rows = [
|
|
{ concept: "harness", status: "covered", stations: ["Tools"], pinned: false, line: 1 },
|
|
{ concept: "deleted-idea", status: "absent", stations: [], pinned: false, line: 2 },
|
|
];
|
|
const out = reconcileConcepts(rows, ["harness"]);
|
|
assert.deepEqual(out.stale.map((r) => r.concept), ["deleted-idea"]);
|
|
assert.deepEqual(out.unsynced, []);
|
|
});
|