docs/ja-JP/skills/tdd-workflow/SKILL.md
新機能の作成、バグ修正、コードのリファクタリング時にこのスキルを使用します。ユニット、統合、E2Eテストを含む80%以上のカバレッジでテスト駆動開発を強制します。
npx skillsauth add affaan-m/everything-claude-code tdd-workflowInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
このスキルは、すべてのコード開発が包括的なテストカバレッジを備えた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
覚えておいてください:テストはオプションではありません。テストは自信を持ってリファクタリングし、迅速に開発し、本番の信頼性を可能にする安全網です。
development
Share durable, inspectable context and handoffs between Claude, Codex, Hermes, Cursor, OpenCode, and other agents through the local ECC Memory Vault. Use when an agent must save work state, transfer context, resume another agent's task, or search shared project knowledge.
development
Use when multiple consumers and providers must evolve an API or event schema without field drift, integration surprises, or one side silently redefining the interface.
tools
Query live GPU inventory, submit an authenticated Itô fixed-rate RFQ, inspect RFQ or procurement status, and run explicitly gated node qualification through the separately installed canonical CLI. Use when a user asks to find H100/H200 capacity, request a fixed compute rate, check Itô compute status, or validate GPU nodes.
data-ai
Instinct-based learning system that observes sessions via hooks, creates atomic instincts with confidence scoring, and evolves them into skills/commands/agents. v2.1 adds project-scoped instincts to prevent cross-project contamination.