docs/zh-TW/skills/tdd-workflow/SKILL.md
Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.
npx skillsauth add SiniyaYousuf/everything_claudecode 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 () => {
// Mock 資料庫失敗
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')
// 等待 debounce 和結果
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) // Mock 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
# 檔案變更時自動執行測試
# 每次 commit 前執行
npm test && npm run lint
# GitHub Actions
- name: Run Tests
run: npm test -- --coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
記住:測試不是可選的。它們是實現自信重構、快速開發和生產可靠性的安全網。
development
X/Twitter API integration for posting tweets, threads, reading timelines, search, and analytics. Covers OAuth auth patterns, rate limits, and platform-native content posting. Use when the user wants to interact with X programmatically.
documentation
Translate visa application documents (images) to English and create a bilingual PDF with original and translation
tools
See, Understand, Act on video and audio. See- ingest from local files, URLs, RTSP/live feeds, or live record desktop; return realtime context and playable stream links. Understand- extract frames, build visual/semantic/temporal indexes, and search moments with timestamps and auto-clips. Act- transcode and normalize (codec, fps, resolution, aspect ratio), perform timeline edits (subtitles, text/image overlays, branding, audio overlays, dubbing, translation), generate media assets (image, audio, video), and create real time alerts for events from live streams or desktop capture.
development
AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.