[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6D7SQ1DMMRMNRS3T0KAWDPQ":3,"skill-same:01M6D7SQ1DMMRMNRS3T0KAWDPQ":101},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":46,"linkOnly":47,"markdownContent":48,"markdownBody":49,"frontMatter":50,"refName":52,"commitSha":53,"skillDirectory":54,"forksCount":55,"repositoryHtmlUrl":56,"repositoryHomepageUrl":6,"ownerHtmlUrl":57,"ownerBlogUrl":58,"ownerDescription":59,"updatedAt":60,"install":61,"resources":74},"01M6D7SQ1DMMRMNRS3T0KAWDPQ","tdd-workflow",null,"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.","oabdelmaksoud\u002FSuperClaw","oabdelmaksoud","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F50699149?v=4","01M6D5CVVN778ZCDP1WHS816SP","Omar Abdelmaksoud","01M6D5CW1RHNSKCJR85GJACBFT",2,"MIT","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002F.agents\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45],"tdd","workflow","tdd workflow","writing","test","e2e tests","development","code","integration","e2e","refactoring","coverage","use","tests","2026-11-10 10:12:30",false,"---\nname: tdd-workflow\ndescription: 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.\norigin: ECC\n---\n\n# Test-Driven Development Workflow\n\nThis skill ensures all code development follows TDD principles with comprehensive test coverage.\n\n## When to Activate\n\n- Writing new features or functionality\n- Fixing bugs or issues\n- Refactoring existing code\n- Adding API endpoints\n- Creating new components\n\n## Core Principles\n\n### 1. Tests BEFORE Code\nALWAYS write tests first, then implement code to make tests pass.\n\n### 2. Coverage Requirements\n- Minimum 80% coverage (unit + integration + E2E)\n- All edge cases covered\n- Error scenarios tested\n- Boundary conditions verified\n\n### 3. Test Types\n\n#### Unit Tests\n- Individual functions and utilities\n- Component logic\n- Pure functions\n- Helpers and utilities\n\n#### Integration Tests\n- API endpoints\n- Database operations\n- Service interactions\n- External API calls\n\n#### E2E Tests (Playwright)\n- Critical user flows\n- Complete workflows\n- Browser automation\n- UI interactions\n\n## TDD Workflow Steps\n\n### Step 1: Write User Journeys\n```\nAs a [role], I want to [action], so that [benefit]\n\nExample:\nAs a user, I want to search for markets semantically,\nso that I can find relevant markets even without exact keywords.\n```\n\n### Step 2: Generate Test Cases\nFor each user journey, create comprehensive test cases:\n\n```typescript\ndescribe('Semantic Search', () => {\n  it('returns relevant markets for query', async () => {\n    \u002F\u002F Test implementation\n  })\n\n  it('handles empty query gracefully', async () => {\n    \u002F\u002F Test edge case\n  })\n\n  it('falls back to substring search when Redis unavailable', async () => {\n    \u002F\u002F Test fallback behavior\n  })\n\n  it('sorts results by similarity score', async () => {\n    \u002F\u002F Test sorting logic\n  })\n})\n```\n\n### Step 3: Run Tests (They Should Fail)\n```bash\nnpm test\n# Tests should fail - we haven't implemented yet\n```\n\n### Step 4: Implement Code\nWrite minimal code to make tests pass:\n\n```typescript\n\u002F\u002F Implementation guided by tests\nexport async function searchMarkets(query: string) {\n  \u002F\u002F Implementation here\n}\n```\n\n### Step 5: Run Tests Again\n```bash\nnpm test\n# Tests should now pass\n```\n\n### Step 6: Refactor\nImprove code quality while keeping tests green:\n- Remove duplication\n- Improve naming\n- Optimize performance\n- Enhance readability\n\n### Step 7: Verify Coverage\n```bash\nnpm run test:coverage\n# Verify 80%+ coverage achieved\n```\n\n## Testing Patterns\n\n### Unit Test Pattern (Jest\u002FVitest)\n```typescript\nimport { render, screen, fireEvent } from '@testing-library\u002Freact'\nimport { Button } from '.\u002FButton'\n\ndescribe('Button Component', () => {\n  it('renders with correct text', () => {\n    render(\u003CButton>Click me\u003C\u002FButton>)\n    expect(screen.getByText('Click me')).toBeInTheDocument()\n  })\n\n  it('calls onClick when clicked', () => {\n    const handleClick = jest.fn()\n    render(\u003CButton onClick={handleClick}>Click\u003C\u002FButton>)\n\n    fireEvent.click(screen.getByRole('button'))\n\n    expect(handleClick).toHaveBeenCalledTimes(1)\n  })\n\n  it('is disabled when disabled prop is true', () => {\n    render(\u003CButton disabled>Click\u003C\u002FButton>)\n    expect(screen.getByRole('button')).toBeDisabled()\n  })\n})\n```\n\n### API Integration Test Pattern\n```typescript\nimport { NextRequest } from 'next\u002Fserver'\nimport { GET } from '.\u002Froute'\n\ndescribe('GET \u002Fapi\u002Fmarkets', () => {\n  it('returns markets successfully', async () => {\n    const request = new NextRequest('http:\u002F\u002Flocalhost\u002Fapi\u002Fmarkets')\n    const response = await GET(request)\n    const data = await response.json()\n\n    expect(response.status).toBe(200)\n    expect(data.success).toBe(true)\n    expect(Array.isArray(data.data)).toBe(true)\n  })\n\n  it('validates query parameters', async () => {\n    const request = new NextRequest('http:\u002F\u002Flocalhost\u002Fapi\u002Fmarkets?limit=invalid')\n    const response = await GET(request)\n\n    expect(response.status).toBe(400)\n  })\n\n  it('handles database errors gracefully', async () => {\n    \u002F\u002F Mock database failure\n    const request = new NextRequest('http:\u002F\u002Flocalhost\u002Fapi\u002Fmarkets')\n    \u002F\u002F Test error handling\n  })\n})\n```\n\n### E2E Test Pattern (Playwright)\n```typescript\nimport { test, expect } from '@playwright\u002Ftest'\n\ntest('user can search and filter markets', async ({ page }) => {\n  \u002F\u002F Navigate to markets page\n  await page.goto('\u002F')\n  await page.click('a[href=\"\u002Fmarkets\"]')\n\n  \u002F\u002F Verify page loaded\n  await expect(page.locator('h1')).toContainText('Markets')\n\n  \u002F\u002F Search for markets\n  await page.fill('input[placeholder=\"Search markets\"]', 'election')\n\n  \u002F\u002F Wait for debounce and results\n  await page.waitForTimeout(600)\n\n  \u002F\u002F Verify search results displayed\n  const results = page.locator('[data-testid=\"market-card\"]')\n  await expect(results).toHaveCount(5, { timeout: 5000 })\n\n  \u002F\u002F Verify results contain search term\n  const firstResult = results.first()\n  await expect(firstResult).toContainText('election', { ignoreCase: true })\n\n  \u002F\u002F Filter by status\n  await page.click('button:has-text(\"Active\")')\n\n  \u002F\u002F Verify filtered results\n  await expect(results).toHaveCount(3)\n})\n\ntest('user can create a new market', async ({ page }) => {\n  \u002F\u002F Login first\n  await page.goto('\u002Fcreator-dashboard')\n\n  \u002F\u002F Fill market creation form\n  await page.fill('input[name=\"name\"]', 'Test Market')\n  await page.fill('textarea[name=\"description\"]', 'Test description')\n  await page.fill('input[name=\"endDate\"]', '2025-12-31')\n\n  \u002F\u002F Submit form\n  await page.click('button[type=\"submit\"]')\n\n  \u002F\u002F Verify success message\n  await expect(page.locator('text=Market created successfully')).toBeVisible()\n\n  \u002F\u002F Verify redirect to market page\n  await expect(page).toHaveURL(\u002F\\\u002Fmarkets\\\u002Ftest-market\u002F)\n})\n```\n\n## Test File Organization\n\n```\nsrc\u002F\n├── components\u002F\n│   ├── Button\u002F\n│   │   ├── Button.tsx\n│   │   ├── Button.test.tsx          # Unit tests\n│   │   └── Button.stories.tsx       # Storybook\n│   └── MarketCard\u002F\n│       ├── MarketCard.tsx\n│       └── MarketCard.test.tsx\n├── app\u002F\n│   └── api\u002F\n│       └── markets\u002F\n│           ├── route.ts\n│           └── route.test.ts         # Integration tests\n└── e2e\u002F\n    ├── markets.spec.ts               # E2E tests\n    ├── trading.spec.ts\n    └── auth.spec.ts\n```\n\n## Mocking External Services\n\n### Supabase Mock\n```typescript\njest.mock('@\u002Flib\u002Fsupabase', () => ({\n  supabase: {\n    from: jest.fn(() => ({\n      select: jest.fn(() => ({\n        eq: jest.fn(() => Promise.resolve({\n          data: [{ id: 1, name: 'Test Market' }],\n          error: null\n        }))\n      }))\n    }))\n  }\n}))\n```\n\n### Redis Mock\n```typescript\njest.mock('@\u002Flib\u002Fredis', () => ({\n  searchMarketsByVector: jest.fn(() => Promise.resolve([\n    { slug: 'test-market', similarity_score: 0.95 }\n  ])),\n  checkRedisHealth: jest.fn(() => Promise.resolve({ connected: true }))\n}))\n```\n\n### OpenAI Mock\n```typescript\njest.mock('@\u002Flib\u002Fopenai', () => ({\n  generateEmbedding: jest.fn(() => Promise.resolve(\n    new Array(1536).fill(0.1) \u002F\u002F Mock 1536-dim embedding\n  ))\n}))\n```\n\n## Test Coverage Verification\n\n### Run Coverage Report\n```bash\nnpm run test:coverage\n```\n\n### Coverage Thresholds\n```json\n{\n  \"jest\": {\n    \"coverageThresholds\": {\n      \"global\": {\n        \"branches\": 80,\n        \"functions\": 80,\n        \"lines\": 80,\n        \"statements\": 80\n      }\n    }\n  }\n}\n```\n\n## Common Testing Mistakes to Avoid\n\n### ❌ WRONG: Testing Implementation Details\n```typescript\n\u002F\u002F Don't test internal state\nexpect(component.state.count).toBe(5)\n```\n\n### ✅ CORRECT: Test User-Visible Behavior\n```typescript\n\u002F\u002F Test what users see\nexpect(screen.getByText('Count: 5')).toBeInTheDocument()\n```\n\n### ❌ WRONG: Brittle Selectors\n```typescript\n\u002F\u002F Breaks easily\nawait page.click('.css-class-xyz')\n```\n\n### ✅ CORRECT: Semantic Selectors\n```typescript\n\u002F\u002F Resilient to changes\nawait page.click('button:has-text(\"Submit\")')\nawait page.click('[data-testid=\"submit-button\"]')\n```\n\n### ❌ WRONG: No Test Isolation\n```typescript\n\u002F\u002F Tests depend on each other\ntest('creates user', () => { \u002F* ... *\u002F })\ntest('updates same user', () => { \u002F* depends on previous test *\u002F })\n```\n\n### ✅ CORRECT: Independent Tests\n```typescript\n\u002F\u002F Each test sets up its own data\ntest('creates user', () => {\n  const user = createTestUser()\n  \u002F\u002F Test logic\n})\n\ntest('updates user', () => {\n  const user = createTestUser()\n  \u002F\u002F Update logic\n})\n```\n\n## Continuous Testing\n\n### Watch Mode During Development\n```bash\nnpm test -- --watch\n# Tests run automatically on file changes\n```\n\n### Pre-Commit Hook\n```bash\n# Runs before every commit\nnpm test && npm run lint\n```\n\n### CI\u002FCD Integration\n```yaml\n# GitHub Actions\n- name: Run Tests\n  run: npm test -- --coverage\n- name: Upload Coverage\n  uses: codecov\u002Fcodecov-action@v3\n```\n\n## Best Practices\n\n1. **Write Tests First** - Always TDD\n2. **One Assert Per Test** - Focus on single behavior\n3. **Descriptive Test Names** - Explain what's tested\n4. **Arrange-Act-Assert** - Clear test structure\n5. **Mock External Dependencies** - Isolate unit tests\n6. **Test Edge Cases** - Null, undefined, empty, large\n7. **Test Error Paths** - Not just happy paths\n8. **Keep Tests Fast** - Unit tests \u003C 50ms each\n9. **Clean Up After Tests** - No side effects\n10. **Review Coverage Reports** - Identify gaps\n\n## Success Metrics\n\n- 80%+ code coverage achieved\n- All tests passing (green)\n- No skipped or disabled tests\n- Fast test execution (\u003C 30s for unit tests)\n- E2E tests cover critical user flows\n- Tests catch bugs before production\n\n---\n\n**Remember**: Tests are not optional. They are the safety net that enables confident refactoring, rapid development, and production reliability.\n","# Test-Driven Development Workflow\n\nThis skill ensures all code development follows TDD principles with comprehensive test coverage.\n\n## When to Activate\n\n- Writing new features or functionality\n- Fixing bugs or issues\n- Refactoring existing code\n- Adding API endpoints\n- Creating new components\n\n## Core Principles\n\n### 1. Tests BEFORE Code\nALWAYS write tests first, then implement code to make tests pass.\n\n### 2. Coverage Requirements\n- Minimum 80% coverage (unit + integration + E2E)\n- All edge cases covered\n- Error scenarios tested\n- Boundary conditions verified\n\n### 3. Test Types\n\n#### Unit Tests\n- Individual functions and utilities\n- Component logic\n- Pure functions\n- Helpers and utilities\n\n#### Integration Tests\n- API endpoints\n- Database operations\n- Service interactions\n- External API calls\n\n#### E2E Tests (Playwright)\n- Critical user flows\n- Complete workflows\n- Browser automation\n- UI interactions\n\n## TDD Workflow Steps\n\n### Step 1: Write User Journeys\n```\nAs a [role], I want to [action], so that [benefit]\n\nExample:\nAs a user, I want to search for markets semantically,\nso that I can find relevant markets even without exact keywords.\n```\n\n### Step 2: Generate Test Cases\nFor each user journey, create comprehensive test cases:\n\n```typescript\ndescribe('Semantic Search', () => {\n  it('returns relevant markets for query', async () => {\n    \u002F\u002F Test implementation\n  })\n\n  it('handles empty query gracefully', async () => {\n    \u002F\u002F Test edge case\n  })\n\n  it('falls back to substring search when Redis unavailable', async () => {\n    \u002F\u002F Test fallback behavior\n  })\n\n  it('sorts results by similarity score', async () => {\n    \u002F\u002F Test sorting logic\n  })\n})\n```\n\n### Step 3: Run Tests (They Should Fail)\n```bash\nnpm test\n# Tests should fail - we haven't implemented yet\n```\n\n### Step 4: Implement Code\nWrite minimal code to make tests pass:\n\n```typescript\n\u002F\u002F Implementation guided by tests\nexport async function searchMarkets(query: string) {\n  \u002F\u002F Implementation here\n}\n```\n\n### Step 5: Run Tests Again\n```bash\nnpm test\n# Tests should now pass\n```\n\n### Step 6: Refactor\nImprove code quality while keeping tests green:\n- Remove duplication\n- Improve naming\n- Optimize performance\n- Enhance readability\n\n### Step 7: Verify Coverage\n```bash\nnpm run test:coverage\n# Verify 80%+ coverage achieved\n```\n\n## Testing Patterns\n\n### Unit Test Pattern (Jest\u002FVitest)\n```typescript\nimport { render, screen, fireEvent } from '@testing-library\u002Freact'\nimport { Button } from '.\u002FButton'\n\ndescribe('Button Component', () => {\n  it('renders with correct text', () => {\n    render(\u003CButton>Click me\u003C\u002FButton>)\n    expect(screen.getByText('Click me')).toBeInTheDocument()\n  })\n\n  it('calls onClick when clicked', () => {\n    const handleClick = jest.fn()\n    render(\u003CButton onClick={handleClick}>Click\u003C\u002FButton>)\n\n    fireEvent.click(screen.getByRole('button'))\n\n    expect(handleClick).toHaveBeenCalledTimes(1)\n  })\n\n  it('is disabled when disabled prop is true', () => {\n    render(\u003CButton disabled>Click\u003C\u002FButton>)\n    expect(screen.getByRole('button')).toBeDisabled()\n  })\n})\n```\n\n### API Integration Test Pattern\n```typescript\nimport { NextRequest } from 'next\u002Fserver'\nimport { GET } from '.\u002Froute'\n\ndescribe('GET \u002Fapi\u002Fmarkets', () => {\n  it('returns markets successfully', async () => {\n    const request = new NextRequest('http:\u002F\u002Flocalhost\u002Fapi\u002Fmarkets')\n    const response = await GET(request)\n    const data = await response.json()\n\n    expect(response.status).toBe(200)\n    expect(data.success).toBe(true)\n    expect(Array.isArray(data.data)).toBe(true)\n  })\n\n  it('validates query parameters', async () => {\n    const request = new NextRequest('http:\u002F\u002Flocalhost\u002Fapi\u002Fmarkets?limit=invalid')\n    const response = await GET(request)\n\n    expect(response.status).toBe(400)\n  })\n\n  it('handles database errors gracefully', async () => {\n    \u002F\u002F Mock database failure\n    const request = new NextRequest('http:\u002F\u002Flocalhost\u002Fapi\u002Fmarkets')\n    \u002F\u002F Test error handling\n  })\n})\n```\n\n### E2E Test Pattern (Playwright)\n```typescript\nimport { test, expect } from '@playwright\u002Ftest'\n\ntest('user can search and filter markets', async ({ page }) => {\n  \u002F\u002F Navigate to markets page\n  await page.goto('\u002F')\n  await page.click('a[href=\"\u002Fmarkets\"]')\n\n  \u002F\u002F Verify page loaded\n  await expect(page.locator('h1')).toContainText('Markets')\n\n  \u002F\u002F Search for markets\n  await page.fill('input[placeholder=\"Search markets\"]', 'election')\n\n  \u002F\u002F Wait for debounce and results\n  await page.waitForTimeout(600)\n\n  \u002F\u002F Verify search results displayed\n  const results = page.locator('[data-testid=\"market-card\"]')\n  await expect(results).toHaveCount(5, { timeout: 5000 })\n\n  \u002F\u002F Verify results contain search term\n  const firstResult = results.first()\n  await expect(firstResult).toContainText('election', { ignoreCase: true })\n\n  \u002F\u002F Filter by status\n  await page.click('button:has-text(\"Active\")')\n\n  \u002F\u002F Verify filtered results\n  await expect(results).toHaveCount(3)\n})\n\ntest('user can create a new market', async ({ page }) => {\n  \u002F\u002F Login first\n  await page.goto('\u002Fcreator-dashboard')\n\n  \u002F\u002F Fill market creation form\n  await page.fill('input[name=\"name\"]', 'Test Market')\n  await page.fill('textarea[name=\"description\"]', 'Test description')\n  await page.fill('input[name=\"endDate\"]', '2025-12-31')\n\n  \u002F\u002F Submit form\n  await page.click('button[type=\"submit\"]')\n\n  \u002F\u002F Verify success message\n  await expect(page.locator('text=Market created successfully')).toBeVisible()\n\n  \u002F\u002F Verify redirect to market page\n  await expect(page).toHaveURL(\u002F\\\u002Fmarkets\\\u002Ftest-market\u002F)\n})\n```\n\n## Test File Organization\n\n```\nsrc\u002F\n├── components\u002F\n│   ├── Button\u002F\n│   │   ├── Button.tsx\n│   │   ├── Button.test.tsx          # Unit tests\n│   │   └── Button.stories.tsx       # Storybook\n│   └── MarketCard\u002F\n│       ├── MarketCard.tsx\n│       └── MarketCard.test.tsx\n├── app\u002F\n│   └── api\u002F\n│       └── markets\u002F\n│           ├── route.ts\n│           └── route.test.ts         # Integration tests\n└── e2e\u002F\n    ├── markets.spec.ts               # E2E tests\n    ├── trading.spec.ts\n    └── auth.spec.ts\n```\n\n## Mocking External Services\n\n### Supabase Mock\n```typescript\njest.mock('@\u002Flib\u002Fsupabase', () => ({\n  supabase: {\n    from: jest.fn(() => ({\n      select: jest.fn(() => ({\n        eq: jest.fn(() => Promise.resolve({\n          data: [{ id: 1, name: 'Test Market' }],\n          error: null\n        }))\n      }))\n    }))\n  }\n}))\n```\n\n### Redis Mock\n```typescript\njest.mock('@\u002Flib\u002Fredis', () => ({\n  searchMarketsByVector: jest.fn(() => Promise.resolve([\n    { slug: 'test-market', similarity_score: 0.95 }\n  ])),\n  checkRedisHealth: jest.fn(() => Promise.resolve({ connected: true }))\n}))\n```\n\n### OpenAI Mock\n```typescript\njest.mock('@\u002Flib\u002Fopenai', () => ({\n  generateEmbedding: jest.fn(() => Promise.resolve(\n    new Array(1536).fill(0.1) \u002F\u002F Mock 1536-dim embedding\n  ))\n}))\n```\n\n## Test Coverage Verification\n\n### Run Coverage Report\n```bash\nnpm run test:coverage\n```\n\n### Coverage Thresholds\n```json\n{\n  \"jest\": {\n    \"coverageThresholds\": {\n      \"global\": {\n        \"branches\": 80,\n        \"functions\": 80,\n        \"lines\": 80,\n        \"statements\": 80\n      }\n    }\n  }\n}\n```\n\n## Common Testing Mistakes to Avoid\n\n### ❌ WRONG: Testing Implementation Details\n```typescript\n\u002F\u002F Don't test internal state\nexpect(component.state.count).toBe(5)\n```\n\n### ✅ CORRECT: Test User-Visible Behavior\n```typescript\n\u002F\u002F Test what users see\nexpect(screen.getByText('Count: 5')).toBeInTheDocument()\n```\n\n### ❌ WRONG: Brittle Selectors\n```typescript\n\u002F\u002F Breaks easily\nawait page.click('.css-class-xyz')\n```\n\n### ✅ CORRECT: Semantic Selectors\n```typescript\n\u002F\u002F Resilient to changes\nawait page.click('button:has-text(\"Submit\")')\nawait page.click('[data-testid=\"submit-button\"]')\n```\n\n### ❌ WRONG: No Test Isolation\n```typescript\n\u002F\u002F Tests depend on each other\ntest('creates user', () => { \u002F* ... *\u002F })\ntest('updates same user', () => { \u002F* depends on previous test *\u002F })\n```\n\n### ✅ CORRECT: Independent Tests\n```typescript\n\u002F\u002F Each test sets up its own data\ntest('creates user', () => {\n  const user = createTestUser()\n  \u002F\u002F Test logic\n})\n\ntest('updates user', () => {\n  const user = createTestUser()\n  \u002F\u002F Update logic\n})\n```\n\n## Continuous Testing\n\n### Watch Mode During Development\n```bash\nnpm test -- --watch\n# Tests run automatically on file changes\n```\n\n### Pre-Commit Hook\n```bash\n# Runs before every commit\nnpm test && npm run lint\n```\n\n### CI\u002FCD Integration\n```yaml\n# GitHub Actions\n- name: Run Tests\n  run: npm test -- --coverage\n- name: Upload Coverage\n  uses: codecov\u002Fcodecov-action@v3\n```\n\n## Best Practices\n\n1. **Write Tests First** - Always TDD\n2. **One Assert Per Test** - Focus on single behavior\n3. **Descriptive Test Names** - Explain what's tested\n4. **Arrange-Act-Assert** - Clear test structure\n5. **Mock External Dependencies** - Isolate unit tests\n6. **Test Edge Cases** - Null, undefined, empty, large\n7. **Test Error Paths** - Not just happy paths\n8. **Keep Tests Fast** - Unit tests \u003C 50ms each\n9. **Clean Up After Tests** - No side effects\n10. **Review Coverage Reports** - Identify gaps\n\n## Success Metrics\n\n- 80%+ code coverage achieved\n- All tests passing (green)\n- No skipped or disabled tests\n- Fast test execution (\u003C 30s for unit tests)\n- E2E tests cover critical user flows\n- Tests catch bugs before production\n\n---\n\n**Remember**: Tests are not optional. They are the safety net that enables confident refactoring, rapid development, and production reliability.\n",{"name":5,"origin":51,"description":7},"ECC","main","7b610356e36623652299fa2acb477ff821b1d920","upstream-sync\u002Fwork\u002Fecc\u002F.agents\u002Fskills\u002Ftdd-workflow",0,"https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fo-abdelmaksoud\u002F","Full-Stack Engineer | AI Systems Architect | Building autonomous multi-agent systems","2026-03-08 21:12:53",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add oabdelmaksoud\u002FSuperClaw --skill tdd-workflow",{"tool":67,"command":68},"bunx","bunx skills add oabdelmaksoud\u002FSuperClaw --skill tdd-workflow",{"tool":70,"command":71},"pnpm","pnpm dlx skills add oabdelmaksoud\u002FSuperClaw --skill tdd-workflow","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002F.agents\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",true,[75,81,85,89,93,97],{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"agents\u002Fopenai.yaml","REFERENCE","参考文档",258,"https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002F.agents\u002Fskills\u002Ftdd-workflow\u002Fagents\u002Fopenai.yaml",{"path":82,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":83,"sourceHtmlUrl":84},"reference\u002Fdata_sources.md",9630,"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fknowledge-work-plugins\u002Fblob\u002Fmain\u002Fsmall-business\u002Fskills\u002Fbusiness-pulse\u002Freference\u002Fdata_sources.md",{"path":86,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":87,"sourceHtmlUrl":88},"reference\u002Fgotchas.md",3193,"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fknowledge-work-plugins\u002Fblob\u002Fmain\u002Fsmall-business\u002Fskills\u002Fbusiness-pulse\u002Freference\u002Fgotchas.md",{"path":90,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":91,"sourceHtmlUrl":92},"reference\u002Foutput_template.md",4062,"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fknowledge-work-plugins\u002Fblob\u002Fmain\u002Fsmall-business\u002Fskills\u002Fbusiness-pulse\u002Freference\u002Foutput_template.md",{"path":94,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":95,"sourceHtmlUrl":96},"reference\u002Fthresholds.md",2210,"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fknowledge-work-plugins\u002Fblob\u002Fmain\u002Fsmall-business\u002Fskills\u002Fbusiness-pulse\u002Freference\u002Fthresholds.md",{"path":98,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":99,"sourceHtmlUrl":100},"reference\u002Fv2_sources.md",3367,"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fknowledge-work-plugins\u002Fblob\u002Fmain\u002Fsmall-business\u002Fskills\u002Fbusiness-pulse\u002Freference\u002Fv2_sources.md",[102,121,134,142,168,187],{"skillNo":103,"name":104,"nameZh":6,"description":105,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":106,"categories":107,"keywords":111,"publishedAt":46},"01M6D88QCPTBZVCRED0NZ1Y8K8","visa-doc-translate","Translate visa application documents (images) to English and create a bilingual PDF with original and translation","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fvisa-doc-translate\u002FSKILL.md",[108],{"categoryNo":109,"categoryName":110,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000002","文档处理",[112,113,114,115,116,117,118,119,120],"translate","doc","visa doc translate","translation","application","create","images","PDF","documents",{"skillNo":122,"name":123,"nameZh":6,"description":124,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":127,"publishedAt":46},"01M6D88NBM95T3TFM50CYYAP65","verification-loop","A comprehensive verification system for Claude Code sessions.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[128,129,130,131,39,132,133],"verification","loop","verification loop","sessions","claude code sessions","system",{"skillNo":135,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":141,"publishedAt":46},"01M6D88JFZ2P996GVRHJNSZSTM","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[138,139,140],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},[32,33,34,37,41,40,39,38,44,36,42,43,45,35],{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":148,"publishedAt":46},"01M6D88FTHRRSVJMXF2G7MQAK3","swiftui-patterns","SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS\u002FmacOS UI best practices.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswiftui-patterns\u002FSKILL.md",[],[149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167],"patterns","swiftui","swiftui patterns","architecture","macos","performance","state management","best practices","state","ui","Optimization","ios","architecture patterns","Composition","performance optimization","view","management","swiftui architecture","navigation",{"skillNo":169,"name":170,"nameZh":6,"description":171,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":172,"categories":173,"keywords":175,"publishedAt":46},"01M6D88D527QTQT9DKHTRFN6EA","swift-protocol-di-testing","Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-protocol-di-testing\u002FSKILL.md",[174],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[176,177,178,179,39,180,181,182,183,133,184,185,186],"swift protocol di testing","protocol","swift","testing","protocols","file","network","injection","dependency","swift testing","dependency injection",{"skillNo":188,"name":189,"nameZh":6,"description":190,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":191,"categories":192,"keywords":193,"publishedAt":46},"01M6D88AJW8H2QNWSW5ZY82R43","swift-concurrency-6-2","Swift 6.2 Approachable Concurrency — single-threaded by default, @concurrent for explicit background offloading, isolated conformances for main actor types.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-concurrency-6-2\u002FSKILL.md",[],[194,195,178,196,197,52],"concurrency","swift concurrency","swift concurrency 6 2","default"]