mantimon-tcg/frontend/TEST_COVERAGE_PLAN.md
Cal Corum d03dc1ddd2 Update test coverage plan with lessons learned and progress
Documentation updates after completing quick wins 1-2:

Progress:
- Tests: 1000 → 1045 (+45, +4.5%)
- Coverage: 63% → ~65% (+2%)
- Quick wins completed: 2/3
- Hours spent: ~4 hours
- TEST-015 (CardBack): 25 tests, ~95% coverage
- TEST-020 (Socket factories): 20 tests, 100% coverage

Key Lessons Learned:
1. Phaser mocking pattern - mock classes inside vi.mock() factory
2. Disable ESLint explicit-any for complex Phaser mocks
3. Test docstrings are essential for maintainability
4. Always verify actual dimensions/constants before asserting
5. Include integration tests for full object lifecycle
6. Factory function testing strategy (structure, uniqueness, variations)
7. Avoid testing browser internals (crypto, etc)
8. Pre-commit hooks catch everything - working perfectly
9. Quick wins build momentum - start simple
10. Coverage updates automatically after tests added

Updated PROJECT_PLAN_TEST_COVERAGE.json:
- Mark TEST-015 and TEST-020 as completed
- Add progress tracking metadata
- Update current coverage estimate
2026-02-02 15:48:35 -06:00

617 lines
18 KiB
Markdown

# 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:**
- [ ] TEST-001: Create Phaser mocks and test utilities *(8h)*
- [ ] TEST-003: Test Board layout and zones *(10h)*
- [ ] TEST-006: Test Zone base class and subclasses *(10h)*
**Deliverables:**
- Phaser testing infrastructure ready
- Board and Zone classes tested
- Game engine coverage: 0% → 20%
**Blockers:** None - can start immediately
---
### Week 2: Core Engine (32 hours)
**Theme:** Scenes & State Synchronization
**Tasks:**
- [ ] TEST-002: Test MatchScene initialization *(8h)*
- [ ] TEST-004: Test Card rendering and interactions *(12h)*
- [ ] TEST-005: Test StateRenderer synchronization *(12h)*
**Deliverables:**
- MatchScene lifecycle tested
- 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:**
- [ ] TEST-016: User store edge cases *(3h)*
- [ ] TEST-017: Drag/drop edge cases *(3h)*
- [ ] TEST-018: Deck builder edge cases *(4h)*
- [ ] TEST-019: Page tests (Home, Campaign, Match) *(6h)*
- [ ] 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
- [ ] Phaser infrastructure works well
- [ ] 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! 🎮✅**