# fuapi Testing Guide

This document describes the comprehensive test suite for the fuapi framework.

## Test Structure

Tests are located in the `tests/` directory at the project root, separate from the source code.

### Unit Tests
- **`tests/def.test.ts`** - Tests for API definition functionality (`defineAPI` function and type safety)
- **`tests/errors-and-results.test.ts`** - Tests for error classes (`APIError`, `InvalidDTOError`, `InvalidVOError`) and Result types
- **`tests/server.test.ts`** - Tests for server-side implementation (`implApi` function with Express)
- **`tests/client.test.ts`** - Tests for client-side functionality (`callAPI` and `clientOfAPI`)
- **`tests/types.test.ts`** - Tests for type utilities (`ReturnType` and `ArgType` type inference)

### Integration Tests
- **`tests/integration.test.ts`** - End-to-end tests with real HTTP communication between client and server

### Test Setup
- **`tests/setup.ts`** - Global test configuration and utilities

## Running Tests

### Prerequisites
```bash
# Install dependencies
pnpm install
```

### Test Commands
```bash
# Run all tests once
pnpm test:run

# Run tests in watch mode
pnpm test

# Run tests with coverage
pnpm test:coverage
```

## Test Coverage

The test suite covers:

### Core Functionality
- ✅ API definition with all patterns (PlainAPI, ArgAPI, RetAPI, StdAPI)
- ✅ Type safety and inference
- ✅ Request/response validation using Zod schemas
- ✅ Error handling and propagation
- ✅ Server-side implementation with Express
- ✅ Client-side HTTP communication
- ✅ End-to-end integration

### API Patterns Tested

#### PlainAPI (No input/output)
```typescript
const healthApi = defineAPI({ path: '/health' })
```

#### ArgAPI (Input only)
```typescript
const logApi = defineAPI({
  path: '/log',
  dtoSchema: z.object({ message: z.string() })
})
```

#### RetAPI (Output only)
```typescript
const statusApi = defineAPI({
  path: '/status',
  voSchema: z.object({ uptime: z.number() })
})
```

#### StdAPI (Both input and output)
```typescript
const getUserApi = defineAPI({
  path: '/user',
  dtoSchema: z.object({ id: z.string() }),
  voSchema: z.object({ id: z.string(), name: z.string() })
})
```

### Error Scenarios
- Input validation failures (InvalidDTOError)
- Output validation failures (InvalidVOError)
- Server errors (APIError)
- Network errors
- Invalid response formats
- HTTP status code handling

### Type Safety
- Compile-time type checking
- Type inference for different API patterns
- Complex nested data structures
- Optional and default values
- Discriminated unions

## Test Features

### Mocking
- Uses Vitest's built-in mocking capabilities
- Mocks Axios for HTTP requests in unit tests
- Mocks Express handlers and middleware

### Integration Testing
- Real Express server with random port assignment
- Real HTTP requests using Axios
- Full request/response cycle testing
- Error propagation across network boundary

### Type Testing
- Uses `expectTypeOf` from Vitest for compile-time type assertions
- Validates type inference and safety
- Tests complex generic type transformations

## Coverage Thresholds

The test suite maintains high coverage standards:
- Branches: 80%
- Functions: 80%
- Lines: 80%
- Statements: 80%

## Test Utilities

### Mock Data Generation
```typescript
import { testUtils } from './tests/setup'

const testUser = testUtils.generateTestData.user()
const testPost = testUtils.generateTestData.post()
```

### Async Testing Helpers
```typescript
// Create async mock with delay
const slowMock = testUtils.createAsyncMock('result', 100)

// Wait for specific duration
await testUtils.delay(50)
```

## Best Practices

### Test Organization
- Group related tests using `describe` blocks
- Use descriptive test names that explain the scenario
- Follow AAA pattern: Arrange, Act, Assert

### Async Testing
- Always `await` async operations
- Use proper error assertions with `rejects.toThrow()`
- Handle cleanup in `afterEach`/`afterAll`

### Type Testing
- Use `expectTypeOf` for compile-time type assertions
- Test both positive and negative type scenarios
- Validate complex generic type transformations

### Integration Testing
- Start servers on random ports to avoid conflicts
- Clean up resources in `afterAll` hooks
- Test realistic data flows and error scenarios

## Debugging Tests

### Enable Console Output
```typescript
// In test files, access original console
const { originalConsole } = global as any
originalConsole.log('Debug message')
```

### Run Specific Tests
```bash
# Run specific test file
pnpm test def.test.ts

# Run tests matching pattern
pnpm test --grep "should handle StdAPI"
```

### Debug Mode
```bash
# Run with detailed output
pnpm test --verbose

# Run with coverage details
pnpm test:coverage --verbose
```

## Common Issues

### Port Conflicts
Integration tests use random ports, but if you encounter port conflicts:
```bash
# Kill processes using common ports
lsof -ti:3000,8080 | xargs kill -9
```

### TypeScript Issues
Make sure your TypeScript configuration includes test files:
```json
{
  "include": ["./src", "./tests"]
}
```

### Mock Issues
If mocks aren't working properly:
```typescript
// Clear mocks between tests
beforeEach(() => {
  vi.clearAllMocks()
})
```

## Contributing

When adding new features:
1. Write tests first (TDD approach)
2. Ensure all existing tests pass
3. Maintain or improve coverage thresholds
4. Add integration tests for new API patterns
5. Update this documentation

## Performance Considerations

- Integration tests are slower due to real HTTP communication
- Use unit tests for rapid feedback during development
- Run full test suite in CI/CD pipeline
- Consider test parallelization for large test suites