AI Skill Report Card
Generated Skill
Test-Driven Development Workflow
Quick Start
TypeScript// 1. Define interface (SCAFFOLD) export function calculateScore(data: InputData): number { throw new Error('Not implemented') } // 2. Write failing test (RED) it('should calculate score correctly', () => { const result = calculateScore(mockData) expect(result).toBe(85) }) // 3. Run tests - verify FAIL // 4. Implement minimal code (GREEN) // 5. Run tests - verify PASS // 6. Refactor while keeping tests green
Recommendation▾
Consider adding more specific examples
Workflow
TDD Cycle: RED → GREEN → REFACTOR
Progress:
- Scaffold: Define interfaces and types
- RED: Write failing test first
- Verify Fail: Run test, confirm it fails for right reason
- GREEN: Write minimal code to pass test
- Verify Pass: Run test, confirm it passes
- REFACTOR: Improve code while keeping tests green
- Coverage: Ensure 80%+ test coverage
Step 1: Scaffold Interfaces
TypeScript// Define types and function signatures first export interface UserData { id: string email: string createdAt: Date } export function validateUser(data: UserData): boolean { // TODO: Implementation throw new Error('Not implemented') }
Step 2: Write Failing Test (RED)
TypeScriptdescribe('validateUser', () => { it('should return true for valid user', () => { const user = { id: 'user123', email: 'test@example.com', createdAt: new Date() } expect(validateUser(user)).toBe(true) }) it('should return false for invalid email', () => { const user = { id: 'user123', email: 'invalid-email', createdAt: new Date() } expect(validateUser(user)).toBe(false) }) })
Step 3: Verify Test Fails
Run tests and confirm they fail with "Not implemented" error.
Step 4: Implement Minimal Code (GREEN)
TypeScriptexport function validateUser(data: UserData): boolean { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ return emailRegex.test(data.email) && data.id.length > 0 && data.createdAt instanceof Date }
Step 5: Verify Test Passes
Run tests and confirm they all pass.
Step 6: Refactor
TypeScriptconst EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ function isValidEmail(email: string): boolean { return EMAIL_REGEX.test(email) } function isValidId(id: string): boolean { return id.length > 0 } function isValidDate(date: Date): boolean { return date instanceof Date && !isNaN(date.getTime()) } export function validateUser(data: UserData): boolean { return isValidEmail(data.email) && isValidId(data.id) && isValidDate(data.createdAt) }
Recommendation▾
Include edge cases
Examples
Example 1: Calculator Function Input: Need function to add two numbers Output:
TypeScript// Test first it('should add two numbers', () => { expect(add(2, 3)).toBe(5) }) // Then implementation export function add(a: number, b: number): number { return a + b }
Example 2: API Endpoint Input: Need user creation endpoint Output:
TypeScript// Test first it('POST /users should create user', async () => { const response = await request(app) .post('/users') .send({ name: 'John', email: 'john@test.com' }) expect(response.status).toBe(201) expect(response.body).toHaveProperty('id') }) // Then implementation app.post('/users', async (req, res) => { const user = await createUser(req.body) res.status(201).json(user) })
Best Practices
Test Writing:
- Write the simplest failing test first
- Test behavior, not implementation
- Use descriptive test names: "should return error when email is invalid"
- Include edge cases: empty strings, null values, boundary conditions
Implementation:
- Write only enough code to make tests pass
- Don't add features not covered by tests
- Keep functions small and focused
- Use meaningful variable names
Refactoring:
- Only refactor when tests are green
- Run tests after each refactoring step
- Extract constants and helper functions
- Improve readability without changing behavior
Coverage:
- Aim for 80% minimum coverage
- 100% for critical business logic
- Include error paths and edge cases
- Test integration points
Common Pitfalls
DON'T write implementation first - Always write test before code
TypeScript// WRONG: Implementation first function calculate(x) { return x * 2 } // RIGHT: Test first it('should double the input', () => { expect(calculate(5)).toBe(10) })
DON'T skip the failing test phase - Must verify test fails before implementing
TypeScript// WRONG: Write test and implementation together // RIGHT: Write test, run it, see it fail, then implement
DON'T test implementation details - Test public behavior
TypeScript// WRONG: Testing internal method calls expect(mockHelper).toHaveBeenCalledWith(data) // RIGHT: Testing output behavior expect(processData(input)).toEqual(expectedOutput)
DON'T ignore test failures - Fix failing tests immediately
TypeScript// WRONG: Commenting out failing tests // it.skip('this test is broken', () => { // RIGHT: Fix the test or the code it('should handle edge case', () => { // Fixed implementation })
DON'T over-mock - Use real objects when possible
TypeScript// WRONG: Mocking simple objects const mockDate = jest.fn().mockReturnValue('2023-01-01') // RIGHT: Use real Date objects const testDate = new Date('2023-01-01')