/** * The era on the daily card is derived, not authored: eraFor() puts the newest * design in the fight on MegaMek's era table. Every way that goes wrong is * quiet — an off-by-one at a boundary labels a Clan Invasion fight FedCom * Civil War, a name that is not a key of ERA_ICONS drops the symbol and shows * a bare word, and a row out of order makes eraFor() answer with whichever era * happens to come first. * * So this pins the table's shape, the boundaries against the chronology on * sarna.net, and the names against the icon map. * * Run with `npm test`. */ import { test } from "node:test"; import assert from "node:assert/strict"; const { ERAS, eraFor } = await import("../src/content/eras.ts"); const { ERA_ICONS } = await import("../src/content/trivia.ts"); test("the table is ordered, and only the last era is open-ended", () => { assert.equal(ERAS.length, 14, "eras.xml has fourteen eras"); const codes = ERAS.map((era) => era.code); assert.equal(new Set(codes).size, codes.length, "two eras share a code"); const open = ERAS.filter((era) => era.end === null); assert.equal(open.length, 1, "exactly one era has no end date"); assert.equal(ERAS.at(-1), open[0], "the open-ended era is not last"); let previous = 0; for (const era of ERAS.slice(0, -1)) { assert.ok( era.end > previous, `${era.code} ends in ${era.end}, at or before the era before it`, ); previous = era.end; } }); test("every era name has an icon the site ships", () => { for (const era of ERAS) { assert.ok( era.name in ERA_ICONS, `${era.code}: "${era.name}" is not a key of ERA_ICONS, so it has no symbol`, ); assert.ok( ERA_ICONS[era.name] !== null, `${era.code}: "${era.name}" is mapped to no icon`, ); } }); test("a year lands in the era sarna puts it in, on both sides of every boundary", () => { // The chronology at https://www.sarna.net/wiki/BattleTech_eras, first and // last year of each era, walked in order. Both ends of every pair, because a // <= that should be a < is right on one side and wrong on the other. const canon = [ [2005, "Age of War"], [2570, "Age of War"], [2571, "Star League"], [2780, "Star League"], [2781, "Early Succession War"], [2900, "Early Succession War"], [2901, "Late Succession War - LosTech"], [3019, "Late Succession War - LosTech"], [3020, "Late Succession War - Renaissance"], [3049, "Late Succession War - Renaissance"], [3050, "Clan Invasion"], [3061, "Clan Invasion"], [3062, "FedCom Civil War"], [3067, "FedCom Civil War"], [3068, "Jihad"], [3080, "Jihad"], [3081, "Republic Age"], [3130, "Republic Age"], [3131, "Dark Age"], [3150, "Dark Age"], [3151, "ilClan"], ]; for (const [year, name] of canon) { assert.equal(eraFor(year)?.name, name, `${year} is not ${name}`); } // Open-ended, so a year past the table is still the last era rather than // nothing at all. assert.equal(eraFor(9999)?.name, "ilClan", "the last era stopped being open"); }); test("a year that is not a year has no era", () => { // mms index writes 0 when arena's report measured nothing, and the card // falls back to the year range on null rather than naming Pre-Star League. for (const year of [0, -1, Number.NaN, 3050.5]) { assert.equal(eraFor(year), null, `${year} was given an era`); } });