Files
systemic-game-design-course/tools/test/verify-references.test.mjs
T
Lucas WintherandClaude Opus 5.5 6f576940b7 fix: module 10 review round 1 (module-local SpellGrid cards, cast target check, CLI without panic hook)
- SpellGrid cards move to course/10-spellgrid/cards; start-module and
  verify-references stage course/cards plus module-local cards up to the module,
  so M5-M9 workspaces get exactly the pre-M10 card set.
- cast() rejects a chosen-target spell without a target (checkCast/checkPlay);
  new test_10_targeted_spell_needs_target.
- Rust CLI pre-validates instead of swapping the global panic hook.
- Catalog: CRIER noun; DEATHRATTLE/BATTLECRY note on lexicon vs catalog role.
- Lesson: design note on mid-movement reparse.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 05:11:09 +01:00

94 lines
4.0 KiB
JavaScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { join } from "node:path";
import { run, fixtures } from "./helpers.mjs";
import { planVerification } from "../verify-references.mjs";
import { moduleDirs } from "../lib.mjs";
const root = join(fixtures, "course");
test("verify_plan_skips_modules_without_reference", () => {
process.env.COURSE_ROOT = root;
const plan = planVerification(moduleDirs(), 3);
assert.deepEqual(plan.map((p) => p.num), ["01", "02", "03"]);
assert.deepEqual(plan[2].testModules.map((m) => m.num), ["01", "02", "03"]);
assert.deepEqual(plan[2].langs, ["rust", "ts"]);
});
test("verify_runs_with_copied_reference_and_tests", () => {
const r = run("verify-references.mjs", ["02"], {
COURSE_ROOT: root,
VERIFY_CMD_RUST: "test -f tests/m01.rs && test -f Cargo.toml && ! test -f tests/m03.rs",
VERIFY_CMD_TS: "test -f tests/m01.test.ts && test -f package.json",
});
assert.equal(r.code, 0, r.out);
assert.match(r.out, /01.*ok/s);
assert.match(r.out, /02.*ok/s);
});
test("verify_reports_failure", () => {
const r = run("verify-references.mjs", ["01"], {
COURSE_ROOT: root,
VERIFY_CMD_RUST: "false",
VERIFY_CMD_TS: "true",
});
assert.equal(r.code, 1);
assert.match(r.out, /FAIL/);
});
test("verify_stage_copies_all_earlier_module_tests", async () => {
process.env.COURSE_ROOT = root;
const { planVerification, stage } = await import("../verify-references.mjs");
const { existsSync } = await import("node:fs");
const plan = planVerification(moduleDirs(), 3)[2];
const dir = stage(plan, "rust");
for (const f of ["m01.rs", "m02.rs", "m03.rs"]) assert.ok(existsSync(join(dir, "tests", f)));
assert.ok(existsSync(join(dir, "Cargo.toml")));
});
test("verify_stage_copies_course_cards", async () => {
// From Module 5 the references load card data from <crate or package root>/cards.
process.env.COURSE_ROOT = root;
const { planVerification, stage } = await import("../verify-references.mjs");
const { existsSync } = await import("node:fs");
for (const lang of ["rust", "ts"]) {
const dir = stage(planVerification(moduleDirs(), 1)[0], lang);
assert.ok(existsSync(join(dir, "cards", "test-fixture.json")), lang);
}
});
test("verify_ts_default_installs_dependencies_first", async () => {
// A staged reference has no node_modules; a bare `npx vitest` fetches the
// latest vitest, which cannot load the reference's vitest.config.ts.
const { commandFor } = await import("../verify-references.mjs");
const cmd = commandFor("ts", {});
assert.match(cmd, /^npm (ci|install)\b.*&& npx vitest run$/);
assert.equal(commandFor("ts", { VERIFY_CMD_TS: "true" }), "true");
assert.equal(commandFor("rust", {}), "cargo test");
});
test("verify_stage_copies_module_levels", async () => {
// From Module 10 the tests load puzzle levels from <crate or package root>/levels.
process.env.COURSE_ROOT = root;
const { planVerification, stage } = await import("../verify-references.mjs");
const { existsSync } = await import("node:fs");
const plans = planVerification(moduleDirs(), 3);
assert.ok(existsSync(join(stage(plans[2], "ts"), "levels", "fixture-level.json")));
assert.ok(!existsSync(join(stage(plans[1], "ts"), "levels")));
});
test("verify_stage_copies_module_cards_up_to_the_module", async () => {
// Module-local cards (Module 10's SpellGrid cards) reach that module and later ones only.
process.env.COURSE_ROOT = root;
const { planVerification, stage } = await import("../verify-references.mjs");
const { existsSync } = await import("node:fs");
const plans = planVerification(moduleDirs(), 3);
for (const lang of ["rust", "ts"]) {
assert.ok(!existsSync(join(stage(plans[0], lang), "cards", "module-fixture.json")), lang);
assert.ok(existsSync(join(stage(plans[1], lang), "cards", "module-fixture.json")), lang);
const later = stage(plans[2], lang);
assert.ok(existsSync(join(later, "cards", "module-fixture.json")), lang);
assert.ok(existsSync(join(later, "cards", "test-fixture.json")), lang);
}
});