π ISMS Alignment: This unit test plan implements Secure Development Policy Section 4.3.1 - Unit Testing Requirements.
This document outlines the comprehensive unit testing strategy for the Black Trigram (νκ΄) project - a realistic 3D precision combat game inspired by Korean martial arts philosophy and the I Ching. The application is built using React 19 with TypeScript and Three.js (@react-three/fiber), with unit tests implemented using Vitest 4.
Per Hack23 AB's Secure Development Policy, this project maintains:
| π― Requirement | π Target | β Current | π ISMS Reference |
|---|---|---|---|
| Line Coverage | β₯80% | 69.72% |
Section 4.3.1.1 |
| Branch Coverage | β₯70% | 60.87% |
Section 4.3.1.2 |
| Test Execution | Every commit | β Automated | Section 4.3.1.3 |
| Public Reporting | Required | β Published | Section 4.3.1.4 |
Evidence Links:
See Also:
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Unit Testing | Vitest | 4.0.6 | Modern, fast unit test runner |
| E2E Testing | Cypress | 15.6.0 | End-to-end browser testing |
| Component Testing | @testing-library/react | 16.3.0 | React component testing utilities |
| Coverage Tool | @vitest/coverage-v8 | 4.0.8 | V8-based code coverage reporting |
| Test Environment | jsdom | 27.2.0 | DOM simulation for Node.js |
| UI Testing | @vitest/ui | 4.0.6 | Visual test interface |
| Coverage Reports | text, html, lcov, json | - | Multiple formats with full filenames (120 cols) |
Black Trigram uses Three.js with @react-three/fiber for game rendering, requiring special test configuration:
// vitest.config.ts
test: {
environment: 'jsdom',
setupFiles: ['./src/test/test-setup.ts'],
server: {
deps: {
inline: [], // Three.js works well with Vitest by default
},
},
}Tests must validate:
- β All 8 trigram stances (건/ν/리/μ§/μ/κ°/κ°/κ³€)
- β All 5 player archetypes (무μ¬/μμ΄μ/ν΄μ»€/μ 보μμ/μ‘°μ§νλ ₯λ°°)
- β Korean-English bilingual text rendering
- β Vital point system accuracy (70 anatomical targets)
- β Combat effectiveness calculations
- β Cultural authenticity of Korean martial arts representation
Unit tests are placed alongside their implementation files with the .test.ts or .test.tsx extension:
src/
βββ systems/
β βββ CombatSystem.ts
β βββ CombatSystem.test.ts # Core combat mechanics tests
β βββ TrigramSystem.ts
β βββ TrigramSystem.test.ts # Eight trigram stance tests
β βββ VitalPointSystem.ts
β βββ VitalPointSystem.test.ts # Vital point targeting tests
β βββ GameIntegration.test.ts # Integration tests
β βββ trigram/
β β βββ StanceManager.ts
β β βββ StanceManager.test.ts # Stance transition logic
β β βββ KoreanCulture.ts
β β βββ KoreanCulture.test.ts # Korean culture validation
β β βββ KoreanTechniques.ts
β β βββ KoreanTechniques.test.ts # Korean technique authenticity
β β βββ TransitionCalculator.ts
β β βββ TransitionCalculator.test.ts
β βββ vitalpoint/
β βββ KoreanAnatomy.ts
β βββ DamageCalculator.ts
β βββ HitDetection.ts
β βββ (tests to be added)
βββ components/
β βββ ui/
β β βββ KoreanHeader.test.tsx # Korean text rendering
β β βββ base/
β β βββ (Three.js 3D components)
β βββ game/
β β βββ DojangBackground.test.tsx # Korean dojo aesthetics
β β βββ GameAudio.test.tsx
β βββ combat/
β βββ components/
β βββ CombatHUD.test.tsx
β βββ CombatControls.test.tsx
β βββ CombatStatsPanel.test.tsx
βββ audio/
β βββ AudioManager.test.ts
β βββ AudioUtils.test.ts
βββ utils/
βββ playerUtils.test.ts # Player archetype creation
| Category | Purpose | Examples | Coverage Target |
|---|---|---|---|
| System Tests | Core game mechanics | Combat, Trigram, VitalPoint systems | 90%+ |
| Component Tests | React/Three.js components | UI elements, game graphics | 70%+ |
| Integration Tests | Multi-system workflows | Complete combat sequences | 80%+ |
| Utility Tests | Helper functions | Player creation, calculations | 90%+ |
| Cultural Tests | Korean authenticity | Names, techniques, stances | 100% |
As of Latest Coverage Run (December 2025):
- Total Tests: 1,192 tests (passed) + 2 skipped = 1,194 total
- Test Files: 63 test suites
- Test Duration: ~40 seconds
- Pass Rate: 100% (1,192/1,192 passing)
- Flaky Tests: 0 β
All tests follow the Arrange-Act-Assert pattern:
import { describe, it, expect, beforeEach } from "vitest";
describe("VitalPointSystem", () => {
it("should calculate damage based on vital point criticality", () => {
// Arrange
const system = new VitalPointSystem();
const criticalPoint = system.getVitalPoint("νμν"); // Solar plexus
const normalPoint = system.getVitalPoint("볡λΆ"); // Abdomen
// Act
const criticalDamage = system.calculateDamage(criticalPoint, 50);
const normalDamage = system.calculateDamage(normalPoint, 50);
// Assert
expect(criticalDamage).toBeGreaterThan(normalDamage);
expect(criticalPoint.korean).toBe("νμν");
});
});React/Three.js components must test:
describe("KoreanHeader", () => {
it("renders Korean and English text", () => {
const { container } = render(
<KoreanHeader korean="νκ΄" english="Black Trigram" />
);
expect(container).toHaveTextContent("νκ΄");
expect(container).toHaveTextContent("Black Trigram");
});
it("uses Korean font family", () => {
render(<KoreanHeader korean="무μ¬" english="Warrior" />);
const text = screen.getByText(/무μ¬/);
expect(text).toHaveStyle({ fontFamily: FONT_FAMILY.KOREAN });
});
});// src/test/test-setup.ts
// Three.js mocking if needed (usually not required for basic tests)
vi.mock("three", () => ({
WebGLRenderer: vi.fn(() => ({
render: vi.fn(),
setSize: vi.fn(),
dispose: vi.fn(),
})),
Scene: vi.fn(),
PerspectiveCamera: vi.fn(),
Mesh: vi.fn(),
BoxGeometry: vi.fn(),
MeshStandardMaterial: vi.fn(),
Texture: {
from: vi.fn(() => ({})),
WHITE: {},
},
}));vi.mock("../audio/AudioProvider", () => ({
useAudio: vi.fn(() => ({
playSFX: vi.fn(),
playMusic: vi.fn(),
setVolume: vi.fn(),
})),
}));Every function must test:
- β Happy path (expected input)
- β Boundary conditions (min/max values)
- β Invalid input (null, undefined, negative)
- β Error handling and recovery
describe("applyDamage", () => {
it("should handle negative damage", () => {
const player = createPlayer();
const result = applyDamage(player, -10);
expect(result.health).toBe(player.health); // No change
});
it("should clamp health to zero", () => {
const player = createPlayer({ health: 50 });
const result = applyDamage(player, 100);
expect(result.health).toBe(0);
expect(result.health).toBeGreaterThanOrEqual(0);
});
});Per ISMS Secure Development Policy:
| Metric | Policy Minimum | Current | Status | Target Date |
|---|---|---|---|---|
| Line Coverage | 80% | 69.72% | Q1 2026 | |
| Branch Coverage | 70% | 60.87% | Q1 2026 | |
| Function Coverage | 75% | 68.00% | Q1 2026 | |
| Statement Coverage | 80% | 69.06% | Q1 2026 |
| Component | Current | Target | Priority | Status |
|---|---|---|---|---|
| Systems (Core) | 95.88% | 90% | High | β Excellent |
| - TrigramSystem | 95.34% | 90% | High | β Excellent |
| - VitalPointSystem | 95.34% | 90% | High | β Excellent |
| - CombatSystem | 94.31% | 90% | Critical | β Excellent |
| Audio | 84.51% | 70% | Medium | β Excellent |
| - AudioManager | 24.62% | 70% | Medium | β Major Gap |
| - AudioUtils | 34.66% | 70% | Medium | β Major Gap |
| Combat Hooks | 84.44% | 70% | High | β Excellent |
| - useCombatLayout | 100.00% | 90% | High | β Excellent |
| UI Components | 32.69% | 70% | Medium | β Major Gap |
| - HealthBar | 25.28% | 70% | Medium | β Major Gap |
| - RoundTimer | 40.00% | 70% | Medium | β Major Gap |
| - StanceIndicator | 29.16% | 70% | Medium | β Major Gap |
| Combat Components | 63.18% | 70% | High | |
| - CombatControls | 24.44% | 70% | High | β Critical Gap |
| - CombatHUD | 16.66% | 70% | High | β Critical Gap |
| - CombatStatsPanel | 34.69% | 70% | High | β Major Gap |
| Vital Point System | 93.33% | 90% | Critical | β Excellent |
| - DamageCalculator | 0.00% | 90% | Critical | β Not Tested |
| - HitDetection | 0.00% | 90% | Critical | β Not Tested |
| - KoreanAnatomy | 19.76% | 90% | Critical | β Critical Gap |
| Utilities | 62.82% | 80% | High | |
| - playerUtils | 94.11% | 90% | High | β Excellent |
| - threeHelpers | 18.36% | 70% | Medium | β Major Gap |
Coverage thresholds are enforced in vitest.config.ts:
coverage: {
provider: 'v8',
reporter: [
['text', { maxCols: 120 }], // Wide columns for full filenames
['html', { subdir: 'html' }], // HTML report in subdirectory
['lcov', { file: 'lcov.info' }], // LCOV format for CI integration
['json', { file: 'coverage.json' }], // JSON format for tooling
['json-summary', { file: 'coverage-summary.json' }], // Summary JSON
],
reportsDirectory: './build/coverage',
skipFull: false, // Show files with 100% coverage
// Note: Global thresholds commented out to avoid breaking existing code
// These should be enforced via CI checks for new/changed files only
// thresholds: {
// lines: 80,
// branches: 70,
// functions: 75,
// statements: 80,
// },
}Regression Prevention: Coverage reports are generated on every commit via CI/CD pipeline to prevent regressions.
| Command | Purpose | Use Case |
|---|---|---|
npm test |
Run all tests once | Quick validation |
npm run test:systems |
Run system tests only | Core mechanics validation |
npm run test:systems:watch |
Watch mode for systems | Active development |
npm run test:systems:ui |
Visual test UI | Interactive debugging |
npm run coverage |
Generate coverage report | Coverage analysis |
npm run test:ci |
CI test execution | Automated pipeline |
# Generate full coverage report with enhanced formatting
npm run coverage
# View HTML coverage report (detailed, interactive)
open build/coverage/html/index.html
# Check specific system coverage
npm run test:systems:coverageCoverage Report Features:
- Text Report: 120-column width for full filenames (no truncation)
- HTML Report: Interactive web interface with drill-down capabilities
- LCOV Report: Standard format for CI/CD integration (e.g., Codecov, Coveralls)
- JSON Reports: Machine-readable formats for custom tooling and analysis
- Summary JSON: Quick overview of overall coverage metrics
Coverage Report Locations:
- HTML Report:
build/coverage/html/index.html - LCOV Report:
build/coverage/lcov.info - JSON Report:
build/coverage/coverage.json - JSON Summary:
build/coverage/coverage-summary.json - Note: Coverage reports are in
build/directory (excluded from git)
# Run tests with UI for debugging
npm run test:systems:ui
# Run specific test file
npx vitest src/systems/CombatSystem.test.ts
# Run tests matching pattern
npx vitest --grep "Korean"
# Debug in Node inspector
node --inspect-brk ./node_modules/.bin/vitestTests are automatically executed via .github/workflows/test-and-report.yml:
name: Test and Report
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
node-version: "25"
- name: Install dependencies
run: npm install
- name: Run unit tests with coverage
run: npm run coverage
env:
JEST_JUNIT_OUTPUT_DIR: "docs/coverage"
JEST_JUNIT_OUTPUT_NAME: "junit.xml"