# Testing Strategy

## Overview

The Oshun monorepo uses a layered testing approach with Vitest for unit and
integration tests, Playwright for E2E tests, and k6 for performance tests.

---

## Test Framework: Vitest

### Configuration Hierarchy

```
testing/
├── vitest.config.base.ts    # Shared base configuration
├── vitest.workspace.ts       # Multi-project workspace definition
├── setup/
│   ├── vitest.setup.ts       # Global test setup
│   └── vitest.jest-compat.ts # Jest compatibility layer
└── ...
```

Each project extends the base configuration with minimal overrides:

```typescript
// libs/{domain}/{lib}/vitest.config.ts
import { defineConfig, mergeConfig } from 'vitest/config';
import baseConfig from '../../../testing/vitest.config.base';

export default mergeConfig(
  baseConfig,
  defineConfig({
    test: {
      // Project-specific overrides only
    },
  })
);
```

### Base Configuration

**Global settings:**

- Environment: `node`
- Globals: enabled (Jest-compatible `describe`, `it`, `expect`)
- ESBuild target: `node20`

**Test file patterns:**

```
src/**/*.{test,spec}.{ts,tsx}
__tests__/**/*.{test,spec}.{ts,tsx}
tests/**/*.{test,spec}.{ts,tsx}
```

**Exclusions:** `node_modules`, `dist`, `build`, `.nx`, E2E tests, integration
tests, performance tests

**Timeouts:**

- Test timeout: 30 seconds
- Hook timeout: 30 seconds
- Teardown timeout: 10 seconds

**Thread pool:**

- CI: Maximum 4 isolated threads
- Development: Unlimited threads

**Retry policy (CI only):**

- Retry count: 2 attempts
- Bail after: 5 failures

### Coverage

**Provider:** v8

**Thresholds (enforced in CI):**

| Metric     | Minimum |
| ---------- | ------- |
| Branches   | 80%     |
| Functions  | 80%     |
| Lines      | 80%     |
| Statements | 80%     |

**Reporters:** text, text-summary, json, html, lcov, cobertura

Coverage reports are generated in each project's `coverage/` directory.

### Path Aliases

The base configuration maps `@oshun/*` and domain-specific imports to source
directories so tests resolve correctly without building first:

```typescript
// Shared libraries
'@oshun/types' → 'libs/shared/types/src'
'@oshun/errors' → 'libs/shared/errors/src'
'@oshun/database' → 'libs/shared/database/src'
// ... (all @oshun/* libraries)

// Domain contracts
'@oshun/contracts/{domain}' → 'libs/contracts/{domain}/src'

// Domain clients
'@oshun/clients/{domain}' → 'libs/shared/clients/{domain}/src'
```

---

## Test Types

### Unit Tests

Run with `pnpm nx test <project>`:

```bash
# Test a specific library
pnpm nx test @oshun/database

# Test with coverage
pnpm nx test @oshun/database --coverage

# Test all affected projects
pnpm nx affected --target=test
```

Unit tests mock external dependencies and focus on individual module behavior.

### Integration Tests

Configuration: `testing/vitest.config.integration.ts`

Integration tests verify interactions between modules and with real databases.
They typically require Docker services to be running:

```bash
# Start infrastructure first
docker compose -f docker/docker-compose.dev.yml up -d

# Run integration tests
pnpm nx test:integration <project>
```

### E2E Tests

Framework: Playwright

Configuration: `testing/e2e/`

E2E tests validate complete user journeys through web applications:

```bash
# Run E2E tests
pnpm nx e2e <project>

# Run with headed browser
pnpm nx e2e <project> --headed
```

The CI pipeline shards E2E tests across 3 workers for faster execution.

### Performance Tests

Framework: k6

Configuration: `testing/performance/`

```bash
# Run performance benchmarks
pnpm nx perf <project>
```

The `benchmarks.yml` workflow runs k6 tests weekly with smoke, load, and stress
modes.

---

## Testing Specialized Areas

### Mobile Tests

Configuration: `testing/mobile/`

Mobile test utilities for React Native apps (Tara, Veritas, Psyche).

### Security Tests

Configuration: `testing/security/`

Security testing utilities including vulnerability scanning and input
validation.

### Chaos Tests

Configuration: `testing/chaos/`

Chaos engineering tests to verify resilience and graceful degradation.

### Boundary Tests

Configuration: `testing/boundary/`

Boundary testing for edge cases and limit validation.

---

## Running Tests

### Common Commands

```bash
# Test a specific project
pnpm nx test @oshun/database

# Test all projects
pnpm test

# Test affected projects only
pnpm nx affected --target=test

# Test with watch mode
pnpm nx test @oshun/database --watch

# Test with coverage
pnpm nx test @oshun/database --coverage

# Run a specific test file
pnpm nx test @oshun/database -- --testPathPattern="sql.spec"
```

### CI Output

In CI, test results are output in multiple formats:

- `test-results/vitest-results.json` - Machine-readable results
- `test-results/junit.xml` - JUnit XML for CI integration
- `test-results/html/` - HTML report for visual inspection

---

## Writing Tests

### Conventions

1. **File naming:** `*.spec.ts` or `*.test.ts` alongside the source file
2. **Describe blocks:** Match the module or function being tested
3. **Test names:** Start with "should" and describe expected behavior
4. **Arrange-Act-Assert:** Structure each test clearly

### Example

```typescript
import { describe, it, expect, vi } from 'vitest';
import { myFunction } from './my-module';

describe('myFunction', () => {
  it('should return the expected result', () => {
    const result = myFunction('input');
    expect(result).toBe('expected');
  });

  it('should throw on invalid input', () => {
    expect(() => myFunction('')).toThrow();
  });
});
```

### Common Patterns

- Use `vi.mock()` for module mocking
- Use `vi.fn()` for function spies
- Use `toEqual()` for deep equality (not `toBe()` for objects)
- Use `toContainEqual()` for array membership with deep equality
- Use `toBeCloseTo()` for floating point comparisons
- Prefix unused parameters with `_` to satisfy
  `@typescript-eslint/no-unused-vars`

---

## Further Reading

- [CI/CD Pipelines](./ci-cd.md) - How tests run in CI
- [Getting Started](./getting-started.md) - Development setup
- [Architecture](./architecture.md) - System architecture
