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.

Informations de source

Dépôt
Hack23/blacktrigram
Dernière activité de la source
31 janvier 2026 à 15:54
Langue détectée de SKILL.md
anglais
Étoiles
8
Forks
7

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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', () => {
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub