新機能の作成、バグ修正、コードのリファクタリング時にこのスキルを使用します。ユニット、統合、E2Eテストを含む80%以上のカバレッジでテスト駆動開発を強制します。
npx skills add https://github.com/loulanyue/awesome-claude-notes --skill tdd-workflow
このスキルは、すべてのコード開発が包括的なテストカバレッジを備えた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
10. カバレッジレポートをレビュー - ギャップを特定
覚えておいてください:テストはオプションではありません。テストは自信を持ってリファクタリングし、迅速に開発し、本番の信頼性を可能にする安全網です。
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Use when implementing any feature or bugfix, before writing implementation code
Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
Expert guidance for systematic backtesting of trading strategies. Use when developing, testing, stress-testing, or validating quantitative trading strategies. Covers "beating ideas to death" methodology, parameter robustness testing, slippage modeling, bias prevention, and interpreting backtest results. Applicable when user asks about backtesting, strategy validation, robustness testing, avoiding overfitting, or systematic trading development.
Cloud laboratory platform for automated protein testing and validation. Use when designing proteins and needing experimental validation including binding assays, expression testing, thermostability measurements, enzyme activity assays, or protein sequence optimization. Also use for submitting experiments via API, tracking experiment status, downloading results, optimizing protein sequences for better expression using computational tools (NetSolP, SoluProt, SolubleMPNN, ESM), or managing protein design workflows with wet-lab validation.
This skill should be used for time series machine learning tasks including classification, regression, clustering, forecasting, anomaly detection, segmentation, and similarity search. Use when working with temporal data, sequential patterns, or time-indexed observations requiring specialized algorithms beyond standard ML approaches. Particularly suited for univariate and multivariate time series analysis with scikit-learn compatible APIs.
Take loulanyue/tdd-workflow from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.