원클릭으로
testing-strategy
// Vitest + Cypress + RTL — deterministic tests, ≥80% line / ≥70% branch coverage, ≥95% on security code, Three.js component testing
// Vitest + Cypress + RTL — deterministic tests, ≥80% line / ≥70% branch coverage, ≥95% on security code, Three.js component testing
AI-assisted development governance — Copilot custom agents, MCP servers, change control, audit trail — per Hack23 ISMS AI Policy
Clear technical documentation — JSDoc, Mermaid, READMEs, ADRs, C4 diagrams, ISMS policy citations
Hack23 ISMS alignment — ISO 27001:2022, NIST CSF 2.0, CIS Controls v8.1, GDPR, NIS2, EU CRA — with policy citations
React re-render optimization, Three.js rendering performance, useMemo/useCallback, bundle size, 60 fps profiling, Lighthouse budgets
Three.js game development with React using @react-three/fiber and @react-three/drei — strict TypeScript, 60 fps, accessible
Defense-in-depth security principles — OWASP Top 10 prevention, input validation, secure error handling, encryption, least privilege
| name | testing-strategy |
| description | Vitest + Cypress + RTL — deterministic tests, ≥80% line / ≥70% branch coverage, ≥95% on security code, Three.js component testing |
| license | MIT |
Applies when writing unit tests, E2E tests, testing Three.js components, mocking dependencies, measuring coverage, diagnosing flakes, or preparing test data.
Aligned with Secure Development Policy §Unit Test Coverage & Quality.
data-testid allowed on intentvi.clearAllMocks() in beforeEachDate.now, Math.random, timers; no real networkimport { render, screen } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { HUD } from './HUD';
const mockGameState = {
score: 42, isPlaying: true, timeLeft: 30, combo: 0,
highScore: 100, targetSize: 0.5, level: 1, isNewHighScore: false,
targets: [] as unknown[], totalClicks: 10, successfulHits: 5,
} as const;
describe('HUD', () => {
beforeEach(() => { vi.clearAllMocks(); });
it('should display the current score', () => {
render(<HUD gameState={mockGameState} />);
expect(screen.getByText(/42/)).toBeInTheDocument();
});
});
import { describe, it, expect } from 'vitest';
import { calculateLevel, getTargetCountForLevel } from './gameConfig';
describe('gameConfig', () => {
it('should return level 1 for score 0', () => {
expect(calculateLevel(0)).toBe(1);
});
it('should return 1 target for levels 1-3', () => {
expect(getTargetCountForLevel(1)).toBe(1);
expect(getTargetCountForLevel(3)).toBe(1);
});
});
import type { ReactNode } from 'react';
import { vi } from 'vitest';
vi.mock('@react-three/fiber', () => ({
Canvas: ({ children }: { children: ReactNode }) => <div>{children}</div>,
useFrame: vi.fn(),
useThree: () => ({ camera: {}, scene: {}, gl: {} }),
}));
vi.mock('@react-three/drei', () => ({
Sparkles: ({ children }: { children?: ReactNode }) => <>{children}</>,
Trail: ({ children }: { children?: ReactNode }) => <>{children}</>,
}));
import { vi, afterEach } from 'vitest';
beforeEach(() => {
const seq = [0.1, 0.2, 0.3];
let i = 0;
vi.spyOn(Math, 'random').mockImplementation(() => seq[i++ % seq.length]);
});
afterEach(() => { vi.restoreAllMocks(); });
it('should reject non-finite scores', () => {
expect(() => saveHighScore(Number.NaN)).toThrow(RangeError);
expect(() => saveHighScore(Infinity)).toThrow(RangeError);
expect(() => saveHighScore(-1)).toThrow(RangeError);
});
// BAD: testing implementation
expect(component.state.internalValue).toBe(5);
// BAD: non-deterministic
expect(result).toBe(Math.random());
// BAD: vague test name
it('works', () => { /* … */ });
// BAD: shared state between tests
let counter = 0;
it('t1', () => { counter++; });
it('t2', () => { expect(counter).toBe(1); }); // order-dependent!
// BAD: production data
const user = { email: 'real.user@company.com' }; // PII in tests
retry as a workaroundsrc/utils/npm run test:ci, npm run test:e2e:ci)