Tests: catch up stale assertions to current prod UX

Two tests had been failing on -short for several phases; the
comfortable "pre-existing failures" framing was masking that both
were stale, not flaky — each test predated a deliberate UX rewire
that nobody updated the assertion against.

TestMageSpellbookLineInRender — commit 8bf7d35 (UX S7 jargon sweep)
reshaped the spellbook line to "**Spellbook:** N / M leveled spells
learned" and intentionally dropped the redundant "(can learn N more)"
trailer. Test was still asserting "2/10" (no spaces) and the dropped
hint. Updated to track the live "N / M leveled spells learned"
format; comment cites the sweep commit.

TestAdv2Scenario_ZoneRunGoblinWarrens — commit 886eb5a (turn-based
elite/boss combat) moved Elite/Boss rooms off the auto-resolve
SimulateCombat path onto the manual !fight + !attack engine; !zone
advance now stops at the doorway and only progresses past a won
CombatSession. The scenario test was only calling !advance, so it
spun in place at room 4 (the elite). Loop now detects Elite/Boss
prev-rooms, opens with !fight if the session doesn't exist, drains
!attack rounds until the session terminates, then falls through to
!advance to clear the room (won → walk graph; lost/fled → terminate
next pass). maxSteps doubled to absorb the fight-then-advance pairs;
inner !attack cap at 60 rounds covers RNG tail.

Both -short tests now pass; full -short suite green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-15 11:29:03 -07:00
parent ad27077329
commit cf092742bb
2 changed files with 44 additions and 9 deletions

View File

@@ -76,10 +76,17 @@ func TestAdv2Scenario_ZoneRunGoblinWarrens(t *testing.T) {
}
// Drive !zone advance until the run terminates (cleared, died, or
// abandoned). When a fork is pending (Phase G branching graphs) auto-pick
// the first option via `!zone go 1` so the test doesn't stall on a
// diamond. Doubled iteration cap covers fork-then-advance pairs.
maxSteps := (run.TotalRooms + 4) * 2
// abandoned). Branches the test handles:
// - Fork queued (Phase G branching graphs): commit with `!zone go 1`.
// - Elite/Boss doorway (commit 886eb5a moved these off auto-resolve):
// !advance now stops at the door and the player engages with
// !fight, then resolves one round per !attack. The test mirrors
// that: call !fight to open the session, !attack until the session
// closes, then the next !advance clears the room and walks the
// graph. Cap the per-fight !attack loop generously — a real fight
// resolves in <20 rounds, but RNG can drag.
maxSteps := (run.TotalRooms + 4) * 4
const maxAttacksPerFight = 60
clearedRoomTypes := []RoomType{}
for step := 0; step < maxSteps; step++ {
before, _ := getActiveZoneRun(uid)
@@ -101,6 +108,31 @@ func TestAdv2Scenario_ZoneRunGoblinWarrens(t *testing.T) {
}
continue
}
// Elite/Boss doorway: !advance won't progress past the door
// without a won CombatSession for the encounter. Open the fight
// if it isn't already open, then attack until the session
// terminates. After the loop, fall through to !advance — the
// won session lets advance clear the room and walk the graph;
// a lost/fled session terminates the run on the next pass.
if prevType == RoomElite || prevType == RoomBoss {
sess, _ := getCombatSessionForEncounter(before.RunID, encounterIDForRoom(before.CurrentRoom))
if sess == nil {
if err := p.handleFightCmd(MessageContext{Sender: uid}); err != nil {
t.Fatalf("zone fight step %d: %v", step, err)
}
}
// Drain the round loop. handleAttackCmd no-ops if there's no
// active session, so the inner loop self-terminates either way.
for atk := 0; atk < maxAttacksPerFight; atk++ {
active, _ := getActiveCombatSession(uid)
if active == nil {
break
}
if err := p.handleAttackCmd(MessageContext{Sender: uid}); err != nil {
t.Fatalf("attack step %d.%d: %v", step, atk, err)
}
}
}
if err := p.handleDnDZoneCmd(MessageContext{Sender: uid}, "advance"); err != nil {
t.Fatalf("zone advance step %d: %v", step, err)
}

View File

@@ -175,11 +175,14 @@ func TestMageSpellbookLineInRender(t *testing.T) {
}
out := renderSpellsList(c)
// L3 cap = 10, count = 2.
if !strings.Contains(out, "Spellbook:") || !strings.Contains(out, "2/10") {
// L3 cap = 10, count = 2. UX S7 jargon sweep (8bf7d35) reshaped
// the line to "**Spellbook:** N / M leveled spells learned" and
// dropped the redundant "(can learn N more)" trailer — the
// "N / M" already conveys remaining capacity. Assertion tracks
// the live format; if the line ever loses the count or the cap
// the substrings still pin the regression.
if !strings.Contains(out, "**Spellbook:**") ||
!strings.Contains(out, "2 / 10 leveled spells learned") {
t.Errorf("renderSpellsList missing/wrong Spellbook line; got\n%s", out)
}
if !strings.Contains(out, "can learn 8 more") {
t.Errorf("renderSpellsList missing headroom hint; got\n%s", out)
}
}