docs: map existing codebase
- STACK.md - Technologies and dependencies - ARCHITECTURE.md - System design and patterns - STRUCTURE.md - Directory layout - CONVENTIONS.md - Code style and patterns - TESTING.md - Test structure - INTEGRATIONS.md - External services - CONCERNS.md - Technical debt and issues
This commit is contained in:
314
.planning/codebase/TESTING.md
Normal file
314
.planning/codebase/TESTING.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# Testing Patterns
|
||||
|
||||
**Analysis Date:** 2026-02-04
|
||||
|
||||
## Test Framework
|
||||
|
||||
**Runner:**
|
||||
- Vitest 4.0.16 - Unit test runner
|
||||
- Playwright 1.57.0 - E2E test runner
|
||||
|
||||
**Config Files:**
|
||||
- Unit tests: `vitest.config.js`
|
||||
- E2E tests: `playwright.config.js`
|
||||
|
||||
**Run Commands:**
|
||||
```bash
|
||||
npm run test # Run unit tests (Vitest)
|
||||
npm run test:ui # Run tests with Vitest UI
|
||||
npm run test:coverage # Run tests with coverage report
|
||||
npm run test:e2e # Run E2E tests (Playwright)
|
||||
npm run test:e2e:ui # Run E2E tests with Playwright UI
|
||||
npm run test:all # Run all tests (unit + E2E)
|
||||
```
|
||||
|
||||
## Test File Organization
|
||||
|
||||
**Location:**
|
||||
- Unit tests: `tests/unit/` directory
|
||||
- E2E tests: `tests/e2e/` directory
|
||||
- Separate from source code (not co-located)
|
||||
|
||||
**Naming:**
|
||||
- Unit tests: `.test.js` suffix: `game-logic.test.js`
|
||||
- E2E tests: `.spec.js` suffix: `game-flow.spec.js`
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
tests/
|
||||
├── unit/
|
||||
│ └── game-logic.test.js
|
||||
└── e2e/
|
||||
└── game-flow.spec.js
|
||||
```
|
||||
|
||||
## Unit Test Structure
|
||||
|
||||
**Framework:** Vitest with globals enabled
|
||||
|
||||
**Pattern from `tests/unit/game-logic.test.js`:**
|
||||
|
||||
```javascript
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('Game Logic - Inventory Management', () => {
|
||||
describe('Barrel Calculations', () => {
|
||||
it('should calculate correct fuel barrel count', () => {
|
||||
const fuel = 100;
|
||||
const barrelCount = Math.ceil(fuel / 10);
|
||||
expect(barrelCount).toBe(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Test Organization:**
|
||||
- Top-level `describe()` blocks group by feature/system (e.g., "Game Logic - Inventory Management")
|
||||
- Nested `describe()` blocks organize related tests (e.g., "Barrel Calculations")
|
||||
- Individual `it()` blocks test single logical assertions
|
||||
- Test names are descriptive: "should [expected behavior]"
|
||||
|
||||
## E2E Test Structure
|
||||
|
||||
**Framework:** Playwright with page object patterns
|
||||
|
||||
**Pattern from `tests/e2e/game-flow.spec.js`:**
|
||||
|
||||
```javascript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Whale Hunting Game - Main Flow', () => {
|
||||
test('should load the intro scene', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const canvas = page.locator('canvas');
|
||||
await expect(canvas).toBeVisible();
|
||||
|
||||
await expect(page).toHaveTitle(/Whale Hunting/);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Test Organization:**
|
||||
- `test.describe()` blocks group related scenarios
|
||||
- Individual `test()` blocks test user flows
|
||||
- Setup patterns: `test.beforeEach()` for common navigation
|
||||
- Viewport configuration: `test.use()` for device-specific testing
|
||||
- Async/await pattern for all page interactions
|
||||
|
||||
## Mocking
|
||||
|
||||
**Framework:** None configured or used
|
||||
|
||||
**Patterns:**
|
||||
- No mocks found in unit tests
|
||||
- Tests verify pure calculation logic (Math.ceil, Math.min)
|
||||
- E2E tests work with actual running game instance
|
||||
|
||||
**What to Mock:**
|
||||
- Not applicable; unit tests use pure functions without external dependencies
|
||||
- Phaser framework is not mocked (games tested in browser context)
|
||||
|
||||
**What NOT to Mock:**
|
||||
- Scene transitions (tested via canvas visibility)
|
||||
- Phaser game instances (tested via E2E)
|
||||
|
||||
## Fixtures and Test Data
|
||||
|
||||
**Test Data:**
|
||||
```javascript
|
||||
// Direct inline values
|
||||
it('should calculate correct fuel barrel count', () => {
|
||||
const fuel = 100;
|
||||
const barrelCount = Math.ceil(fuel / 10);
|
||||
expect(barrelCount).toBe(10);
|
||||
});
|
||||
|
||||
// Inventory object template
|
||||
const inventory = { whaleOil: 0, fuel: 100, penguins: 0 };
|
||||
```
|
||||
|
||||
**Location:**
|
||||
- No shared fixture files; test data created inline within test functions
|
||||
- Inventory object structure repeated across multiple tests
|
||||
|
||||
## Coverage
|
||||
|
||||
**Configuration:**
|
||||
```javascript
|
||||
// vitest.config.js
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html', 'lcov'],
|
||||
exclude: [
|
||||
'node_modules/',
|
||||
'dist/',
|
||||
'*.config.js',
|
||||
'tests/e2e/**'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**View Coverage:**
|
||||
```bash
|
||||
npm run test:coverage
|
||||
# Creates HTML report in coverage/
|
||||
# View: coverage/index.html
|
||||
```
|
||||
|
||||
**Excluded from Coverage:**
|
||||
- E2E tests (`tests/e2e/**`)
|
||||
- Config files (`*.config.js`)
|
||||
- Dependencies and build output
|
||||
|
||||
## Test Types
|
||||
|
||||
**Unit Tests:**
|
||||
- Scope: Pure calculation logic (barrel counts, fuel consumption, bounds checking)
|
||||
- Approach: Direct function calls with known inputs
|
||||
- No DOM interaction; test game logic in isolation
|
||||
- Coverage: `tests/unit/game-logic.test.js`
|
||||
- Examples:
|
||||
- Barrel calculation: `Math.ceil(fuel / 10)`
|
||||
- Inventory limits: `Math.min(currentFuel + 10, maxFuel)`
|
||||
- Whale health: Health deduction logic
|
||||
- Mobile detection: User agent regex testing
|
||||
- Crosshair bounds: Clamp function testing
|
||||
|
||||
**Integration Tests:**
|
||||
- Not explicitly used
|
||||
- Closest: E2E tests that verify scene transitions
|
||||
|
||||
**E2E Tests:**
|
||||
- Scope: Complete user workflows (game startup to hunting)
|
||||
- Approach: Browser automation via Playwright
|
||||
- Tests: Canvas visibility, scene transitions, button clicks, viewport scaling
|
||||
- Coverage: `tests/e2e/game-flow.spec.js`
|
||||
- Desktop & mobile scenarios tested with viewport configuration
|
||||
- Examples:
|
||||
- "should load the intro scene"
|
||||
- "should navigate to hunting grounds"
|
||||
- "should work on mobile viewport"
|
||||
- "should scale properly on desktop"
|
||||
|
||||
## Common Patterns
|
||||
|
||||
**Async Testing (E2E):**
|
||||
```javascript
|
||||
test('should start game from intro scene', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const canvas = page.locator('canvas');
|
||||
await canvas.click({ position: { x: 400, y: 400 } });
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
await expect(canvas).toBeVisible();
|
||||
});
|
||||
```
|
||||
|
||||
- `async ({ page })` destructures Playwright fixture
|
||||
- `await` on page navigation and interactions
|
||||
- `page.waitForTimeout()` for animation/transition delays
|
||||
- `page.locator()` for element selection
|
||||
|
||||
**Error Testing (Unit):**
|
||||
```javascript
|
||||
it('should not process whale without enough fuel', () => {
|
||||
let fuel = 1;
|
||||
const requiredFuel = 2;
|
||||
const canProcess = fuel >= requiredFuel;
|
||||
expect(canProcess).toBe(false);
|
||||
});
|
||||
```
|
||||
|
||||
- Boolean logic to test conditions
|
||||
- No exception throwing; test state validation
|
||||
|
||||
**Mobile Testing (E2E):**
|
||||
```javascript
|
||||
test.describe('Mobile Compatibility', () => {
|
||||
test.use({
|
||||
viewport: { width: 375, height: 667 },
|
||||
isMobile: true,
|
||||
});
|
||||
|
||||
test('should work on mobile viewport', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const canvas = page.locator('canvas');
|
||||
await expect(canvas).toBeVisible();
|
||||
|
||||
const canvasBox = await canvas.boundingBox();
|
||||
expect(canvasBox?.width).toBeLessThanOrEqual(375);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- `test.use()` sets viewport and device context
|
||||
- Tap interactions: `canvas.tap()`
|
||||
- BoundingBox assertions: verify canvas scaling
|
||||
|
||||
## Test Isolation
|
||||
|
||||
**Setup:**
|
||||
- E2E tests use `test.beforeEach()` for repeated navigation setup
|
||||
- No shared state between tests
|
||||
- Each test starts fresh from home page
|
||||
|
||||
**Teardown:**
|
||||
- Playwright automatically closes browser context between tests
|
||||
- No explicit cleanup required
|
||||
|
||||
## Configuration Details
|
||||
|
||||
**Vitest (`vitest.config.js`):**
|
||||
- Environment: jsdom (browser-like DOM)
|
||||
- Globals enabled: `describe`, `it`, `expect` available without imports
|
||||
- Include pattern: `tests/unit/**/*.test.js`
|
||||
- Server runs on port 51204 for Vitest UI
|
||||
|
||||
**Playwright (`playwright.config.js`):**
|
||||
- Projects: Chromium and mobile (iPhone 12)
|
||||
- Base URL: `http://localhost:5173` (dev server)
|
||||
- Test directory: `tests/e2e/`
|
||||
- Retries: 2 in CI, 0 locally
|
||||
- Screenshots: Only on failure
|
||||
- Trace: On first retry
|
||||
- Server: Runs `npm run dev` before tests
|
||||
|
||||
## Test Execution Flow
|
||||
|
||||
1. **Unit Tests (Vitest):**
|
||||
- Runs isolated game logic tests
|
||||
- Uses jsdom environment
|
||||
- No Phaser instance needed
|
||||
- Fast execution
|
||||
|
||||
2. **E2E Tests (Playwright):**
|
||||
- Starts dev server via `npm run dev`
|
||||
- Launches Chromium and mobile browsers
|
||||
- Navigates to `http://localhost:5173`
|
||||
- Performs user interactions
|
||||
- Verifies game state via canvas visibility
|
||||
- Slower execution but tests full stack
|
||||
|
||||
## Coverage Gaps
|
||||
|
||||
**Not Tested (Unit):**
|
||||
- Scene rendering and graphics creation
|
||||
- Phaser animation timing and tweens
|
||||
- Player input handling (mouse/touch)
|
||||
- Collision detection logic
|
||||
|
||||
**Not Tested (E2E):**
|
||||
- Detailed game mechanics (whale health, harpoon trajectory)
|
||||
- Inventory state persistence
|
||||
- Exact positioning of game elements
|
||||
- Performance under load
|
||||
|
||||
---
|
||||
|
||||
*Testing analysis: 2026-02-04*
|
||||
Reference in New Issue
Block a user