diablo2-web/TEST_INFRA.md

9.1 KiB
Raw Blame History

Test Infrastructure & Strategy — diablo2-web Module Split (TEST_INFRA.md)

1. Test Philosophy

  • Requirement-Driven & Opaque-Box Verification: Every test case in tests/e2e-module-split/ is derived directly from ORIGINAL_REQUEST.md (R1–R4 and Acceptance Criteria), PROJECT.md (F1–F10 and Interface Contracts 1–4), and AGENTS.md (Diablo II v1.13c Ground Truth Parity Rules).
  • 1.13c Ground Truth & Anti-Silent Failure Enforcement:
    • Universal DT1 libraries (data\global\tiles\Act1\Outdoors\Blank.dt1, data\global\tiles\Act1\Barracks\InvisWal.dt1 with style=49 sequence=7 collision floor, data\global\tiles\Act1\Barracks\Warp.dt1) must be unconditionally loaded per D2Common.dll DRLGROOM_LoadDt1Files (0x6fdb8400).
    • Sparse/void cells must be blocked (blocked === 1) and masked with COLLIDE_MASK_INVALID (COLLIDE_BLANK | COLLIDE_WALL), and findIsoSpawn must never spawn in void or default blindly to geometric center (width/2, height/2).
    • Tile variant selection (pickVariant) must use high-entropy SplitMix64 2D spatial coordinate hashing without 45-degree diagonal striping.
    • All 66 SuperUniques must preserve exact 1.13c Class and minion identifiers (scarab2, zombie5, fetishshaman4, nihlathakboss, minion1..minion11 -> token 'XX', etc.).
    • Missing required parameters (e.g., D2DataRegistry / getSharedDataRegistry called without an ArchiveSource) must fail fast by throwing an explicit Error.
  • Dynamic Import & AST/Filesystem Inspection: All module imports inside tests/e2e-module-split/*.test.ts use runtime dynamic await import(...), node:fs inspection, and source/AST boundary scanning inside it(...) blocks so the test files remain 100% valid TypeScript at all times and execute against the post-split architecture (src/common/, src/netproto/, src/server/, src/client/, src/baker/, tools/, play.html).

2. Feature Inventory (F1–F10)

Feature ID Feature Name Target Module / Path Core Requirements & Contracts Tier 1 Tier 2 Tier 3 Tier 4
F1 src/common/ Pure Module & Data Registry Decoupling src/common/{mpq,formats,data,drlg,world,items,skills,units,i18n,rng,pack-contract}, tsconfig.common.json Pure ES2022 (types: [], zero DOM, zero node:*), D2DataRegistry & getSharedDataRegistry require injected ArchiveSource (no /usr/local/google/home/taodao/d2-data), D2Rng, SplitMix64 pickVariant, pure lookupTbl. 6 6 ✓ ✓
F2 Shared Pack Contract (src/common/pack-contract/) src/common/pack-contract/index.ts Exports PackedDrlgBundleManifest, PackedTileCatalogIndex, PackIndex, PackSceneJson, EntityMeta, ClipMeta, validateUniversalDt1Libraries, validatePackManifest. 5 5 ✓ ✓
F3 Elimination of All 23 Server-to-Client Reverse Dependencies src/common/{items,units,skills,i18n,world}, src/server/** Extract inventory-model, belt-model, item-bridge, CharacterAttributes, resolvePlayerCharToken, HotkeySkillEntry, getSkillName, subTileToScene; zero imports from src/server/** into src/client/**. 5 5 ✓ ✓
F4 src/baker/ Offline Baker Module & Unified CLI src/baker/{cli.ts,io,packers,extract,audit}, tsconfig.baker.json Node-only offline baker (types: ["node"], zero DOM, zero client/server imports), unified src/baker/cli.ts (npm run bake -- <target> & --verify). 5 5 ✓ ✓
F5 tools/ CLI Consolidation & Legacy Relay Deletion tools/*.ts, package.json Migrate 93 CLI/bot/replay/verify tools to tools/; delete scripts/net-relay.ts, scripts/net-server.ts, and scripts/ directory; update package.json scripts. 5 5 ✓ ✓
F6 src/server/ Authoritative Simulation & LocalLoopbackAdapter src/server/{engine,ai,skills,items,world,save,scene,adapter}, tsconfig.server.json Zero DOM globals, zero Math.random/Date.now/performance.now, zero node:* in skills/registry.ts; LocalLoopbackAdapter implements GameServerAdapter. 6 6 ✓ ✓
F7 src/client/ Pure Browser Module & MapService Decoupling src/client/{main.ts,render,ui,frontend,scene,audio,sim,i18n,map,session,world}, tsconfig.client.json Pure browser (types: [], zero node:*, zero server/baker imports); MapService.fromLoader / fromPackedUrls without node:fs/node:path. 5 5 ✓ ✓
F8 Single HTML Entry (play.html) & Legacy Entry Removal play.html, vite.config.ts play.html is sole .html in root and vite.config.ts (with D2Exocet/D2Formal436 @font-face); index.html, acts*.html, bnet.html, act-scene.ts, net-scene.ts, src/net/* deleted. 5 5 ✓ ✓
F9 Compiler-Level Isolation & Boundary Gate (tests/arch/boundaries.test.ts) tsconfig.*.json, tests/arch/boundaries.test.ts All 5 tsconfig.<module>.json files wired into npm run typecheck; src/ contains only {common,netproto,server,client,baker}; tests/arch/boundaries.test.ts passes with 0 whitelist exceptions. 5 5 ✓ ✓
F10 Full 1.13c Parity, Baker, Replay & DRLG Invariants src/common/drlg/, src/common/world/, src/common/units/, tools/netproto-replay.ts Universal DT1s (Blank.dt1, InvisWal.dt1, Warp.dt1), void blocking (COLLIDE_MASK_INVALID), non-void findIsoSpawn, SplitMix64 pickVariant, SuperUnique minion closure, .d2cap replay parity. 5 5 ✓ ✓

3. Test Architecture

tests/e2e-module-split/
├── tier1-feature-coverage.test.ts       # >= 50 tests (>= 5 per feature F1–F10): happy-path module layout, exports, & contracts
├── tier2-boundary-corner.test.ts        # >= 50 tests (>= 5 per feature F1–F10): fail-fast, negative, boundary & isolation invariants
├── tier3-cross-feature.test.ts          # >= 15 tests: pairwise cross-module & cross-feature integration contracts
└── tier4-real-world-scenarios.test.ts   # >= 6 tests: realistic end-to-end gameplay, DRLG, item/socket, .d2cap replay, & repo audit scenarios
  • Test Runner Command: npx vitest run tests/e2e-module-split/

4. Real-World Application Scenarios (Tier 4)

  1. Scenario 1 — End-to-End Single-Player Game Loop (LocalLoopbackAdapter → OnlineSession → ClientWorld):
    • Connect LocalLoopbackAdapter to OnlineSession and ClientWorld, verify initial handshake (LoadAct, UnitAssign, MapSeed), dispatch movement (RunToLocation / WalkToLocation) and skill cast (CastLeftSkillAtLocation / CastRightSkillAtLocation), step server ticks, verify authoritative ClientWorld state updates, and cleanly disconnect.
  2. Scenario 2 — End-to-End DRLG Level Generation, Void Collision & findIsoSpawn Across Act 1–5:
    • Verify universal DT1 inclusion (Blank.dt1, InvisWal.dt1 style=49 seq=7, Warp.dt1), void cell collision masking (COLLIDE_MASK_INVALID = COLLIDE_BLANK | COLLIDE_WALL), largest walkable floor region spawn resolution (findIsoSpawn), and SplitMix64 pickVariant spatial decorrelation across Act 1–5 levels.
  3. Scenario 3 — End-to-End Item, Inventory, Belt & Socket Pipeline (src/common/items/ ↔ src/server/items/):
    • Generate and bridge items via itemToUiInventoryItem, place items into InventoryGrid (findFreeGridSlot), manage belt potions (BeltHud / BeltModel / itemToBeltPotion / column gravity shift), and socket gems/runes into host items (socketItemIntoHost, checkRunewordMatch).
  4. Scenario 4 — End-to-End .d2cap Binary Packet Capture Replay into ClientWorld:
    • Replay all 4 real .d2cap capture fixtures (01-bncs-mcp-lobby.d2cap, 02-d2gs-town-walk-chat.d2cap, 03-d2gs-items-npc-skills.d2cap, 04-d2gs-idle-60s.d2cap) via replayD2CapText(..., { strict: true }) and verify unknownPackets === 0, opaquePackets === 0, protocolErrors === 0, and populated ClientWorld state.
  5. Scenario 5 — End-to-End Offline Asset Pack Manifest & Entity/Tile Pack Integrity:
    • Load and validate public/act-packs/tiles/{index.json, drlg-bundle.json, drlg-bundle.bin} against src/common/pack-contract/ validators (validateUniversalDt1Libraries, validatePackManifest), and initialize MapService.fromLoader with an injected loader to generate an Act 1 level view without node:fs in src/client/.
  6. Scenario 6 — End-to-End Repository Architectural & Module Boundary Audit:
    • Programmatically scan every .ts file in src/**, tools/**, root *.html, vite.config.ts, package.json, and tsconfig*.json to verify all R1–R4 architectural invariants with zero exceptions.

5. Coverage Thresholds

Tier File Minimum Required Tests Target Tests
Tier 1 tests/e2e-module-split/tier1-feature-coverage.test.ts 50 (>= 5 per F1–F10) 52
Tier 2 tests/e2e-module-split/tier2-boundary-corner.test.ts 50 (>= 5 per F1–F10) 52
Tier 3 tests/e2e-module-split/tier3-cross-feature.test.ts 15 16
Tier 4 tests/e2e-module-split/tier4-real-world-scenarios.test.ts 6 6
Total tests/e2e-module-split/ 121 126