From claude-code-settings
新機能の作成、バグ修正、リファクタリング時に使用。テスト駆動開発を徹底し、ユニット・統合・E2Eテストで80%以上のカバレッジを確保。
npx claudepluginhub joshuarweaver/cascade-code-general-misc-1 --plugin tubone24-claude-code-settingsThis skill uses the workspace's default tool permissions.
このスキルは、すべてのコード開発が包括的なテストカバレッジを持つTDD原則に従うことを保証します。
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
このスキルは、すべてのコード開発が包括的なテストカバレッジを持つTDD原則に従うことを保証します。
常に最初にテストを書き、その後テストを通すコードを実装します。
[役割]として、[アクション]したい、そうすれば[メリット]
例:
ユーザーとして、マーケットをセマンティック検索したい、
そうすれば正確なキーワードなしでも関連するマーケットを見つけられる。
各ユーザージャーニーに対して包括的なテストケースを作成:
describe('Semantic Search', () => {
it('returns relevant markets for query', async () => {
// テスト実装
})
it('handles empty query gracefully', async () => {
// エッジケースをテスト
})
it('falls back to substring search when Redis unavailable', async () => {
// フォールバック動作をテスト
})
it('sorts results by similarity score', async () => {
// ソートロジックをテスト
})
})
npm test
# テストは失敗するはず - まだ実装していないので
テストを通すための最小限のコードを書く:
// テストに導かれた実装
export async function searchMarkets(query: string) {
// ここに実装
}
npm test
# テストは今度は通るはず
テストをグリーンに保ちながらコード品質を改善:
npm run test:coverage
# 80%以上のカバレッジを達成したか確認
import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from './Button'
describe('Button Component', () => {
it('renders with correct text', () => {
render(<Button>Click me</Button>)
expect(screen.getByText('Click me')).toBeInTheDocument()
})
it('calls onClick when clicked', () => {
const handleClick = jest.fn()
render(<Button onClick={handleClick}>Click</Button>)
fireEvent.click(screen.getByRole('button'))
expect(handleClick).toHaveBeenCalledTimes(1)
})
it('is disabled when disabled prop is true', () => {
render(<Button disabled>Click</Button>)
expect(screen.getByRole('button')).toBeDisabled()
})
})
import { NextRequest } from 'next/server'
import { GET } from './route'
describe('GET /api/markets', () => {
it('returns markets successfully', async () => {
const request = new NextRequest('http://localhost/api/markets')
const response = await GET(request)
const data = await response.json()
expect(response.status).toBe(200)
expect(data.success).toBe(true)
expect(Array.isArray(data.data)).toBe(true)
})
it('validates query parameters', async () => {
const request = new NextRequest('http://localhost/api/markets?limit=invalid')
const response = await GET(request)
expect(response.status).toBe(400)
})
it('handles database errors gracefully', async () => {
// データベース障害をモック
const request = new NextRequest('http://localhost/api/markets')
// エラーハンドリングをテスト
})
})
import { test, expect } from '@playwright/test'
test('user can search and filter markets', async ({ page }) => {
// マーケットページに移動
await page.goto('/')
await page.click('a[href="/markets"]')
// ページが読み込まれたことを確認
await expect(page.locator('h1')).toContainText('Markets')
// マーケットを検索
await page.fill('input[placeholder="Search markets"]', 'election')
// デバウンスと結果を待つ
await page.waitForTimeout(600)
// 検索結果が表示されたことを確認
const results = page.locator('[data-testid="market-card"]')
await expect(results).toHaveCount(5, { timeout: 5000 })
// 結果に検索語が含まれていることを確認
const firstResult = results.first()
await expect(firstResult).toContainText('election', { ignoreCase: true })
// ステータスでフィルタ
await page.click('button:has-text("Active")')
// フィルタ結果を確認
await expect(results).toHaveCount(3)
})
test('user can create a new market', async ({ page }) => {
// まずログイン
await page.goto('/creator-dashboard')
// マーケット作成フォームを入力
await page.fill('input[name="name"]', 'Test Market')
await page.fill('textarea[name="description"]', 'Test description')
await page.fill('input[name="endDate"]', '2025-12-31')
// フォームを送信
await page.click('button[type="submit"]')
// 成功メッセージを確認
await expect(page.locator('text=Market created successfully')).toBeVisible()
// マーケットページへのリダイレクトを確認
await expect(page).toHaveURL(/\/markets\/test-market/)
})
src/
├── components/
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.test.tsx # ユニットテスト
│ │ └── Button.stories.tsx # Storybook
│ └── MarketCard/
│ ├── MarketCard.tsx
│ └── MarketCard.test.tsx
├── app/
│ └── api/
│ └── markets/
│ ├── route.ts
│ └── route.test.ts # 統合テスト
└── e2e/
├── markets.spec.ts # E2Eテスト
├── trading.spec.ts
└── auth.spec.ts
jest.mock('@/lib/supabase', () => ({
supabase: {
from: jest.fn(() => ({
select: jest.fn(() => ({
eq: jest.fn(() => Promise.resolve({
data: [{ id: 1, name: 'Test Market' }],
error: null
}))
}))
}))
}
}))
jest.mock('@/lib/redis', () => ({
searchMarketsByVector: jest.fn(() => Promise.resolve([
{ slug: 'test-market', similarity_score: 0.95 }
])),
checkRedisHealth: jest.fn(() => Promise.resolve({ connected: true }))
}))
jest.mock('@/lib/openai', () => ({
generateEmbedding: jest.fn(() => Promise.resolve(
new Array(1536).fill(0.1) // 1536次元の埋め込みをモック
))
}))
npm run test:coverage
{
"jest": {
"coverageThresholds": {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
}
}
}
}
// 内部状態をテストしない
expect(component.state.count).toBe(5)
// ユーザーが見るものをテスト
expect(screen.getByText('Count: 5')).toBeInTheDocument()
// 簡単に壊れる
await page.click('.css-class-xyz')
// 変更に強い
await page.click('button:has-text("Submit")')
await page.click('[data-testid="submit-button"]')
// テストが互いに依存
test('creates user', () => { /* ... */ })
test('updates same user', () => { /* 前のテストに依存 */ })
// 各テストが自分のデータをセットアップ
test('creates user', () => {
const user = createTestUser()
// テストロジック
})
test('updates user', () => {
const user = createTestUser()
// 更新ロジック
})
npm test -- --watch
# ファイル変更時に自動的にテストが実行
# すべてのコミット前に実行
npm test && npm run lint
# GitHub Actions
- name: Run Tests
run: npm test -- --coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
重要: テストはオプションではありません。自信を持ってリファクタリング、迅速な開発、本番の信頼性を可能にするセーフティネットです。