Skip to main content

testing-strategy-enforcement

Enforces comprehensive testing standards for Black Trigram including >90% coverage, unit tests (Vitest), E2E tests (Cypress), Three.js component testing, performance testing (60fps target), and accessibility testing. Ensures test quality and coverage.

Quellinformationen

Repository
Hack23/blacktrigram
Letzte Quellaktivität
31. Januar 2026 um 15:54
Erkannte Sprache von SKILL.md
Englisch
Sterne
8
Forks
7

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
testing-strategy-enforcement
description
Enforces comprehensive testing standards for Black Trigram including >90% coverage, unit tests (Vitest), E2E tests (Cypress), Three.js component testing, performance testing (60fps target), and accessibility testing. Ensures test quality and coverage.
license
MIT
# Testing Strategy Enforcement Skill ## Purpose This skill ensures that all code changes in Black Trigram maintain exceptional test coverage, proper testing strategies across unit/E2E layers, and validate performance and accessibility standards throughout the codebase. ## When to Apply **Automatically trigger this skill when:** - Adding new features or components - Modifying existing game logic or systems - Implementing UI components (React or Three.js) - Working with combat, animation, or vital point systems - Creating or updating state management logic - Adding performance-critical code - Implementing accessibility features - Refactoring existing code - Reviewing pull requests with code changes ## Core Principles ### 1. Test Coverage Requirements **ALWAYS maintain these coverage thresholds:** ✅ **Overall Coverage Targets** ```typescript // Partial excerpt from vitest.config.ts - Coverage configuration import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { coverage: { provider: 'v8', reporter: ['text', 'json', 'html', 'lcov'], lines: 90, // Minimum 90% line coverage functions: 90, // Minimum 90% function coverage branches: 85, // Minimum 85% branch coverage statements: 90, // Minimum 90% statement coverage exclude: [ 'node_modules/', 'dist/', 'coverage/', '**/*.test.ts', '**/*.test.tsx', 'src/test/**', ], }, }, }); ``` ✅ **Coverage by Component Type** ```typescript // Target coverage levels per component category const COVERAGE_TARGETS = { // Core game systems - CRITICAL combatSystem: { unit: 95, e2e: 85 }, vitalPointSystem: { unit: 95, e2e: 80 }, trigramSystem: { unit: 95, e2e: 80 }, animationSystem: { unit: 90, e2e: 75 }, // Three.js components - MODERATE (harder to test) threejsComponents: { unit: 85, e2e: 70 }, sceneComponents: { unit: 85, e2e: 70 }, // UI components - HIGH reactComponents: { unit: 95, e2e: 80 }, screens: { unit: 90, e2e: 85 }, // Utility functions - MAXIMUM utilities: { unit: 100, e2e: 0 }, constants: { unit: 100, e2e: 0 }, // Audio system - HIGH audioSystem: { unit: 90, e2e: 75 }, // State management - CRITICAL stateManagement: { unit: 95, e2e: 80 }, } as const; ``` ### 2. Unit Testing Strategy (Vitest) **ALWAYS write comprehensive unit tests:** ✅ **Test File Organization** ```typescript // ALWAYS place unit tests in __tests__ directory src/ ├── systems/ │ ├── combat/ │ │ ├── CombatSystem.ts │ │ └── __tests__/ │ │ ├── CombatSystem.test.ts │ │ ├── VitalPointSystem.test.ts │ │ └── DamageCalculation.test.ts │ ├── trigram/ │ │ ├── TrigramSystem.ts │ │ └── __tests__/ │ │ └── TrigramSystem.test.ts ``` ✅ **Comprehensive Test Structure** ```typescript import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { CombatSystem } from '../CombatSystem'; import { TRIGRAM_STANCES } from '@/types/constants'; describe('CombatSystem', () => { let combatSystem: CombatSystem; beforeEach(() => { // Setup fresh instance for each test combatSystem = new CombatSystem(); }); afterEach(() => { // Cleanup resources vi.clearAllMocks(); }); // Group related tests describe('Stance Management', () => { it('should initialize with Geon stance by default', () => { expect(combatSystem.currentStance).toBe('GEON'); }); it('should transition between all 8 trigram stances', () => { Object.keys(TRIGRAM_STANCES).forEach(stance => { combatSystem.setStance(stance); expect(combatSystem.currentStance).toBe(stance); }); }); it('should reject invalid stance names', () => { expect(() => combatSystem.setStance('INVALID')).toThrow(); }); }); describe('Vital Point Targeting', () => { it('should detect all 70 vital points', () => { const vitalPoints = combatSystem.getVitalPoints(); expect(vitalPoints).toHaveLength(70); }); it('should calculate correct damage for vital point hit', () => { const damage = combatSystem.calculateVitalPointDamage({ point: 'BAIHUI', // GV20 force: 100, accuracy: 0.95, }); expect(damage).toBeGreaterThan(100); // Vital point multiplier expect(damage).toBeLessThanOrEqual(200); }); it('should apply reduced damage for missed vital points', () => { const missedDamage = combatSystem.calculateVitalPointDamage({ point: 'BAIHUI', force: 100, accuracy: 0.3, // Poor accuracy }); expect(missedDamage).toBeLessThan(100); }); }); describe('Performance', () => { it('should calculate combat within 5ms', () => { const start = performance.now(); for (let i = 0; i < 1000; i++) { combatSystem.calculateDamage(100, 0.8, 'BAIHUI'); } const duration = performance.now() - start; expect(duration).toBeLessThan(5); // <5ms per frame budget }); }); describe('Edge Cases', () => { it('should handle zero damage gracefully', () => { const damage = combatSystem.calculateDamage(0, 1.0, 'BAIHUI'); expect(damage).toBe(0); }); it('should handle negative force by clamping to zero', () => { const damage = combatSystem.calculateDamage(-50, 1.0, 'BAIHUI'); expect(damage).toBe(0); }); it('should handle accuracy outside 0-1 range', () => { expect(() => combatSystem.calculateDamage(100, 1.5, 'BAIHUI') ).toThrow(); }); }); }); ``` ✅ **Testing Three.js Components** ```typescript import { render } from '@testing-library/react'; import { Canvas } from '@react-three/fiber'; import { describe, it, expect } from 'vitest'; import { CombatCharacter3D } from '../CombatCharacter3D'; describe('CombatCharacter3D', () => { // Helper to render Three.js components const render3D = (component: React.ReactElement) => { return render( <Canvas data-testid="test-canvas"> <Suspense fallback={null}> {component} </Suspense> </Canvas> ); }; it('should render without crashing', () => { const { container } = render3D( <CombatCharacter3D position={[0, 0, 0]} stance="GEON" /> ); const canvas = container.querySelector('canvas'); expect(canvas).toBeInTheDocument(); }); it('should apply Korean theming colors', () => { const { container } = render3D( <CombatCharacter3D position={[0, 0, 0]} stance="GEON" data-testid="combat-character" /> ); // Verify component renders (color testing requires more complex setup) expect(container).toBeTruthy(); }); it('should update stance color when stance changes', () => { const { rerender } = render3D( <CombatCharacter3D position={[0, 0, 0]} stance="GEON" /> ); rerender( <Canvas> <CombatCharacter3D position={[0, 0, 0]} stance="TAE" /> </Canvas> ); // Verify re-render succeeds expect(true).toBe(true); }); }); ``` ### 3. E2E Testing Strategy (Cypress) **ALWAYS write E2E tests for user workflows:** ✅ **E2E Test Organization** ```typescript // cypress/e2e/ - User workflow tests cypress/ ├── e2e/ │ ├── combat-system.cy.ts // Combat gameplay flows │ ├── trigram-selection.cy.ts // Stance selection UI │ ├── vital-points.cy.ts // Vital point targeting │ ├── intro-screen.cy.ts // Navigation flows │ └── performance.cy.ts // 60fps validation ``` ✅ **Comprehensive E2E Test** ```typescript describe('Combat System E2E', () => { beforeEach(() => { cy.visit('/'); cy.get('[data-testid="start-button"]').click(); cy.get('[data-testid="combat-screen"]').should('be.visible'); }); describe('Trigram Stance Selection', () => { it('should allow selecting all 8 trigram stances', () => { const stances = ['GEON', 'TAE', 'LI', 'JIN', 'SON', 'GAM', 'GAN', 'GON']; stances.forEach(stance => { cy.get(`[data-testid="stance-${stance}"]`).click(); cy.get('[data-testid="current-stance"]') .should('contain', stance); }); }); it('should display bilingual Korean | English text', () => { cy.get('[data-testid="stance-GEON"]') .should('contain', '건') .and('contain', 'Heaven'); }); it('should show trigram symbol (☰)', () => { cy.get('[data-testid="stance-GEON"]') .should('contain', '☰'); }); }); describe('Vital Point Targeting', () => { it('should highlight all 70 vital points', () => { cy.get('[data-testid="vital-point-overlay"]').click(); cy.get('[data-testid^="vital-point-"]') .should('have.length', 70); }); it('should show Korean and TCM names on hover', () => { cy.get('[data-testid="vital-point-BAIHUI"]').trigger('mouseover'); cy.get('[data-testid="vital-point-tooltip"]') .should('contain', '백회') .and('contain', 'Baihui (GV20)'); }); it('should calculate critical damage on precise hit', () => { cy.get('[data-testid="vital-point-BAIHUI"]').click(); cy.get('[data-testid="damage-indicator"]') .should('contain', 'CRITICAL') .and('have.css', 'color', 'rgb(255, 68, 68)'); // KOREAN_COLORS.CRITICAL_HIT }); }); describe('Combat Performance', () => { it('should maintain 60fps during combat', () => { cy.window().then(win => { let frameCount = 0; let lastTime = performance.now(); const measureFPS = () => { const currentTime = performance.now(); const deltaTime = currentTime - lastTime; if (deltaTime >= 1000) { const fps = frameCount / (deltaTime / 1000); expect(fps).to.be.greaterThan(55); // Allow 5fps tolerance frameCount = 0; lastTime = currentTime; } frameCount++; if (frameCount < 300) { // Test for 5 seconds requestAnimationFrame(measureFPS); } }; requestAnimationFrame(measureFPS); }); }); }); describe('Accessibility', () => { it('should be keyboard navigable', () => {
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen