import { describe, expect, test } from "vitest" import { generateWilderness, buildLandmarkEntitiesFromTables, spawnLandmarkEntities, CANONICAL_LANDMARK_ENTITIES, type LandmarkEntityDef, type WildernessPiece, } from "../src/game/wilderness.ts" import { planLevelMonsters, CANONICAL_SUPER_UNIQUES_BY_LEVEL, CANONICAL_ELITE_MODIFIERS, lookupSuperUnique, buildSuperUniqueLandmarkSpecs, CANONICAL_SUPERUNIQUES_TABLE, } from "../src/game/monsters.ts" import { parseTable } from "../src/game/acts.ts" import type { D2Table } from "../src/game/acts.ts" import type { Ds1, Ds1Cell } from "../src/formats/ds1.ts" function mockTable(tsv: string): D2Table { const encoder = new TextEncoder() return parseTable(encoder.encode(tsv.trim())) } function makeMockDs1(width: number, height: number): Ds1 { const cells: Ds1Cell[][] = [] for (let y = 0; y < height; y += 1) { const row: Ds1Cell[] = [] for (let x = 0; x < width; x += 1) { row.push({ walls: [], floors: [{ prop1: 1, sequence: 0, style: 1, unknown1: 0, unknown2: 0, hidden: false }], shadows: [], substitutions: [], }) } cells.push(row) } return { version: 18, width, height, act: 1, substitutionType: 0, wallLayers: 1, floorLayers: 1, cells, objects: [], npcPathOffset: null, } } describe("Wilderness SuperUniques & Landmark Entities (Issue #57)", () => { describe("CANONICAL_LANDMARK_ENTITIES Catalog", () => { test("contains all 19 canonical landmark entities across Acts 2-5", () => { expect(CANONICAL_LANDMARK_ENTITIES.length).toBe(19) // Act 1: none. Act I outdoor levels come from the DRLG port (src/game/drlg), whose preset units // place Bishibosh, Rakanishu, Treehead WoodFist, Blood Raven, the Cow King and Flavie; that is // checked on the port's output in tests/drlg-act1-population.test.ts. expect(CANONICAL_LANDMARK_ENTITIES.filter(e => e.act < 2 || e.levelIds.some(id => id < 40))).toEqual([]) // Act 2 (5 entities) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Beetleburst" && e.levelIds.includes(43))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Dark Elder" && e.levelIds.includes(44))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Creeping Feature" && e.levelIds.includes(59))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Bloodwitch the Wild" && e.levelIds.includes(60))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Fangskin" && e.levelIds.includes(61))).toBe(true) // Act 3 (4 entities) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Stormtree" && e.levelIds.includes(78))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Sszark the Burning" && e.levelIds.includes(84))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Witch Doctor Endugu" && e.levelIds.includes(91))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Battlemaid Sarina" && e.levelIds.includes(94))).toBe(true) // Act 4 (3 entities: 2 SuperUniques + 1 NPC) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Izual" && e.levelIds.includes(105))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Hephasto the Armorer" && e.levelIds.includes(107))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Hadriel" && e.levelIds.includes(108))).toBe(true) // Act 5 (7 entities) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Dac Farren" && e.levelIds.includes(110))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Shenk the Overseer" && e.levelIds.includes(110))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Eyeback the Unleashed" && e.levelIds.includes(111))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Thresh Socket" && e.levelIds.includes(112))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Frozenstein" && e.levelIds.includes(114))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Bonesaw Breaker" && e.levelIds.includes(115))).toBe(true) expect(CANONICAL_LANDMARK_ENTITIES.some(e => e.name === "Nihlathak" && e.levelIds.includes(124))).toBe(true) }) }) describe("buildLandmarkEntitiesFromTables", () => { test("returns canonical definitions when no tables are supplied", () => { const entities = buildLandmarkEntitiesFromTables() expect(entities.length).toBe(CANONICAL_LANDMARK_ENTITIES.length) expect(entities[0].name).toBe(CANONICAL_LANDMARK_ENTITIES[0].name) }) test("overrides boss modifiers and properties from SuperUniques.txt", () => { // Mod id 8 is 'magicresistant', 9 is 'fireenchant', 17 is 'lightenchant', 6 is 'fast' const superUniquesTsv = [ "Superunique\tClass\tMod1\tMod2\tMod3\tMinGrp\tMaxGrp\tEClass\tAutoPos\tStacks\tUtrans\tTC\tTC(N)\tTC(H)", "Beetleburst\tscarab3\t8\t9\t0\t2\t5\tscarab1\t0\t0\t0\tAct 2 Super A\tAct 2 Super A\tAct 2 Super A", "Dark Elder\tzombie4\t17\t6\t0\t3\t6\tzombie1\t0\t0\t0\tAct 2 Super A\tAct 2 Super A\tAct 2 Super A", ].join("\n") const suTable = mockTable(superUniquesTsv) const entities = buildLandmarkEntitiesFromTables(suTable) const beetleburst = entities.find(e => e.id === "Beetleburst") expect(beetleburst).toBeDefined() expect(beetleburst?.monsterId).toBe("scarab3") expect(beetleburst?.modifiers).toEqual(["magicresistant", "fireenchant"]) expect(beetleburst?.minionCount).toEqual([2, 5]) const darkElder = entities.find(e => e.id === "Dark Elder") expect(darkElder).toBeDefined() expect(darkElder?.monsterId).toBe("zombie4") expect(darkElder?.modifiers).toEqual(["lightenchant", "fast"]) expect(darkElder?.minionCount).toEqual([3, 6]) }) test("resolves objectId from MonPreset.txt", () => { const monPresetTsv = [ "Act\tPlace\tComponent\tObjectId", "2\tDesert Oasis 1\t1\t105", "4\tChaos Sanctuary\t1\t350", ].join("\n") const mpTable = mockTable(monPresetTsv) const entities = buildLandmarkEntitiesFromTables(undefined, mpTable) const beetleburst = entities.find(e => e.name === "Beetleburst") expect(beetleburst?.objectId).toBe(105) const hadriel = entities.find(e => e.name === "Hadriel") expect(hadriel?.objectId).toBe(350) }) }) describe("spawnLandmarkEntities in Wilderness Generator", () => { // Act I SuperUniques (Rakanishu on the Cairn Stones, ...) are preset units of the DRLG port's // maps; tests/drlg-act1-population.test.ts checks them. The same anchoring for Acts 2-5: test("places Creeping Feature centered on the Desert Tomb 1 preset piece", () => { const tombDs1 = makeMockDs1(16, 16) const borderDs1 = makeMockDs1(8, 8) const pieces: WildernessPiece[] = [ { name: "Act 2 - Desert Border 1", border: true, levels: [borderDs1] }, { name: "Act 2 - Desert Tomb 1", border: false, levels: [tombDs1] }, ] const result = generateWilderness({ levelId: 41, levelName: "Rocky Waste", levelTypeName: "Act 2 - Desert", sizeX: 80, sizeY: 80, subType: 6, subTheme: 0, seed: 42, pieces, substitutions: [], specialPresets: ["Act 2 - Desert Tomb 1"], }) expect(result.stats.landmarkEntities).toBeDefined() const creeping = result.stats.landmarkEntities?.find(e => e.name === "Creeping Feature") expect(creeping).toBeDefined() expect(creeping?.levelId).toBe(41) // Verify subtile coordinates: tileX * 5 + 2 expect(creeping?.subtileX).toBe(creeping!.tileX * 5 + 2) expect(creeping?.subtileY).toBe(creeping!.tileY * 5 + 2) // Verify canvas.objects contains the Type 1 entity const obj = result.level.objects.find( o => o.type === 1 && o.x === creeping!.subtileX && o.y === creeping!.subtileY ) expect(obj).toBeDefined() expect(obj?.id).toBe(creeping?.objectId) }) test("places multiple SuperUniques on Level 110 (Bloody Foothills: Dac Farren & Shenk)", () => { const stripDs1 = makeMockDs1(16, 48) const pieces: WildernessPiece[] = [ { name: "Act 5 - Siege To Barricade", border: false, levels: [stripDs1] }, ] const result = generateWilderness({ levelId: 110, levelName: "Bloody Foothills", levelTypeName: "Act 5 - Siege", sizeX: 240, sizeY: 48, subType: -1, subTheme: -1, seed: 110, pieces, substitutions: [], }) const landmarks = result.stats.landmarkEntities ?? [] const dacFarren = landmarks.find(e => e.name === "Dac Farren") const shenk = landmarks.find(e => e.name === "Shenk the Overseer") expect(dacFarren).toBeDefined() expect(shenk).toBeDefined() expect(dacFarren?.objectId).toBe(87) expect(shenk?.objectId).toBe(88) // Both must be recorded in canvas.objects as type 1 const dacObj = result.level.objects.find( o => o.type === 1 && o.x === dacFarren!.subtileX && o.y === dacFarren!.subtileY ) const shenkObj = result.level.objects.find( o => o.type === 1 && o.x === shenk!.subtileX && o.y === shenk!.subtileY ) expect(dacObj).toBeDefined() expect(shenkObj).toBeDefined() }) test("places Act 4 Hadriel on Chaos Sanctuary (Level 108)", () => { const csDs1 = makeMockDs1(25, 25) const pieces: WildernessPiece[] = [ { name: "Act 4 - Diablo Entry", border: false, levels: [csDs1] }, ] const result = generateWilderness({ levelId: 108, levelName: "Chaos Sanctuary", levelTypeName: "Act 4 - Lava", sizeX: 120, sizeY: 120, subType: -1, subTheme: -1, seed: 108, pieces, substitutions: [], }) const hadriel = result.stats.landmarkEntities?.find(e => e.name === "Hadriel") expect(hadriel).toBeDefined() expect(hadriel?.objectId).toBe(86) expect(hadriel?.role).toBe("npc_guard") const obj = result.level.objects.find( o => o.type === 1 && o.x === hadriel!.subtileX && o.y === hadriel!.subtileY ) expect(obj).toBeDefined() expect(obj?.id).toBe(86) }) test("supports customLandmarks override in WildernessRequest", () => { const borderDs1 = makeMockDs1(8, 8) const customLandmarks: LandmarkEntityDef[] = [ { id: "CustomBoss", name: "Test Custom Boss", role: "superunique", act: 2, levelIds: [42], monsterId: "fallen1", defaultLandmark: "Custom Landmark", modifiers: ["lightenchant", "fast"], minionCount: [4, 6], minionMonsterId: "fallen1", objectId: 999, defaultRelativePos: { x: 0.5, y: 0.5 }, }, ] const result = generateWilderness({ levelId: 42, levelName: "Dry Hills", levelTypeName: "Act 2 - Desert", sizeX: 80, sizeY: 80, subType: 6, subTheme: 0, seed: 123, pieces: [{ name: "Act 2 - Desert Border 1", border: true, levels: [borderDs1] }], substitutions: [], customLandmarks, }) expect(result.stats.landmarkEntities?.length).toBe(1) const custom = result.stats.landmarkEntities?.[0] expect(custom?.name).toBe("Test Custom Boss") expect(custom?.tileX).toBe(40) expect(custom?.tileY).toBe(40) expect(custom?.objectId).toBe(999) }) test("falls back to relative canvas coordinates when preset pieces are absent", () => { const borderDs1 = makeMockDs1(8, 8) const result = generateWilderness({ levelId: 43, // Far Oasis (Beetleburst) levelName: "Far Oasis", levelTypeName: "Act 2 - Desert", sizeX: 100, sizeY: 100, subType: 6, subTheme: 0, seed: 99, pieces: [{ name: "Act 2 - Desert Border 1", border: true, levels: [borderDs1] }], substitutions: [], }) const beetleburst = result.stats.landmarkEntities?.find(e => e.name === "Beetleburst") expect(beetleburst).toBeDefined() expect(beetleburst?.tileX).toBeGreaterThanOrEqual(1) expect(beetleburst?.tileX).toBeLessThan(99) expect(beetleburst?.tileY).toBeGreaterThanOrEqual(1) expect(beetleburst?.tileY).toBeLessThan(99) }) }) describe("Integration with planLevelMonsters (src/game/monsters.ts)", () => { test("Aura Enchanted modifier exists in CANONICAL_ELITE_MODIFIERS", () => { const aura = CANONICAL_ELITE_MODIFIERS.find(m => m.name === "aura") expect(aura).toBeDefined() expect(aura?.label).toBe("Aura Enchanted") expect(aura?.id).toBe(30) }) test("CANONICAL_SUPER_UNIQUES_BY_LEVEL maps all 5 Acts correctly", () => { // Act 1 expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[3]).toBeDefined() // Bishibosh expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[4]).toBeDefined() // Rakanishu expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[5]).toBeDefined() // Treehead WoodFist expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[17]).toBeDefined() // Blood Raven expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[25]).toBeDefined() // Countess // Act 2 expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[43]).toBeDefined() // Beetleburst expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[44]).toBeDefined() // Dark Elder expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[59]).toBeDefined() // Creeping Feature expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[60]).toBeDefined() // Bloodwitch expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[61]).toBeDefined() // Fangskin // Act 3 expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[76]).toBeDefined() // Sszark expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[78]).toBeDefined() // Stormtree & Endugu expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[84]).toBeDefined() // Sszark expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[88]).toBeDefined() // Endugu expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[91]).toBeDefined() // Endugu expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[94]).toBeDefined() // Sarina // Act 4 expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[105]).toBeDefined() // Izual expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[107]).toBeDefined() // Hephasto // Act 5 const act5Bloody = CANONICAL_SUPER_UNIQUES_BY_LEVEL[110] // Dac Farren & Shenk expect(Array.isArray(act5Bloody)).toBe(true) expect((act5Bloody as readonly unknown[]).length).toBe(2) expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[111]).toBeDefined() // Eyeback expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[112]).toBeDefined() // Thresh Socket expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[114]).toBeDefined() // Frozenstein expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[115]).toBeDefined() // Bonesaw expect(CANONICAL_SUPER_UNIQUES_BY_LEVEL[124]).toBeDefined() // Nihlathak }) test("planLevelMonsters creates deterministic boss packs for multi-boss level 110", () => { const levelsTxt = mockTable([ "Id\tName\tMonDen\tMonUMin\tMonUMax\tMonLvl1Ex\tm1\tm2\tm3", "110\tBloody Foothills\t600\t2\t4\t35\tsiegebeast1\tdemonimp1\tenflayer1", ].join("\n")) const monstatsTxt = mockTable([ "Id\tBaseId\tNameStr\tLevel\tMinGrp\tMaxGrp\tVelocity\trun\tAC\tExp\tminHP\tmaxHP\tA1MinD\tA1MaxD\tA1TH\tenabled\tissend\tisSpawn\tisMelee", "imp1\timp1\tDemon Imp\t35\t3\t6\t8\t12\t5\t15\t8\t14\t1\t3\t20\t1\t1\t1\t1", "demonimp1\tdemonimp1\tDemon Imp\t35\t3\t6\t8\t12\t5\t15\t8\t14\t1\t3\t20\t1\t1\t1\t1", "overseer1\toverseer1\tOverseer\t35\t1\t2\t7\t10\t10\t35\t16\t26\t3\t6\t30\t1\t1\t1\t1", "siegebeast1\tsiegebeast1\tSiege Beast\t35\t1\t2\t6\t8\t15\t50\t20\t35\t4\t8\t30\t1\t1\t1\t1", ].join("\n")) const monlvlTxt = mockTable([ "Level\tAC\tTH\tHP\tDM\tXP", "35\t100\t100\t100\t100\t100", ].join("\n")) const tables = { levels: levelsTxt, monstats: monstatsTxt, monlvl: monlvlTxt } const plan = planLevelMonsters(tables, 110, 240 * 48, 11042, 3.5, "normal") expect(plan.superUniques).toContain("Dac Farren") expect(plan.superUniques).toContain("Shenk the Overseer") const dacPack = plan.packs.find(p => p.superUniqueId === "Dac Farren") const shenkPack = plan.packs.find(p => p.superUniqueId === "Shenk the Overseer") expect(dacPack).toBeDefined() expect(shenkPack).toBeDefined() expect(dacPack?.members[0]?.rank).toBe("unique") expect(shenkPack?.members[0]?.rank).toBe("unique") expect(dacPack?.members[0]?.modifiers?.includes("coldenchant")).toBe(true) expect(shenkPack?.members[0]?.modifiers?.includes("strong")).toBe(true) }) test("lookupSuperUnique retrieves canonical superuniques by id or name", () => { const bishibosh = lookupSuperUnique(CANONICAL_SUPERUNIQUES_TABLE, "Bishibosh") expect(bishibosh).toBeDefined() expect(bishibosh?.monsterId).toBe("fallenshaman1") expect(bishibosh?.minMinions).toBe(5) expect(bishibosh?.maxMinions).toBe(7) const caseInsensitive = lookupSuperUnique(CANONICAL_SUPERUNIQUES_TABLE, "rakanishu") expect(caseInsensitive).toBeDefined() expect(caseInsensitive?.id).toBe("Rakanishu") expect(caseInsensitive?.monsterId).toBe("fallen1") expect(lookupSuperUnique(CANONICAL_SUPERUNIQUES_TABLE, "nonexistent")).toBeUndefined() }) test("buildSuperUniqueLandmarkSpecs builds specs from custom SuperUniques table", () => { const customSuTable = mockTable([ "Superunique\tName\tClass\tMod1\tMod2\tMod3\tMinGrp\tMaxGrp\tAutoPos\tStacks\tReplaceable\tUtrans\tTC\tTC(N)\tTC(H)", "Bishibosh\tBishibosh Custom\tfallenshaman2\t6\t28\t0\t8\t10\t0\t0\t0\t0\tAct 1 Super A\tAct 1 (N) Super A\tAct 1 (H) Super A", ].join("\n")) const specsByLevel = buildSuperUniqueLandmarkSpecs(customSuTable) const bishiboshSpec = specsByLevel[3] expect(bishiboshSpec).toBeDefined() expect(Array.isArray(bishiboshSpec)).toBe(false) const spec = bishiboshSpec as import("../src/game/monsters.ts").SuperUniqueLandmarkSpec expect(spec.name).toBe("Bishibosh Custom") expect(spec.monsterId).toBe("fallenshaman2") expect(spec.minMinions).toBe(8) expect(spec.maxMinions).toBe(10) expect(spec.modifiers).toEqual(["fast", "stoneskin"]) }) test("planLevelMonsters skips boss without falling back to fallen1 when boss monster is missing", () => { const levelsTxt = mockTable([ "Id\tName\tMonDen\tMonUMin\tMonUMax\tMonLvl1Ex\tm1\tm2\tm3", "4\tStony Field\t600\t2\t4\t7\tzombie1\tquillrat1\tbrute1", ].join("\n")) // Only define zombie1 in monstats - Rakanishu is fallen1, which is absent const monstatsTxt = mockTable([ "Id\tBaseId\tNameStr\tLevel\tMinGrp\tMaxGrp\tVelocity\trun\tAC\tExp\tminHP\tmaxHP\tA1MinD\tA1MaxD\tA1TH\tenabled\tissend\tisSpawn\tisMelee", "zombie1\tzombie1\tZombie\t7\t1\t2\t4\t6\t10\t20\t10\t20\t2\t5\t20\t1\t1\t1\t1", ].join("\n")) const monlvlTxt = mockTable([ "Level\tAC\tTH\tHP\tDM\tXP", "7\t100\t100\t100\t100\t100", ].join("\n")) const tables = { levels: levelsTxt, monstats: monstatsTxt, monlvl: monlvlTxt } const plan = planLevelMonsters(tables, 4, 6400, 12345, 3.5, "normal") // Rakanishu should NOT be spawned as zombie1 or fallen1 (fallen1 fallback was removed) expect(plan.superUniques?.includes("Rakanishu")).toBeFalsy() const rakanishuPack = plan.packs.find(p => p.superUniqueId === "Rakanishu") expect(rakanishuPack).toBeUndefined() }) test("planLevelMonsters uses tables.superuniques when provided", () => { const levelsTxt = mockTable([ "Id\tName\tMonDen\tMonUMin\tMonUMax\tMonLvl1Ex\tm1\tm2\tm3", "3\tCold Plains\t600\t2\t4\t5\tfallenshaman1\tfallen1\tzombie1", ].join("\n")) const monstatsTxt = mockTable([ "Id\tBaseId\tNameStr\tLevel\tMinGrp\tMaxGrp\tVelocity\trun\tAC\tExp\tminHP\tmaxHP\tA1MinD\tA1MaxD\tA1TH\tenabled\tissend\tisSpawn\tisMelee", "fallenshaman1\tfallenshaman1\tFallen Shaman\t5\t1\t1\t6\t9\t10\t20\t15\t25\t2\t4\t20\t1\t1\t1\t1", "fallen1\tfallen1\tFallen\t5\t3\t5\t8\t12\t5\t10\t5\t10\t1\t2\t15\t1\t1\t1\t1", ].join("\n")) const monlvlTxt = mockTable([ "Level\tAC\tTH\tHP\tDM\tXP", "5\t100\t100\t100\t100\t100", ].join("\n")) const customSuTable = mockTable([ "Superunique\tName\tClass\tMod1\tMod2\tMod3\tMinGrp\tMaxGrp\tAutoPos\tStacks\tReplaceable\tUtrans\tTC\tTC(N)\tTC(H)", "Bishibosh\tBishibosh Ultra\tfallenshaman1\t6\t0\t0\t3\t3\t0\t0\t0\t0\tAct 1 Super A\tAct 1 (N) Super A\tAct 1 (H) Super A", ].join("\n")) const tables = { levels: levelsTxt, monstats: monstatsTxt, monlvl: monlvlTxt, superuniques: customSuTable } const plan = planLevelMonsters(tables, 3, 6400, 54321, 3.5, "normal") expect(plan.superUniques).toContain("Bishibosh") const bishiboshPack = plan.packs.find(p => p.superUniqueId === "Bishibosh") expect(bishiboshPack).toBeDefined() expect(bishiboshPack?.members[0]?.name).toBe("Bishibosh Ultra") expect(bishiboshPack?.members[0]?.modifiers).toEqual(["fast"]) // 1 boss + 3 minions = 4 members expect(bishiboshPack?.members.length).toBe(4) }) }) })