tdd-workflow

Test-Driven Development Workflow

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "tdd-workflow" with this command: npx skills add oldwinter/skills/oldwinter-skills-tdd-workflow

Test-Driven Development Workflow

This skill ensures all code development follows TDD principles with comprehensive test coverage.

When to Activate

  • Writing new features or functionality

  • Fixing bugs or issues

  • Refactoring existing code

  • Adding API endpoints

  • Creating new components

Core Principles

  1. Tests BEFORE Code

ALWAYS write tests first, then implement code to make tests pass.

  1. Coverage Requirements
  • Minimum 80% coverage (unit + integration + E2E)

  • All edge cases covered

  • Error scenarios tested

  • Boundary conditions verified

  1. Test Types

Unit Tests

  • Individual functions and utilities

  • Component logic

  • Pure functions

  • Helpers and utilities

Integration Tests

  • API endpoints

  • Database operations

  • Service interactions

  • External API calls

E2E Tests (Playwright)

  • Critical user flows

  • Complete workflows

  • Browser automation

  • UI interactions

TDD Workflow Steps

Step 1: Write User Journeys

As a [role], I want to [action], so that [benefit]

Example: As a user, I want to search for markets semantically, so that I can find relevant markets even without exact keywords.

Step 2: Generate Test Cases

For each user journey, create comprehensive test cases:

describe('Semantic Search', () => { it('returns relevant markets for query', async () => { // Test implementation })

it('handles empty query gracefully', async () => { // Test edge case })

it('falls back to substring search when Redis unavailable', async () => { // Test fallback behavior })

it('sorts results by similarity score', async () => { // Test sorting logic }) })

Step 3: Run Tests (They Should Fail)

npm test

Tests should fail - we haven't implemented yet

Step 4: Implement Code

Write minimal code to make tests pass:

// Implementation guided by tests export async function searchMarkets(query: string) { // Implementation here }

Step 5: Run Tests Again

npm test

Tests should now pass

Step 6: Refactor

Improve code quality while keeping tests green:

  • Remove duplication

  • Improve naming

  • Optimize performance

  • Enhance readability

Step 7: Verify Coverage

npm run test:coverage

Verify 80%+ coverage achieved

Testing Patterns

Unit Test Pattern (Jest/Vitest)

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() }) })

API Integration Test Pattern

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 database failure const request = new NextRequest('http://localhost/api/markets') // Test error handling }) })

E2E Test Pattern (Playwright)

import { test, expect } from '@playwright/test'

test('user can search and filter markets', async ({ page }) => { // Navigate to markets page await page.goto('/') await page.click('a[href="/markets"]')

// Verify page loaded await expect(page.locator('h1')).toContainText('Markets')

// Search for markets await page.fill('input[placeholder="Search markets"]', 'election')

// Wait for debounce and results await page.waitForTimeout(600)

// Verify search results displayed const results = page.locator('[data-testid="market-card"]') await expect(results).toHaveCount(5, { timeout: 5000 })

// Verify results contain search term const firstResult = results.first() await expect(firstResult).toContainText('election', { ignoreCase: true })

// Filter by status await page.click('button:has-text("Active")')

// Verify filtered results await expect(results).toHaveCount(3) })

test('user can create a new market', async ({ page }) => { // Login first await page.goto('/creator-dashboard')

// Fill market creation form 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')

// Submit form await page.click('button[type="submit"]')

// Verify success message await expect(page.locator('text=Market created successfully')).toBeVisible()

// Verify redirect to market page await expect(page).toHaveURL(//markets/test-market/) })

Test File Organization

src/ ├── components/ │ ├── Button/ │ │ ├── Button.tsx │ │ ├── Button.test.tsx # Unit tests │ │ └── Button.stories.tsx # Storybook │ └── MarketCard/ │ ├── MarketCard.tsx │ └── MarketCard.test.tsx ├── app/ │ └── api/ │ └── markets/ │ ├── route.ts │ └── route.test.ts # Integration tests └── e2e/ ├── markets.spec.ts # E2E tests ├── trading.spec.ts └── auth.spec.ts

Mocking External Services

Supabase Mock

jest.mock('@/lib/supabase', () => ({ supabase: { from: jest.fn(() => ({ select: jest.fn(() => ({ eq: jest.fn(() => Promise.resolve({ data: [{ id: 1, name: 'Test Market' }], error: null })) })) })) } }))

Redis Mock

jest.mock('@/lib/redis', () => ({ searchMarketsByVector: jest.fn(() => Promise.resolve([ { slug: 'test-market', similarity_score: 0.95 } ])), checkRedisHealth: jest.fn(() => Promise.resolve({ connected: true })) }))

OpenAI Mock

jest.mock('@/lib/openai', () => ({ generateEmbedding: jest.fn(() => Promise.resolve( new Array(1536).fill(0.1) // Mock 1536-dim embedding )) }))

Test Coverage Verification

Run Coverage Report

npm run test:coverage

Coverage Thresholds

{ "jest": { "coverageThresholds": { "global": { "branches": 80, "functions": 80, "lines": 80, "statements": 80 } } } }

Common Testing Mistakes to Avoid

❌ WRONG: Testing Implementation Details

// Don't test internal state expect(component.state.count).toBe(5)

✅ CORRECT: Test User-Visible Behavior

// Test what users see expect(screen.getByText('Count: 5')).toBeInTheDocument()

❌ WRONG: Brittle Selectors

// Breaks easily await page.click('.css-class-xyz')

✅ CORRECT: Semantic Selectors

// Resilient to changes await page.click('button:has-text("Submit")') await page.click('[data-testid="submit-button"]')

❌ WRONG: No Test Isolation

// Tests depend on each other test('creates user', () => { /* ... / }) test('updates same user', () => { / depends on previous test */ })

✅ CORRECT: Independent Tests

// Each test sets up its own data test('creates user', () => { const user = createTestUser() // Test logic })

test('updates user', () => { const user = createTestUser() // Update logic })

Continuous Testing

Watch Mode During Development

npm test -- --watch

Tests run automatically on file changes

Pre-Commit Hook

Runs before every commit

npm test && npm run lint

CI/CD Integration

GitHub Actions

  • name: Run Tests run: npm test -- --coverage
  • name: Upload Coverage uses: codecov/codecov-action@v3

Best Practices

  • Write Tests First - Always TDD

  • One Assert Per Test - Focus on single behavior

  • Descriptive Test Names - Explain what's tested

  • Arrange-Act-Assert - Clear test structure

  • Mock External Dependencies - Isolate unit tests

  • Test Edge Cases - Null, undefined, empty, large

  • Test Error Paths - Not just happy paths

  • Keep Tests Fast - Unit tests < 50ms each

  • Clean Up After Tests - No side effects

  • Review Coverage Reports - Identify gaps

Success Metrics

  • 80%+ code coverage achieved

  • All tests passing (green)

  • No skipped or disabled tests

  • Fast test execution (< 30s for unit tests)

  • E2E tests cover critical user flows

  • Tests catch bugs before production

Remember: Tests are not optional. They are the safety net that enables confident refactoring, rapid development, and production reliability.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

github-cli

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

aws-cli

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

argocd-cli

No summary provided by upstream source.

Repository SourceNeeds Review