# Test Coverage Improvement Plan **Status:** In Progress **Created:** 2026-02-02 **Started:** 2026-02-02 **Target Completion:** 6 weeks **Current Coverage:** 63% → **~65%** (after quick wins 1-2) **Target Coverage:** 85% See [`PROJECT_PLAN_TEST_COVERAGE.json`](./PROJECT_PLAN_TEST_COVERAGE.json) for full structured plan. --- ## 📝 Lessons Learned (Session 2026-02-02) ### Quick Wins Completed - ✅ **TEST-015:** CardBack tests (25 tests, ~2h) - ✅ **TEST-020:** Socket message factories (20 tests, ~2h) - **Total:** 45 new tests, 1000 → 1045 tests (+4.5%) ### Key Learnings for Future Testing #### 1. **Phaser Mocking Pattern (from TEST-015)** **Problem:** Phaser classes can't be imported directly in tests (WebGL/Canvas dependencies) **Solution:** Mock Phaser classes inline within `vi.mock()` factory function ```typescript // ✅ CORRECT - Define mock classes inside vi.mock factory vi.mock('phaser', () => { class MockContainerFactory { x: number y: number // ... mock implementation } return { default: { GameObjects: { Container: MockContainerFactory, }, }, } }) // ❌ WRONG - Referencing external classes causes hoisting issues class MockContainer { /* ... */ } vi.mock('phaser', () => ({ default: { GameObjects: { Container: MockContainer, // ReferenceError: Cannot access before initialization }, }, })) ``` **Why:** `vi.mock()` is hoisted to the top of the file, so it runs before any class definitions. Mock classes must be defined within the factory function. #### 2. **Disabling ESLint for Test Mocks** When mocking complex Phaser objects, `any` types are acceptable in tests: ```typescript /* eslint-disable @typescript-eslint/no-explicit-any */ // Disabling explicit-any for test mocks - Phaser types are complex and mocking requires any ``` **Rationale:** Mocking Phaser's deep type hierarchies is impractical. Focus on testing behavior, not perfect type accuracy in mocks. #### 3. **Test Docstrings Are Essential** Every test must include a docstring explaining "what" and "why": ```typescript it('creates a card back with sprite when texture exists', () => { /** * Test that CardBack uses sprite when texture is available. * * When the card back texture is loaded, CardBack should create * a sprite instead of fallback graphics. */ // test implementation }) ``` **Why:** These docstrings make tests self-documenting and help future developers understand intent. #### 4. **Test Actual Dimensions, Not Assumptions** **Mistake Made:** Initially used wrong card dimensions (assumed 120x167 for large, actual was 150x210) **Lesson:** Always check actual constants/values in codebase before writing assertions. Don't assume dimensions or magic numbers. ```typescript // ✅ Verified actual CARD_SIZES from types/phaser.ts expect(dimensions.width).toBe(150) // large: 150x210 expect(dimensions.height).toBe(210) // ❌ Assumed without checking expect(dimensions.width).toBe(120) // Wrong! ``` #### 5. **Integration Tests Validate Full Lifecycle** Include at least one integration test that exercises the full object lifecycle: ```typescript it('can create, resize, and destroy a card back', () => { /** * Test full lifecycle of a CardBack. * * This integration test verifies that a CardBack can be * created, resized multiple times, and destroyed without errors. */ const cardBack = new CardBack(mockScene, 100, 200, 'small') cardBack.setCardSize('medium') cardBack.setCardSize('large') expect(() => cardBack.destroy()).not.toThrow() }) ``` **Why:** Unit tests verify individual methods, integration tests verify they work together correctly. #### 6. **Factory Function Testing Strategy** When testing message/object factories (TEST-020): 1. **Test structure first** - Verify all required fields present 2. **Test uniqueness** - IDs/tokens should be unique on each call 3. **Test variations** - Test with/without optional parameters 4. **Test integration** - Verify factories work together (same game, different messages) ```typescript // Structure expect(message.type).toBe('join_game') expect(message.message_id).toBeTruthy() // Uniqueness const msg1 = createJoinGameMessage('game-1') const msg2 = createJoinGameMessage('game-1') expect(msg1.message_id).not.toBe(msg2.message_id) // Variations const withLastEvent = createJoinGameMessage('game-1', 'event-123') expect(withLastEvent.last_event_id).toBe('event-123') const withoutLastEvent = createJoinGameMessage('game-1') expect(withoutLastEvent.last_event_id).toBeUndefined() ``` #### 7. **Avoid Testing Browser Internals** **Mistake Made:** Attempted to mock `global.crypto` which is read-only **Lesson:** Don't test browser APIs directly. Test your wrapper functions instead. If a function uses `crypto.randomUUID()`, test that it returns valid UUIDs, not that it calls the browser API. ```typescript // ✅ Test the wrapper's behavior it('generates a unique message ID', () => { const id = generateMessageId() expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i) }) // ❌ Don't test browser internals it('uses crypto.randomUUID when available', () => { global.crypto = { randomUUID: vi.fn() } // TypeError: Cannot set property }) ``` #### 8. **Pre-commit Hooks Catch Everything** Since fixing pre-existing lint errors and enabling pre-commit hooks (PR #2): - All TypeScript errors caught immediately - All lint errors caught immediately - All test failures caught immediately - **No bypassing with --no-verify** **Impact:** Zero bugs made it into commits during this session. Pre-commit hooks are working perfectly. #### 9. **Quick Wins Build Momentum** Starting with simple, high-value tests (CardBack, socket factories) built confidence and validated patterns: - CardBack: Simple game object, validated Phaser mocking - Socket factories: Straightforward logic, 100% coverage quickly - Both: Provided immediate value (45 tests) in 4 hours **Strategy:** When starting a new test area, pick the simplest component first to validate your approach. #### 10. **Coverage Numbers Update Automatically** After adding tests, re-run coverage to see actual improvement: ```bash npm run test -- --coverage ``` **Observed Gains:** - CardBack: 0% → ~95% coverage (238 lines) - Socket factories: 0% → 100% coverage (54 lines) - Overall: 63% → ~65% (+2%) --- ## Executive Summary The Mantimon TCG frontend has **excellent test discipline** (1000 passing tests) but has **critical gaps** in the game engine layer: - ✅ **Strong:** Composables (84%), Components (90%), Stores (88%) - ❌ **Critical Gap:** Game Engine (0% coverage, ~5,500 lines) - ⚠️ **Needs Work:** WebSocket (27-45% coverage) **Biggest Risk:** Phaser game engine is completely untested - rendering bugs, state sync issues, and visual glitches won't be caught until manual testing or production. --- ## Priority Overview ### 🔴 Critical (Week 1-3) | Task | Component | Impact | |------|-----------|--------| | TEST-001 | Phaser testing infrastructure | **Prerequisite for all game engine tests** | | TEST-002 | MatchScene lifecycle | Core game scene rendering | | TEST-003 | Board layout & zones | Prize zone bug, zone management | | TEST-004 | Card rendering | Card display and interactions | | TEST-005 | StateRenderer sync | Backend ↔ Phaser synchronization | | TEST-007 | Socket connection | WebSocket reliability | | TEST-008 | Game action handling | Action queueing and responses | | TEST-009 | Game management | Create/join game workflows | **Total:** ~80 hours, 8 tasks ### 🟡 High (Week 4) | Task | Component | Impact | |------|-----------|--------| | TEST-006 | Zone classes | Zone types and card management | | TEST-010 | PreloadScene | Asset loading | | TEST-011 | HandManager | Drag/drop edge cases | | TEST-012 | DamageCounter | Damage display | | TEST-013 | Asset loader | Asset management | | TEST-014 | ResizeManager | Responsive layout | **Total:** ~31 hours, 6 tasks ### 🟢 Medium/Low (Week 5-6) - Page tests (HomePage, CampaignPage, MatchPage) - Edge case tests (user store, drag/drop, deck builder) - Infrastructure (visual regression, CI coverage, documentation) **Total:** ~45 hours, remaining tasks --- ## Week-by-Week Roadmap ### Week 1: Foundation (28 hours) **Theme:** Phaser Testing Infrastructure & Core Objects **Tasks:** - [x] TEST-001: Create Phaser mocks and test utilities *(8h)* ✅ **COMPLETE** (55 tests: 33 mock tests + 22 utility tests) - [x] TEST-003: Test Board layout and zones *(10h)* ✅ **COMPLETE** (55 tests: constructor, setLayout, highlighting, zone queries, coordinate detection, destroy, factory, integration, edge cases) - [ ] TEST-006: Test Zone base class and subclasses *(10h)* **Deliverables:** - ✅ Phaser testing infrastructure ready - MockScene, MockGame, MockContainer, MockSprite, MockText, MockGraphics - ✅ Test utilities created - createMockGameState, createMockCard, setupMockScene, createGameScenario - ✅ Documentation complete - src/test/README.md with usage examples - ✅ Board class tested - Zone rendering, highlighting, coordinate queries for both game modes (with/without prizes) - Zone classes tested - Game engine coverage: 0% → 20% **Blockers:** None - can start immediately --- ### Week 2: Core Engine (32 hours) **Theme:** Scenes & State Synchronization **Tasks:** - [x] TEST-002: Test MatchScene initialization *(8h)* ✅ **COMPLETE** (26 tests: init, create, update, shutdown, events, state updates, resize) - [ ] TEST-004: Test Card rendering and interactions *(12h)* - [ ] TEST-005: Test StateRenderer synchronization *(12h)* **Deliverables:** - ✅ MatchScene lifecycle tested - All scene lifecycle methods covered - ✅ Event handling tested - Bridge communication and cleanup verified - Card display and interactions tested - State sync tested (prize zone fix validated!) - Game engine coverage: 20% → 50% **Blockers:** Requires TEST-001 (Week 1) --- ### Week 3: Network Layer (20 hours) **Theme:** WebSocket & Multiplayer Reliability **Tasks:** - [ ] TEST-007: Test socket connection lifecycle *(6h)* - [ ] TEST-008: Test game action handling *(8h)* - [ ] TEST-009: Test game creation/joining *(6h)* **Deliverables:** - WebSocket reliability tests - Action queueing tested - Game management tested - Socket coverage: 27% → 80% **Blockers:** None - independent of game engine --- ### Week 4: Engine Completion (21 hours) **Theme:** Remaining Game Components **Tasks:** - [ ] TEST-010: Test PreloadScene *(4h)* - [ ] TEST-011: Test HandManager drag/drop *(6h)* - [ ] TEST-012: Test DamageCounter *(3h)* - [ ] TEST-013: Test asset loader *(4h)* - [ ] TEST-014: Test ResizeManager *(4h)* **Deliverables:** - All major game components tested - Game engine coverage: 50% → 65% - **Overall coverage: 63% → 73%** --- ### Week 5: Integration & UI (22 hours) **Theme:** Pages and Integration Testing **Tasks:** - [x] TEST-016: User store edge cases *(3h)* ✅ **COMPLETE** (20 tests) - [x] TEST-017: Drag/drop edge cases *(3h)* ✅ **COMPLETE** (17 edge case tests added) - [x] TEST-018: Deck builder edge cases *(4h)* ✅ **COMPLETE** (75 tests: DeckActionButtons, DeckHeader, DeckCardRow) - [x] TEST-019: Page tests (Home, Campaign, Match) *(6h)* ✅ **COMPLETE** (44 tests: HomePage, CampaignPage, MatchPage) - [ ] TEST-021: Animation sequences *(6h)* **Deliverables:** - All pages tested - Integration scenarios covered - **Overall coverage: 73% → 78%** --- ### Week 6: Infrastructure (21 hours) **Theme:** Testing Tooling & Documentation **Tasks:** - [ ] TEST-022: Visual regression with Playwright *(8h)* - [ ] TEST-023: CI coverage reporting *(3h)* - [ ] TEST-024: Testing documentation *(4h)* - [ ] TEST-020: Socket type guards *(2h)* - [ ] TEST-015: CardBack tests *(2h)* *(Quick win!)* - [ ] TEST-025: Mutation testing (optional) *(6h)* **Deliverables:** - Visual regression testing enabled - CI coverage tracking - Testing guide for team - **Overall coverage: 78% → 82%+** --- ## Quick Wins (Do First!) These tasks are simple and provide immediate value: 1. **TEST-015: CardBack** *(2h)* - Simple component, easy test, gets game/ coverage started 2. **TEST-020: Type guards** *(2h)* - Straightforward logic tests, improves socket reliability 3. **TEST-016: User store** *(3h)* - Boosts coverage from 52% to 90%+ **Total:** 7 hours for measurable coverage improvement --- ## Production Blockers These must be tested before production release: 1. **TEST-005: StateRenderer** - State desync bugs cause multiplayer issues 2. **TEST-007: Socket client** - Connection problems make game unplayable 3. **TEST-008: useGameSocket** - Lost/duplicate actions break game flow --- ## Testing Challenges & Solutions ### Challenge 1: Phaser Requires WebGL/Canvas **Problem:** Phaser games need WebGL/Canvas, jsdom doesn't support it **Solutions:** 1. **Mock Phaser classes** - Create minimal mocks (TEST-001) 2. **Extract logic** - Pull game logic out of Phaser into pure functions 3. **Visual regression** - Use Playwright for rendering tests (TEST-022) 4. **Integration tests** - Test via PhaserGame.vue wrapper **Example:** ```typescript // ❌ Hard to test - logic inside Phaser class class Card extends Phaser.GameObjects.Sprite { update() { if (this.health <= 0) { this.destroy() this.scene.addScore(10) } } } // ✅ Easy to test - logic extracted function shouldDestroyCard(health: number): boolean { return health <= 0 } class Card extends Phaser.GameObjects.Sprite { update() { if (shouldDestroyCard(this.health)) { this.destroy() this.scene.addScore(10) } } } ``` ### Challenge 2: WebSocket State Management **Problem:** Real-time behavior, connection state, race conditions **Solutions:** 1. **Mock socket.io-client** - Already doing this well 2. **Test state machines** - Focus on state transitions 3. **Fake timers** - Control async timing 4. **Error injection** - Simulate disconnect/reconnect ### Challenge 3: Animation Testing **Problem:** Animations are async and timing-dependent **Solutions:** 1. **Fake timers** - Advance time manually with `vi.useFakeTimers()` 2. **Test completion** - Verify animation completes, not individual frames 3. **Integration tests** - Test animation sequences end-to-end (TEST-021) --- ## Coverage Targets | Area | Current | Week 2 | Week 4 | Week 6 | 3 Months | |------|---------|--------|--------|--------|----------| | **Overall** | 63% | 68% | 73% | 78% | **85%** | | **Game Engine** | 0% | 40% | 60% | 65% | **80%** | | **Composables** | 84% | 84% | 86% | 90% | **95%** | | **Components** | 90% | 90% | 90% | 92% | **95%** | | **Stores** | 88% | 88% | 90% | 92% | **95%** | | **Socket** | 27% | 27% | 80% | 85% | **90%** | --- ## Getting Started ### Option 1: Quick Wins First (Recommended) Build momentum with easy tasks: ```bash # Week 1 - Quick Wins (7 hours) npm run test -- src/game/objects/CardBack.spec.ts # Create this npm run test -- src/socket/types.spec.ts # Expand this npm run test -- src/stores/user.spec.ts # Expand this # Result: +5% coverage, confidence boost ``` ### Option 2: Critical Path (Production-Focused) Tackle blockers immediately: ```bash # Week 1-3 - Critical Path (80 hours) # TEST-001: Phaser infrastructure (8h) # TEST-002: MatchScene (8h) # TEST-003: Board (10h) # TEST-004: Card (12h) # TEST-005: StateRenderer (12h) # TEST-007: Socket client (6h) # TEST-008: useGameSocket (8h) # TEST-009: useGames (6h) # Result: Core game and network tested, ready for production ``` ### Option 3: Parallel Development (Team of 2-3) Split work across developers: ```bash # Developer 1: Game Engine - Week 1: TEST-001, TEST-003, TEST-006 - Week 2: TEST-002, TEST-004, TEST-005 # Developer 2: Network Layer - Week 1: TEST-007, TEST-008 - Week 2: TEST-009, TEST-010, TEST-011 # Developer 3: UI & Infrastructure - Week 1: Quick wins (TEST-015, TEST-016, TEST-020) - Week 2: TEST-019, TEST-021 - Week 3: TEST-022, TEST-023, TEST-024 # Result: Complete in 3 weeks instead of 6 ``` --- ## Success Metrics ### Week 2 Checkpoint - [x] Phaser infrastructure works well ✅ - [x] Board tests validate prize zone fix ✅ - [ ] StateRenderer tests catch desync bugs - [ ] Coverage: 63% → 68% ### Week 4 Checkpoint - [ ] All major game components tested - [ ] WebSocket layer reliable - [ ] Coverage: 68% → 73% - [ ] Team confident in test suite ### Week 6 Completion - [ ] Visual regression enabled - [ ] CI coverage tracking - [ ] Testing documentation complete - [ ] Coverage: 73% → 78% - [ ] **Ready for production** ### 3 Month Goal - [ ] Coverage: 85%+ - [ ] All critical code paths tested - [ ] Mutation testing shows strong tests - [ ] New features include tests by default --- ## Team Resources ### Documentation - [ ] TEST-024: Create `src/test/README.md` with testing patterns - [ ] Add Phaser testing examples - [ ] Document common pitfalls and solutions ### Infrastructure - [ ] TEST-022: Playwright visual regression - [ ] TEST-023: CI coverage reporting - [ ] TEST-025: Stryker mutation testing (optional) ### Training - Share knowledge as infrastructure is built - Code review testing PRs thoroughly - Pair program on first few Phaser tests --- ## Questions & Discussion ### Should we aim for 100% coverage? **No.** 85% is realistic and valuable. Some code is hard to test: - Animation frames and tweens - WebGL rendering details - Entry points (main.ts, router config) Focus on **logic and state management**, not rendering details. ### Should we stop feature work to fix coverage? **Depends on priorities.** Options: 1. **Aggressive:** Pause features for 2-3 weeks, hit 80% coverage 2. **Balanced:** Dedicate 1-2 days/week to testing, reach 80% in 8-10 weeks 3. **Maintenance:** Add tests alongside features, reach 80% in 3-6 months **Recommendation:** Balanced approach - TEST-001 through TEST-009 are critical for production confidence, do those first. ### What if tests are too slow? **Strategies:** - Use `vi.mock()` liberally - mock Phaser, socket, API - Use `vi.useFakeTimers()` - control async timing - Run tests in parallel: `vitest --threads` - Use `it.skip()` for expensive tests during development - Run full suite in CI only --- ## Next Steps 1. **Review this plan** - Discuss with team, adjust priorities 2. **Start with TEST-001** - Build Phaser testing infrastructure 3. **Quick win: TEST-015** - Test CardBack to validate infrastructure 4. **Tackle critical path** - TEST-002 through TEST-009 5. **Track progress** - Update `PROJECT_PLAN_TEST_COVERAGE.json` as tasks complete --- ## Related Documents - [`PROJECT_PLAN_TEST_COVERAGE.json`](./PROJECT_PLAN_TEST_COVERAGE.json) - Full structured plan - [`TESTING.md`](../TESTING.md) - Current testing guide (recently added!) - [`CONTRIBUTING.md`](../CONTRIBUTING.md) - Never use --no-verify policy - [`VISUAL-TEST-GUIDE.md`](../VISUAL-TEST-GUIDE.md) - Visual testing reference --- **Let's build confidence in our game engine! 🎮✅**