2d-games
무료2D game development principles. Sprites, tilemaps, physics, camera.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Comprehensive testing skill covering unit, integration, and e2e testing with TDD. Use when writing tests, improving coverage, or setting up testing infrastructure. Keywords: test, TDD, unit test, integration, e2e, coverage, mock, jest, vitest
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Philosophy: If it's not tested, it's broken. You just don't know it yet.
Use this skill when:
Do NOT use this skill when:
╱╲
╱ ╲
╱ E2E╲ Few, slow, expensive
╱──────╲ Full system tests
╱ ╲
╱Integration╲ Medium amount
╱────────────╲ Component interaction
╱ ╲
╱ Unit Tests ╲ Many, fast, cheap
╱──────────────────╲ Single unit isolation
// Write the test BEFORE the implementation
describe('calculateDiscount', () => {
it('should apply 10% discount for orders over $100', () => {
// This test will FAIL because function doesn't exist yet
const result = calculateDiscount(150);
expect(result).toBe(135);
});
});
Run test → Should FAIL (RED)
// Write the MINIMUM code to pass the test
function calculateDiscount(amount: number): number {
if (amount > 100) {
return amount * 0.9;
}
return amount;
}
Run test → Should PASS (GREEN)
// Improve code while keeping tests green
const DISCOUNT_THRESHOLD = 100;
const DISCOUNT_RATE = 0.1;
function calculateDiscount(amount: number): number {
if (amount > DISCOUNT_THRESHOLD) {
return amount * (1 - DISCOUNT_RATE);
}
return amount;
}
Run test → Should still PASS
describe('UserService', () => {
describe('createUser', () => {
it('should create user with valid data', async () => {
// Arrange
const userData = { email: 'test@example.com', name: 'Test' };
const mockRepo = { create: jest.fn().mockResolvedValue({ id: '1', ...userData }) };
const service = new UserService(mockRepo);
// Act
const result = await service.createUser(userData);
// Assert
expect(result.id).toBe('1');
expect(result.email).toBe(userData.email);
expect(mockRepo.create).toHaveBeenCalledWith(userData);
});
});
});
describe('createUser', () => {
it('should throw on duplicate email', async () => {
// Arrange
const mockRepo = {
findByEmail: jest.fn().mockResolvedValue({ id: 'existing' }),
};
const service = new UserService(mockRepo);
// Act & Assert
await expect(
service.createUser({ email: 'exists@example.com' })
).rejects.toThrow('Email already registered');
});
});
describe('fetchUserData', () => {
it('should fetch and transform user data', async () => {
// Arrange
const mockApi = {
get: jest.fn().mockResolvedValue({ data: { name: 'John' } }),
};
// Act
const result = await fetchUserData(mockApi, 'user-id');
// Assert
expect(result).toEqual({ name: 'John' });
expect(mockApi.get).toHaveBeenCalledWith('/users/user-id');
});
it('should handle API errors gracefully', async () => {
const mockApi = {
get: jest.fn().mockRejectedValue(new Error('Network error')),
};
await expect(fetchUserData(mockApi, 'user-id'))
.rejects.toThrow('Failed to fetch user');
});
});
// Create mock function
const mockFn = jest.fn();
// Define return value
mockFn.mockReturnValue('static value');
mockFn.mockResolvedValue('async value');
mockFn.mockRejectedValue(new Error('error'));
// Implementation
mockFn.mockImplementation((x) => x * 2);
// Verify calls
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');
expect(mockFn).toHaveBeenCalledTimes(3);
// Mock entire module
jest.mock('./database', () => ({
connect: jest.fn(),
query: jest.fn(),
}));
// Mock with factory
jest.mock('./config', () => ({
get: (key: string) => {
const config = { API_URL: 'http://test-api.com' };
return config[key];
},
}));
// Spy on existing method
const spy = jest.spyOn(userService, 'sendEmail');
// Call the code
await userService.createUser({ email: 'test@example.com' });
// Verify the spy
expect(spy).toHaveBeenCalled();
// Restore original
spy.mockRestore();
describe('POST /users', () => {
let app: Express;
let db: Database;
beforeAll(async () => {
db = await Database.connect(TEST_DB_URL);
app = createApp(db);
});
afterAll(async () => {
await db.disconnect();
});
beforeEach(async () => {
await db.clear('users');
});
it('should create user and return 201', async () => {
const response = await request(app)
.post('/users')
.send({ email: 'test@example.com', password: 'Password123!' })
.expect(201);
expect(response.body.email).toBe('test@example.com');
expect(response.body.password).toBeUndefined();
// Verify in database
const user = await db.users.findOne({ email: 'test@example.com' });
expect(user).toBeDefined();
});
it('should return 400 for invalid email', async () => {
const response = await request(app)
.post('/users')
.send({ email: 'invalid', password: 'Password123!' })
.expect(400);
expect(response.body.errors).toContainEqual(
expect.objectContaining({ field: 'email' })
);
});
});
describe('UserRepository', () => {
let db: Database;
let repo: UserRepository;
beforeAll(async () => {
db = await Database.connect(TEST_DB_URL);
repo = new UserRepository(db);
});
beforeEach(async () => {
await db.clear('users');
await db.seed('users', testUsers);
});
it('should find user by email', async () => {
const user = await repo.findByEmail('john@example.com');
expect(user?.name).toBe('John Doe');
});
it('should return null for non-existent email', async () => {
const user = await repo.findByEmail('nobody@example.com');
expect(user).toBeNull();
});
});
import { test, expect } from '@playwright/test';
test.describe('User Registration', () => {
test('should complete registration flow', async ({ page }) => {
// Navigate to registration
await page.goto('/register');
// Fill form
await page.fill('[data-testid="email"]', 'newuser@example.com');
await page.fill('[data-testid="password"]', 'SecurePassword123!');
await page.fill('[data-testid="name"]', 'New User');
// Submit
await page.click('[data-testid="submit"]');
// Verify redirect to dashboard
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('[data-testid="welcome-message"]'))
.toContainText('Welcome, New User');
});
test('should show validation errors', async ({ page }) => {
await page.goto('/register');
await page.fill('[data-testid="email"]', 'invalid-email');
await page.click('[data-testid="submit"]');
await expect(page.locator('[data-testid="email-error"]'))
.toBeVisible();
});
});
coverage_targets:
statements: 80%
branches: 80%
functions: 80%
lines: 80%
priority_areas:
critical: 95%+ # Auth, payments, core business logic
high: 85%+ # API endpoints, services
medium: 70%+ # Utilities, helpers
low: 50%+ # UI components, config
// jest.config.js
module.exports = {
collectCoverage: true,
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/**/*.stories.{ts,tsx}',
'!src/test/**/*',
],
};
| Cause | Symptom | Solution |
|---|---|---|
| Race conditions | Fails randomly | Add proper waits, use async/await correctly |
| Shared state | Fails when run together | Isolate test data, proper cleanup |
| Time-dependent | Fails at certain times | Mock Date/time |
| External dependencies | Fails intermittently | Mock external services |
| Order dependency | Fails when run in different order | Make tests independent |
// Add retries for known flaky tests (use sparingly!)
test('flaky network test', { retry: 2 }, async () => {
// ...
});
// Log more info on failure
afterEach(function() {
if (this.currentTest?.state === 'failed') {
console.log('Test state:', JSON.stringify(testState, null, 2));
}
});
// Increase timeout if needed
test('slow test', async () => {
// ...
}, 30000); // 30 second timeout
src/
├── users/
│ ├── users.service.ts
│ ├── users.service.spec.ts # Unit tests
│ └── users.controller.ts
│
tests/
├── unit/ # Additional unit tests
├── integration/
│ ├── api/
│ │ └── users.api.spec.ts
│ └── db/
│ └── users.repo.spec.ts
├── e2e/
│ └── user-registration.spec.ts
├── fixtures/
│ └── users.fixture.ts
└── helpers/
├── database.helper.ts
└── auth.helper.ts
// Use descriptive names
describe('UserService')
describe('createUser method')
// "should" format
it('should create user with valid data')
it('should throw when email is duplicate')
it('should hash password before saving')
// Given-When-Then for complex scenarios
it('given authenticated admin, when deleting user, should succeed')
test_quality:
- Tests run independently in any order
- Tests don't depend on external services
- Tests are deterministic (not flaky)
- Tests are fast (<100ms for unit tests)
- Tests have meaningful assertions
- Tests cover happy path AND error cases
- Tests are readable and maintainable
- Tests use realistic data
Before considering testing complete:
skills/kilo-kit/quality/code-review/ - For reviewing test qualityskills/kilo-kit/debugging/verification/ - For verifying fixesskills/kilo-kit/development/backend/ - For testing APIsTesting Strategy Skill v1.0.0 — Test it or regret it
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
2D game development principles. Sprites, tilemaps, physics, camera.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
3D game development principles. Rendering, shaders, physics, cameras.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Create aesthetically beautiful interfaces following proven design principles. Use when building UI/UX, analyzing designs from inspiration sites, generating design images with ai-multimodal, implementing visual hierarchy and color theory, adding micro-interactions, or creating design documentation. Includes workflows for capturing and analyzing inspiration screenshots with chrome-devtools and ai-multimodal, iterative design image generation until aesthetic standards are met, and comprehensive design system guidance covering BEAUTIFUL (aesthetic principles), RIGHT (functionality/accessibility), SATISFYING (micro-interactions), and PEAK (storytelling) stages. Integrates with chrome-devtools, ai-multimodal, media-processing, ui-styling, and web-frameworks skills.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when implementing or managing persistent, hierarchical memory systems for AI agents. Covers cross-session state, fact supersession, and self-managed memory tools to enable long-term recall and adaptive agent behavior.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when monitoring, tracing, or debugging agentic workflows in production. Keywords: observability, tracing, OpenTelemetry, Langfuse, latency, token cost, loop detection, telemetry.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when building self-correcting retrieval systems for AI agents. Keywords: RAG, retrieval, Corrective RAG, Self-RAG, query decomposition, reranking, hallucination, grounding.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.